ultimate-jekyll-manager 1.2.0 → 1.2.1

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.
package/CHANGELOG.md CHANGED
@@ -14,6 +14,13 @@ 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.2.1] - 2026-05-18
19
+
20
+ ### Changed
21
+
22
+ - **Default `/extension` page** — removed the redundant downloads-section heading block ("Install" badge + "Available on every browser" headline + "Choose your browser below to get started" subheadline) that duplicated the role of the page hero. Browser-selector pills now sit directly under the hero. Affects `src/defaults/dist/_layouts/themes/classy/frontend/pages/extension/index.html` and drops the now-unused `downloads.superheadline` / `downloads.headline` / `downloads.headline_accent` / `downloads.subheadline` frontmatter keys.
23
+
17
24
  ---
18
25
  ## [1.2.0] - 2026-05-12
19
26
 
package/CLAUDE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultimate Jekyll Manager (UJM)
2
2
 
3
- > **Note for contributors and Claude:** This file is the architectural overview — identity, top-level conventions, and a map to deep references. The **meat** (per-subsystem APIs, page customization recipes, theming, behavior tables, defaults lists) lives in `docs/<topic>.md`. When extending or adding content, write it in the matching `docs/*.md` file and cross-link from here — do NOT inline it. If a topic doesn't have a doc yet, create one. Goal: keep this file under 300 lines. Long-form content that hasn't been migrated yet lives in `docs/_legacy-claude-md.md` — a holding pen for material to be split into proper `docs/<topic>.md` files over time.
3
+ > **Note for contributors and Claude:** This file is the architectural overview — identity, top-level conventions, and a map to deep references. The **meat** (per-subsystem APIs, page customization recipes, theming, behavior tables, defaults lists) lives in `docs/<topic>.md`. When extending or adding content, write it in the matching `docs/*.md` file and cross-link from here — do NOT inline it. If a topic doesn't have a doc yet, create one. Goal: keep this file under 250 lines.
4
4
 
5
5
  ## Identity
6
6
 
@@ -20,6 +20,19 @@ The only things that ARE safe to run inside UJM itself:
20
20
  - `npm run prepare` — copies `src/` → `dist/` via prepare-package
21
21
  - `npm test` (aka `npx mgr test`) — runs UJM's own three-layer test suite
22
22
 
