jekyll-theme-zer0 1.20.2 → 1.22.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2871e1d0cd0522e37b6bac85065edfe6767fc749c39a0ac257fec51dbff97691
4
- data.tar.gz: 12d1d870ed1115cd2044446c66b318f4d6e6c65b1ca3a59493353e5a9d6402a9
3
+ metadata.gz: 9bb7f0d10a0dcb7cbe5297c6a412db670fc837d5acc43c85b6752baab5acf5a9
4
+ data.tar.gz: '0095e82963f7316a63fecdf355f6fb3e8a126c7528666ab540d274175dda515c'
5
5
  SHA512:
6
- metadata.gz: 25198dd08404a6ae41724e8e172ce38f832f19b34efd83761cff86ba033c5952e2d315dad70c75b343cb0c94e216c1d5755a0c53048252a2bd7a1c1a61ac590b
7
- data.tar.gz: 49d28d829375c95f39986c6e19ff37d524e06f00ae7c388b743e6cd073a35f9c4717aa47f877bb8802d7c5f12fc1f2dd2d618c12785a6342f8a2164774fe6576
6
+ metadata.gz: 0240ae6516cbc159ae33925ad991e74b958ddbbe19c3806fdf6cde01ba7e625ae6a530184cde8a3e51d5e7748944eba105fec439cde7332910bce2e027f2b5d7
7
+ data.tar.gz: 80283b4cb1950832efac7b7713f660bab1d106adcc0dbeb320c385570a95cc5fd8e6f88614fd09fabdbc44081369300bc6e4e88ade905125edf5caad4ac14c74
data/CHANGELOG.md CHANGED
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.22.0](https://github.com/bamr87/zer0-mistakes/compare/v1.21.0...v1.22.0) (2026-06-26)
9
+
10
+
11
+ ### Features
12
+
13
+ * **ci:** autonomous CI self-repair loop (pipeline Phase 6) ([#237](https://github.com/bamr87/zer0-mistakes/issues/237)) ([a43db45](https://github.com/bamr87/zer0-mistakes/commit/a43db45eae2da2fcf141ac959d0268dd7e6a52bd))
14
+ * **comments:** enable Giscus + wire Claude Code conversation building ([#214](https://github.com/bamr87/zer0-mistakes/issues/214)) ([fef60a5](https://github.com/bamr87/zer0-mistakes/commit/fef60a5cf78697e94c40f098c336112fe5cdd845))
15
+ * **obsidian:** interactive callouts, parity fixes, a11y + vendored graph ([#200](https://github.com/bamr87/zer0-mistakes/issues/200)) ([affbcd6](https://github.com/bamr87/zer0-mistakes/commit/affbcd62b3f7023457195d5137d5ace2a3751367))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **ci:** enable auto-merge via GraphQL (no git checkout) + graceful no-op ([#232](https://github.com/bamr87/zer0-mistakes/issues/232)) ([4c8c74c](https://github.com/bamr87/zer0-mistakes/commit/4c8c74cfb0775feda9103b379ebcecc4874d517f))
21
+ * **includes:** existence-gate category badge links for remote-theme consumers ([#235](https://github.com/bamr87/zer0-mistakes/issues/235)) ([16ed0a8](https://github.com/bamr87/zer0-mistakes/commit/16ed0a8c77f4cd66b98918a66d00133fa90f4457))
22
+ * **includes:** make component-showcase demo links inert to avoid consumer 404s ([#236](https://github.com/bamr87/zer0-mistakes/issues/236)) ([e96646b](https://github.com/bamr87/zer0-mistakes/commit/e96646b196c2931fc240411ded23184a1e01c8f5))
23
+ * **navigation:** existence-gate the section-sidebar /tags/ links ([#231](https://github.com/bamr87/zer0-mistakes/issues/231)) ([a02b062](https://github.com/bamr87/zer0-mistakes/commit/a02b0622a4f16dfea375629ad347891861283fe3))
24
+ * **search:** degrade search UI gracefully when /search.json is absent ([#234](https://github.com/bamr87/zer0-mistakes/issues/234)) ([f3a718d](https://github.com/bamr87/zer0-mistakes/commit/f3a718d1a9219bee92e2d1a46d2e32c870efb624))
25
+
26
+ ## [1.21.0](https://github.com/bamr87/zer0-mistakes/compare/v1.20.2...v1.21.0) (2026-06-26)
27
+
28
+
29
+ ### Features
30
+
31
+ * **automation:** committee planning + specialized executor agents (Phase 4) ([#226](https://github.com/bamr87/zer0-mistakes/issues/226)) ([1e9016b](https://github.com/bamr87/zer0-mistakes/commit/1e9016b869ff33f26fc60d3ae27e7fcd0216e802))
32
+ * **automation:** issue intake + /issue-implement routing (Phases 2-3) ([#225](https://github.com/bamr87/zer0-mistakes/issues/225)) ([21a7008](https://github.com/bamr87/zer0-mistakes/commit/21a70080b2814827bd390201e1ec76fb2b9a874e))
33
+ * **scripts:** issue adoption in sync-backlog (Phase 1) ([#224](https://github.com/bamr87/zer0-mistakes/issues/224)) ([512068e](https://github.com/bamr87/zer0-mistakes/commit/512068e2556be7fe3a4c7870d9feab0ca52955d8))
34
+
8
35
  ## [1.20.2](https://github.com/bamr87/zer0-mistakes/compare/v1.20.1...v1.20.2) (2026-06-25)
9
36
 
10
37
 
data/_data/backlog.yml CHANGED
@@ -44,8 +44,15 @@
44
44
  # summary: 1–2 lines of context
45
45
  # acceptance: List of checkable done-criteria the implement routine verifies
46
46
  # links: { issue: <#|null>, pr: <#|null>, roadmap: "<version>|null" }
47
+ # When `issue:` points at an EXISTING issue, sync ADOPTS it (adds
48
+ # a managed block, preserves the author's text, no duplicate)
49
+ # instead of creating a new one. At most one task per issue.
47
50
  # created: YYYY-MM-DD
48
51
  # updated: YYYY-MM-DD
52
+ # route: (optional) executor-lane hint for /issue-implement; resolved via
53
+ # _data/routing.yml (defaults to the lane for `area`).
54
+ # depends_on: (optional) [T-NNN, …] tasks that must land first; consumed by the
55
+ # /issue-plan committee for ordering. Advisory.
49
56
  #
50
57
  # `risk: low` + area in {docs, deps, lint} makes a task auto-merge eligible once
51
58
  # CI is green (see `.github/prompts/backlog-implement.prompt.md`). Everything
@@ -55,8 +62,8 @@
55
62
 
56
63
  meta:
57
64
  title: "zer0-mistakes Backlog"
58
- updated: 2026-06-15
59
- next_id: 27
65
+ updated: 2026-06-26
66
+ next_id: 32
60
67
 
61
68
  tasks:
62
69
  # --- Housekeeping (seeded so the loop has work on day one) ------------------
@@ -706,3 +713,125 @@ tasks:
706
713
  links: { issue: null, pr: null, roadmap: null }
707
714
  created: 2026-06-15
708
715
  updated: 2026-06-15
716
+
717
+ # --- Issue intake 2026-06-26: remote-theme 404 cluster + docs ----------------
718
+ # Cap: 5 of 7 open issues triaged this run. Deferred (next run): #203 (consumer
719
+ # checklist docs — companion to T-031); #201 (giscus typo — already in-flight in
720
+ # PR #214, so no task, to avoid duplicating live work).
721
+
722
+ - id: T-027
723
+ title: "Theme chrome injects unconditional links (/authors/, /news/, /tags/, /posts/, graph) that 404 for remote-theme consumers"
724
+ status: open
725
+ priority: P2
726
+ area: a11y
727
+ risk: standard
728
+ effort: M
729
+ source: issue
730
+ route: a11y
731
+ summary: >-
732
+ Umbrella for the remote-theme 404 class (#204): the theme chrome itself
733
+ injects internal links to pages whose generators live in `_plugins` (skipped
734
+ by GitHub Pages safe mode), so a built consumer site has broken links on
735
+ every page. Guard each link by existence the way the footer "Quick Links"
736
+ block already does. Specific instances are T-029 (#218 sidebar) and T-030
737
+ (#219 showcase); T-028 (#202) is the search/sitemap variant. Any fix that
738
+ edits `_plugins/` is CODEOWNERS-gated -> human review.
739
+ acceptance:
740
+ - "Theme-injected chrome links render only when their target exists (mirror the footer Quick-Links existence guard)."
741
+ - "A link check over a built remote-theme `_site` reports no theme-injected 404s."
742
+ - "No edit to `lib/jekyll-theme-zer0/version.rb` or release files."
743
+ links: { issue: 204, pr: null, roadmap: null }
744
+ created: 2026-06-26
745
+ updated: 2026-06-26
746
+
747
+ - id: T-028
748
+ title: "remote_theme Pages consumers 404 on /search.json and /sitemap/ (generator is plugin-only)"
749
+ status: open
750
+ priority: P2
751
+ area: feat
752
+ risk: standard
753
+ effort: M
754
+ source: issue
755
+ route: code-fixer
756
+ summary: >-
757
+ On a pure remote-theme Pages consumer, `/search.json` and `/sitemap/` 404
758
+ because `_plugins/search_and_sitemap_generator.rb` never runs under Pages
759
+ safe mode (#202). Provide a Pages-safe fallback (committed stubs the navbar
760
+ search + sitemap link can resolve, or graceful degradation in
761
+ `assets/js/search-modal.js`). NOTE: editing `_plugins/` is CODEOWNERS-gated
762
+ -> human review; prefer the non-plugin path.
763
+ acceptance:
764
+ - "On a remote-theme Pages build, the navbar search resolves (no /search.json 404) or degrades gracefully."
765
+ - "The /sitemap/ link resolves (no 404) for a remote-theme consumer."
766
+ - "No new runtime dependency; no edit to version/release files."
767
+ links: { issue: 202, pr: null, roadmap: null }
768
+ created: 2026-06-26
769
+ updated: 2026-06-26
770
+
771
+ - id: T-029
772
+ title: "Guard the unconditional /tags/ link in section-sidebar.html for remote-theme consumers"
773
+ status: open
774
+ priority: P2
775
+ area: feat
776
+ risk: low
777
+ effort: S
778
+ source: issue
779
+ route: theme-ui
780
+ summary: >-
781
+ `_includes/navigation/section-sidebar.html:69` hardcodes a `/tags/` link;
782
+ remote-theme consumers have no `/tags/` index (plugin-only), so it 404s
783
+ (#218). Guard it the way `_includes/core/footer.html` (~138-147) guards its
784
+ links, or gate on a `site.tags_page` flag. Instance of the T-027 class.
785
+ acceptance:
786
+ - "The sidebar 'View All Tags' link renders only when the tags index exists (or a documented site flag is set)."
787
+ - "Remote-theme consumers no longer 404 from the sidebar link; the Jekyll build stays green."
788
+ - "A `test/visual/*.spec.js` regression asserts the conditional render (theme-ui / visual-evidence)."
789
+ links: { issue: 218, pr: null, roadmap: null }
790
+ created: 2026-06-26
791
+ updated: 2026-06-26
792
+
793
+ - id: T-030
794
+ title: "component-showcase.html hardcodes demo links (/docs/, /pages/, /docs/customization/) that 404 for consumers"
795
+ status: open
796
+ priority: P3
797
+ area: feat
798
+ risk: low
799
+ effort: S
800
+ source: issue
801
+ route: theme-ui
802
+ summary: >-
803
+ `_includes/components/component-showcase.html` hardcodes absolute demo links
804
+ (~323-325, 417/421) that 404 for any consumer without those exact routes
805
+ (#219). Parameterize them (the component already accepts `sections`) or guard
806
+ each by existence. Low priority — demo component — but it makes the showcase
807
+ un-includable as-is. Instance of the T-027 class.
808
+ acceptance:
809
+ - "The showcase's demo links are parameterized or existence-guarded (no hardcoded absolute paths that can 404)."
810
+ - "Including the showcase on a consumer site produces no theme-injected 404s; the Jekyll build stays green."
811
+ - "A `test/visual/*.spec.js` regression covers the parameterized/guarded links (theme-ui / visual-evidence)."
812
+ links: { issue: 219, pr: null, roadmap: null }
813
+ created: 2026-06-26
814
+ updated: 2026-06-26
815
+
816
+ - id: T-031
817
+ title: "Document the safe-mode build-overlay recipe for consumers building outside GitHub Pages"
818
+ status: open
819
+ priority: P3
820
+ area: docs
821
+ risk: low
822
+ effort: S
823
+ source: issue
824
+ route: content
825
+ summary: >-
826
+ Consumers who build the theme outside GitHub Pages (own CI/Actions) must
827
+ reinvent the safe-mode overlay: clone the remote theme, overlay content,
828
+ strip `_plugins`, then `jekyll build --strict_front_matter` (#220). Document
829
+ the recipe in the docs (companion to the #203 consumer checklist). A proven
830
+ reference exists in lifehacker.dev's `scripts/ci/build.sh`.
831
+ acceptance:
832
+ - "A docs page/section under `pages/_docs/` documents the build-overlay recipe (clone -> overlay -> strip _plugins -> strict build)."
833
+ - "It is cross-linked from the remote-theme/deploy docs and passes markdownlint + the content-review deterministic tier."
834
+ - "No code change; docs only."
835
+ links: { issue: 220, pr: null, roadmap: null }
836
+ created: 2026-06-26
837
+ updated: 2026-06-26
@@ -0,0 +1,37 @@
1
+ # =============================================================================
2
+ # Roadmap plan — ORDER-ONLY sequencing artifact
3
+ # =============================================================================
4
+ # Produced by the /issue-plan committee (.github/prompts/issue-plan.prompt.md).
5
+ # Validated + mirrored by scripts/sync-plan.rb.
6
+ #
7
+ # This file sequences OPEN backlog tasks into batches. It is ADVISORY input to
8
+ # the human-dispatched /issue-implement ordering — it does not dispatch anything.
9
+ #
10
+ # HARD INVARIANT (enforced by `sync-plan.rb --check`): order only. A batch may
11
+ # carry ONLY `id`, `goal`, `tasks` (bare T-NNN ids that exist + are open),
12
+ # `depends_on` (other batch ids; the DAG must be acyclic), and `test_framework`.
13
+ # It may NEVER carry risk / priority / area / status / effort / acceptance —
14
+ # those are DERIVED at read-time from `_data/backlog.yml` (the single source of
15
+ # truth), exactly as /backlog-implement already does. Two sources of truth drift.
16
+ #
17
+ # Example batch shape:
18
+ # batches:
19
+ # - id: B-1
20
+ # goal: "Unblock remote-theme consumers"
21
+ # tasks: [T-027, T-031]
22
+ # depends_on: []
23
+ # test_framework: "Playwright smoke for the 404 path + a remote-theme build matrix job"
24
+ # - id: B-2
25
+ # goal: "Theme chrome a11y pass"
26
+ # tasks: [T-033]
27
+ # depends_on: [B-1]
28
+ # test_framework: "axe-core checks + before/after visual evidence per the visual-evidence skill"
29
+ # =============================================================================
30
+
31
+ meta:
32
+ title: "zer0-mistakes Roadmap Plan"
33
+ updated: 2026-06-25
34
+ generated_by: "/issue-plan"
35
+
36
+ # Populated by the committee. Empty is valid (nothing sequenced yet).
37
+ batches: []
data/_data/routing.yml ADDED
@@ -0,0 +1,73 @@
1
+ # =============================================================================
2
+ # Issue routing — area:* (+ optional path globs) → executor lane
3
+ # =============================================================================
4
+ # Used by /issue-implement to pick the specialized executor for a task/issue.
5
+ #
6
+ # Resolution order:
7
+ # 1. explicit task.route -> that lane (override)
8
+ # 2. first `rules` entry whose `area` matches the task's area AND (if it lists
9
+ # `paths`) a path glob matches a file the work is expected to touch
10
+ # 3. `default` lane
11
+ #
12
+ # A "lane" pairs a specialized .claude/agents/<agent>.md executor with the
13
+ # file-scoped instructions + skills it must load. In v1 (until the cloud-routine
14
+ # substrate spike proves prompt->subagent dispatch), /issue-implement loads the
15
+ # lane's `instructions` + `skills` INLINE and the named `agent` is advisory; once
16
+ # the spike passes it delegates to the agent. Either way the lane is the same.
17
+ #
18
+ # NOTE: this file is DATA. It never grants autonomy — risk/auto-merge eligibility
19
+ # is derived from the backlog task per the autonomy policy in
20
+ # docs/systems/continuous-evolution.md, not from the lane.
21
+ # =============================================================================
22
+
23
+ default: code-fixer
24
+
25
+ lanes:
26
+ content:
27
+ agent: content-reviewer
28
+ instructions: [content-review.instructions.md, documentation.instructions.md]
29
+ skills: [content-review, validate-build]
30
+ done: "content builds; deterministic + AI content review clean"
31
+ theme-ui:
32
+ agent: theme-ui
33
+ instructions: [layouts.instructions.md, includes.instructions.md, sass.instructions.md, visual-evidence.instructions.md]
34
+ skills: [change-workflow, visual-evidence, validate-build]
35
+ done: "jekyll build green; regression spec + before/after evidence committed"
36
+ code-fixer:
37
+ agent: code-fixer
38
+ instructions: [includes.instructions.md, layouts.instructions.md, scripts.instructions.md]
39
+ skills: [change-workflow, validate-build]
40
+ done: "targeted tests green; jekyll build green if templates touched"
41
+ infra-scripts:
42
+ agent: infra-scripts
43
+ instructions: [scripts.instructions.md]
44
+ skills: [change-workflow, validate-build]
45
+ done: "scripts run; shellcheck/tests green; no CODEOWNERS-owned path touched"
46
+ test-author:
47
+ agent: test-author
48
+ instructions: [testing.instructions.md, visual-evidence.instructions.md]
49
+ skills: [validate-build]
50
+ done: "new test fails before the fix and passes after; suite green"
51
+ a11y:
52
+ agent: a11y-fixer
53
+ instructions: [includes.instructions.md, layouts.instructions.md, sass.instructions.md, visual-evidence.instructions.md]
54
+ skills: [change-workflow, visual-evidence, validate-build]
55
+ done: "axe/a11y checks pass; regression spec + evidence committed"
56
+ deps:
57
+ agent: deps-bumper
58
+ instructions: []
59
+ skills: [change-workflow, validate-build]
60
+ done: "lockfiles consistent; build + tests green"
61
+
62
+ # First match wins. `feat` appears twice on purpose: a UI-touching feat routes to
63
+ # theme-ui, anything else falls through to the default code-fixer.
64
+ rules:
65
+ - { area: docs, lane: content }
66
+ - { area: a11y, lane: a11y }
67
+ - { area: tests, lane: test-author }
68
+ - { area: infra, lane: infra-scripts }
69
+ - { area: deps, lane: deps }
70
+ - { area: feat, paths: ["_layouts/**", "_includes/**", "_sass/**", "assets/**"], lane: theme-ui }
71
+ - { area: feat, lane: code-fixer }
72
+ - { area: perf, lane: code-fixer }
73
+ - { area: lint, lane: code-fixer }
@@ -15,13 +15,21 @@
15
15
  tabs,progress,breadcrumbs,table,tooltips,list-group
16
16
  Default: all sections
17
17
 
18
- Usage:
19
- {% include components/component-showcase.html %}
20
- {% include components/component-showcase.html sections="alerts,buttons,cards" %}
18
+ Usage (wrapped in raw so these examples are shown literally and NOT executed —
19
+ un-wrapped, Liquid runs them even inside this HTML comment and the include
20
+ recursively includes itself "stack level too deep"):
21
+ {% raw %}{% include components/component-showcase.html %}
22
+ {% include components/component-showcase.html sections="alerts,buttons,cards" %}{% endraw %}
21
23
 
22
24
  Dependencies:
23
25
  - Bootstrap 5.3 CSS & JS (loaded by theme)
24
26
  - Bootstrap Icons (loaded by theme)
27
+
28
+ Note: The breadcrumb and list-group links are DEMO links only — they are
29
+ intentionally inert (href="#" with onclick="return false;") so the
30
+ showcase never injects site-absolute paths (/docs/, /pages/, ...) that
31
+ would 404 on consumer sites that lack those exact routes (issue #219).
32
+ Do not point them at absolute paths.
25
33
  ===================================================================
26
34
  -->
27
35
  {% assign sections = include.sections | default: "alerts,buttons,badges,cards,accordion,tabs,progress,breadcrumbs,table,tooltips,list-group" %}
@@ -320,9 +328,9 @@ theme: jekyll-theme-zer0</code></pre>
320
328
  <p>Hierarchical navigation trail showing current page position:</p>
321
329
  <nav aria-label="breadcrumb example" class="mb-4">
322
330
  <ol class="breadcrumb">
323
- <li class="breadcrumb-item"><a href="/" class="text-decoration-none"><i class="bi bi-house me-1"></i>Home</a></li>
324
- <li class="breadcrumb-item"><a href="/docs/" class="text-decoration-none">Documentation</a></li>
325
- <li class="breadcrumb-item"><a href="/docs/customization/" class="text-decoration-none">Customization</a></li>
331
+ <li class="breadcrumb-item"><a href="#" class="text-decoration-none" onclick="return false;"><i class="bi bi-house me-1"></i>Home</a></li>
332
+ <li class="breadcrumb-item"><a href="#" class="text-decoration-none" onclick="return false;">Documentation</a></li>
333
+ <li class="breadcrumb-item"><a href="#" class="text-decoration-none" onclick="return false;">Customization</a></li>
326
334
  <li class="breadcrumb-item active" aria-current="page">Theme Colors</li>
327
335
  </ol>
328
336
  </nav>
@@ -414,19 +422,19 @@ document.addEventListener('DOMContentLoaded', () => {
414
422
  <div class="row g-4 mb-4">
415
423
  <div class="col-md-6">
416
424
  <div class="list-group">
417
- <a href="/pages/" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
425
+ <a href="#" onclick="return false;" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
418
426
  <span><i class="bi bi-journal-richtext text-primary me-2"></i>Blog Posts</span>
419
427
  <span class="badge bg-primary rounded-pill">{{ site.posts.size | default: "12" }}</span>
420
428
  </a>
421
- <a href="/docs/" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
429
+ <a href="#" onclick="return false;" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
422
430
  <span><i class="bi bi-book text-success me-2"></i>Documentation</span>
423
431
  <span class="badge bg-success rounded-pill">{{ site.documents.size | default: "8" }}</span>
424
432
  </a>
425
- <a href="/categories/" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
433
+ <a href="#" onclick="return false;" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
426
434
  <span><i class="bi bi-collection text-info me-2"></i>Categories</span>
427
435
  <span class="badge bg-info rounded-pill">{{ site.categories.size | default: "6" }}</span>
428
436
  </a>
429
- <a href="/tags/" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
437
+ <a href="#" onclick="return false;" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
430
438
  <span><i class="bi bi-tags text-warning me-2"></i>Tags</span>
431
439
  <span class="badge bg-warning text-dark rounded-pill">{{ site.tags.size | default: "24" }}</span>
432
440
  </a>
@@ -44,15 +44,23 @@
44
44
  {% endif %}
45
45
 
46
46
  <!-- Obsidian wiki-link / embed / tag client-side resolver (fallback for the
47
- remote_theme GH Pages build, where _plugins/obsidian_links.rb cannot run). -->
47
+ remote_theme GH Pages build, where _plugins/obsidian_links.rb cannot run).
48
+ Honours `obsidian: { enabled: false }` in _config.yml — when disabled the
49
+ resolver script is not loaded and the flag self-disables any fork that
50
+ loads it another way. Note: `| default: true` would flip `false` back to
51
+ true (Liquid treats false as falsy), so test enabled == false explicitly. -->
48
52
  {%- assign obsidian_attachments_path = site.obsidian.attachments_path | default: '/assets/images/notes' -%}
49
53
  <script>
50
54
  window.OBSIDIAN_CONFIG = window.OBSIDIAN_CONFIG || {};
55
+ window.OBSIDIAN_CONFIG.enabled = {% if site.obsidian.enabled == false %}false{% else %}true{% endif %};
51
56
  window.OBSIDIAN_CONFIG.wikiIndexUrl = {{ '/assets/data/wiki-index.json' | relative_url | jsonify }};
52
57
  window.OBSIDIAN_CONFIG.attachmentsPath = {{ obsidian_attachments_path | relative_url | jsonify }};
53
58
  window.OBSIDIAN_CONFIG.tagBase = {{ '/tags/' | relative_url | jsonify }};
59
+ window.OBSIDIAN_CONFIG.cytoscapeUrl = {{ '/assets/vendor/cytoscape/cytoscape.min.js' | relative_url | jsonify }};
54
60
  </script>
55
- <script defer src="{{ '/assets/js/obsidian-wiki-links.js' | relative_url }}"></script>
61
+ {%- if site.obsidian.enabled != false -%}
62
+ <script defer src="{{ '/assets/js/obsidian-wiki-links.js' | relative_url }}?v={{ site.time | date: '%s' }}"></script>
63
+ {%- endif -%}
56
64
 
57
65
  <!-- Optional fork overrides: opt-in via `site.user_overrides: true` in _config.yml. -->
58
66
  {% if site.user_overrides %}
@@ -108,16 +108,30 @@
108
108
  <div class="card-body d-flex flex-column">
109
109
 
110
110
  <!-- Category Badge -->
111
- {% comment %} Category base is configurable (`category_base`, default `/news`)
112
- to avoid hardcoded 404s for remote-theme consumers. See issue #204. {% endcomment %}
111
+ {% comment %} Category base is configurable (`category_base`, default `/news`).
112
+ Only link the badge when that category index page exists in the build;
113
+ otherwise render a plain badge so remote-theme consumers (whose category
114
+ section is plugin/page-generated and absent) don't get a 404. Mirrors
115
+ the tag-badge / footer Quick-Links existence guard. See issue #204. {% endcomment %}
113
116
  {% if show_category and include.post.categories.size > 0 %}
114
117
  {% assign _category_base = site.category_base | default: '/news' %}
118
+ {% assign primary_category = include.post.categories | first %}
119
+ {% capture _category_url %}{{ _category_base }}/{{ primary_category | slugify }}/{% endcapture %}
120
+ {% comment %} Category index pages can live in site.pages (a regular page) or
121
+ site.posts (a dated section index), so check both. {% endcomment %}
122
+ {% assign _category_page = site.html_pages | where: "url", _category_url | first %}
123
+ {% unless _category_page %}
124
+ {% assign _category_page = site.posts | where: "url", _category_url | first %}
125
+ {% endunless %}
115
126
  <div class="mb-2">
116
- {% assign primary_category = include.post.categories | first %}
117
- <a href="{{ site.baseurl }}{{ _category_base }}/{{ primary_category | slugify }}/"
127
+ {% if _category_page %}
128
+ <a href="{{ site.baseurl }}{{ _category_url }}"
118
129
  class="badge bg-primary text-decoration-none">
119
130
  {{ primary_category }}
120
131
  </a>
132
+ {% else %}
133
+ <span class="badge bg-primary">{{ primary_category }}</span>
134
+ {% endif %}
121
135
  </div>
122
136
  {% endif %}
123
137
 
@@ -21,11 +21,26 @@
21
21
  ===================================================================
22
22
  {%- endcomment -%}
23
23
 
24
- {%- if page.backlinks != false -%}
24
+ {%- if page.backlinks != false and site.obsidian.enabled != false -%}
25
25
  {%- assign _self_url = page.url -%}
26
26
  {%- assign _self_title = page.title | default: "" | downcase | strip -%}
27
27
  {%- assign _self_basename = page.path | split: "/" | last | replace: ".md", "" | replace: ".markdown", "" | downcase -%}
28
28
 
29
+ {%- comment -%}
30
+ Needles = every name another page could wiki-link this page by: title,
31
+ file basename, and any frontmatter aliases. Normalized to lowercase + strip
32
+ to match the resolver. A backlink is a [[needle]] with a terminator
33
+ (]] | # ^) so [[Foobar]] does NOT match the needle "foo".
34
+ {%- endcomment -%}
35
+ {%- assign _needles = "" | split: "" -%}
36
+ {%- if _self_title != "" -%}{%- assign _needles = _needles | push: _self_title -%}{%- endif -%}
37
+ {%- if _self_basename != "" -%}{%- assign _needles = _needles | push: _self_basename -%}{%- endif -%}
38
+ {%- for _alias in page.aliases -%}
39
+ {%- assign _an = _alias | downcase | strip -%}
40
+ {%- if _an != "" -%}{%- assign _needles = _needles | push: _an -%}{%- endif -%}
41
+ {%- endfor -%}
42
+ {%- assign _needles = _needles | uniq -%}
43
+
29
44
  {%- assign _candidates = "" | split: "" -%}
30
45
  {%- for _coll in site.collections -%}
31
46
  {%- for _doc in _coll.docs -%}
@@ -46,31 +61,44 @@
46
61
  {%- if _doc.published == false or _doc.draft == true -%}{%- continue -%}{%- endif -%}
47
62
  {%- endunless -%}
48
63
  {%- assign _body = _doc.content | default: "" -%}
49
- {%- assign _body_lower = _body | downcase -%}
50
64
  {%- assign _matched = false -%}
51
65
 
66
+ {%- comment -%} A markdown link to this page's permalink is a backlink. {%- endcomment -%}
52
67
  {%- if _self_url and _self_url != "" and _self_url != "/" -%}
53
68
  {%- if _body contains _self_url -%}
54
69
  {%- assign _matched = true -%}
55
70
  {%- endif -%}
56
71
  {%- endif -%}
57
72
 
73
+ {%- comment -%}
74
+ Wiki-link match: strip fenced (```) and inline (`) code first so a page
75
+ that merely *documents* [[syntax]] doesn't register as a backlink, then
76
+ require a terminator after the needle.
77
+ {%- endcomment -%}
58
78
  {%- unless _matched -%}
59
- {%- if _self_title != "" -%}
60
- {%- assign _needle = "[[" | append: _self_title -%}
61
- {%- if _body_lower contains _needle -%}
79
+ {%- assign _nb = "" -%}
80
+ {%- assign _fp = _body | split: "```" -%}
81
+ {%- for _p in _fp -%}
82
+ {%- assign _m = forloop.index0 | modulo: 2 -%}
83
+ {%- if _m == 0 -%}{%- assign _nb = _nb | append: _p -%}{%- endif -%}
84
+ {%- endfor -%}
85
+ {%- assign _nb2 = "" -%}
86
+ {%- assign _ip = _nb | split: "`" -%}
87
+ {%- for _p in _ip -%}
88
+ {%- assign _m = forloop.index0 | modulo: 2 -%}
89
+ {%- if _m == 0 -%}{%- assign _nb2 = _nb2 | append: _p -%}{%- endif -%}
90
+ {%- endfor -%}
91
+ {%- assign _body_lower = _nb2 | downcase -%}
92
+ {%- for _n in _needles -%}
93
+ {%- assign _v1 = "[[" | append: _n | append: "]]" -%}
94
+ {%- assign _v2 = "[[" | append: _n | append: "|" -%}
95
+ {%- assign _v3 = "[[" | append: _n | append: "#" -%}
96
+ {%- assign _v4 = "[[" | append: _n | append: "^" -%}
97
+ {%- if _body_lower contains _v1 or _body_lower contains _v2 or _body_lower contains _v3 or _body_lower contains _v4 -%}
62
98
  {%- assign _matched = true -%}
99
+ {%- break -%}
63
100
  {%- endif -%}
64
- {%- endif -%}
65
- {%- endunless -%}
66
-
67
- {%- unless _matched -%}
68
- {%- if _self_basename != "" -%}
69
- {%- assign _needle2 = "[[" | append: _self_basename -%}
70
- {%- if _body_lower contains _needle2 -%}
71
- {%- assign _matched = true -%}
72
- {%- endif -%}
73
- {%- endif -%}
101
+ {%- endfor -%}
74
102
  {%- endunless -%}
75
103
 
76
104
  {%- if _matched -%}
@@ -92,11 +120,12 @@
92
120
  <strong>{{ _ref.title | default: _ref.path | split: "/" | last }}</strong>
93
121
  </a>
94
122
  {%- if _ref.collection -%}
95
- <span class="badge bg-light text-dark ms-1">{{ _ref.collection }}</span>
123
+ <span class="badge rounded-pill border text-body-secondary ms-1">{{ _ref.collection }}</span>
96
124
  {%- endif -%}
97
- {%- if _ref.description -%}
125
+ {%- assign _ref_excerpt = _ref.description | default: _ref.excerpt | strip_html | strip | truncate: 160 -%}
126
+ {%- if _ref_excerpt and _ref_excerpt != "" -%}
98
127
  <div class="obsidian-backlink-excerpt small text-muted">
99
- {{ _ref.description | strip_html | truncate: 160 }}
128
+ {{ _ref_excerpt }}
100
129
  </div>
101
130
  {%- endif -%}
102
131
  </li>
@@ -1,49 +1,35 @@
1
1
  <!--
2
- ╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
3
- ║ giscus.html ║
4
- ║ GitHub Discussions Comment System ║
5
- ╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
6
- ║ ║
7
- ║ Purpose: Integrates Giscus comment system powered by GitHub Discussions ║
8
- Location: /_includes/content/giscus.html ║
9
- ║ Usage: include content/giscus.html (Liquid tag; braces omitted — Liquid ║
10
- ║ parses include tags even inside HTML comments, which would error)
11
- Dependencies: GitHub repository with Discussions enabled, site.repository, site.giscus configuration ║
12
- ║ ║
13
- Features: ║
14
- ║ • GitHub Discussions-based commenting system ║
15
- ║ • Automatic theme detection (preferred_color_scheme) ║
16
- Pathname-based mapping for unique comment threads ║
17
- Reaction support for enhanced user engagement ║
18
- Top-positioned input for better UX ║
19
- ║ ║
20
- ║ Configuration Options: ║
21
- ║ • data-repo: GitHub repository (site.repository) ║
22
- ║ • data-repo-id: GitHub repository ID (site.giscus.data-repo-id) ║
23
- ║ • data-category-id: Discussions category ID (site.giscus.data-category-id) ║
24
- ║ • data-mapping: "pathname" - maps comments to page URL ║
25
- ║ • data-strict: "1" - enables strict mapping mode ║
26
- ║ ║
27
- ║ Setup Requirements: ║
28
- ║ • GitHub repository with Discussions feature enabled ║
29
- ║ • Giscus app installed on the repository ║
30
- ║ • Correct repo-id and category-id in _config.yml ║
31
- ║ ║
32
- ║ Reference: Feature Request #FR000001 ║
33
- ║ Documentation: https://giscus.app/ ║
34
- ║ ║
35
- ╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
36
- -->
2
+ giscus.html — GitHub Discussions comment system
3
+ ===============================================
4
+
5
+ Purpose: Embeds the Giscus widget so page comments are stored as
6
+ GitHub Discussions (no database, privacy-friendly).
7
+ Location: _includes/content/giscus.html
8
+ Usage: Rendered by the article / note / notebook layouts, gated on
9
+ `page.comments != false and site.giscus.enabled`.
10
+ To include manually elsewhere, use the FULL path:
11
+ include content/giscus.html (wrap in Liquid tags)
12
+ Dependencies: site.repository, site.giscus.* (see _config.yml), a public
13
+ repo with Discussions enabled + the Giscus app installed.
14
+
15
+ Features:
16
+ GitHub Discussions-based commenting
17
+ Automatic light/dark theme (preferred_color_scheme)
18
+ Pathname-based mapping for one thread per page (data-strict)
19
+ • Reactions enabled, input positioned at the top
37
20
 
38
- <!-- ===================================================================================================== -->
39
- <!-- GISCUS COMMENT SYSTEM -->
40
- <!-- ===================================================================================================== -->
41
- <!-- GitHub Discussions-powered comment system integration -->
42
- <!-- Feature Request: #FR000001 -->
43
- <!-- Documentation: https://giscus.app/ -->
44
- <!-- Async loading: Non-blocking comment system initialization -->
21
+ Config-driven attributes (from _config.yml `giscus:` block):
22
+ data-repo ← site.repository
23
+ data-repo-id ← site.giscus.data-repo-id
24
+ data-category-id site.giscus.data-category-id
45
25
 
46
- <!-- giscus app - https://giscus.app/ - Feature # FR000001 -->
26
+ Docs: pages/_docs/features/giscus-comments.md
27
+ Reference: https://giscus.app/ (Feature Request #FR000001)
28
+
29
+ NOTE: do not write a bare `include giscus.html` example with live Liquid
30
+ braces inside this file — Liquid evaluates tags even inside HTML comments,
31
+ which would recursively (and wrongly) try to include "giscus.html".
32
+ -->
47
33
 
48
34
  <script src="https://giscus.app/client.js"
49
35
  data-repo="{{ site.repository }}"
@@ -58,4 +44,4 @@
58
44
  data-lang="en"
59
45
  crossorigin="anonymous"
60
46
  async>
61
- </script>
47
+ </script>