ultimate-jekyll-manager 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/.claude/scheduled_tasks.lock +1 -0
  2. package/CHANGELOG.md +68 -1
  3. package/CLAUDE.md +36 -15
  4. package/README.md +4 -2
  5. package/TODO-AUTH-TESTING.md +1 -1
  6. package/dist/assets/js/libs/form-manager.js +4 -1
  7. package/dist/assets/js/pages/payment/confirmation/index.js +9 -0
  8. package/dist/assets/themes/newsflash/README.md +58 -0
  9. package/dist/assets/themes/newsflash/_config.scss +138 -0
  10. package/dist/assets/themes/newsflash/_theme.js +27 -0
  11. package/dist/assets/themes/newsflash/_theme.scss +37 -0
  12. package/dist/assets/themes/newsflash/css/base/_mixins.scss +50 -0
  13. package/dist/assets/themes/newsflash/css/base/_root.scss +134 -0
  14. package/dist/assets/themes/newsflash/css/base/_typography.scss +49 -0
  15. package/dist/assets/themes/newsflash/css/base/_utilities.scss +58 -0
  16. package/dist/assets/themes/newsflash/css/components/_badges.scss +65 -0
  17. package/dist/assets/themes/newsflash/css/components/_buttons.scss +139 -0
  18. package/dist/assets/themes/newsflash/css/components/_cards.scss +52 -0
  19. package/dist/assets/themes/newsflash/css/components/_editorial.scss +182 -0
  20. package/dist/assets/themes/newsflash/css/components/_forms.scss +75 -0
  21. package/dist/assets/themes/newsflash/css/components/_infinite-scroll.scss +102 -0
  22. package/dist/assets/themes/newsflash/css/components/_panels.scss +91 -0
  23. package/dist/assets/themes/newsflash/css/components/_ticker.scss +70 -0
  24. package/dist/assets/themes/newsflash/css/layout/_general.scss +264 -0
  25. package/dist/assets/themes/newsflash/css/layout/_navigation.scss +164 -0
  26. package/dist/assets/themes/newsflash/js/initialize-tooltips.js +20 -0
  27. package/dist/assets/themes/newsflash/js/masthead-scroll.js +29 -0
  28. package/dist/assets/themes/newsflash/pages/404/index.scss +27 -0
  29. package/dist/assets/themes/newsflash/pages/about/index.scss +70 -0
  30. package/dist/assets/themes/newsflash/pages/blog/index.scss +17 -0
  31. package/dist/assets/themes/newsflash/pages/blog/post.js +29 -0
  32. package/dist/assets/themes/newsflash/pages/blog/post.scss +164 -0
  33. package/dist/assets/themes/newsflash/pages/index.scss +159 -0
  34. package/dist/assets/themes/newsflash/pages/pricing/index.scss +194 -0
  35. package/dist/assets/themes/newsflash/pages/test/libraries/layers/index.js +9 -0
  36. package/dist/assets/themes/newsflash/pages/test/libraries/layers/index.scss +7 -0
  37. package/dist/commands/blogify.js +6 -3
  38. package/dist/commands/test.js +34 -5
  39. package/dist/defaults/CLAUDE.md +17 -4
  40. package/dist/defaults/dist/_includes/core/pricing/resolve-plan.html +59 -0
  41. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/footer.html +20 -3
  42. package/dist/defaults/dist/_layouts/themes/classy/admin/core/minimal-viewport-locked.html +1 -1
  43. package/dist/defaults/dist/_layouts/themes/classy/admin/core/minimal.html +1 -1
  44. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +5 -40
  45. package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/pages/pricing.html +33 -34
  46. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/core/base.html +61 -0
  47. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/404.html +86 -0
  48. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/about.html +353 -0
  49. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/categories/category.html +105 -0
  50. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/categories/index.html +93 -0
  51. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/index.html +373 -0
  52. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/post.html +289 -0
  53. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/tags/index.html +90 -0
  54. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/tags/tag.html +107 -0
  55. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/contact.html +340 -0
  56. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/index.html +522 -0
  57. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/pricing.html +485 -0
  58. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/team/index.html +207 -0
  59. package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/team/member.html +134 -0
  60. package/dist/defaults/test/README.md +4 -0
  61. package/dist/gulp/tasks/jekyll.js +4 -2
  62. package/dist/test/runner.js +50 -3
  63. package/dist/test/suites/build/attach-log-file.test.js +102 -0
  64. package/dist/test/suites/build/theme-contract.test.js +173 -0
  65. package/dist/test/utils/extended-mode-warning.js +13 -0
  66. package/dist/utils/attach-log-file.js +70 -43
  67. package/docs/appearance.md +1 -0
  68. package/docs/assets.md +9 -0
  69. package/docs/audit.md +27 -7
  70. package/docs/build-system.md +57 -0
  71. package/docs/common-mistakes.md +15 -0
  72. package/docs/{project-structure.md → directory-structure.md} +1 -1
  73. package/docs/environment-detection.md +1 -1
  74. package/docs/javascript-libraries.md +38 -1
  75. package/docs/layouts-and-pages.md +146 -0
  76. package/docs/local-development.md +1 -8
  77. package/docs/logging.md +30 -0
  78. package/docs/migration.md +131 -0
  79. package/docs/no-inline-scripts.md +304 -0
  80. package/docs/purgecss.md +164 -0
  81. package/docs/seo.md +131 -4
  82. package/docs/templating.md +23 -0
  83. package/docs/test-boot-layer.md +1 -1
  84. package/docs/test-framework.md +56 -8
  85. package/docs/themes.md +254 -13
  86. package/logs/test.log +111 -0
  87. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"sessionId":"76fefdf0-10f3-4795-b5eb-56e35f724e5e","pid":53082,"procStart":"Wed Jun 10 11:57:56 2026","acquiredAt":1781141001890}
package/CHANGELOG.md CHANGED
@@ -14,6 +14,73 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
14
14
  - `Fixed` for any bug fixes.
15
15
  - `Security` in case of vulnerabilities.
16
16
 
