Page-Specific Assets Plugin


#1

Hi,

I’m rying to write a plugin for Jekyll to achieve what I’ve been trying to accomplish with my site but not found a suitable solution for so far. I was hoping if I could get some comments of the design of the plugin/the idea and also some pointers with the code as I’m just searching through the repo and looking through the stack at the moment.

In brief

I would like to be able to add sass to my pages, where the sass file has access to my page variables. That way I can change spoecific elements of the page style in the page front matter rather than create many different styles and include each one

In detail

My site is going to have a number of colour themes, which I’ll call palettes. In addition to this, different page types will have different stylesheets applied to them. So in my page/layout’s frontmatter, I’d like to be able to specify both a colour palette and a stylesheet type (e.g. blog, video, about) and merge the two styles into one sass file that then gets included in the build process.

I know that it is possible to access site variables in sass files not in the _sass folder, and use them in liquid in the sass file. However as the sass is built separately from the pages and the layouts, there’s no way to access the page variables.

Say I want to create a blog post page, so I define a layout for blogs that includes the blog stylesheet. And say I then add the green_palette stylesheet to my page like this:

Page

  • blog layout
    • links to blog stylesheet
  • links to green stylesheet

as far as I know this won’t work, because the blogs stylesheet needs to access the palette to define colours from it and the palette and the blog stylesheets are built separately. Equally, I could set variables in the page’s front matter for the palette and the style:

---
palette: "green"
layout: blog
---

The layout then would have access to the palette name through {{page.palette}} . But the problem persists as the layout is in html and can only include compiled stylesheets. The layout can’t trigger a build of the blog sass stylesheet with the green palette. So again the only option would be to precompile all the possible combinations using a script and then include the right one.

As far as I know I can;t achieve this with sections, because whilst a sass section could get access to the palette name and @include it, if I {% include %} the sass section into my layout or my page, I get a long sass string, not css, so there’d be now way to fit it inline into my page, and neither could I link to a stylesheet built from the section.

The solution:

What I’d like to do is to include a _page_assets folder in the root directory. Then any readable assets, such as stylesheets, yaml, or anything else Jekyll can process, can be put in this folder, or a subdirectory. When a page has the following topmatter:

---
palette: "green"
page_assets: "css/blog.scss"
---

then the plugin is hooked before the build process to build the file _page_assets/css/blog.scss BUT in this file, any liquid references to page variables would be correctly linked. Thus the blog.scss can

@include {{ page.palette }}

and then have access to the colours referenced within. I would propose that the resulting css file output by the build would then go in something like

_site/assets/page_assets/path/to/page.html/blog.css 

and can then be included in the page or layout using a link tag and that path.

So far I have the following code

Jekyll::Hooks.register :pages, :pre_render do |page|

  assets = post.data['page_assets'].split ';'
  asset_dir = post.site.source + '/_page_assets'

  assets.each { |asset|

    asset_path = page.site.source + '/' + asset
    if File.exist? asset then
		
      doc = Jekyll::Document.new asset_path, { :site => page.site, :collection => ???? }
      ren = Jekyll::Renderer.new page.site, document
		
      output = ren.run
		
	else
		Jekyll.logger.warn "The page-specific asset #{asset_path} for page #{page.path} could not be found - skipping"
	end
  }

end

however the run doesn’t seem to work and I’m not sure I’m going about this the right way, but I don’t know where else to start. Ideally I’d just like to trigger a new subbuild in the _page_assets directory with the same configuration, except a separate output directory, and I push the page variables into scope for the build within the directory.

If anyone could provide any pointers I’d be very grateful.

Thanks very much


#2

@stellarpower Why don’t you simply compile your palettes as multiple stylesheets instead?
For example, If your palettes are red, blue, green, then have Jekyll compile into the following:

  • assets/css/red.css,
  • assets/css/blue.css
  • assets/css/green.css.

The source files for them would be:

// assets/css/red.scss

@import "base"; // common styles for all skins.
@import "palettes/red";
// assets/css/blue.scss

@import "base"; // common styles for all skins.
@import "palettes/blue";
// assets/css/green.scss

@import "base"; // common styles for all skins.
@import "palettes/green";

and then your _sass directory will consist of the partials:

_sass/
  _base.scss
  palettes/
    _blue.scss
    _green.scss
    _red.scss

Once you have the multiple stylesheets, you just reference them in your templates:

<head>
  <meta charset="UTF-8"/>
  <title>{{ page.title }}</title>
  <link rel="stylesheet" href="{{ page.palette | append: '.css' | prepend: 'assets/css/' | relative_url }}" />
</head>

#3

Hi @ashmaroli,

That is an option, but it’s simply because there are multipls page styles, so for example the blog style, the about style, and the calendar style all depend on the palette style too, so this requires combining every palette with every page style to get all possibilities. For example blogPostHighlighted may depend on roundedBoxHighlighted which then needs the palette in order to determine the highlight colour. Currently I have a bash script that achieves thisv by combining every palette with every style using @includes but I think it would be useful to have assets that can be compiled with access to information about the page too in a general sense tp save duplication.

Thanks


#4

Seems like a waste of energy. Just make one large CSS file. It gets cached by the browser anyway. Then use page specific classes to load the right style.