Eleventy-based static site generator that creates a FAQ website for ORC WG's CRA Hub at cra.orcwg.org. The site consumes FAQ content from an external GitHub repository and generates a categorized FAQ website.
- Node.js
- npm
git clone https://github.com/orcwg/cra.orcwg.org.git
cd cra.orcwg.org
npm installnpm run serve- Start development server with live reload (no cache update)npm run watch- Watch for file changes and rebuild (no cache update)npm run build- Build the production site (no cache update)npm run update-cache- Update external content cachenpm run update-cache -- branch-name- Update the external content cache to use a different branch of theorcwg/cra-hubrepositiory. Great for testing the build with unmerged pull requests.
This is an Eleventy site that acts as a content processor and renderer for external FAQ content rather than managing content locally. The site uses a semantic HTML-first architecture with minimal component classes and CSS-only interactions.
- Semantic HTML Elements: Uses native HTML5 elements (
<details>,<summary>,<aside>,<article>) with minimal class names - CSS-Only Interactions: Accordions and animations use native browser features without JavaScript
- Component Independence: Components are self-contained and don't rely on parent context
- Modern CSS Features: Leverages
color-mix(),:has(),:empty, grid template rows, and CSS Custom Properties - Accessibility First: Native HTML semantics provide built-in keyboard navigation and screen reader support
The site uses a hybrid approach combining semantic HTML selectors with light component classes:
Semantic Elements:
<header class="site-header">- Site header with flexbox layout<nav class="site-nav">- Navigation menu<main>- Main content area<footer>- Site footer with grid layout<aside>- Warnings and disclaimers (styled automatically)<blockquote>- Minimal italic quotes
Component Classes:
.section-card- White boxes for FAQ content and list sections.section-intro- Light gray introductory text boxes.card-grid- Responsive card grids (with.half-widthvariant).link-list- FAQ link lists with hover states.faq-accordion-item- Native<details>with CSS animations
Utility Classes:
.badge- Status indicators with semantic color variants.info,.success,.warning,.danger,.important- Semantic colors usingcolor-mix()
- External Content - FAQ content is maintained in the
orcwg/cra-hubrepository - Cache Update - The
update-cache.shscript clones/updates external content into_cache/faq/ - Data Processing -
src/_data/data.jsorchestrates the complete data pipeline:- Text Processing: Markdown to plain text conversion for titles and summaries
- File Operations: Parsing markdown files with frontmatter
- FAQ Processing: Extract questions, answers, and metadata from FAQ markdown files
- Guidance Request Processing: Parse pending guidance request documents
- FAQ List Processing: Load and normalize README.yml files from FAQ subdirectories
- Authors Processing: Load and merge AUTHORS.md from FAQ repository and CONTRIBUTORS.md from website repository
- Cross-referencing: Cross-reference FAQs with guidance requests and lists
- Permalink Generation: URLs computed once in data layer, not reconstructed in templates
- Template Rendering - Nunjucks templates consume processed data using semantic HTML components
- Site Generation - Final site is output to
_site/for deployment
- FAQs: Questions and answers with status tracking (
draft,approved,pending guidance) - Guidance Requests: Items awaiting EU Commission clarification
The data processing pipeline in src/_data/data.js is organized into modular sections:
-
Utility Functions
- Text processing: Convert markdown to plain text for page titles
- File operations: Parse markdown files with frontmatter using gray-matter
-
Content Processors
- FAQs: Extract questions from
#headings, answers from subsequent content, status badges, and GitHub edit links - Guidance Requests: Parse pending guidance documents, extract titles and "Guidance Needed" sections
- FAQ Lists: Load README.yml files from FAQ subdirectories, normalize FAQ references
- Authors: Load and process AUTHORS.md from FAQ repository and CONTRIBUTORS.md from website repository, extract name lists for acknowledgements
- FAQs: Extract questions from
-
Relationship Building
- Link FAQs to their related guidance requests via
guidance-idfrontmatter field - Bidirectionally connect lists with their referenced FAQs
- Each FAQ knows which lists include it; each list knows its FAQs
- Link FAQs to their related guidance requests via
- README.yml files in FAQ subdirectories define FAQ collections
- Each README.yml file creates a new list page at
/lists/{category}/ - Lists reference FAQs by filename (short form) or category/filename (long form)
- FAQ references are automatically normalized to category/filename format
- Lists maintain bidirectional links with FAQs for navigation
- Lists are displayed using native HTML
<details>accordions for compact navigation
The system automatically generates special lists based on FAQ properties. These are configured in the DYNAMIC_LISTS array in src/_data/data.js and are automatically added to the Topics page.
Available Dynamic Lists:
new- FAQs created within the last 30 days (sorted newest first)recently-updated- FAQs updated within the last 14 days (sorted by update date)unlisted- FAQs not yet assigned to any curated list
Configuration Properties:
id- Unique identifier for the listtitle,icon,description- Display metadataemptyMsg- Message shown when the list has no itemsinclusionFilter- Function determining which FAQs to includesortChildren- Optional function to sort FAQs in the listhideInAllFaqsFilter- Function controlling visibility in "All FAQs" viewhideInTopicsFilter- Function controlling visibility in topics viewinsertAt- Position in root list ('top'or'bottom')
How Dynamic Lists Work:
Dynamic lists are generated at build time by the createAndInsertDynamicLists() function:
- Each dynamic list is created from its configuration
- FAQs matching the
inclusionFilterare added as children - Bidirectional parent-child relationships are established
- Children are sorted using
sortChildrenif configured - Metadata (timestamps, visibility) is calculated from children
- Lists are inserted into the root list based on
insertAt:'top'lists appear at the beginning (in array order)'bottom'lists appear at the end (in array order)
Dynamic lists are fully automatic and cannot be manually referenced in YAML files.
The site uses two reusable FAQ components with minimal markup:
-
faq-list-simple.njk- Simple link lists using semantic<ul class="link-list">- Displays FAQ questions as clickable links
- Shows status badges when present
- Used in main FAQ list page and list indexes
-
faq-accordion.njk- Native<details>accordions with CSS-only animations- Uses HTML5
<details>and<summary>elements - Exclusive accordion behavior via
name="faq-accordion"attribute - Smooth open/close animations using CSS grid template rows
- No JavaScript required for accordion functionality
- Used in lists for inline FAQ browsing
- Uses HTML5
Components follow a consistent data pattern:
{% set componentData = {
title: "Section Title",
description: "Optional description",
icon: "π",
faqs: arrayOfFaqObjects
} %}
{% include "components/faq-accordion.njk" %}- Global site settings in
src/_data/site.json - Navigation menu configuration (used in header, homepage cards, and footer)
- List ordering controlled via
listOrderarray - Footer content structured as sections with titles and lists
- Repository:
orcwg/cra-hub - Purpose: Contains all FAQ content and guidance requests in markdown format
- Update: Automatically pulled during builds via
update-cache.sh
- Static Site Generator: Eleventy 3.x
- Template Engine: Nunjucks
- Markdown Processing: markdown-it with GitHub alerts plugin
- Diagram Support: Mermaid.js (for rendering code blocks with
language-mermaid) - CSS Architecture:
- Semantic HTML-first approach with minimal utility classes
- CSS Custom Properties for theming
- Modern CSS features:
color-mix(),:has(),:empty, grid template rows - CSS-only accordions using native
<details>elements
- JavaScript: Minimal - only used for Mermaid diagram initialization (
src/assets/js/site.js)
- Style Guide: Visit
/style-guide/to preview all components, design patterns, and semantic HTML structures used throughout the site. The style guide is excluded from collections but available during development.
.section-card- White content boxes with shadow and border.section-intro- Light gray intro/description sections.card-grid- Responsive grid layout for navigation cards.card- Individual cards with hover effects and animated arrows.link-list- Styled FAQ link lists with badge support.faq-accordion-item- Native<details>elements with CSS animations- Semantic color utilities:
.info,.success,.warning,.danger,.important
The site is deployed to GitHub Pages at cra.orcwg.org with automatic updates triggered by changes to the content repository.
This repository (cra.orcwg.org) acts as the website generator, while orcwg/cra-hub is the content source. The two repositories work together through an automated workflow:
flowchart TD
A[orcwg/cra-hub<br/>Content Repository]
B[Push to main]
C[orcwg/cra.orcwg.org<br/>Website Repository]
D[Push to main]
E[Build and Deploy<br/>GitHub Actions]
F[cra.orcwg.org<br/>Live Website]
A -->|Update content source| B
B -->|Webhook trigger| E
C -->|Update website generator| D
D -->|Direct trigger| E
E -->|Deploy to Pages| F
style A fill:#e1f5ff
style C fill:#fff4e1
style E fill:#ffe1e1
style F fill:#e8f5e9
The website automatically rebuilds and deploys through two triggers:
- Content updates - When content is pushed to
maininorcwg/cra-hub - Website changes - When code is pushed to
mainin this repository
When content is pushed to the main branch of orcwg/cra-hub, a GitHub Action workflow sends a repository_dispatch webhook to trigger a rebuild of this website.
How it works:
- The workflow listens for pushes to the
mainbranch incra-hub - It sends a
repository_dispatchevent with typecra-hub-updateto this repository via the GitHub API using a GitHub token (WEBSITE_DISPATCH_TOKENsecret stored incra-hub).
Note
The WEBSITE_DISPATCH_TOKEN must be renewed annually and requires the permissions listed below.
- Repository access: Only
orcwg/cra.orcwg.org - Contents: Read & Write (required for repository_dispatch)
- Metadata: Read (auto-selected)
When changes are pushed to the main branch of this repository (template updates, styling changes, configuration), the deployment workflow runs directly without needing a webhook.
Both triggers execute the same deployment workflow:
- Pulls latest content from
cra-hubviaupdate-cache.sh - Processes FAQ data through the Eleventy data pipeline
- Generates static HTML pages
- Publishes to GitHub Pages at
https://cra.orcwg.org
For manual deployments or testing, the build process:
- Runs
update-cache.shto clone/updatecra-hubinto_cache/ - Processes FAQ data from cloned repository via
src/_data/data.js - Generates static HTML pages using Eleventy
- Outputs complete site to
_site/directory
When developing locally:
# Start development server (updates cache and serves with live reload)
npm run serve
# Build production site (updates cache and builds)
npm run build
# Manually update content cache only
npm run update-cacheThe update-cache.sh script clones or pulls the latest cra-hub content into _cache/
This project is licensed under the terms of the Apache License Version 2.0.
SPDX-License-Identifier: Apache-2.0