assemble / grunt-assemble-permalinks

Permalinks middleware for Assemble, the static site generator for Grunt.js and Yeoman. This plugin enables powerful and configurable URI replacement patterns, presets, uses Moment.js for parsing dates, and much more.
MIT License
43 stars 11 forks source link

index pages #52

Open jonschlinkert opened 10 years ago

jonschlinkert commented 10 years ago

@doowb and I have talked a lot about different approaches to generating index pages for collections, blog posts, etc.

I think this functionality belongs in the permalinks plugin, since a lot of the logic for dynamically generating destination paths is already done.

@doowb / @hariadi, anyone else? thoughts?

doowb commented 10 years ago

I'm not sure it does. I think the generating the index pages is logic for adding dynamically generated pages to the assemble build, then permalinks could run after to modify the destination paths if needed.

The other option is to pull most of the permalinks logic out so other plugins that need to create some form of a permalink path could reuse that code.

jonschlinkert commented 10 years ago

The other option is to pull most of the permalinks logic out so other plugins that need to create some form of a permalink path could reuse that code.

that's what I've been thinking. it's where I was going with the milestone goals

dustintheweb commented 9 years ago

@doowb @jonschlinkert Is this now possible in some way?

I'm using a custom replacement pattern for subcategories, combined w/ the Pretty URL concept:

blog: {
  options: {
    layout: '<%= config.app %>/templates/layouts/blog.hbs',
    permalinks: {
      structure: ':category/:subcat/:basename/index.html'
    }
  },
  files: {
    '<%= config.app %>/blog/': ['<%= config.app %>/templates/blog/**/*.hbs']
  }
}

creating this structure:

/blog
|_ /blog/category/
   |_ /blog/category/subcategory/
      |_ index.html

It would make a ton of sense to have index.html be present in every directory down the cascade so that I could create archive / roll-up pages of the contained categories. Is this now possible?

dustintheweb commented 9 years ago

Update: So I found a way to pull this off in 0.4.42 - albeit it's a bit of a hack...

Just to reiterate, my initial goal was to generate the following type of path:

baseurl/blog/directory/subdirectory/prettyposturl

-- or more specifically, something like

http://dustintheweb.com/blog/design/ux/make-sketch-less-sketchy

while also producing a dedicated index for each directory level down the path (for the purpose of using collection loops that display the contents of contained subdirectories, posts, etc)

Step 1: Gruntfile

assemble: {
  options: {
    flatten: true,
    layout: '<%= config.app %>/templates/layouts/main.hbs',
    partials: ['<%= config.app %>/templates/partials/{,*/}*.hbs'],
    data: '<%= config.app %>/templates/data/*.json',
    plugins: ['brace assemble-contrib-permalinks']
  },
  pages: {
    files: {
      '<%= config.app %>/': ['<%= config.app %>/templates/pages/*.hbs']
    }
  },
  blog: {
    options: {
      collections: [
        { name: 'tier-one', sortorder: 'asc' },
        { name: 'tier-two', sortorder: 'desc' },
        { name: 'post', sortby: 'posted', sortorder: 'desc' }
      ],
      permalinks: {
        structure: ':dir/:sub/:basename/index:ext'
      }
    },
    files: {
      '<%= config.app %>/blog/': ['<%= config.app %>/templates/blog/**/*.hbs']
    },
  },
},

I chose to create my own custom collections for the sake of avoiding confusion in my Front Matter YAML. There is prob a more concise way to do this, but for me it was easier for me to cognitively follow what needed to happen if I just let the permalink plugin do its thing, while separately using custom collections to control sorting, etc

Step 2: .hbs fun time

As you know, the concept behind the assemble-contrib-permalinks is that it takes whatever .hbs files you have in the targeted directory and builds the export path using variables specified in the Front Matter of each file.

Setting this up is super easy from a "post" .hbs, as it just follows whatever trail of variables you tell it and it spits out the index file. From any other perspective however, this gets complicated because the plugin has to parse everything using the same context that is specified in the permalinks structure in the Gruntfile - in this case:dir/:sub/:basename/index:ext. So if you were looking to create cascading archive indexes, you have to find a way to account for instances where a tier1 directory has no parent, and a tier2 directory has no child, in order for the files to end up in the correct place.

Solution

