Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 109 additions & 105 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,112 +20,116 @@ const javascript = require("./src/config/processors/javascript");
// 🛠️ Utilities
const filterPostDate = require("./src/config/filters/postDate");
const filterIsoDate = require("./src/config/filters/isoDate");
const filterTitleCase = require("./src/config/filters/titleCase");
const isProduction = process.env.ELEVENTY_ENV === "PROD";

module.exports = function (eleventyConfig) {
// ═════════════════════════════════════════════════════════════════════════
// LANGUAGES
// Using Eleventy's build events to process non-template languages
// Learn more: https://www.11ty.dev/docs/events/
// ═════════════════════════════════════════════════════════════════════════

/*
* JavaScript & CSS Processing
* These processors handle bundling, transpiling, and minification
* - JavaScript: Compiled with esbuild for modern bundling
* - CSS/LESS: Processed and minified for production, including a PostCSS pipeline
*/
eleventyConfig.on("eleventy.after", javascript);
eleventyConfig.on("eleventy.after", less);

// ═════════════════════════════════════════════════════════════════════════
// PLUGINS
// Extend Eleventy with additional functionality
// Learn more: https://www.11ty.dev/docs/plugins/
// ═════════════════════════════════════════════════════════════════════════

/*
* 🖼️ Image Optimization
* Resize and optimize images for better performance using {% getUrl %}
* Documentation: https://github.com/CodeStitchOfficial/eleventy-plugin-sharp-images
*/
eleventyConfig.addPlugin(pluginImages, configImages);

/*
* 🗺️ Sitemap Generation
* Creates sitemap.xml automatically using domain from _data/client.json
* Documentation: https://github.com/quasibit/eleventy-plugin-sitemap
*/
eleventyConfig.addPlugin(pluginSitemap, configSitemap);

/*
* 📦 Production Minification
* Minifies HTML, CSS, JSON, XML, XSL, and webmanifest files
* Only runs during production builds (npm run build)
* Documentation: https://github.com/CodeStitchOfficial/eleventy-plugin-minify
*/
if (isProduction) {
eleventyConfig.addPlugin(pluginMinifier);
}

// ═════════════════════════════════════════════════════════════════════════
// PASSTHROUGH COPIES
// Copy files directly to output without processing
// Learn more: https://www.11ty.dev/docs/copy/
// ═════════════════════════════════════════════════════════════════════════

eleventyConfig.addPassthroughCopy("./src/assets"); // Static assets
eleventyConfig.addPassthroughCopy("./src/admin"); // CMS admin files
eleventyConfig.addPassthroughCopy("./src/_redirects"); // Redirect rules

// ═════════════════════════════════════════════════════════════════════════
// FILTERS
// Transform data in templates at build time
// Learn more: https://www.11ty.dev/docs/filters/
// ═════════════════════════════════════════════════════════════════════════

/*
* 📅 Human-Readable Date Formatting Filter
* Converts JavaScript dates to human-readable format
* Usage: {{ "2023-12-02" | postDate }}
* Powered by Luxon: https://moment.github.io/luxon/api-docs/
*/
eleventyConfig.addFilter("postDate", filterPostDate);

/*
* 📅 ISO Date Formatting Filter
* Converts JavaScript dates to ISO 8601 format
* Usage: {{ "2023-12-02" | isoDate }}
* Powered by Luxon: https://moment.github.io/luxon/api-docs/
*/
eleventyConfig.addFilter("isoDate", filterIsoDate);

// ═════════════════════════════════════════════════════════════════════════
// SHORTCODES
// Generate dynamic content with JavaScript
// Learn more: https://www.11ty.dev/docs/shortcodes/
// ═════════════════════════════════════════════════════════════════════════

/*
* 📆 Current Year Shortcode
* Outputs the current year (useful for copyright notices)
* Usage: {% year %}
* Updates automatically with each build
*/
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);

// ═════════════════════════════════════════════════════════════════════════
// BUILD CONFIGURATION
// Define input/output directories and template engine
// ═════════════════════════════════════════════════════════════════════════

return {
dir: {
input: "src", // Source files directory
output: "public", // Build output directory
includes: "_includes", // Partial templates directory
data: "_data", // Global data files directory
},
htmlTemplateEngine: "njk", // Nunjucks for HTML templates
};
// ═════════════════════════════════════════════════════════════════════════
// LANGUAGES
// Using Eleventy's build events to process non-template languages
// Learn more: https://www.11ty.dev/docs/events/
// ═════════════════════════════════════════════════════════════════════════

/*
* JavaScript & CSS Processing
* These processors handle bundling, transpiling, and minification
* - JavaScript: Compiled with esbuild for modern bundling
* - CSS/LESS: Processed and minified for production, including a PostCSS pipeline
*/
eleventyConfig.on("eleventy.after", javascript);
eleventyConfig.on("eleventy.after", less);

// ═════════════════════════════════════════════════════════════════════════
// PLUGINS
// Extend Eleventy with additional functionality
// Learn more: https://www.11ty.dev/docs/plugins/
// ═════════════════════════════════════════════════════════════════════════

