How do you specify a default layout for all pages in eleventy? - eleventy

It seems like you should be able to specify a fallback layout for all pages in an 11ty site using global data files and the data cascade, but I can't figure out how.
I've tried the following JSON in several locations:
{
"layout": "layouts/page.njk"
}
I've put this JSON in:
_data/default.json
_data/site.json
_data/site.11tydata.json
_data/11tydata.json
So far no luck.

This is actually something which is (as far as I'm aware) not yet possible by default in Eleventy. You can use a directory data file to specify a layout for all files nested within that directory, but that doesn't currently work from the root of the project. There was a feature request for this on GitHub.
In that same GitHub issue a workaround was suggested, which works pretty well: namely to make a layout.js file in the _data folder which exports a string pointing to the layout location.
I gave it a quick test just now with the following setup, and it seems to work as desired:
I hope that helps!

My solution is to put all of my template files in a directory called pages. In my .eleventy.js config, I set my input to pages. Ex:
module.exports = eleventyConfig => {
return {
dir: {
input: 'pages',
}
};
};
Then, following the Eleventy documentation, you can set a JSON file in pages called pages.json. That file should look like the following:
{
"layout": "default"
}
And with that, all of my pages, the index page included, default to the default layout. If you need to override a page, you can include the layout in the frontmatter. Or if you want to override everything in the directory, just include a <directory-name>.json file in that directory with the layout specified.
I haven't personally ran into any issues with this setup, and it is an added bonus to keep all of my templates together and not mixed with other config files as well.

The method given by #user13601182 worked for me.
Another option is to add a data file at the top level of your source folder. It needs to have the same name as the folder followed by 11tydata.js or 11tydata.json. For example, if your source folder is named src, the file would be src.11tydata.js or src.11tydata.json
Ex:
src/src.11tydata.js
module.exports = {
// Set a default layout for everything in the src folder and below.
layout: "layouts/default.njk"
}

From the Eleventy docs:
Try adding { "layout": "layouts/post.njk" } to posts/posts.json to configure a layout for all of the templates inside of posts/*.

Related

How to make eleventy include assets such as CSS and images in the output?

I'm trying out the eleventy static site generator for the first time. Whenever I build, the content files are generated just fine, but none of the assets (CSS, JS, images, etc.) end up in the output directory - all that appears is the HTML, with broken links to the assets.
For now I'm using the default directory structure:
project/
_includes/
_site/
css/
index.html
node_modules/
package-lock.json
package.json
I've tried building it just like it is above, and I've tried putting the css in the _includes directory. I also tried putting the css in the output folder (_site/), and that worked, but it seems wrong to have to edit a source file in the output.
I've searched around, but none of the tutorials I've found ever address things like including CSS.
Is there a proper way to go about this that I'm missing, or are you really supposed to edit files in both the source and the output?
The solution was to use passthrough file copy. I hadn't looked into that before because, as a beginner, it seemed like an advanced topic, and I figured something as basic as getting your CSS into the output directory should be some simple setting that's turned on by default. It is simple once you know how to do it, but it's not a default for some reason.
Here's the code that fixed my problem. "_src/assets" is the folder holding all the CSS and images, relative to the project root.
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy("_src/assets");
return {
dir: {
includes: "_templates",
input: "_src",
output: "_site"
}
};
};

How can I reference a script that is in my pages directory?

I'm trying to keep a good practice of keeping context together and in that regard, I like how Razor Pages forces you to place your view models next to its view. I'd like to do this with script files as well.
For example, if script is a bit large and is only used on this particular page, it may not be the cleanest thing to have it in a render section in the cshtml. Instead, I'd want to place it into its own .js file. But to keep the project easy to navigate for team members, I'd like to place that .js file in the same folder next to its view and view model. I'm not sure how to link that file, or if I even can. If I give src a path to the file, it is not found. Assuming that's because wwwroot is the only folder setup to host static files.
Suggestions?
You can add an option to the StaticFilesProvider in your Configure method:
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),"Pages")), RequestPath="/Pages"
});
See the documentation on Static Files in ASP.NET Core: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-2.1

Generate URL of resources that are handled by Grails AssetPipeline

I need to access a local JSON file. Since Grails 2.4 implements the AssetPipeline plugin by default, I saved my local JSON file at:
/grails-app/assets/javascript/vendor/me/json/local.json
Now what I need is to generate a URL to this JSON file, to be used as a function parameter on my JavaScript's $.getJSON() . I've tried using:
var URL.local = ""${ raw(asset.assetPath(src: "local.json")) }";
but it generates an invalid link:
console.log(URL.local);
// prints /project/assets/local.json
// instead of /project/assets/vendor/me/json/local.json
I also encountered the same scenario with images that are handled by AssetPipeline1.9.9— that are supposed to be inserted dynamically on the page. How can I generate the URL pointing this resource? I know, I can always provide a static String for the URL, but it seems there would be a more proper solution.
EDIT
I was asked if I could move the local JSON file directly under the assets/javascript root directory instead of placing it under a subdirectory to for an easier solution. I prefer not to, for organization purposes.
Have you tried asset.assetPath(src: "/me/json/local.json")
The assets plugin looks in all of the immediate children of assets/. Your local.json file would need to be placed in /project/assets/foo/ for your current code to pick it up.
Check out the relevant documentation here which contains an example.
The first level deep within the assets folder is simply used for organization purposes and can contain folders of any name you wish. File types also don't need to be in any specific folder. These folders are omitted from the URL mappings and relative path calculations.

load images from javascript

In my Grails app, I have a dir web-app/images/carousel/slides that contains files such as:
foo.png
foo.thumbnail.png
bar.png
bar.thumbnail.png
My app is using the resources Grails plugin, and the main images are loaded in a GSP using one of it's tags:
<r:img file="carousel/slides/foo.png"/>
which generates:
<img src="/myapp/static/images/carousel/slides/foo.png">
I attempt to load the thumbnail images from JavaScript by constucting a path such as /myapp/static/images/carousel/slides/foo.thumbnail.png. But when I attempt to display one of these images, I get a 404.
Similarly, if enter the following path in the browser's address bar
http://localhost:8080/myapp/static/images/carousel/slides/foo.png
the image displays correctly, but if I enter
http://localhost:8080/myapp/static/images/carousel/slides/foo.thumbnail.png
I get a 404. Why are my thumbnail images not available at the same path at runtime, given that they're in the same source directory? I suspect the answer has something to do with the fact that the main images are loaded using the resources framework whereas I attempt to load the thumbnails from JavaScript.
You mostly answered your own question: if you don't reference the images using resources in some way, then they don't get processed.
Your best bet is to create a resources module that contains a list of all the images. The add this resource to the page.
// grails-app/conf/CarouselResource.groovy
modules = {
carousel {
resource url:'/images/carousel/foo.jpg'
resource url:'/images/carousel/foo.thumbnail.jpg'
...
}
}
then in your GSP
<r:require module="carousel"/>
Now, the module description is a DSL, so you might be able to use some sort of file loop to automatically add all the files, but I'm not 100% sure how. You also might try something like '/images/carousel/**', but the docs don't say if that would work or not.
Also, I should mention, if you use any of the caching-based resources plugins, this won't help. You will then need to manually call r.img() and set it within your JavaScript, something like this (if it works):
<r:script>
var images = [
'${r.img(...)}'
];
</r:script>
This is because the URLs generated using, for example, cached-resources, are often hashes of the file content to allow for long-term caching. They usually are only indirectly related to the original filename.
Update based on comment below:
To load a common JS remotely, but include the images, you could do something like this. Realize, I don't know your carousel code, and you will almost certainly have to modify the carousel library to handle these changes.
<r:script>
window.carouselImages = [
{
image: '${r.external(url:'images/carousel/image1.jpg'}.encodeAsJavaScript();}',
thumbnail: '${r.external(url:'images/carousel/image1.thumbnail.jpg'}.encodeAsJavaScript();}'
},
...
];
</r:script>
<r:resource url="js/carousel.js"/>
Then in carousel.js you reference window.carouselImages to get your array of images. It also should be possible it flip the order, and use some method within carousel.js to add images, like this:
<r:script>
carousel.addImage('${r.external(url:'images/carousel/image1.jpg'}.encodeAsJavaScript();}', '${r.external(url:'images/carousel/image1.thumbnail.jpg'}.encodeAsJavaScript();}');
...
</r:script>
You can improve this by looping over the file list instead of encoding each image explicitly (and example was given in the JIRA I posted below).
Finally, if you aren't going to use any of the caching or file manipulation plugins (so the files always end up at the same URL), you could just simply loop over the files from within the controller or a service method, calling r.img() on each one. This would ensure that they are copied to the static directory. The return value from r.img() can be ignored.
You can use HTML5's data-* Attribute
<element data-*="somevalue">
Here is an example if your image is located at /grails-app/assets/images:
In page (i.e. index.gsp) you have to add the following:
And from the javascript all you have to do is:
<script>
var calImg = document.getElementById('calendar-icon').getAttribute('data-calendaricon');
</script>
Pretty straightforward, moreover it is a clean approach :)

rendering open office files in ruby on rails

I'm trying to render .odf files from a controller action in a rails application. I'd like to be able to put templates inside my view folders called show.odp.erb, show.odf.erb, etc.. and have that represent the content.xml file that is inside the zip. I'd also like to be able to render these actions in the controller like so:
respond_to do |format|
format.odf {
#odf code here
}
format.odp {
#probably about the same as the odf code, but renders a different template with a different file extension.
}
I would also like to have a template content.xml file in my layouts directory that has the necessary headers and footers. The main questions I have are these:
should I put all .odf files in one folder in the layouts directory? or should i put the static ones in the public directory?
how can i insert the dynamic content.xml file into the directory before I zip it up and serve it? I hope this is an easy enough question for a render guru out there ;)
this was not easy. I wound up writing a module, that essentially pulls templates from a directory, applies a layout, zips up the whole package and serves it up. details are included with the module, as it's a bit too complicated to explain here, but it can be found at this pastebin link
hope this helps someone else
-C

Resources