My solution is 2 parts:

  1. In your templates/blog folder create an additional set of .hbs files that will act as your archive indexes. These will be used by the plugin to generate & inject index files where needed.
    • Example: phones.hbs, iphone.hbs, etc
    • For organizational purposes, I use 2 folders: Posts & Categories
      • In Categories you can further organize however you want, remember that this structure has nothing to do with how the plugin will parse things out - it only cares about how the variables are defined in the Front Matter
  2. The hack: For the plugin variables in the Front Matter of the archive .hbs files (dir & sub), you have to use a character that still tells the plugin to observe this file in the build process, but not to give it it's own folder
    • Example Front Matter for a tier 1 directory:
---
dir: .
sub: .
---
---
dir: phones
sub: .
---
---
dir: phones
sub: iphone
---

and so forth. This is how I was able to achieve cascading archive indexes.

Step 3: Collection management

As mentioned earlier, I opted to create custom collections in an effort to keep operations separate in my mind. This does create a small level of redundancy, but its worth it to me as it makes it simpler for understanding the process as a whole.

The following are some examples of archive pages, and what could be done on them:

Blog Index

---
title: Blog Index
meta-title: Blog Index
meta-desc: Blog Index
---
<main role="main">
  <h1>{{title}}</h1>
  <h2>Recent Posts</h2>
    {{#withSort post 'data.posted'}} 
    <ul>
      {{#each this.pages}}
      <li>
        <a href="/blog/{{this.data.class}}/{{this.data.subclass}}/{{basename}}">{{this.data.title}}</a>
     {{/each}}
    </ul> 
    {{/withSort}}

  <h2>All Categories</h2>
  {{#tier-one}}
  <ul>
    {{#each this.pages}}
    <li>
      <a href="/blog/{{this.data.class}}">{{this.data.class}}</a>
    {{/each}}
  </ul>
  {{/tier-one}}
</main>

Tier 1 Index

---
### Build Hooks
dir: .
sub: .

### Collection Hooks
tier-one: true
class: phones

### Details
title: Phones Archive
meta-title: Phones Archive
meta-desc: Phones Archive
---
<main role="main">
  <h1>{{title}}</h1>

  <h2>Phone Posts</h2>
    {{#withSort post 'data.posted'}}
    <ul>
      {{#each this.pages}}
      {{#is this.data.class 'phones'}}
      <li>
        <a href="/blog/{{this.data.class}}/{{this.data.subclass}}/{{basename}}">{{this.data.title}}</a>
      {{/is}}
      {{/each}}
    </ul>
    {{/withSort}}

    <h2>Phones Sub Categories</h2>
    {{#tier-two}}
    <ul>
    {{#each this.pages}}
    {{#is this.data.class 'phones'}}
      <li>
        <a href="/blog/{{this.data.class}}/{{this.data.subclass}}">{{this.data.subclass}}</a>
    {{/is}}
    {{/each}}
    </ul>
    {{/tier-two}}

Tier 2 Index

---
### Build Hooks
dir: phones
sub: .

### Collection Hooks
tier-two: true
class: phones
subclass: iphone

### Details
title: iPhone Archive
meta-title: iPhone Archive
meta-desc: iPhone Archive
---
<main role="main">
  <h1>{{title}}</h1>

  <h2>iPhone Posts</h2>
    {{#withSort post 'data.posted'}}
    <ul>
      {{#each this.pages}}
      {{#is this.data.subclass 'iphone'}}
      <li>
        <a href="/blog/{{this.data.class}}/{{this.data.subclass}}/{{basename}}">{{this.data.title}}</a>
      {{/is}}
      {{/each}}
    </ul>
    {{/withSort}}

Post

---
### Build Hooks
dir: phones
sub: iphone

### Collection Hooks
post: true
class: phones
subclass: iphone

### Details
title: "Post Title"
meta-title: "Post Title"
meta-desc: "Post Title"
posted: Mar 26 2015 GMT-0500 (CST)
---
<main role="main">
    <h1>{{title}}</h1> 
    <p>posted {{timeago posted}}</p>
    <p>blog stuff</p>
</main>

In the not too distant future, I will turn this into a blog post and link back to it - hope it helps some folks!

jonschlinkert commented 9 years ago

This is great! nice work! If you're able to upgrade to assemble v0.6.0 I think you'll be able to achieve a lot more, although we still need to get permalinks working for that version.

In the not too distant future, I will turn this into a blog post and link back to it - hope it helps some folks!

I was about to suggest that before I saw the last line! maybe you can do a guest post for us when we get the site updated :)

dustintheweb commented 9 years ago

@jonschlinkert :+1: hit me back when things are ready to rock & roll.

jonschlinkert commented 9 years ago

I'll make a note of it!