/*
* 🖼️ Image Optimization
* Resize and optimize images for better performance using {% getUrl %}
* Documentation: https://github.com/CodeStitchOfficial/eleventy-plugin-sharp-images
*/
eleventyConfig.addPlugin(pluginImages, configImages);

/*
* 🗺️ Sitemap Generation
* Creates sitemap.xml automatically using domain from _data/client.json
* Documentation: https://github.com/quasibit/eleventy-plugin-sitemap
*/
eleventyConfig.addPlugin(pluginSitemap, configSitemap);

/*
* 📦 Production Minification
* Minifies HTML, CSS, JSON, XML, XSL, and webmanifest files
* Only runs during production builds (npm run build)
* Documentation: https://github.com/CodeStitchOfficial/eleventy-plugin-minify
*/
if (isProduction) {
eleventyConfig.addPlugin(pluginMinifier);
}

// ═════════════════════════════════════════════════════════════════════════
// PASSTHROUGH COPIES
// Copy files directly to output without processing
// Learn more: https://www.11ty.dev/docs/copy/
// ═════════════════════════════════════════════════════════════════════════

eleventyConfig.addPassthroughCopy("./src/assets"); // Static assets
eleventyConfig.addPassthroughCopy("./src/admin"); // CMS admin files
eleventyConfig.addPassthroughCopy("./src/_redirects"); // Redirect rules

// ═════════════════════════════════════════════════════════════════════════
// FILTERS
// Transform data in templates at build time
// Learn more: https://www.11ty.dev/docs/filters/
// ═════════════════════════════════════════════════════════════════════════

// Custom filter to convert file slug to title case (e.g., about-us -> About Us)
eleventyConfig.addFilter("titleCase", filterTitleCase);

/*
* 📅 Human-Readable Date Formatting Filter
* Converts JavaScript dates to human-readable format
* Usage: {{ "2023-12-02" | postDate }}
* Powered by Luxon: https://moment.github.io/luxon/api-docs/
*/
eleventyConfig.addFilter("postDate", filterPostDate);

/*
* 📅 ISO Date Formatting Filter
* Converts JavaScript dates to ISO 8601 format
* Usage: {{ "2023-12-02" | isoDate }}
* Powered by Luxon: https://moment.github.io/luxon/api-docs/
*/
eleventyConfig.addFilter("isoDate", filterIsoDate);

// ═════════════════════════════════════════════════════════════════════════
// SHORTCODES
// Generate dynamic content with JavaScript
// Learn more: https://www.11ty.dev/docs/shortcodes/
// ═════════════════════════════════════════════════════════════════════════

/*
* 📆 Current Year Shortcode
* Outputs the current year (useful for copyright notices)
* Usage: {% year %}
* Updates automatically with each build
*/
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);

// ═════════════════════════════════════════════════════════════════════════
// BUILD CONFIGURATION
// Define input/output directories and template engine
// ═════════════════════════════════════════════════════════════════════════