23
+ ## Recommended skills
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`.
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
+
28
+ ## 🚨 READ WEB-MANAGER TOO
29
+
30
+ **UJM ships `web-manager` as a runtime singleton on every page** — it powers auth, Firebase, reactive `data-wm-bind` directives, analytics, error tracking, and utilities (`escapeHTML`, etc.). Any task that touches auth flows, Firestore reads/writes, subscription resolution, push notifications, or DOM bindings means you are working with web-manager as much as with UJM.
31
+
32
+ **Required reading:**
33
+ - **`node_modules/web-manager/CLAUDE.md`** — top-level overview + index
34
+ - **`node_modules/web-manager/docs/`** — module deep references (Auth, Bindings, Firestore, Notifications, etc.)
35
+
23
36
  ## Quick Start
24
37
 
25
38
  ### For Consuming Projects
@@ -35,7 +48,7 @@ The only things that ARE safe to run inside UJM itself:
35
48
 
36
49
  1. `npm install` — install UJM's own deps
37
50
  2. `npm start` (≡ `npm run prepare:watch`) — copies `src/` → `dist/` on file change
38
- 3. Test in a consumer project: `npm install --save-dev /Users/ian/.../ultimate-jekyll-manager`
51
+ 3. Test in a consumer project: from inside the consumer, run `npx mgr install local` (swaps UJM to the local repo via the `install` CLI). Reverse with `npx mgr install prod`.
39
52
  4. `npm test` — runs UJM's own 60 test suites
40
53
 
41
54
  ## Architecture
@@ -166,30 +179,44 @@ Don't ship behavioral changes with stale docs. Validate first, then document —
166
179
 
167
180
  ## Documentation
168
181
 
169
- Deep references live in `docs/`. Treat docs as a first-class deliverable.
182
+ Deep references live in `docs/`. Treat docs as a first-class deliverable. **Whenever you make a behavioral change, update both this overview AND the relevant `docs/*.md` deep reference.**
183
+
184
+ ### Framework reference
170
185
 
171
186
  - [docs/test-framework.md](docs/test-framework.md) — three-layer test harness reference (build / page / boot)
172
187
  - [docs/test-boot-layer.md](docs/test-boot-layer.md) — boot layer deep-dive (_site/ discovery, HTTP server, fixture vs consumer)
173
188
  - [docs/cross-context-helpers.md](docs/cross-context-helpers.md) — `isTesting`/`isDevelopment`/`isProduction`/`getVersion`
174
- - [docs/_legacy-claude-md.md](docs/_legacy-claude-md.md) — holding pen for content not yet split into proper subsystem docs. Anything still in here should be migrated to the appropriate `docs/<topic>.md` when touched.
175
-
176
- Planned/expected (create as needed, sourcing from `_legacy-claude-md.md`):
177
- - `docs/build-system.md` gulp pipeline, task graph, env-var matrix
178
- - `docs/cli.md` — CLI command surface, env-var conventions
179
- - `docs/templating.md``{ }` vs `[ ]` brackets, variable resolution
180
- - `docs/defaults.md`FILE_MAP routing, merge strategies, theme fallback
181
- - `docs/webpack.md`entry points, aliases, dev-block stripping
182
- - `docs/sass.md` — page-specific bundles, purgecss safelist, theme load paths
183
- - `docs/jekyll.md` — config merge chain, build.json, hooks
184
- - `docs/audit.md` — HTML validation, spellcheck, Lighthouse
185
- - `docs/translation.md`AI translation pipeline, cache, ignored pages
186
- - `docs/imagemin.md`responsive variants, GitHub cache
187
- - `docs/service-worker.md`SW lifecycle, cache composition, Firebase messaging
188
- - `docs/managers.md`frontend Manager class, dynamic page module loading
189
- - `docs/config-schema.md` — `_config.yml` fields, `ultimate-jekyll-manager.json` fields
190
- - `docs/setup.md` — what `npx mgr setup` does (7+ phases)
191
- - `docs/themes.md` — classy theme structure, custom themes, fallback
192
- - `docs/components.md`account dropdown, nav, footer JSON-driven sections
193
- - `docs/page-customization.md`frontmatter-driven page customization without HTML
189
+ - [docs/jekyll-plugin.md](docs/jekyll-plugin.md) — UJ Powertools gem: filters, tags, page variables (`page.resolved`, `uj_icon`, `uj_hash`, `iftruthy`, etc.)
190
+ - [docs/audit.md](docs/audit.md) — workflow for fixing issues raised by `gulp/tasks/audit.js`
191
+
192
+ ### Project & dev environment
193
+
194
+ - [docs/project-structure.md](docs/project-structure.md)UJM repo layout and consuming-project layout
195
+ - [docs/local-development.md](docs/local-development.md)browsersync URL, Firebase emulator connect, PurgeCSS safelist
196
+ - [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
197
+
198
+ ### Pages, layouts, content
199
+
200
+ - [docs/layouts-and-pages.md](docs/layouts-and-pages.md)page types, layout chain, `asset_path` frontmatter
201
+ - [docs/images.md](docs/images.md)`@post/` shortcut for blog post images, BEM admin/post image handling
202
+ - [docs/icons.md](docs/icons.md)Font Awesome conventions, `{% uj_icon %}` vs prerendered icons in JS, size reference
203
+ - [docs/seo.md](docs/seo.md)Alternatives collection (competitor comparison pages) + Schema/JSON-LD (`SoftwareApplication`, `FAQPage`)
204
+
205
+ ### Frontend behavior
206
+
207
+ - [docs/css.md](docs/css.md)section padding rule, theme-adaptive classes, cards in colored sections, `<html>` data attributes
208
+ - [docs/appearance.md](docs/appearance.md)dark/light/system mode switching: JS API, HTML attributes
209
+ - [docs/page-loading.md](docs/page-loading.md) — page-loading protection, `.btn-action`, layered form-protection strategy
210
+ - [docs/lazy-loading.md](docs/lazy-loading.md) — `data-lazy="@type value"` syntax and supported types
211
+ - [docs/ads.md](docs/ads.md) — Vert units: AdSense include + Promo Server fallback, size presets
212
+
213
+ ### JS libraries & security
214
+
215
+ - [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)
216
+ - [docs/xss-prevention.md](docs/xss-prevention.md) — zero-trust DOM injection rules, `escapeHTML`, postMessage origin checks, redirect validation
217
+
218
+ ### Analytics
219
+
220
+ - [docs/analytics.md](docs/analytics.md) — ITM tracking, gtag/fbq/ttq guidelines, TikTok-specific rules
194
221
 
195
222
  `TODO.md` + `TODO-*.md` files at the repo root track pass-by-pass progress and decisions.
@@ -0,0 +1,15 @@
1
+ # CHANGELOG
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
+
7
+ ## Changelog Categories
8
+
9
+ - `BREAKING` for breaking changes.
10
+ - `Added` for new features.
11
+ - `Changed` for changes in existing functionality.
12
+ - `Deprecated` for soon-to-be removed features.
13
+ - `Removed` for now removed features.
14
+ - `Fixed` for any bug fixes.
15
+ - `Security` in case of vulnerabilities.
@@ -1,15 +1,25 @@
1
1
  # ========== Default Values ==========
2
2
  # Ultimate Jekyll Manager (UJM) — consumer project
3
3
 
4
- > **Auto-managed file.** Everything between `# ========== Default Values ==========` and `# ========== Custom Values ==========` is owned by `ultimate-jekyll-manager` and rewritten on every `npx mgr setup`. Put your own project-specific notes BELOW the `Custom Values` marker — that section is preserved verbatim across setups.
5
-
6
4
  ## Framework
7
5
 
8
6
  This project consumes **Ultimate Jekyll Manager** (UJM) — a comprehensive framework for building modern Jekyll-powered static sites. UJM provides one-line bootstrap per context (build / frontend / service-worker), a multi-stage gulp pipeline (defaults / distribute / webpack / sass / imagemin / jekyll / audit / translation / minifyHtml / serve), default Jekyll layouts + themes, a frontend ES-module Manager with dynamic per-page module loading, a service worker with Firebase Messaging + cache management, and a built-in three-layer test framework.
9
7
 
10
- **Framework's own docs** (read these for deep-dives; both paths point to the same files, the absolute path works regardless of working directory):
11
- - Top-level overview: `/Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-manager/CLAUDE.md` (or `node_modules/ultimate-jekyll-manager/CLAUDE.md`)
12
- - Subsystem references: `/Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-manager/docs/` (or `node_modules/ultimate-jekyll-manager/docs/`)
8
+ ## 🚨 READ THE FRAMEWORK DOCS FIRST
9
+
10
+ **Before doing ANY work on this codebase, Claude MUST read the framework documentation — that is where the architecture, conventions, APIs, and gotchas live. Skipping these will result in solutions that conflict with framework patterns.**
11
+
12
+ **Required reading:**
13
+ - **`node_modules/ultimate-jekyll-manager/CLAUDE.md`** — top-level overview + index
14
+ - **`node_modules/ultimate-jekyll-manager/docs/`** — subsystem deep references (read the relevant ones for the task at hand)
15
+
16
+ ## 🚨 READ WEB-MANAGER TOO
17
+
18
+ **UJM ships `web-manager` as a runtime singleton on every page** — it powers auth, Firebase, reactive `data-wm-bind` directives, analytics, error tracking, and utilities (`escapeHTML`, etc.). Any task that touches auth flows, Firestore reads/writes, subscription resolution, push notifications, or DOM bindings means you are working with web-manager as much as with UJM.
19
+
20
+ **Required reading:**
21
+ - **`node_modules/web-manager/CLAUDE.md`** — top-level overview + index
22
+ - **`node_modules/web-manager/docs/`** — module deep references (Auth, Bindings, Firestore, Notifications, etc.)
13
23
 
14
24
  ## Quick start
15
25
 
@@ -67,6 +77,8 @@ At build time, `require('ultimate-jekyll-manager/build')` exposes:
67
77
  - `Manager.logger(name)` — timestamped logger instance
68
78
  - `Manager.require(path)` — escape hatch for UJM transitive deps (use sparingly)
69
79
 
80
+ <!-- Everything above this marker is owned by the framework and rewritten on every `npx mgr setup`. Add your project-specific notes below — they are preserved across setups. -->
81
+
70
82
  # ========== Custom Values ==========
71
83
 
72
84
  ## Project-specific notes
@@ -11,12 +11,6 @@ hero:
11
11
 
12
12
  # Downloads Section
13
13
  downloads:
14
- superheadline:
15
- icon: "puzzle-piece"
16
- text: "Install"
17
- headline: "Available on every"
18
- headline_accent: "browser"
19
- subheadline: "Choose your browser below to get started"
20
14
  loading:
21
15
  headline: "Detecting Browser"
22
16
  description: "Determining your browser..."
@@ -124,26 +118,6 @@ cta:
124
118
  <!-- Downloads Section -->
125
119
  <section class="pt-0">
126
120
  <div class="container">
127
- <div class="text-center mb-5" data-lazy="@class animation-slide-up">
128
- {% iftruthy page.resolved.downloads.superheadline.text %}
129
- <span class="badge bg-body-tertiary border-gradient-rainbow border-1 text-body p-2 mb-1 fw-semibold small">
130
- {% iftruthy page.resolved.downloads.superheadline.icon %}
131
- {% uj_icon page.resolved.downloads.superheadline.icon, "me-1" %}
132
- {% endiftruthy %}
133
- {{ page.resolved.downloads.superheadline.text }}
134
- </span>
135
- {% endiftruthy %}
136
- <h2 class="h2 mb-2">
137
- {{ page.resolved.downloads.headline }}
138
- {% iftruthy page.resolved.downloads.headline_accent %}
139
- <span class="text-accent">{{ page.resolved.downloads.headline_accent }}</span>
140
- {% endiftruthy %}
141
- </h2>
142
- {% iftruthy page.resolved.downloads.subheadline %}
143
- <p class="fs-5 text-muted">{{ page.resolved.downloads.subheadline }}</p>
144
- {% endiftruthy %}
145
- </div>
146
-
147
121
  <!-- Browser Selector -->
148
122
  <div class="row justify-content-center mb-5">
149
123
  <div class="col-12">
@@ -0,0 +1,17 @@
1
+ # Project docs
2
+
3
+ Per-subsystem deep references live here. Keep `CLAUDE.md` short — it should read as a **table of contents** that points at files in this directory.
4
+
5
+ ## Pattern
6
+
7
+ When you find yourself adding more than a paragraph to `CLAUDE.md`, create a new `docs/<topic>.md` instead and link to it from `CLAUDE.md`. Goal: the project's `CLAUDE.md` stays under ~250 lines.
8
+
9
+ Examples of good `docs/*.md` topics:
10
+ - Subsystem deep-dives (one per area of the codebase)
11
+ - Architectural decisions / "why we built it this way"
12
+ - Defaults tables, behavior matrices, edge cases
13
+ - Setup walkthroughs that don't belong in `README.md`
14
+
15
+ ## See also
16
+
17
+ The framework's own docs follow this same pattern — browse `node_modules/ultimate-jekyll-manager/docs/` for the canonical examples.
@@ -0,0 +1,31 @@
1
+ # Project tests
2
+
3
+ Drop your project test suites here. The framework auto-runs them alongside its own when you run `npx mgr test`.
4
+
5
+ ## Layers
6
+
7
+ Match the framework's three layers — Ultimate Jekyll Manager's test runner discovers files by the directory they sit in:
8
+
9
+ | Directory | Runtime | Use for |
10
+ |---|---|---|
11
+ | `test/build/` | Plain Node | Build-time logic, config validation, pure utilities |
12
+ | `test/page/` | Browser page served from a local HTTP server | DOM, frontend Manager, page-specific scripts, `data-wm-bind` directives |
13
+ | `test/boot/` | Consumer's actual built `_site/` | End-to-end smoke tests (does the site boot, does the service worker register, do dynamic pages load) |
14
+
15
+ ## Quick example
16
+
17
+ ```js
18
+ // test/build/my-feature.test.js
19
+ const assert = require('ultimate-jekyll-manager/test/assert');
20
+
21
+ module.exports = {
22
+ 'my feature does the thing': async () => {
23
+ const result = await doTheThing();
24
+ assert.equal(result, 'expected');
25
+ },
26
+ };
27
+ ```
28
+
29
+ ## See also
30
+
31
+ `node_modules/ultimate-jekyll-manager/docs/test-framework.md` — full reference for the test framework (layers, assert API, fixtures, runner internals).
package/docs/ads.md ADDED
@@ -0,0 +1,78 @@
1
+ # Ad Units (Verts)
2
+
3
+ Ultimate Jekyll provides ad unit includes that display Google AdSense ads with automatic fallback to in-house ads served from promo-server when AdSense is blocked or unfilled.
4
+
5
+ ## Include Files
6
+
7
+ | Include | Purpose |
8
+ |---------|---------|
9
+ | `modules/adunits/adsense.html` | AdSense ad with promo-server fallback |
10
+ | `modules/adunits/promo-server.html` | Direct promo-server ad (no AdSense) |
11
+
12
+ ## AdSense Include
13
+
14
+ ```liquid
15
+ {% include /modules/adunits/adsense.html type="in-article" %}
16
+ {% include /modules/adunits/adsense.html type="in-article" vert-size="rectangle" %}
17
+ {% include /modules/adunits/adsense.html type="display" vert-size="banner" %}
18
+ {% include /modules/adunits/adsense.html type="display" vert-size="300" %}
19
+ ```
20
+
21
+ **Parameters:**
22
+
23
+ | Parameter | Required | Default | Description |
24
+ |-----------|----------|---------|-------------|
25
+ | `type` | No | `display` | Ad type: `display`, `in-article`, `in-feed`, `multiplex` |
26
+ | `slot` | No | From site config | Override the ad slot ID |
27
+ | `vert-size` | No | (unconstrained) | Max height preset or pixel value (cannot use `size` — conflicts with Liquid's built-in `size` filter) |
28
+ | `style` | No | `""` | Custom inline CSS |
29
+ | `layout` | No | `image-above` | Layout for `in-feed` type: `image-above`, `image-side` |
30
+
31
+ ## Promo Server Include
32
+
33
+ ```liquid
34
+ {% include /modules/adunits/promo-server.html vert-id="/verts/units/test/google" %}
35
+ {% include /modules/adunits/promo-server.html vert-id="/verts/units/test/google" vert-size="banner" %}
36
+ ```
37
+
38
+ **Parameters:**
39
+
40
+ | Parameter | Required | Default | Description |
41
+ |-----------|----------|---------|-------------|
42
+ | `vert-id` | Yes | `""` | Path to the vert on promo-server |
43
+ | `vert-size` | No | (unconstrained) | Max height preset or pixel value |
44
+ | `style` | No | `""` | Custom inline CSS |
45
+
46
+ ## Size Presets
47
+
48
+ The `vert-size` parameter accepts preset names or raw pixel values. Presets constrain the ad unit's max-height:
49
+
50
+ | Preset | Max Height | Typical Use |
51
+ |--------|-----------|-------------|
52
+ | `banner` | 150px | Horizontal banner ads |
53
+ | `leaderboard` | 90px | Wide horizontal ads (alias for banner) |
54
+ | `rectangle` | 250px | Medium rectangle, in-content ads |
55
+ | `large-rectangle` | 600px | Large rectangle, sidebar ads |
56
+ | `skyscraper` | 600px | Tall sidebar ads |
57
+
58
+ Raw pixel values are also accepted: `vert-size="300"` → 300px max-height.
59
+
60
+ When no `vert-size` is specified, the ad unit renders unconstrained.
61
+
62
+ ## How It Works
63
+
64
+ 1. The include renders a `data-lazy="@script ..."` div that lazy-loads `vert.bundle.js` when scrolled into view
65
+ 2. `vert.js` creates a `<vert-unit>` custom element with `max-height` + `overflow: hidden` (if `vert-size` is set)
66
+ 3. For AdSense types: loads the AdSense script, pushes the ad, and monitors fill status
67
+ 4. If AdSense is blocked or unfilled, falls back to a promo-server iframe
68
+ 5. The promo-server iframe content uses CSS container queries to adapt its layout to the available space
69
+ 6. Ad units are hidden for non-basic plan users via `data-wm-bind="@hide auth.account.subscription.product.id !== basic"`
70
+
71
+ ## File Locations
72
+
73
+ | Purpose | Path |
74
+ |---------|------|
75
+ | AdSense include | `src/defaults/dist/_includes/modules/adunits/adsense.html` |
76
+ | Promo Server include | `src/defaults/dist/_includes/modules/adunits/promo-server.html` |
77
+ | Vert JS module | `src/assets/js/modules/vert.js` |
78
+ | Vert CSS | `src/assets/css/core/_verts.scss` |
@@ -0,0 +1,90 @@
1
+ # Analytics & Tracking
2
+
3
+ Ultimate Jekyll uses three tracking platforms: Google Analytics (gtag), Facebook Pixel (fbq), and TikTok Pixel (ttq).
4
+
5
+ ## ITM (Internal Tracking Medium)
6
+
7
+ Internal tracking system modeled after UTM for cross-property user journey tracking.
8
+
9
+ | Parameter | Purpose | Examples |
10
+ |-----------|---------|----------|
11
+ | `itm_source` | Platform/origin | `website`, `browser-extension`, `app`, `email` |
12
+ | `itm_medium` | Delivery mechanism | `modal`, `prompt`, `banner`, `tooltip` |
13
+ | `itm_campaign` | Specific campaign/feature | `exit-popup`, `premium-unlock`, `newsletter-signup` |
14
+ | `itm_content` | Specific context | Page path, feature ID, variant |
15
+
16
+ **Examples:**
17
+
18
+ ```
19
+ # Website exit popup
20
+ ?itm_source=website&itm_medium=modal&itm_campaign=exit-popup&itm_content=/pricing
21
+
22
+ # Extension premium unlock
23
+ ?itm_source=browser-extension&itm_medium=prompt&itm_campaign=premium-unlock&itm_content=bulk-export
24
+ ```
25
+
26
+ ## Tracking Guidelines
27
+
28
+ **IMPORTANT Rules:**
29
+ - Track important user events with `gtag()`, `fbq()`, and `ttq()` functions
30
+ - NEVER add conditional checks for tracking functions (e.g., `if (typeof gtag !== 'undefined')`)
31
+ - Always assume tracking functions exist — they're globally available or stubbed
32
+ - Reference standard events documentation before implementing custom tracking
33
+
34
+ **Standard Events Documentation:**
35
+ - **Google Analytics GA4:** https://developers.google.com/analytics/devguides/collection/ga4/reference/events
36
+ - **Facebook Pixel:** https://www.facebook.com/business/help/402791146561655?id=1205376682832142
37
+ - **TikTok Pixel:** https://ads.tiktok.com/help/article/standard-events-parameters?redirected=2
38
+
39
+ ## Platform-Specific Requirements
40
+
41
+ ### TikTok Pixel Requirements
42
+
43
+ TikTok has strict validation requirements:
44
+
45
+ **Required Parameters:**
46
+ - `content_id` — MUST be included in all events
47
+
48
+ **Valid Content Types:**
49
+ - `"product"`
50
+ - `"product_group"`
51
+ - `"destination"`
52
+ - `"hotel"`
53
+ - `"flight"`
54
+ - `"vehicle"`
55
+
56
+ Any other content type will generate a validation error.
57
+
58
+ **Example:**
59
+
60
+ ```javascript
61
+ // ✅ CORRECT
62
+ ttq.track('ViewContent', {
63
+ content_id: 'product-123',
64
+ content_type: 'product'
65
+ });
66
+
67
+ // ❌ WRONG - Missing content_id
68
+ ttq.track('ViewContent', {
69
+ content_type: 'product'
70
+ });
71
+
72
+ // ❌ WRONG - Invalid content_type
73
+ ttq.track('ViewContent', {
74
+ content_id: 'product-123',
75
+ content_type: 'custom' // Not in approved list
76
+ });
77
+ ```
78
+
79
+ ## Tracking Implementation
80
+
81
+ **IMPORTANT:** Always track events to ALL THREE platforms in this order:
82
+ 1. Google Analytics (gtag)
83
+ 2. Facebook Pixel (fbq)
84
+ 3. TikTok Pixel (ttq)
85
+
86
+ Track events directly without existence checks. All three tracking calls should be made together for every event.
87
+
88
+ **Development Mode:**
89
+
90
+ In development mode, all tracking calls are intercepted and logged to the console for debugging. See `src/assets/js/libs/dev.js` for implementation.
@@ -0,0 +1,65 @@
1
+ # Appearance Switching System
2
+
3
+ Ultimate Jekyll supports dark/light/system theme switching with user preference persistence.
4
+
5
+ ## Supported Modes
6
+
7
+ - `dark` — Force dark mode
8
+ - `light` — Force light mode
9
+ - `system` — Auto-detect from OS preference (`prefers-color-scheme`)
10
+
11
+ ## JavaScript API
12
+
13
+ ```javascript
14
+ // Get/set preference
15
+ webManager.uj().appearance.get(); // Returns 'dark', 'light', 'system', or null
16
+ webManager.uj().appearance.set('dark'); // Save and apply preference
17
+ webManager.uj().appearance.getResolved(); // Returns actual theme: 'dark' or 'light'
18
+
19
+ // Utilities
20
+ webManager.uj().appearance.toggle(); // Toggle between dark/light
21
+ webManager.uj().appearance.cycle(); // Cycle: dark → light → system → dark
22
+ webManager.uj().appearance.clear(); // Clear saved preference
23
+ ```
24
+
25
+ ## HTML Data Attributes
26
+
27
+ ```html
28
+ <!-- Buttons to set appearance (auto-gets 'active' class) -->
29
+ <button data-appearance-set="light">Light</button>
30
+ <button data-appearance-set="dark">Dark</button>
31
+ <button data-appearance-set="system">System</button>
32
+
33
+ <!-- Display current mode as text -->
34
+ <span data-appearance-current></span>
35
+
36
+ <!-- Show/hide icons based on current mode -->
37
+ <span data-appearance-icon="light" hidden>☀️</span>
38
+ <span data-appearance-icon="dark" hidden>🌙</span>
39
+ <span data-appearance-icon="system" hidden>💻</span>
40
+ ```
41
+
42
+ ## Dropdown Example
43
+
44
+ ```html
45
+ <div class="dropdown">
46
+ <button class="btn dropdown-toggle" data-bs-toggle="dropdown">
47
+ <span data-appearance-icon="light" hidden>{% uj_icon "sun", "fa-md me-2" %}</span>
48
+ <span data-appearance-icon="dark" hidden>{% uj_icon "moon-stars", "fa-md me-2" %}</span>
49
+ <span data-appearance-icon="system" hidden>{% uj_icon "circle-half-stroke", "fa-md me-2" %}</span>
50
+ <span data-appearance-current></span>
51
+ </button>
52
+ <ul class="dropdown-menu">
53
+ <li><a class="dropdown-item" href="#" data-appearance-set="light">Light</a></li>
54
+ <li><a class="dropdown-item" href="#" data-appearance-set="dark">Dark</a></li>
55
+ <li><a class="dropdown-item" href="#" data-appearance-set="system">System</a></li>
56
+ </ul>
57
+ </div>
58
+ ```
59
+
60
+ ## Implementation
61
+
62
+ - **Inline script:** `src/defaults/dist/_includes/core/body.html` — Runs immediately to prevent flash
63
+ - **Module:** `src/assets/js/core/appearance.js` — API and UI handling
64
+ - **Storage:** Saved under `_manager.appearance.preference` in localStorage
65
+ - **Test page:** `/test/libraries/appearance`