11ty / eleventy

A simpler site generator. Transforms a directory of templates (of varying types) into HTML.
https://www.11ty.dev/
MIT License
17.03k stars 492 forks source link

How do I generate a site with one template and many data files in sub folders? #1261

Open markboulton opened 4 years ago

markboulton commented 4 years ago

I have 56 json files in a _data/languages subfolder – one for each language – labelled 'english.json', 'arabic.json' etc. In each json file is an array of objects structured like this:

[
  {
    "id": "01",
    "content": "هلا سكنت بذي ضغثٍ فقد زعموا — شخصت تطلب ظبياً راح مجتازا",
    "notes": "",
    "source" : "Wikipedia"
   },
  {
    "id": "02",
    "content": "اصبر على حفظ خضر واستشر فطنا، وزج همك في بغداذ منثملا",
    "notes": "",
    "source" : "Wikipedia 2014."
   }
]

I'm using nunjucks for my templating.

What I'd like to do is build a single page for each language (one for each json file), and build navigation to navigate between them. I'm sure this is possible using a single template, but I can't seem to figure it out. Any pointers?

denisbrodbeck commented 4 years ago

@markboulton I've done something similar before.

Here's a minimal project to get you started. Also, check out the docs for JavaScript Data Files and Create Pages From Data.

// package.json
{
  "name": "the-website",
  "version": "0.1.0",
  "description": "A business website 👌",
  "private": true,
  "scripts": {
    "start": "npm run dev",
    "dev": "npm run clean eleventy:dev",
    "build": "run-s clean eleventy:prod",
    "eleventy:dev": "cross-env NODE_ENV=development eleventy --serve",
    "eleventy:prod": "cross-env NODE_ENV=production eleventy",
    "clean": "shx rm -rf ./dist/*",
    "format": "prettier --write \"src/**/*.{css,html,js,json,md}\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "@11ty/eleventy": "^0.11.0",
    "@11ty/eleventy-plugin-rss": "^1.0.7",
    "cross-env": "^7.0.2",
    "npm-run-all": "^4.1.5",
    "prettier": "^2.0.5",
    "shx": "^0.3.2"
  }
}
// .eleventy.js
const isProduction = process.env.NODE_ENV === `production`;

module.exports = function (config) {
  // Plugins
  config.addPlugin(require(`@11ty/eleventy-plugin-rss`));
  // More config...

  // Base Config
  return {
    dir: {
      input: `src`,
      output: `dist`,
      includes: `_includes`,
      layouts: `_layouts`,
      data: `_data`,
    },
    templateFormats: [`njk`, `md`, `11ty.js`],
    htmlTemplateEngine: `njk`,
    markdownTemplateEngine: `njk`,
  };
};
// src/page.11ty.js
exports.data = () => ({
  title: `Default Title`,
  layout: `base.njk`,
  pagination: {
    data: `pages`,
    size: 1,
    alias: `page`,
    addAllPagesToCollections: true,
  },
  permalink: ({ page }) => `/${page.language}/${page.id}/index.html`,
});

exports.render = ({ page }) => `
<div>
  <div>${page.content}</div>
  <div>${page.source}</div>
  <div>${page.notes}</div>
</div>`;
{# src/_layouts/base.njk #}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ page.title if page.title else title }}</title>
  </head>
  <body>
    <div>
      {{ content | safe }}
    </div>
  </body>
</html>
// src/_data/pages.js
const fs = require(`fs`);
const path = require(`path`);

module.exports = async () => {
  const result = [];
  const files = await fs.promises.readdir(path.join(__dirname, `languages`));
  for (const file of files) {
    const data = await fs.promises.readFile(
      path.join(__dirname, `languages/${file}`),
      { encoding: `utf8` }
    );
    const pages = JSON.parse(data).map((page) => {
      page.date = new Date(); // each pagination object needs a date
      page.language = file.substring(0, file.indexOf(`.json`)); // add extra meta
      page.title = `${page.language} - ${page.id}`; // some title
      return page;
    });
    result.push(...pages);
  }
  return result;
};
// src/_data/languages/arabic.json
[
  {
    "id": "01",
    "content": "هلا سكنت بذي ضغثٍ فقد زعموا — شخصت تطلب ظبياً راح مجتازا",
    "notes": "",
    "source": "Wikipedia"
  },
  {
    "id": "02",
    "content": "اصبر على حفظ خضر واستشر فطنا، وزج همك في بغداذ منثملا",
    "notes": "",
    "source": "Wikipedia 2014."
  }
]
// src/_data/languages/english.json
[
  {
    "id": "01",
    "content": "lorem ipsum dolor 01",
    "notes": "",
    "source": "Wikipedia"
  },
  {
    "id": "02",
    "content": "lorem ipsum dolor 02",
    "notes": "",
    "source": "Wikipedia 2014."
  }
]
markboulton commented 4 years ago

@denisbrodbeck This is great! Thank you. Works like a charm! One slight thing: how would I need to tweak this to build just one page per language json file? Thanks for your help!

markboulton commented 4 years ago

@denisbrodbeck This is great! Thank you. Works like a charm! One slight thing: how would I need to tweak this to build just one page per language json file? Thanks for your help!

I should clarify - in addition to building a page for each. So, sort of an index page which would link to each further generated page.