17
+ ---
18
+ ## [1.8.0] - 2026-06-11
19
+
20
+ ### Added
21
+
22
+ - **`docs/migration.md` + expanded `docs/audit.md` + dashboard-pages pattern (action-skill consolidation).** The standalone `UJM:migrate`/`UJM:audit`/`UJM:new-page`/`UJM:new-site` skills were deleted and folded into `omega:ujm` as process checklists; their framework facts landed in the repo: new `docs/migration.md` (full old-UJ→UJM migration incl. `_legacy/` flow + config re-mapping, `_config.yml` quick-fix key schema, revert-posts procedure), `docs/audit.md` expanded to the full two-stage workflow (AI content pass → `npx mgr audit` fix loop), and `docs/layouts-and-pages.md` gained the dashboard list/detail/edit page pattern (separate pages, `?id=` redirects, breadcrumbs).
23
+ - **Dev-process guidance relaxed: only `npm start` is off-limits.** The "NEVER run" rule in CLAUDE.md + `src/defaults/CLAUDE.md` now prohibits only the long-running dev server (instruct the user to start it if it isn't running; read `logs/*.log`, never tail the process) — `npx mgr test` and `npm run build` are fine to run.
24
+ - **Skills-as-routers migration — `docs/no-inline-scripts.md` + `docs/purgecss.md` (new), plus `seo.md` / `layouts-and-pages.md` / `javascript-libraries.md` / `assets.md` extensions.** Framework facts migrated from the `omega:ujm` skill into the repo so they version-match the installed package: `no-inline-scripts.md` carries the full hard-rule playbook (where scripts move, Liquid `data-*`/`<template>`/conditional bridges, window-global callbacks, step-by-step migration, verification grep); `purgecss.md` carries the safelist playbook (two locations, RegExp anchoring, `variables: false` gotcha, per-file processing, current UJM safelist, category guide); `seo.md` retitled "SEO & Content" and gains the content writing rules (action-verb H1s, sentence case, headline/accent structure, frontmatter SEO, superheadline rules) + Services and Solutions page strategies + alternatives content guidelines; `layouts-and-pages.md` gains default-page customization rules (.md vs .html, page exclusions), the per-page customization-levels table (homepage/pricing/about/contact/download incl. hero display modes, pricing feature comments, testimonial/FAQ guidelines), and the custom-page creation checklist; `javascript-libraries.md` gains the reads-vs-writes rule (Firestore SDK for dashboard reads, Cloud Functions for writes) + Firestore read examples; `assets.md` gains the account-dropdown item field reference. The `data-wm-bind` deep reference moved to `web-manager/docs/bindings.md` (the module that owns the feature). All indexed in CLAUDE.md; the skill is now a thin router (pointers + hard rules + process checklists).
25
+
26
+ ### Changed
27
+
28
+ - **Router skill renamed `UJM:patterns` → `omega:ujm`** — all framework skills now live under the `omega:` namespace (`omega:em`/`omega:bxm`/`omega:ujm`/`omega:bem` + the `omega:main` hub). CLAUDE.md's Recommended skills section updated.
29
+ - **newsflash homepage post slots are strictly deduplicated.** Each section consumes its own slice of `site.posts` so no story repeats down the page: hero = post 1, top stories = 2–4, "the latest" feed = 5–9, most-read rail = 10–14, "more to chew on" = 15–17 (only the ticker repeats the latest — it's chrome, not content). Sections disappear gracefully when the site doesn't have enough posts to fill their slice.
30
+ - **Dev builds raise `--limit_posts` from 15 to 18** so a fully-populated newsflash front page (17 distinct posts) is visible during development (`--all-posts` still disables the cap entirely).
31
+ - **Footer appearance picker is now icon-only.** The toggle button in classy's and newsflash's footers shows just the mode icon (`data-appearance-icon` spans) — the `data-appearance-current` text label was removed from the button (the mode words remain in the dropdown items). Pure HTML change; the framework `data-appearance-*` logic is untouched. Docs updated in [docs/themes.md](docs/themes.md#the-appearance-picker-is-required-in-every-footer) + [docs/appearance.md](docs/appearance.md).
32
+ - **newsflash homepage desk cards link to their category pages.** Each desk card is now a story-card link (`href` per item, falling back to the slugified title → `/blog/categories/<slug>`) with a "Read the desk" affordance.
33
+ - **newsflash testimonials moved from the homepage to the about page.** The "From our readers" quote-card section (universal `testimonials` key) now lives on about between the principles and the team CTA; the `.quote-card` styles moved from the homepage page CSS to the about page CSS.
34
+ - **newsflash nav + footer include forks deleted — chrome now inherits from classy.** The nav fork was a verbatim copy of classy's (the fallback regenerates an identical file); the footer's editorial look (oversized serif wordmark, hidden avatar, 24em description measure, panel-color repaints of the `.link-muted`/`.text-body` utilities, weight-800 volt column heads) was ported into the theme's `_general.scss` footer rules, so classy's inherited markup renders the same ink-slab design in both modes.
35
+ - **Classy footer language icon is now theme-adaptive.** The language dropdown button's hardcoded multicolor inline SVG (fixed fills that ignored `currentColor` and clashed on dark surfaces like newsflash's ink-slab footer) is replaced with `{% uj_icon "language" %}`, which inherits the button's color in every theme and mode.
36
+ - **`docs/project-structure.md` renamed `docs/directory-structure.md`** (H1 `# Project Structure` → `# Directory Structure`) for cross-framework doc-file parity — BEM names the same concept `docs/directory-structure.md`, and mirrored docs must match down to the file name. All references updated (`CLAUDE.md`, historical CHANGELOG links). Also normalized `docs/test-boot-layer.md`'s H1 to `# Test Framework — Boot Layer` (matches BXM; EM normalized likewise).
37
+
38
+ ### Added
39
+
40
+ - **Docs parity — new `docs/build-system.md`, `docs/templating.md`, `docs/logging.md`, `docs/common-mistakes.md`.** `build-system.md` makes CLAUDE.md's existing pipeline-reference link real (was a dead link) — gulp task list, config flow, build modes, pure helpers; `templating.md` graduates from "(planned)" — node-powertools bracket conventions + Liquid coexistence; `logging.md` is now the SSOT for the log-file tee (extracted from local-development.md, which keeps a pointer — mirrors EM/BXM); `common-mistakes.md` extracts the canonical anti-pattern list into the repo (BEM already had one). All indexed in CLAUDE.md → Documentation.
41
+ - **Test coverage convention (docs).** New mirrored "Test coverage" sections in `CLAUDE.md`, `docs/test-framework.md`, `src/defaults/CLAUDE.md`, and `src/defaults/test/README.md` — every feature ships with tests at every layer it has a surface in (logic `build`/`page`, UI `page`, end-to-end `boot`); a layer is skipped only when the feature genuinely has no surface there. Mirrored across EM/BXM/BEM.
42
+ - **New `newsflash` theme — editorial news site.** Paper + ink + vermilion design language with volt highlights: Fraunces serif headlines over Schibsted Grotesk, a live news-ticker marquee above the sticky blurred masthead, framed editorial images, hard-offset "lift" pill buttons, film-grain overlay, and first-class dark mode (deep warm near-black paper, cream ink). Ships custom layouts for base (fonts + ticker), homepage (cover-story hero + top-story tiles + "the latest" editorial post feed with sticky most-read/newsletter rails + numbered rundown playbook + "more to chew on" story tiles + dark big-read CTA band), blog index (lead-story splash + editorial tiles), blog post (reading-progress bar, drop cap, serif crossheads, pullquotes, author card), blog category archives (desk directory with stroked story-count numerals + per-desk fronts), blog tag archives (topics wall + per-topic fronts), pricing (membership tiers with "Editor's pick" + flash-sale promo banner), about (newsroom timeline), contact ("contact the desk" + tips line), team ("the masthead" byline cards + ink-slab charter + newsroom principles), team member (reporter profile with beat facts strip), and a 404 "correction notice". Functional pages (download, feedback, updates, auth, account) intentionally inherit classy markup restyled. Select with `theme.id: "newsflash"`. See [docs/themes.md](docs/themes.md).
43
+ - **Theme-authoring convention: genre-native frontmatter defaults.** A theme's layout frontmatter defaults are part of its identity and must be written for the theme's genre (newsflash ships news copy + news-purposed `rundown`/`desks` homepage sections), never copied from classy's SaaS demo data. Universal section keys (`hero`, `cta`, `stats`, `faqs`, `pricing.plans`, …) stay shared so consumer overrides survive theme swaps. Documented in [docs/themes.md](docs/themes.md#frontmatter-defaults-are-part-of-the-themes-identity) + the Path A authoring checklist.
44
+ - **Appearance picker in every footer.** Classy's footer now ships the appearance (light/dark/system) dropdown next to the language dropdown — a pure drop-in block driven by the framework's `data-appearance-*` attributes. Every theme inherits it via the footer fallback; themes with custom footers (newsflash) include it themselves. Documented as required footer furniture in [docs/themes.md](docs/themes.md) + [docs/appearance.md](docs/appearance.md).
45
+ - **Theme-authoring convention: inherit classy's nav + footer chrome, restyle via CSS.** Themes do NOT fork the chrome includes — `copyFallbackThemeFiles()` supplies classy's nav/footer (with paths rewritten into the theme's namespace) and the chrome's identity comes from theme CSS (newsflash's serif masthead + editorial ink-slab footer are pure `css/layout/` restyles of classy's markup). Fork an include only when the structure genuinely diverges — a re-skin fork is a copy that silently drifts (newsflash's nav fork had diverged from classy by nothing but a comment, and the icon-only picker fix had to be applied twice). Documented in [docs/themes.md](docs/themes.md) + the Path A authoring checklist.
46
+ - **Theme-contract build test.** New `mgr:build/theme-contract` suite turns the docs/themes.md conventions into executable assertions, globbing every shipped theme (`_template` included) so a new theme is covered the moment it lands: entry files + `$avatar-sizes` + shared bootstrap-overrides import, `[ site.theme.id ]` bracket parents (swappability), no theme-prefixed classes in markup, no inline `<script>` bodies, the pricing JS-contract markers, `blog-post-content` in post layouts, and page-asset files matching a layout-declared `asset_path` shape (wrong shape = silent bundle skip). It caught neobrutalism's missing promo banner + `.card-title` on its first run.
47
+ - **Shared plan-pricing include — `core/pricing/resolve-plan.html`.** The plan price-resolution Liquid (product lookup from `site.web_manager.payment.products`, frontmatter-over-config monthly/annual precedence, per-unit math) was copy-pasted across all three themes' pricing layouts; it's now a single shared "logic include" (Jekyll includes share caller scope) that every theme calls per plan and renders the assigned variables from. Also guards the per-unit `divided_by` against nil/zero unit values, which previously crashed the build when the per-unit feature value couldn't resolve.
48
+ - **Theme-authoring convention: develop in ONE appearance mode, ship with BOTH.** Build against a primary mode (the consumer's `theme.appearance` default), then validate light AND dark before declaring the theme done — including a live click-through of the footer appearance picker. Documented in [docs/themes.md](docs/themes.md) authoring conventions + validation checklist.
49
+ - **Theme-authoring gotchas documented:** theme page bundles re-emit Bootstrap after the main bundle (use doubled selectors — `:root:root`, `[data-bs-theme="dark"][data-bs-theme="dark"]`, `.btn.btn`), and `.bg-body-*`/`.text-body-*` utilities paint from the `--bs-*-rgb` companion variables, which must be remapped alongside the hex vars. See [docs/themes.md](docs/themes.md).
50
+ - **`npx mgr blogify --count=<n>`.** The blogify command now accepts a post count (default 12, matching the old hardcoded behavior) — e.g. `--count=18` fills every deduplicated post slot on the newsflash homepage. Documented in README + the CLAUDE.md CLI table.
51
+ - **`npx mgr test` tees output to `logs/test.log`.** All test-runner output is now duplicated (ANSI-stripped) to `<projectRoot>/logs/test.log`, truncated fresh on each run, via the existing `attach-log-file` util (skipped on CI through `isServer()`) — mirrors EM's and BEM's `test.log` pattern. Grep the file after a run instead of scrolling terminal scrollback.
52
+ - **`TEST_EXTENDED_MODE` — extended test mode (`--extended`).** `npx mgr test --extended` (or `TEST_EXTENDED_MODE=true npx mgr test`) opts in tests that hit REAL external services (network fetches, Firebase via web-manager, live APIs); off by default so `npx mgr test` stays fast and offline-safe. The signal is the unprefixed `TEST_EXTENDED_MODE` env var — the SAME name across BEM/BXM/UJM/EM (cross-framework parity) — and once set it propagates to every spawned child (the Jekyll build, the boot HTTP server / Puppeteer browsers) via inherited `process.env`. A warning prints (and is teed to `logs/test.log`) when on. Gate live tests on `process.env.TEST_EXTENDED_MODE`. New `src/test/utils/extended-mode-warning.js` is the SSOT for the warning copy. Documented in [docs/test-framework.md](docs/test-framework.md#extended-mode-test_extended_mode) + the env-vars table.
53
+
54
+ ### Changed
55
+
56
+ - **Test command standardizes on `TEST_EXTENDED_MODE`, replacing `--integration` / `UJ_TEST_INTEGRATION`** (no backwards compat — the old flag/env are gone). Mirrors the canonical unprefixed `TEST_EXTENDED_MODE` shared across BEM/BXM/EM.
57
+
58
+ ### Fixed
59
+
60
+ - **`attach-log-file` no longer truncates `logs/test.log` mid-run.** The tee state is now wrapped in a `createTee()` factory (independent, stackable instances) with the process-wide singleton built on top. A later `attach()` captures the CURRENT `process.stdout.write` (which may already be an outer tee) and restores that exact reference on `detach()`, so stacked tees fan out and unwind in LIFO order. The new build-layer `attach-log-file` test uses its OWN `createTee()` instance, so exercising attach/detach no longer detaches the live singleton tee that's capturing the actual run (which previously cut `logs/test.log` to ~9 lines). UJM's name-based signature (`attachLogFile('test')`) and synchronous `detach()` are preserved. Mirrors EM's `createTee()` refactor.
61
+
62
+ - **neobrutalism pricing page now satisfies the full framework JS contract.** Same two gaps newsflash had: the flash-sale promo banner block (`#pricing-promo-banner` + badge/text/countdown/code ids, shipped `hidden`) was missing entirely, and plan names lacked the `.card-title` class the pricing JS reads for analytics. Both caught by the new theme-contract test on its first run.
63
+ - **Classy admin minimal layouts use bracket parents.** `admin/core/minimal.html` + `minimal-viewport-locked.html` hardcoded `layout: themes/classy/backend/...` instead of the `themes/[ site.theme.id ]/...` convention (the fallback's path rewrite masked it for non-classy themes). Normalized to brackets; now enforced by the theme-contract test.
64
+ - **newsflash nav + dropdown hover text is readable again.** The hover fill (ink pill) left the label ink-on-ink: the shared nav/account includes put Bootstrap's `.text-body` utility (`!important`) on every link and dropdown item, which beat the theme's hover `color`. The hover/active colors now carry `!important`, and dropdown-item child spans with text utilities flip to `inherit` on hover (fixes the blacked-out account-dropdown rows too).
65
+ - **newsflash dropdown item pills no longer press edge-to-edge against the panel.** Bootstrap's re-emitted `.dropdown-menu` rule (`--bs-dropdown-padding-x: 0`) was stripping the theme's panel inset on pages with page CSS — the highlighted pill touched the panel edges. The theme's dropdown rule now uses the doubled selector (`.dropdown-menu.dropdown-menu`), the established page-bundle-gotcha pattern.
66
+ - **newsflash headings no longer go thin on pages with page CSS.** Bootstrap's re-emitted `.display-*` / `.lead` rules (stock weights 300) were clobbering the theme's main-bundle typography on every page that ships a page bundle (post + about read spindly; contact — no page bundle — looked right). Type metrics now ship as Bootstrap variables in the config `@forward with (...)` block (`$display-font-weight: 550`, `$display-line-height: 1.04`, `$lead-font-weight: 400`, `$headings-line-height: 1.1`, `$line-height-base: 1.55`) so every Bootstrap copy compiles them natively. Documented as an extension of the page-bundle gotcha in [docs/themes.md](docs/themes.md).
67
+ - **newsflash post hero image fills its frame.** Two stacked causes: `uj_post` image-tags render as `<picture><img>`, so the img's percentage height resolved against the auto-height picture wrapper (the base `.art-frame` now makes `picture` fill the frame), and the framework's generic `.blog-post-image { max-height: 480px }` capped the image inside the 21/10 frame (the article-hero rule now lifts it with `max-height: none`).
68
+ - **Footer brand description no longer disappears when its data value liquifies to empty.** Both classy's and newsflash's footers resolve the brand blurb via `data.logo.description | default: site.brand.description`, but `default:` only sees the RAW string — a footer.json value like `'{{ site.meta.description }}'` with no `meta.description` set passed the default check and then liquified to nothing, hiding the description even when `brand.description` was set. The footers now re-check after liquification and fall back to `site.brand.description`.
69
+ - **newsflash dark mode no longer stomps consumer brand colors.** The dark-mode `--bs-primary`/`--bs-link-color` remaps were hardcoded to the brightened vermilion, so a consumer's `$primary` override (via `main.scss` `with (...)`) held in light mode but snapped back to vermilion in dark. The remap now derives from the compile-time `$primary` (stock vermilion keeps its hand-tuned brightening; other brand colors get a generic white-mix lift). Documented as a theme-authoring gotcha in [docs/themes.md](docs/themes.md#derive-dark-mode-brand-remaps-from-primary-gotcha).
70
+ - **newsflash pricing page now satisfies the full framework JS contract.** Added the flash-sale promo banner (`#pricing-promo-banner` + badge/text/countdown/code ids, shipped `hidden` — the framework pricing JS reveals it, fills the rotating sale name + countdown, and offsets the masthead) and the `.card-title` class on plan names (read for add-to-cart analytics). The pricing JS contract — billing radios, `.amount`/`.billing-info`/`.price-per-unit` data attributes, `button[data-plan-id]`, plan-name selector, promo banner ids — is now documented as a required cross-theme contract in [docs/themes.md](docs/themes.md#the-pricing-page-has-a-js-contract-too).
71
+ - **`npx mgr test <target>` now correctly scopes by source.** The positional test target was previously ignored — every run executed all suites regardless of the argument. It now selects which test FILES run: `project:` runs project tests only, `mgr:` / `ujm:` / `framework:` run framework tests only (`mgr:` is the universal cross-framework alias, equivalent to the UJM-specific `ujm:` / `framework:`), and a bare path (no prefix) matches both sources. The `--filter=<substring>` flag stays orthogonal — it matches test NAMES within the already-selected files and composes with the target. See [docs/test-framework.md](docs/test-framework.md#filtering-tests).
72
+
73
+ ---
74
+ ## [1.7.2] - 2026-06-09
75
+
76
+ ### Added
77
+
78
+ - **Push notification subscribe on payment confirmation CTA click** — hooks `subscribe()` onto CTA button clicks on the payment confirmation page. Requires a user gesture for the browser permission prompt, so uses `{ once: true }` click listeners.
79
+
80
+ ### Fixed
81
+
82
+ - **FormManager spinner layout in icon-only buttons** — `_showSpinner()` no longer adds `me-2` margin when `submittingText` is empty. Previously, the unnecessary right margin squished the spinner off-center in small round buttons (e.g. chat send).
83
+
17
84
  ---
18
85
  ## [1.7.1] - 2026-06-09
19
86
 
@@ -351,7 +418,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
351
418
 
352
419
  ### Added
353
420
 
354
- - **`docs/<topic>.md` deep references** — 17 new files referenced by the v1.2.0 CLAUDE.md reorg that hadn't been committed yet: `ads.md`, `analytics.md`, `appearance.md`, `assets.md`, `audit.md`, `css.md`, `icons.md`, `images.md`, `javascript-libraries.md`, `jekyll-plugin.md`, `layouts-and-pages.md`, `lazy-loading.md`, `local-development.md`, `page-loading.md`, `project-structure.md`, `seo.md`, `xss-prevention.md`. Restores parity with the cross-links already shipped in [CLAUDE.md](CLAUDE.md).
421
+ - **`docs/<topic>.md` deep references** — 17 new files referenced by the v1.2.0 CLAUDE.md reorg that hadn't been committed yet: `ads.md`, `analytics.md`, `appearance.md`, `assets.md`, `audit.md`, `css.md`, `icons.md`, `images.md`, `javascript-libraries.md`, `jekyll-plugin.md`, `layouts-and-pages.md`, `lazy-loading.md`, `local-development.md`, `page-loading.md`, `directory-structure.md`, `seo.md`, `xss-prevention.md`. Restores parity with the cross-links already shipped in [CLAUDE.md](CLAUDE.md).
355
422
  - **`src/defaults/docs/README.md`, `src/defaults/test/README.md`, `src/defaults/CHANGELOG.md`** — consumer-project scaffolding files distributed via the `defaults` gulp task.
356
423
 
357
424
  ---
package/CLAUDE.md CHANGED
@@ -8,7 +8,7 @@ Ultimate Jekyll Manager (UJM) is a comprehensive framework for building modern J
8
8
 
9
9
  - One-line bootstrap per context (build / frontend / service-worker)
10
10
  - Multi-stage gulp pipeline (15 tasks: defaults / distribute / webpack / sass / imagemin / jekyll / jsonToHtml / preprocess / audit / translation / minifyHtml / serve / setup / developmentRebuild)
11
- - Default Jekyll layouts + themes (`classy` + `neobrutalism` shipped; new themes inherit classy's layouts via the build-time fallback — see [docs/themes.md](docs/themes.md))
11
+ - Default Jekyll layouts + themes (`classy` + `neobrutalism` + `newsflash` shipped; new themes inherit classy's layouts AND nav/footer chrome via the build-time fallback — restyle chrome via theme CSS, fork an include only on real structural divergence — ship **genre-native frontmatter defaults**, and must validate **both appearance modes**; conventions are enforced by the build-layer **theme-contract test** — see [docs/themes.md](docs/themes.md))
12
12
  - Frontend ES-module Manager with dynamic per-page module loading
13
13
  - Service worker with Firebase Messaging + cache management
14
14
  - A built-in **three-layer test framework** (build / page / boot)
@@ -22,7 +22,7 @@ The only things that ARE safe to run inside UJM itself:
22
22
 
23
23
  ## Recommended skills
24
24
 
25
- - **`UJM:patterns`** — SSOT for Ultimate Jekyll Manager architecture, gulp pipeline, frontend Manager, and theme conventions. Auto-loads on UJM-specific keywords (`_config.yml`, `theme.id`, `uj_icon`, `page.resolved`, `npx mgr setup`, etc.) and when touching files in `src/_layouts/`, `src/_includes/`, `src/pages/`, `src/assets/`, `config/ultimate-jekyll-manager.json`.
25
+ - **`omega:ujm`** — router skill. Auto-loads on UJM-specific keywords (`_config.yml`, `theme.id`, `uj_icon`, `page.resolved`, `npx mgr setup`, etc.) and points back to this CLAUDE.md + `docs/` (the SSOT), carrying only Claude-workflow hard rules and process checklists.
26
26
  - **`js:patterns`** — JavaScript/Node.js conventions: file structure, JSDoc, defensive coding (`?.` usage), template literals, `package.json` conventions. Auto-loads when creating new `.js` files or touching JS module structure.
27
27
 
28
28
  ## 🚨 READ WEB-MANAGER TOO
@@ -43,16 +43,19 @@ The only things that ARE safe to run inside UJM itself:
43
43
  4. `npm run build` — production build (`UJ_BUILD_MODE=true`)
44
44
  5. `npm run deploy` — build + `npu sync --message='Deploy'`
45
45
  6. `npm test` (or `npx mgr test`) — runs framework + project test suites
46
- - `npx mgr test pages/home` — run a specific test by path (relative to `test/`)
46
+ - `npx mgr test pages/home` — run a specific test by path (relative to `test/`, matches both sources)
47
+ - `npx mgr test project:` — run ONLY consumer project tests (`project:custom-test` to match a path)
48
+ - `npx mgr test mgr:` — run ONLY framework tests (`ujm:` / `framework:` are equivalent UJM aliases)
47
49
  - `npx mgr test ujm:pages/home` — run only framework tests matching a path
48
- - `npx mgr test project:custom-test` run only consumer project tests matching a path
49
- - Prefix with `TEST_EXTENDED_MODE=true` for tests that hit real external APIs
50
+ - The `--filter=<substring>` flag matches test NAMES within the selected files (composes with the target); `--layer=build|page|boot` narrows to one layer
51
+ - Output is teed (ANSI-stripped) to `<projectRoot>/logs/test.log`, truncated fresh each run (skipped on CI) — `cat logs/test.log` instead of scrolling scrollback
52
+ - `--extended` (or `TEST_EXTENDED_MODE=true`) opts in tests that hit real external services — off by default, unprefixed name shared across BEM/BXM/UJM/EM, propagates to spawned envs (Jekyll/boot server); see [docs/test-framework.md](docs/test-framework.md#extended-mode-test_extended_mode)
50
53
 
51
54
  ### For Framework Development (This Repository)
52
55
 
53
56
  1. `npm install` — install UJM's own deps
54
57
  2. `npm start` (≡ `npm run prepare:watch`) — copies `src/` → `dist/` on file change
55
- 3. Test in a consumer project: from inside the consumer, run `npx mgr install dev` to swap UJM to this local repo — required whenever you edit the framework source and want the consumer to pick up the changes (the consumer otherwise keeps its installed `node_modules/ultimate-jekyll-manager`). Reverse with `npx mgr install live`.
58
+ 3. Test in the **designated test consumer** `../ultimate-jekyll-website` is UJM's consumer for validating framework changes end-to-end (exercise any consumer-level flow there freely: builds, tests, runtime). From inside it, run `npx mgr install dev` to swap UJM to this local repo — required whenever you edit the framework source and want the consumer to pick up the changes (the consumer otherwise keeps its installed `node_modules/ultimate-jekyll-manager`). Reverse with `npx mgr install live`.
56
59
  4. `npm test` — runs UJM's own 60 test suites
57
60
 
58
61
  ## Architecture
@@ -96,7 +99,7 @@ UJM uses node-powertools' `template()` with two bracket conventions:
96
99
  - `{ x }` (default) — used wherever `template()` is called without `brackets:` (e.g. defaults.js Gemfile templating)
97
100
  - `[ x ]` — used by distribute.js theme fallback and [template-transform.js](src/gulp/tasks/utils/template-transform.js) (for `.html/.md/.liquid/.json`)
98
101
 
99
- Jekyll's Liquid `{{ }}` is processed by Jekyll itself, NOT by node-powertools — those placeholders pass through node-powertools untouched. See [docs/templating.md](docs/templating.md) (planned).
102
+ Jekyll's Liquid `{{ }}` is processed by Jekyll itself, NOT by node-powertools — those placeholders pass through node-powertools untouched. See [docs/templating.md](docs/templating.md).
100
103
 
101
104
  ### Frontend Manager (`src/index.js`)
102
105
 
@@ -135,6 +138,10 @@ Cache name is `${brand.id}-${cache_breaker}` from `UJ_BUILD_JSON.config`. See [d
135
138
 
136
139
  Same `{ layer, description, run(ctx) }` contract as EM/BXM. JSON-line reporter protocol uses `__UJM_TEST__` marker. See [docs/test-framework.md](docs/test-framework.md) + [docs/test-boot-layer.md](docs/test-boot-layer.md).
137
140
 
141
+ ### Test coverage
142
+
143
+ Every feature ships with tests at EVERY layer it has a surface in — logic (`build`, or `page` for frontend module logic), UI (`page` — real events on the real DOM), and end-to-end (`boot`). Skip a layer ONLY when the feature genuinely has no surface there (a pure build utility has no UI; a CSS-only tweak has no logic). "The logic test already covers it" is NOT a reason to skip the UI test — logic tests prove the logic, UI tests prove the wiring, boot tests prove the built site. See [docs/test-framework.md](docs/test-framework.md).
144
+
138
145
  ## CLI
139
146
 
140
147
  `npx mgr <command>` (aliases `uj`, `ujm`, `ultimate-jekyll`):
@@ -152,15 +159,22 @@ Same `{ layer, description, run(ctx) }` contract as EM/BXM. JSON-line reporter p
152
159
  | `minify-html` | minify HTML (preserves JSON-LD + inline scripts + IE conditional comments) |
153
160
  | `optimize` | AI-optimize pages via OpenAI |
154
161
  | `migrate` | migrate consumer project layout (legacy → current) |
155
- | `blogify` | generate test blog posts from Unsplash |
162
+ | `blogify` | generate test blog posts from Unsplash (`--count=<n>`, default 12) |
156
163
  | `cloudflare-purge` | purge Cloudflare cache |
157
164
  | `test` | run framework + project test suites (three layers) |
158
165
 
159
166
  Note: `-t` short alias belongs to `translation`. The `test` command uses `--test` flag + `test` positional only. See [docs/cli.md](docs/cli.md) (planned).
160
167
 
168
+ ## Dependency Resolution
169
+
170
+ - **Consumer code can `import`/`require()` any UJM dependency** — webpack's `resolve.modules` includes the framework's own `node_modules/`. Consumer projects do NOT need to `npm install firebase`, `web-manager`, or any other UJM transitive dep. If a dep doesn't resolve, the fix is in UJM's webpack config — not the consumer's `package.json`.
171
+ - **web-manager owns Firebase.** Consumer code NEVER imports Firebase directly (`import firebase from 'firebase/app'`). Use `import webManager from 'web-manager'` → `webManager.auth()`, `webManager.firestore()`. Same rule in EM and BXM.
172
+ - **`Manager.require(name)`** resolves from UJM's module context at runtime (static + prototype). Use in gulp tasks or unbundled code (e.g. test fixtures). Webpack `resolve.modules` handles the bundled case.
173
+
161
174
  ## Development Workflow
162
175
 
163
- - **🚫 NEVER run `npm start` / `npm run build` / `npm test` in a consumer project** unless the user explicitly asks. The user runs the dev server running it again kills theirs. Instead, **check `logs/dev.log`** after editing files to confirm the watcher recompiled successfully (`Reloading Browsers...` = success; `errored` = fix the error). If editing multiple files, check the log once after the last edit. A change that breaks the build is not a completed change.
176
+ - **🚫 NEVER run `npm start` in a consumer project** the user runs the dev server; running it again kills theirs. Assume it's already running; if it isn't, **instruct the user to run it** rather than running it yourself. Instead, **check `logs/dev.log`** after editing files to confirm the watcher recompiled successfully (`Reloading Browsers...` = success; `errored` = fix the error) — never tail/attach to the process. If editing multiple files, check the log once after the last edit. A change that breaks the build is not a completed change. Running `npx mgr test` is fine.
177
+ - **Live-test UI changes via CDP.** After code changes compile, use the `chrome-devtools` MCP tools (screenshots, click, evaluate JS, console logs) to verify the change works in the running browser. This is the primary way to confirm UI changes — type-checking and test suites verify code correctness, not feature correctness. See `~/.claude/mcp-server/servers/chrome-devtools/CLAUDE.md`.
164
178
 
165
179
  ## File Conventions
166
180
 
@@ -195,26 +209,32 @@ Deep references live in `docs/`. Treat docs as a first-class deliverable. **When
195
209
  - [docs/test-boot-layer.md](docs/test-boot-layer.md) — boot layer deep-dive (_site/ discovery, HTTP server, fixture vs consumer)
196
210
  - [docs/environment-detection.md](docs/environment-detection.md) — `isTesting`/`isDevelopment`/`isProduction`/`getVersion`
197
211
  - [docs/jekyll-plugin.md](docs/jekyll-plugin.md) — UJ Powertools gem: filters, tags, page variables (`page.resolved`, `uj_icon`, `uj_hash`, `iftruthy`, etc.)
198
- - [docs/audit.md](docs/audit.md) — workflow for fixing issues raised by `gulp/tasks/audit.js`
212
+ - [docs/audit.md](docs/audit.md) — two-stage audit workflow: AI content pass (conventions/XSS/inline scripts) + `npx mgr audit` fix loop
213
+ - [docs/migration.md](docs/migration.md) — full migration (old UJ → latest UJM base), `_config.yml` quick-fix schema, revert-posts procedure
199
214
 
200
215
  ### Project & dev environment
201
216
 
202
- - [docs/project-structure.md](docs/project-structure.md) — UJM repo layout and consuming-project layout
203
- - [docs/local-development.md](docs/local-development.md) — browsersync URL, Firebase emulator connect, PurgeCSS safelist, log files (`logs/dev.log`, `logs/build.log`)
217
+ - [docs/directory-structure.md](docs/directory-structure.md) — UJM repo layout and consuming-project layout
218
+ - [docs/build-system.md](docs/build-system.md) — gulp pipeline (15 tasks), config flow, build modes, pure helpers
219
+ - [docs/templating.md](docs/templating.md) — node-powertools bracket conventions, Liquid coexistence
220
+ - [docs/local-development.md](docs/local-development.md) — browsersync URL, Firebase emulator connect, PurgeCSS safelist
221
+ - [docs/logging.md](docs/logging.md) — `dev.log` / `build.log` / `test.log` tee, CI skip
222
+ - [docs/common-mistakes.md](docs/common-mistakes.md) — the canonical "don't do this" list
204
223
  - [docs/assets.md](docs/assets.md) — UJM vs consumer file layout, section config (nav/footer/account), frontmatter-driven page customization, webpack aliases, page module pattern
205
224
 
206
225
  ### Pages, layouts, content
207
226
 
208
227
  - [docs/animation-studio.md](docs/animation-studio.md) — Animation Studio admin page: clip registration via `window.STUDIO_CLIPS`, helpers (`animate`, `el`, `flowClip`, `cardClip`, `chatClip`), resolution picker, recording, aspect ratio modes
209
228
  - [docs/themes.md](docs/themes.md) — theme system: selection + resolution (SCSS loadPaths, `__theme__`, classy layout fallback), shared vs per-theme layers, authoring a theme inside UJM OR in a consumer project, live validation
210
- - [docs/layouts-and-pages.md](docs/layouts-and-pages.md) — page types, layout chain, `asset_path` frontmatter
229
+ - [docs/layouts-and-pages.md](docs/layouts-and-pages.md) — page types, layout chain, `asset_path` frontmatter, default-page customization rules + per-page levels, dashboard list/detail/edit pattern, custom page creation
211
230
  - [docs/images.md](docs/images.md) — `@post/` shortcut for blog post images, BEM admin/post image handling, imagemin pipeline + source-size constraints + `UJ_IMAGEMIN_REWRITE_SOURCES` cleanup flag
212
231
  - [docs/icons.md](docs/icons.md) — Font Awesome conventions, `{% uj_icon %}` vs prerendered icons in JS, size reference, country flag SVGs (`assets/icons/flags/modern-square/`)
213
- - [docs/seo.md](docs/seo.md) — Alternatives collection (competitor comparison pages) + Schema/JSON-LD (`SoftwareApplication`, `FAQPage`)
232
+ - [docs/seo.md](docs/seo.md) — content writing rules (headlines, sentence case, accents), Services/Solutions page strategies, Alternatives collection (competitor comparison pages), Schema/JSON-LD (`SoftwareApplication`, `FAQPage`)
214
233
 
215
234
  ### Frontend behavior
216
235
 
217
236
  - [docs/css.md](docs/css.md) — section padding rule, theme-adaptive classes, cards in colored sections, `<html>` data attributes
237
+ - [docs/purgecss.md](docs/purgecss.md) — PurgeCSS safelist playbook: two safelist locations, RegExp anchoring, gotchas (`variables: false`, per-file processing), current UJM safelist
218
238
  - [docs/appearance.md](docs/appearance.md) — dark/light/system mode switching: JS API, HTML attributes
219
239
  - [docs/page-loading.md](docs/page-loading.md) — page-loading protection, `.btn-action`, layered form-protection strategy
220
240
  - [docs/lazy-loading.md](docs/lazy-loading.md) — `data-lazy="@type value"` syntax and supported types
@@ -222,7 +242,8 @@ Deep references live in `docs/`. Treat docs as a first-class deliverable. **When
222
242
 
223
243
  ### JS libraries & security
224
244
 
225
- - [docs/javascript-libraries.md](docs/javascript-libraries.md) — WebManager singleton + UJM libs at `src/assets/js/libs/` (prerendered icons, authorizedFetch, usage bindings, payment-config, FormManager)
245
+ - [docs/javascript-libraries.md](docs/javascript-libraries.md) — WebManager singleton + UJM libs at `src/assets/js/libs/` (prerendered icons, authorizedFetch, usage bindings, payment-config, FormManager), reads-vs-writes rule (Firestore SDK for reads, Cloud Functions for writes)
246
+ - [docs/no-inline-scripts.md](docs/no-inline-scripts.md) — HARD RULE: no inline `<script>` bodies; full migration playbook incl. Liquid `data-*`/`<template>` bridges
226
247
  - [docs/xss-prevention.md](docs/xss-prevention.md) — zero-trust DOM injection rules, `escapeHTML`, postMessage origin checks, redirect validation
227
248
 
228
249
  ### Analytics
package/README.md CHANGED
@@ -28,7 +28,7 @@
28
28
  * **SEO Optimized**: Ultimate Jekyll is fully SEO optimized.
29
29
  * **Blazingly Fast**: Ultimate Jekyll is blazingly fast.
30
30
  * **NPM & Gulp**: Ultimate Jekyll is fueled by an intuitive incorporation of npm and gulp.
31
- * **Themes**: Pick a shipped theme with `theme.id` (`classy` or `neobrutalism`), or author your own. New themes inherit all default page layouts automatically and only restyle/override what differs. See [docs/themes.md](docs/themes.md).
31
+ * **Themes**: Pick a shipped theme with `theme.id` (`classy`, `neobrutalism`, or `newsflash` — an editorial news-site theme), or author your own. New themes inherit all default page layouts automatically and only restyle/override what differs. See [docs/themes.md](docs/themes.md).
32
32
  * **Built-in test framework**: three layers (`build` / `page` / `boot`) — plain Node, headless Chromium tab, headless Chromium against real `_site/` with SW registration verification.
33
33
 
34
34
  ## 🚀 Getting started
@@ -48,6 +48,7 @@ npx mgr test # all layers
48
48
  npx mgr test --layer build # plain Node, fast
49
49
  npx mgr test --layer page # headless Chromium tab against harness HTML
50
50
  npx mgr test --layer boot # headless Chromium against built _site/
51
+ npx mgr test --extended # also run tests that hit real external services (off by default)
51
52
  ```
52
53
 
53
54
  Test files use Jest-compatible matchers:
@@ -183,9 +184,10 @@ npm run prepare:watch
183
184
  ```
184
185
 
185
186
  ### Run the `blogify` task:
186
- Create 12 test blog posts in the `_posts` directory with the `blogify` task. This is useful for testing and development purposes.
187
+ Create test blog posts in the `_posts` directory with the `blogify` task (default 12; pass `--count=<n>` for more — e.g. 18 fills every post slot on the newsflash homepage). This is useful for testing and development purposes.
187
188
  ```bash
188
189
  npx mgr blogify
190
+ npx mgr blogify --count=18
189
191
  ```
190
192
 
191
193
  ## Page Frontmatter
@@ -162,4 +162,4 @@ The test harness should stay vanilla Mocha + JSDOM + fixture HTML files.
162
162
  - All 6 test files above written and green
163
163
  - `npm test` in UJM runs them as part of the standard suite
164
164
  - The v1.3.1 bug (consent guard ordering) is caught by `auth-guard-ordering.test.js` — verify by reverting the v1.3.2 fix in a branch and watching the test fail
165
- - Documented in `docs/testing.md` so contributors know to add auth tests when touching auth code
165
+ - Documented in `docs/test-framework.md` so contributors know to add auth tests when touching auth code
@@ -813,7 +813,10 @@ export class FormManager {
813
813
  if (show) {
814
814
  // Store original content
815
815
  $btn._originalHTML = $btn.innerHTML;
816
- $btn.innerHTML = `<span class="spinner-border spinner-border-sm me-2"></span>${webManager.utilities().escapeHTML(this.config.submittingText)}`;
816
+ const text = this.config.submittingText;
817
+ $btn.innerHTML = text
818
+ ? `<span class="spinner-border spinner-border-sm me-2"></span>${webManager.utilities().escapeHTML(text)}`
819
+ : '<span class="spinner-border spinner-border-sm"></span>';
817
820
  } else if ($btn._originalHTML) {
818
821
  $btn.innerHTML = $btn._originalHTML;
819
822
  }
@@ -35,6 +35,15 @@ async function initializeConfirmation() {
35
35
 
36
36
  // Trigger celebration animation
37
37
  await triggerCelebration();
38
+
39
+ // Subscribe to push notifications on CTA click (requires user gesture)
40
+ document.querySelectorAll('.btn').forEach(($btn) => {
41
+ $btn.addEventListener('click', () => {
42
+ webManager.notifications().subscribe().catch((e) => {
43
+ console.warn('[Confirmation] Notification subscribe failed:', e.message);
44
+ });
45
+ }, { once: true });
46
+ });
38
47
  }
39
48
 
40
49
  // Parse URL parameters into minimal state
@@ -0,0 +1,58 @@
1
+ # Newsflash Theme
2
+
3
+ An editorial news theme: warm paper surfaces, ink text and hairline frames,
4
+ vermilion accents with volt highlights, optical-sized serif headlines
5
+ (Fraunces) over a clean grotesk (Schibsted Grotesk). Signature elements: the
6
+ live news ticker above the masthead, framed editorial images, kickers,
7
+ section rules, drop caps, and pill controls that lift off small hard shadows.
8
+
9
+ ## Select the theme
10
+
11
+ ```yaml
12
+ # src/_config.yml (consuming project)
13
+ theme:
14
+ id: "newsflash"
15
+ target: "frontend"
16
+ appearance: "light" # or "dark" / "system" — dark mode is first-class
17
+ ```
18
+
19
+ ## Customize tokens
20
+
21
+ Every variable in `_config.scss` is `!default` — override any of them in your
22
+ project BEFORE the theme import:
23
+
24
+ ```scss
25
+ // src/assets/css/main.scss (consuming project)
26
+ @use 'ultimate-jekyll-manager' with (
27
+ $primary: #0E7C3A, // swap vermilion for forest green
28
+ $nf-volt: #FFD966, // warmer highlighter
29
+ $nf-radius: 12px, // tighter frames
30
+ $nf-font-display: ('Lora', serif), // different serif voice
31
+ );
32
+ ```
33
+
34
+ Runtime tokens live in `css/base/_root.scss` as `--nf-*` CSS custom
35
+ properties; dark mode is a single `[data-bs-theme="dark"]` remap block.
36
+
37
+ ## What ships custom
38
+
39
+ - **Layouts** (`_layouts/themes/newsflash/`): base (ticker + fonts), homepage,
40
+ blog index, blog post, pricing, about, contact, 404. Everything else
41
+ inherits Classy markup restyled by this theme's CSS.
42
+ - **Chrome** (`_includes/themes/newsflash/frontend/sections/`): the serif
43
+ masthead nav + the editorial ink-slab footer (volt column heads, language +
44
+ appearance pickers in the bottom rail). Same `nav.json`/`footer.json` data
45
+ contract as classy.
46
+ - **Page assets** (`pages/`): homepage rails/big-read band, blog index splash,
47
+ blog post reading-progress + drop cap, pricing/about/404 accents.
48
+ - **Behaviors** (`js/`): masthead scroll shadow, Bootstrap tooltips. The
49
+ ticker and marquees are pure CSS.
50
+
51
+ ## Conventions
52
+
53
+ - Markup uses standard Bootstrap classes + universal semantic names
54
+ (`.kicker`, `.ticker`, `.section-head`, `.art-frame`) — never `nf-*`
55
+ prefixes. `nf-*` survives only on SCSS internals (`$nf-*`, `--nf-*`,
56
+ mixins).
57
+ - Fonts load via the `theme.head.content` block in
58
+ `_layouts/themes/newsflash/frontend/core/base.html`, never SCSS `@import`.
@@ -0,0 +1,138 @@
1
+ // Newsflash Theme Configuration
2
+ // ALL customizable variables are defined here with !default.
3
+ // Consuming projects override any of these BEFORE the theme is imported.
4
+ //
5
+ // Design language: warm paper surfaces; ink text + hairline ink frames;
6
+ // vermilion accents with volt highlights; serif display type over a clean
7
+ // grotesk; pill controls sitting on small hard offset shadows that "lift"
8
+ // on hover. An editorial newsroom — modern front page, not a brochure.
9
+
10
+ // ============================================
11
+ // Bootstrap Color Overrides
12
+ // ============================================
13
+ // Editorial ink-and-accent palette mapped onto Bootstrap's semantic colors.
14
+ $primary: #F03612 !default; // vermilion — the signature accent
15
+ $secondary: #5C544A !default; // ink-soft — muted secondary actions
16
+ $success: #2E7D4F !default; // editorial green
17
+ $info: #2742F5 !default; // electric blue
18
+ $warning: #D9F24E !default; // volt — highlighter yellow-green
19
+ $danger: #C81E1E !default; // deep red (distinct from vermilion)
20
+ $light: #F7F2E7 !default; // paper
21
+ $dark: #171310 !default; // ink
22
+
23
+ // ============================================
24
+ // Paper & Ink (the structural neutrals)
25
+ // ============================================
26
+ // "Paper" = the page surface. "Ink" = text, frames, and hard shadows.
27
+ $nf-paper: #F7F2E7 !default; // body background (light mode)
28
+ $nf-paper-2: #EFE8D8 !default; // wells / alt surfaces (light mode)
29
+ $nf-ink: #171310 !default; // text + frames (light mode)
30
+ $nf-ink-soft: #5C544A !default; // deks, metas, muted text (light mode)
31
+
32
+ // Dark mode counterparts — deep warm near-black paper, cream ink.
33
+ $nf-paper-dark: #181210 !default;
34
+ $nf-paper-2-dark: #221A14 !default;
35
+ $nf-ink-dark: #F2E8D9 !default;
36
+ $nf-ink-soft-dark: #A8998A !default;
37
+
38
+ // ============================================
39
+ // Accent Palette
40
+ // ============================================
41
+ $nf-vermilion: #F03612 !default;
42
+ $nf-vermilion-dark-mode: #FF4A26 !default; // brightened for contrast on dark paper
43
+ $nf-blue: #2742F5 !default;
44
+ $nf-blue-dark-mode: #5B72FF !default;
45
+ $nf-volt: #D9F24E !default; // stays vibrant in both modes
46
+ $nf-volt-ink: #171310 !default; // readable text on volt
47
+
48
+ // Ink panels (footer, ticker, big-read band) — dark slabs in BOTH modes.
49
+ $nf-panel-bg: #171310 !default;
50
+ $nf-panel-color: #F7F2E7 !default;
51
+ $nf-panel-bg-dark: #0E0B09 !default; // deeper than dark paper so it still reads as a slab
52
+ $nf-panel-color-dark: #F2E8D9 !default;
53
+
54
+ // ============================================
55
+ // Borders — hairline ink frames
56
+ // ============================================
57
+ $nf-border-width: 1.5px !default;
58
+ $nf-radius: 18px !default; // frames, cards, panels
59
+ $nf-radius-sm: 12px !default; // small frames, inputs
60
+
61
+ // ============================================
62
+ // Shadows — small hard offsets (controls) + soft pop (frames)
63
+ // ============================================
64
+ // Controls rest on a 3px hard ink shadow and LIFT on hover (shadow grows to
65
+ // 6px while the element translates up-left). Frames use a soft "pop" blur.
66
+ $nf-shadow-offset: 3px !default;
67
+ $nf-shadow-offset-hover: 6px !default;
68
+ $nf-shadow-pop: 0 18px 40px -18px rgba(23, 19, 16, .35) !default;
69
+
70
+ // ============================================
71
+ // Typography
72
+ // ============================================
73
+ // Fraunces (optical-sized serif) for display; Schibsted Grotesk for body/UI.
74
+ $font-family-sans-serif: 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif !default;
75
+ $nf-font-display: 'Fraunces', Georgia, 'Times New Roman', serif !default;
76
+
77
+ $headings-font-weight: 600 !default;
78
+ $nf-heading-letter-spacing: -0.02em !default;
79
+ $font-weight-bold: 700 !default;
80
+
81
+ // ============================================
82
+ // Motion — smooth editorial easing
83
+ // ============================================
84
+ $nf-transition: all 0.2s cubic-bezier(0.22, 1, 0.36, 1) !default;
85
+
86
+ // ============================================
87
+ // Component Sizing
88
+ // ============================================
89
+ // Avatar sizes map (matches Classy so shared layouts/includes render correctly)
90
+ $avatar-sizes: (
91
+ null: 3rem,
92
+ 2xs: 0.5rem,
93
+ xs: 1.5rem,
94
+ sm: 2rem,
95
+ md: 2.5rem,
96
+ lg: 3.5rem,
97
+ xl: 5rem,
98
+ 2xl: 7.5rem,
99
+ 3xl: 10rem,
100
+ 4xl: 12.5rem,
101
+ 5xl: 15rem
102
+ ) !default;
103
+
104
+ // ============================================
105
+ // Forward Bootstrap with our configuration
106
+ // ============================================
107
+ @forward '../bootstrap/scss/bootstrap.scss' with (
108
+ $primary: $primary,
109
+ $secondary: $secondary,
110
+ $success: $success,
111
+ $info: $info,
112
+ $warning: $warning,
113
+ $danger: $danger,
114
+ $light: $light,
115
+ $dark: $dark,
116
+ $font-family-sans-serif: $font-family-sans-serif,
117
+ $headings-font-family: $nf-font-display,
118
+ $headings-font-weight: $headings-font-weight,
119
+ $font-weight-bold: $font-weight-bold,
120
+ // Type metrics MUST live in Bootstrap vars (not element rules in the main
121
+ // bundle): page bundles re-emit Bootstrap AFTER main, so Bootstrap's own
122
+ // .display-*/.lead/body rules would win there with the stock 300 weights.
123
+ $headings-line-height: 1.1,
124
+ $display-font-family: $nf-font-display,
125
+ $display-font-weight: 550,
126
+ $display-line-height: 1.04,
127
+ $lead-font-weight: 400,
128
+ $line-height-base: 1.55,
129
+ // Hairline ink borders everywhere; editorial radii (controls go pill in
130
+ // component SCSS — cards/frames keep these).
131
+ $border-width: $nf-border-width,
132
+ $border-radius: $nf-radius-sm,
133
+ $border-radius-sm: 8px,
134
+ $border-radius-lg: $nf-radius,
135
+ $border-radius-xl: 24px,
136
+ $enable-shadows: false,
137
+ $enable-negative-margins: true
138
+ );
@@ -0,0 +1,27 @@
1
+ // Newsflash Theme — JS entry point
2
+ // Loaded at runtime via webpack's __theme__ alias (import('__theme__/_theme.js')).
3
+ // Exposes Bootstrap globally and wires up theme behaviors on DOM ready.
4
+ import bootstrap from '__main_assets__/themes/bootstrap/js/index.umd.js';
5
+ import { ready as domReady } from 'web-manager/modules/dom.js';
6
+
7
+ // Make Bootstrap available globally (used by UJM utilities + components)
8
+ window.bootstrap = bootstrap;
9
+
10
+ /* @dev-only:start */
11
+ {
12
+ console.log('Newsflash theme loaded successfully (assets/themes/newsflash/_theme.js)');
13
+ }
14
+ /* @dev-only:end */
15
+
16
+ // Theme behaviors
17
+ import setupMastheadScroll from './js/masthead-scroll.js';
18
+ import initializeTooltips from './js/initialize-tooltips.js';
19
+
20
+ // Initialize when DOM is ready
21
+ domReady().then(() => {
22
+ // Newsflash behaviors
23
+ setupMastheadScroll();
24
+
25
+ // Generic Bootstrap initializations
26
+ initializeTooltips();
27
+ });
@@ -0,0 +1,37 @@
1
+ // Newsflash Theme — SCSS entry point
2
+ // Forwards config (so consuming projects can override vars), loads Bootstrap
3
+ // via config, then layers the editorial system on top. Import order matters:
4
+ // config → mixins → root vars → base → layout → components → bootstrap overrides.
5
+
6
+ // Forward theme configuration (allows consuming project to override)
7
+ @forward 'config';
8
+ @use 'config' as *;
9
+
10
+ // Mixins must be available to every partial below.
11
+ // @import (not @use) so the mixins land in the global scope the @imports share.
12
+ @import 'css/base/mixins';
13
+
14
+ // CSS custom properties (light/dark bridge)
15
+ @import 'css/base/root';
16
+
17
+ // Base styles
18
+ @import 'css/base/typography';
19
+ @import 'css/base/utilities';
20
+
21
+ // Layout styles
22
+ @import 'css/layout/general';
23
+ @import 'css/layout/navigation';
24
+
25
+ // Component styles
26
+ @import 'css/components/buttons';
27
+ @import 'css/components/cards';
28
+ @import 'css/components/forms';
29
+ @import 'css/components/badges';
30
+ @import 'css/components/ticker';
31
+ @import 'css/components/editorial';
32
+ @import 'css/components/panels';
33
+ @import 'css/components/infinite-scroll';
34
+
35
+ // Universal Bootstrap overrides (shared across all UJ themes).
36
+ // Must come AFTER Bootstrap is loaded via config to use @extend.
37
+ @import '../bootstrap/overrides';