Commit Graph

246 Commits

Author SHA1 Message Date
Timothy DeHerrera
8e1f8cbb95 refactor(content): remove gray_matter, manual frontmatter
Implement extract_frontmatter (--- delimiters) and parse_frontmatter
(simple YAML key:value pairs). Handles taxonomies.tags for blog posts.
~70 lines replaces external dependency.
2026-02-05 23:59:53 -07:00
Timothy DeHerrera
8034e24f75 refactor(main): remove walkdir, use recursive std::fs
Add walk_dir/walk_dir_inner helpers (~20 lines) to replace walkdir
crate. Single call site in copy_static_assets didn't justify the
dependency.
2026-02-05 23:55:33 -07:00
Timothy DeHerrera
f1e3add292 chore: add .rustfmt.toml 2026-02-05 23:48:08 -07:00
Timothy DeHerrera
13e728de80 refactor(error): remove thiserror, implement Error manually
Manual Display and Error trait implementations replace derive macro.
Preserves source() chaining for all io::Error and tera::Error variants.
One less dependency, same behavior.
2026-02-05 23:46:14 -07:00
Timothy DeHerrera
15f886735c chore: update predicate and AGENTS.md instruction 2026-02-05 17:28:44 -07:00
Timothy DeHerrera
8df8aa434f fix(render): fix code block rendering and quote escaping
Two issues fixed:

1. Language-less code blocks (``` without lang) were not accumulating
   text content. The guard `code_block_lang.is_some()` was false for
   them, so content fell through to regular text rendering.

   Fix: Add `in_code_block` flag to track code block state separately
   from language presence.

2. Single quotes in code blocks were being HTML-escaped as ',
   breaking CSP headers like 'self' in documentation.

   Fix: Create code_escape/code_escape_into in escape.rs that only
   escapes <, >, & (required to prevent HTML tag injection) but
   preserves quotes (safe inside <pre><code> content).

Rationale for code_escape:
- < and > MUST be escaped to prevent browser interpreting code as HTML
- & MUST be escaped to prevent HTML entity interpretation
- Quotes are safe inside element content (no attribute context)

Also:
- Add test for unlabeled code block quote preservation

All 71 tests pass.
2026-02-05 17:26:17 -07:00
Timothy DeHerrera
1e5ed28788 docs: add security documentation with trust model and CSP
Add Security section to README documenting:
- Trust model (untrusted content, trusted binary)
- HTML passthrough implications
- URL escaping behavior

Create docs/content/features/security.md with:
- Detailed trust model table
- Content processing security notes
- CSP header recommendations
- Platform-specific examples (Cloudflare, Netlify, Nginx)

Closes audit recommendations 4 and 5.
2026-02-05 17:22:34 -07:00
Timothy DeHerrera
6638696dea fix(render): escape URLs in links and images to prevent XSS
Apply html_escape to:
- Link href and title attributes (start_tag_to_html)
- Image src attribute (Event::End TagEnd::Image handler)

Add test cases for:
- Quote-breaking URL attacks
- Link title escaping
- Image src escaping

Addresses HIGH severity finding from security audit.
All 70 tests pass.
2026-02-05 17:10:48 -07:00
Timothy DeHerrera
e4a6305a50 fix(escape): add single-quote escaping to html_escape
Add '\'' → '&#39;' case to html_escape_into for complete XSS
protection in HTML attribute contexts. Update documentation
and add test case.

Addresses LOW severity finding from security audit.
2026-02-05 17:07:54 -07:00
Timothy DeHerrera
899f904160 docs(architecture): update module count and tree-house code example
- Fix module count: 12 → 13 (add escape.rs)
- Add escape.rs to module responsibilities table
- Update code example from old HighlightConfiguration API
  to current tree-house LanguageConfig pattern

Reflects tree-house migration and API coherence audit findings.
2026-02-05 15:09:12 -07:00
Timothy DeHerrera
c60c7851a8 refactor(api): restrict visibility of internal items
- content: DEFAULT_WEIGHT, DEFAULT_WEIGHT_HIGH → pub(crate)
- sitemap: SitemapEntry → pub(crate)

These items are implementation details not exposed to consumers.
2026-02-05 15:03:52 -07:00
Timothy DeHerrera
16f04eb95b refactor: consolidate escape functions and extract weight constants
- Create escape.rs with shared html_escape, html_escape_into, xml_escape
- Remove duplicate implementations from render.rs, highlight.rs, feed.rs, sitemap.rs
- Add DEFAULT_WEIGHT (50) and DEFAULT_WEIGHT_HIGH (99) constants to content.rs
- Replace all magic number weight defaults with named constants

No functional changes; all 67 tests pass.
2026-02-05 14:35:24 -07:00
Timothy DeHerrera
7a7dc929b1 chore: attribute credit to helix 2026-02-05 14:31:13 -07:00
Timothy DeHerrera
af762d0d1f style: use snazzy syntax hl theme for doc site 2026-02-05 13:06:55 -07:00
Timothy DeHerrera
5ae8ae6e53 feat(themes): add popular themes, remove redundant default
- Delete default.css (redundant with dracula.css)
- Add snazzy, catppuccin_mocha, tokyonight, rose_pine, onedark themes
- Update docs/static/style.css to import dracula.css
- Update themes/README.md and syntax-highlighting.md

Theme collection now contains 10 well-designed options.
2026-02-05 13:04:39 -07:00
Timothy DeHerrera
113b7e4a4c docs(themes): add syntax highlighting documentation and test coverage
- Update syntax-highlighting.md with tree-house integration details
- Add themes/README.md explaining copy-to-project workflow
- Add 13 tests: hierarchical scopes, injections (Nix+bash, MD, HTML)
- All 64 tests passing
2026-02-05 12:38:00 -07:00
Timothy DeHerrera
3f218ed49c chore: address clippy lints 2026-02-05 12:26:22 -07:00
Timothy DeHerrera
caf2d506a7 feat(themes): add decoupled CSS theme system with lightningcss bundling
- Add 6 syntax highlighting themes (dracula, gruvbox, nord, github)
- Rewrite css.rs to use lightningcss bundler for @import resolution
- Theme CSS is inlined at build time, producing single bundled output
2026-02-05 12:19:47 -07:00
Timothy DeHerrera
f9a978bdd6 feat(highlight): implement tree-house syntax highlighting engine
Replace tree-sitter-highlight with Helix's tree-house crate for
advanced syntax highlighting:

- Add tree-house and tree-house-bindings dependencies
- Implement SukrLoader with LanguageLoader trait
- Add hierarchical scope resolution with fallback
  (e.g., keyword.control.conditional → keyword.control → keyword)
- Create custom HTML renderer processing HighlightEvents
- Support all 14 languages with Helix queries
- Handle JS/TS inheritance chain (ecma → _javascript/_typescript)

Benefits:
- Richer semantic highlighting with ~75 scope classes
- Proper language injection support
- Hierarchical theme scopes matching Helix themes
- Foundation for converting Helix TOML themes to CSS
2026-02-05 12:04:53 -07:00
Timothy DeHerrera
136be19533 feat(highlight): migrate to tree-house with Helix queries
Replace tree-sitter-highlight dep with tree-house crate from Helix
editor. Add ropey dependency required by tree-house.

Reorganize query files from Helix's runtime/queries/ for all 14
supported languages:
- bash, c, css, go, html, javascript, json, markdown, nix, python,
  rust, toml, typescript, yaml
- Include ecma, _javascript, _typescript base dirs for JS/TS inheritance
- Copy highlights.scm, injections.scm, locals.scm where available

This commit establishes the foundation; highlight.rs implementation
will follow in subsequent commits.
2026-02-04 16:49:04 -07:00
Timothy DeHerrera
98977136c8 feat(docs): add CSS-only scrollspy for TOC navigation
Use CSS Overflow Level 5 properties (scroll-target-group, :target-current)
to highlight the current section in the sidebar TOC as the user scrolls.

Progressive enhancement: gracefully degrades in unsupported browsers
(Firefox, Safari) — they retain existing hover/click behavior.

Browser support: Chrome 140+, Edge 140+, Opera 124+ (~65% global).
2026-02-04 11:26:49 -07:00
Timothy DeHerrera
7af7fa34e4 docs(architecture): add implementation notes on dependency trade-offs
Document that sukr prioritizes output quality over minimal build-time
weight. Acknowledges KaTeX and mermaid-rs are heavier than alternatives,
leaving door open for future evaluation without committing to redesign.
2026-02-04 11:18:13 -07:00
Timothy DeHerrera
6e0d16d1bb docs: clarify JS-free comparison claims
Rename "Zero JS Output" to "JS-Free Rich Content" with footnote
explaining that all generators can produce JS-free basic HTML—sukr's
distinction is built-in build-time math and diagram rendering.
2026-02-04 11:15:45 -07:00
Timothy DeHerrera
d97aec30f4 docs: add comparison with other SSGs
- Create comparison.md documenting sukr vs Zola/Hugo/Eleventy
- Feature matrix covers highlighting, math, diagrams, JS, binary
- Add condensed comparison table to README
- Link to full comparison page at sukr.io
2026-02-01 14:49:37 -07:00
Timothy DeHerrera
5ab8198ddf docs: add architecture documentation
Explains sukr's internal design:
- Pipeline overview with Mermaid flowchart
- Module responsibilities table
- Event-based interception pattern
- Zero-JS philosophy rationale
- Static configuration and single-pass discovery patterns
2026-02-01 14:35:36 -07:00
Timothy DeHerrera
cfb0881d1f refactor(math): use native MathML instead of KaTeX CDN
Remove external KaTeX stylesheet dependency in favor of browser-native
MathML rendering. Aligns with suckless philosophy—zero external deps,
works offline, smaller page loads.

- Remove KaTeX CDN links from base.html
- Hide katex-html layer, let browsers render MathML natively
- Clean up obsolete CSS (.hide-tail, .katex-display)
- Add minimal .math-display for block math layout
2026-02-01 14:09:27 -07:00
Timothy DeHerrera
56ae6c2e67 style(mermaid): add dark theme styling with transparent backgrounds
Override mermaid's default white backgrounds to blend with dark theme:
- Transparent SVG background
- Node fills use --bg-sidebar
- Labels use --fg color
- Edges use --fg-muted
2026-02-01 12:20:58 -07:00
Timothy DeHerrera
04bf87c02a docs(math): render all LaTeX examples
Replace code-only examples with syntax/rendered table showing:
- Greek letters, fractions, subscripts, sums, integrals, roots, matrices

Add display math examples: Gaussian integral, Euler's identity,
Schrödinger equation.
2026-02-01 12:08:52 -07:00
Timothy DeHerrera
96275b0751 doc(README): update content structure 2026-02-01 11:21:49 -07:00
Timothy DeHerrera
73459e5d17 doc(README): update to reflect current state 2026-02-01 11:19:45 -07:00
Timothy DeHerrera
f38303b7e0 docs: document navigation, TOC, and template context
Add comprehensive documentation for recently implemented features:
- [nav] config section (nested, toc toggles)
- Complete frontmatter fields reference (10 fields)
- Hierarchical navigation behavior with ASCII diagram
- Template context: nested_nav, anchors array, page.toc
- Nav item structure including children for nested menus
2026-02-01 11:00:20 -07:00
Timothy DeHerrera
3d5682c59f fix(docs): prevent mermaid diagram overflow on mobile
Add scrollable container rules for .mermaid-diagram in mobile
media query. SVG diagrams now scroll horizontally within their
container instead of extending the page width and obscuring
the hamburger menu.
2026-02-01 10:25:23 -07:00
Timothy DeHerrera
b61e8e8866 chore(fmt): format css 2026-02-01 10:10:40 -07:00
Timothy DeHerrera
e607454af6 feat(css): add :target highlighting for anchor navigation
- Highlight heading with accent border-left when targeted via URL hash
- Show pilcrow anchor visibly on targeted headings
- Add scroll-margin-top for better scroll positioning
2026-02-01 10:10:21 -07:00
Timothy DeHerrera
4392487629 fix(mobile): make nav independently scrollable
- Use viewport-relative max-height instead of fixed 500px
- Add overflow-y:auto for internal scrolling on long anchor lists
2026-02-01 10:04:02 -07:00
Timothy DeHerrera
ce8a9e8f00 feat(ux): add hover-reveal ¶ anchors, strip parens from nav
- Add pilcrow (¶) anchor link after heading text for deep-linking
- CSS: hidden by default, visible on heading hover, user-overridable
- Add strip_parens Tera filter for cleaner nav anchor labels
- Update test expectations for new heading format
2026-02-01 09:57:47 -07:00
Timothy DeHerrera
fc9e75d687 test(nav): add unit tests for anchor extraction and TOC fallback
- test_anchor_extraction: verify h2-h6 extracted, h1 skipped, IDs slugified
- test_slugify_edge_cases: verify special char handling, spaces, case
- test_toc_config_fallback: verify frontmatter override and config default
2026-02-01 09:48:13 -07:00
Timothy DeHerrera
c8c2506e16 feat(config): add global nav.toc setting with frontmatter override
- Add toc: bool to [nav] config section (default: false)
- Frontmatter toc: true/false overrides global config
- If frontmatter toc is not specified, falls back to config.nav.toc
- Enable nav.toc = true in docs/site.toml for global TOC
2026-02-01 09:42:00 -07:00
Timothy DeHerrera
dcc98dccef feat(nav): add anchor TOC in sidebar for toc-enabled pages
- Pass extracted anchors through template context
- Render anchor links under active page when page.toc is true
- Hierarchical indentation by heading level (h2-h6)
- CSS styling: smaller font, muted color, border-left indicator
- Add toc: true to templates.md as example
2026-02-01 09:37:01 -07:00
Timothy DeHerrera
a59b8ff2ab feat(render): add anchor extraction during markdown rendering
- Add Anchor struct with id, label, level fields
- markdown_to_html() now returns (String, Vec<Anchor>) tuple
- Headings h2-h6 are extracted with slugified IDs
- Add toc: bool frontmatter field for per-page TOC opt-in
- All heading tags now include id attributes for anchor links
2026-02-01 09:31:54 -07:00
Timothy DeHerrera
d50a8c3fbe feat(nav): add context-aware expansion for nested navigation
Children are only visible when user is viewing a page within that
section. Uses Tera's starting_with test to detect ancestor relationship.
2026-02-01 09:16:47 -07:00
Timothy DeHerrera
7f765b32e1 feat(nav): complete Tier 1 hierarchical navigation
Add config option [nav] nested (defaults false), update base.html
template with nested nav rendering, and add .nav-children CSS styling
for indented section children.

- Add NavConfig struct with nested: bool
- Template renders item.children in .nav-children div
- CSS: left border + indent for nested items
2026-02-01 09:09:41 -07:00
Timothy DeHerrera
b3a540651a feat(content): add nested children to NavItem for hierarchical nav
Extend NavItem struct with children field to support nested navigation.
discover_nav() now populates children for section items by collecting
section pages via Section::collect_items() and mapping them to child
NavItem entries. Children are sorted by weight then alphabetically.
2026-02-01 09:00:04 -07:00
Timothy DeHerrera
4cd0c86688 fix(docs): prevent table overflow on mobile
Add responsive table rules: horizontal scroll within container,
word-break for inline code, and constrained max-width. Fixes
hamburger menu being pushed off-screen on pages with wide tables.
2026-02-01 08:43:07 -07:00
Timothy DeHerrera
99fc4c0fc7 feat(docs): add responsive hamburger menu with animations
Implement pure CSS mobile navigation with the following features:

- Collapsible sidebar nav hidden behind hamburger toggle on mobile
- Animated hamburger → X icon morph using CSS transforms
- Smooth slide-down transition for nav reveal (max-height/opacity)
- Hamburger positioned on right side of header via absolute positioning
- Uses :has() selector to detect checkbox state without JavaScript
- Overflow fixes to prevent horizontal scroll on mobile devices

The implementation follows suckless principles with zero JavaScript.
2026-02-01 08:32:24 -07:00
Timothy DeHerrera
516df62796 docs(templates): fix Lighthouse SEO and accessibility issues
- Defer KaTeX CDN CSS with media="print" onload pattern
- Add noscript fallback for non-JS browsers
2026-02-01 07:07:40 -07:00
Timothy DeHerrera
3752cc5234 fix(render): properly capture image alt text from markdown
pulldown-cmark emits alt text as Text events between Image start/end
tags. Previously, images were rendered immediately on the Start event
with empty alt text, losing the user-provided description.

Refactored to accumulate alt text using the same pattern as code block
handling: state variables track image attributes and alt content, then
the full <img> tag is rendered on the End event.

Also omits the title attribute entirely when no title is provided,
producing cleaner HTML output.

Fixes Lighthouse "Image elements have [alt] attributes" audit issue.
2026-01-31 22:50:05 -07:00
Timothy DeHerrera
0bb59dd1d5 docs(features): add sitemap documentation
Add docs/content/features/sitemap.md documenting the automatic
XML sitemap generation feature:

- Output location and contents
- Auto-generation behavior
- lastmod date handling
- Linking and validation tips

Follows established pattern from feeds.md.
2026-01-31 22:24:39 -07:00
Timothy DeHerrera
922aeba834 refactor(main): use manifest.homepage in generate_homepage
Eliminate redundant Content::from_path call by using the pre-discovered
manifest.homepage content. Also uses manifest.nav directly.

- Removes dead_code warning on SiteManifest.homepage field
- Reduces I/O by reusing discovered content
- Simplifies function signature (4 args vs 5)
2026-01-31 22:18:49 -07:00
Timothy DeHerrera
759838e7f5 refactor(main): integrate SiteManifest for unified content discovery
Replace separate discover_nav + discover_sections calls with single
SiteManifest::discover() in run() pipeline:

- Update generate_feed() to accept &SiteManifest
- Update generate_sitemap_file() to accept &SiteManifest
- Simplify process_pages() to return Result<()>
- Remove redundant all_posts collection (now in manifest.posts)
- Remove unused discover_nav and discover_sections imports

All 49 tests pass, site builds identically.
2026-01-31 22:13:09 -07:00