return {
dir: {
input: "src", // Source files directory
output: "public", // Build output directory
includes: "_includes", // Partial templates directory
data: "_data", // Global data files directory
},
htmlTemplateEngine: "njk", // Nunjucks for HTML templates
};
};
87 changes: 44 additions & 43 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
{
"name": "intermediate-website-kit-less",
"version": "2.0.1",
"description": "The official CodeStitch Intermediate kit, featuring 11ty, Decap CMS and LESS - all set up for you! Perfect for websites of all sizes.",
"main": "index.js",
"scripts": {
"watch:cms": "npx decap-server",
"watch:eleventy": "cross-env ELEVENTY_ENV=DEV eleventy --serve",
"build:eleventy": "cross-env ELEVENTY_ENV=PROD eleventy",
"start": "run-p watch:*",
"build": "run-s build:*",
"preview": "cross-env ELEVENTY_ENV=PROD eleventy --serve",
"remove-dark-mode": "node scripts/remove-dark-mode.js",
"remove-decap": "node scripts/remove-decap.js",
"remove-demo": "node scripts/remove-demo.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/CodeStitchOfficial/Intermediate-Website-Kit-LESS.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/CodeStitchOfficial/Intermediate-Website-Kit-LESS/issues"
},
"homepage": "https://github.com/CodeStitchOfficial/Intermediate-Website-Kit-LESS#readme",
"dependencies": {
"@11ty/eleventy": "^3.1.2",
"@codestitchofficial/eleventy-plugin-minify": "^1.1.3",
"@codestitchofficial/eleventy-plugin-sharp-images": "^2.2.0",
"@quasibit/eleventy-plugin-sitemap": "^2.2.0",
"autoprefixer": "^10.4.27",
"codestitch-sharp-image-automation": "^0.4.0",
"cross-env": "^10.1.0",
"cssnano": "^7.1.2",
"decap-server": "^3.5.2",
"esbuild": "^0.27.3",
"glob": "^13.0.6",
"less": "^4.5.1",
"netlify-plugin-cache": "^1.0.3",
"npm-run-all2": "^5.0.2",
"postcss": "^8.5.6"
}
"name": "intermediate-website-kit-less",
"version": "2.0.1",
"description": "The official CodeStitch Intermediate kit, featuring 11ty, Decap CMS and LESS - all set up for you! Perfect for websites of all sizes.",
"main": "index.js",
"scripts": {
"watch:cms": "npx decap-server",
"watch:eleventy": "cross-env ELEVENTY_ENV=DEV eleventy --serve",
"build:eleventy": "cross-env ELEVENTY_ENV=PROD eleventy",
"start": "run-p watch:*",
"build": "run-s build:*",
"preview": "cross-env ELEVENTY_ENV=PROD eleventy --serve",
"remove-dark-mode": "node scripts/remove-dark-mode.js",
"remove-decap": "node scripts/remove-decap.js",
"remove-demo": "node scripts/remove-demo.js",
"create-page": "node scripts/create-page.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/CodeStitchOfficial/Intermediate-Website-Kit-LESS.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/CodeStitchOfficial/Intermediate-Website-Kit-LESS/issues"
},
"homepage": "https://github.com/CodeStitchOfficial/Intermediate-Website-Kit-LESS#readme",
"dependencies": {
"@11ty/eleventy": "^3.1.2",
"@codestitchofficial/eleventy-plugin-minify": "^1.1.3",
"@codestitchofficial/eleventy-plugin-sharp-images": "^2.2.0",
"@quasibit/eleventy-plugin-sitemap": "^2.2.0",
"autoprefixer": "^10.4.27",
"codestitch-sharp-image-automation": "^0.4.0",
"cross-env": "^10.1.0",
"cssnano": "^7.1.2",
"decap-server": "^3.5.2",
"esbuild": "^0.27.3",
"glob": "^13.0.6",
"less": "^4.5.1",
"netlify-plugin-cache": "^1.0.3",
"npm-run-all2": "^5.0.2",
"postcss": "^8.5.6"
}
}
35 changes: 35 additions & 0 deletions scripts/create-page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const fs = require("fs");
const path = require("path");

const input = process.argv[2];

if (!input) {
console.log('Please provide page names. Example: npm run create-page -- "Contact, About, Services"');
process.exit(1);
}

const pages = input.split(",").map((p) => p.trim());

const templatePath = path.join("src/content/pages", "_template.txt");
let template = fs.readFileSync(templatePath, "utf8");

pages.forEach((page) => {
const slug = page
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, "")
.replace(/\s+/g, "-")
.replace(/-+/g, "-")
.replace(/^-+|-+$/g, "");

if (!slug) return;

const htmlPath = path.join("src/content/pages", `${slug}.html`);
const lessPath = path.join("src/assets/less", `${slug}.less`);

// const pageTemplate = template.replaceAll("{{PAGE}}", slug);

fs.writeFileSync(htmlPath, template);
fs.writeFileSync(lessPath, "");

console.log(`Created ${htmlPath} and ${lessPath}`);
});
8 changes: 8 additions & 0 deletions src/config/filters/titleCase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function filterTitleCase(value) {
return value
.split("-")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(" ");
}

module.exports = filterTitleCase;
27 changes: 22 additions & 5 deletions src/content/pages/_template.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
---
title: "Page title for <title> and OG tags"
description: "Description for <meta> description and OG tags"
permalink: "/page-path/"
description: "Meta description for the page"
image: "OPTIONAL - If an image path is specified here, it will be used for that page's OG image. Useful for blog posts (implemented as standard with this kit)"
eleventyComputed:
title: "{{ page.fileSlug | titleCase }} | {{ client.name }} | {{ client.address.city }}, {{ client.address.state }}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd rather NOT have an opinionated, computed value for the title to keep it simple for the developer. Current pages use a simple string value for the title, and the computed version requires some level of understanding of the Eleventy cascade and project.
Thoughts?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I fully understand where your coming from, the way that I see it is that most people would follow the original title structure in the kit which is "About Us | Johns Plumbing", and instead of manually typing it as a string, it could be automated, with the addition of "City, State" so "About Us | Johns Plumbing | Calgary, AB".

Yes you are correct that it requires some level of understanding, but so does the rest of the kit, in my opinion.

permalink: "/{{ page.fileSlug | slugify }}/"
---


{% extends "layouts/base.html" %}

{% block head %}
<!-- Any page-specific tags that belong in the <head>, such as a page-specific stylesheet -->

<link rel="stylesheet" href="/assets/css/{{ page.fileSlug }}.css">

<!-- Any page-specific tags that belong in the <head> -->


{% endblock %}

{% block body %}

<!-- Page HTML goes here, without a <main> wrapper. The <main> tag is already presented in layouts/base.html -->
{% endblock %}

<!-- If you want the page to have a "CTA", uncomment the line below -->

<!-- {% include 'sections/cta.html' %} -->

{% endblock %}




Loading