jekyll-obsidian-site 0.3.1 → 0.3.2

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +44 -86
  3. data/website/_includes/website/archive-card-footer.html +1 -1
  4. data/website/_includes/website/archive-pagination.html +5 -2
  5. data/website/_includes/website/contact-icon.html +12 -12
  6. data/website/_includes/website/dialogs.html +2 -2
  7. data/website/_includes/website/favorites-ui.html +1 -1
  8. data/website/_includes/website/footer.html +25 -0
  9. data/website/_includes/website/local-graph.html +1 -0
  10. data/website/_includes/website/note-header.html +4 -0
  11. data/website/_includes/website/note-source.html +1 -1
  12. data/website/_includes/website/system-page.html +0 -1
  13. data/website/_includes/website/tag-filter.html +1 -1
  14. data/website/_layouts/website-minimal.html +2 -2
  15. data/website/assets/archive-filters-R5WW6IKE.js +12 -0
  16. data/website/assets/{archive-worker-2YFJRTHP.js → archive-worker-G2I544NV.js} +1 -1
  17. data/website/assets/chunks/{abnfDiagram-WEYOIA3C-Z5V7NHNW.js → abnfDiagram-WEYOIA3C-H6XY6TGQ.js} +1 -1
  18. data/website/assets/chunks/{architectureDiagram-ZHVYKT53-3Q3V5WBD.js → architectureDiagram-ZHVYKT53-4FFTTUL4.js} +1 -1
  19. data/website/assets/chunks/{blockDiagram-RJAE7QA3-OAF7LPDQ.js → blockDiagram-RJAE7QA3-AXWKL2AZ.js} +1 -1
  20. data/website/assets/chunks/{c4Diagram-XDPPPE54-EJWLHA47.js → c4Diagram-XDPPPE54-2GAHNEQW.js} +1 -1
  21. data/website/assets/chunks/{chunk-KY2Z6HIV.js → chunk-2NQ22GFO.js} +1 -1
  22. data/website/assets/chunks/{chunk-OEBMYWCF.js → chunk-4KPJTMZ4.js} +1 -1
  23. data/website/assets/chunks/{chunk-BYAY7DUZ.js → chunk-6ZQ7VHWN.js} +1 -1
  24. data/website/assets/chunks/{chunk-P2OPVFT2.js → chunk-7AU45BWK.js} +1 -1
  25. data/website/assets/chunks/{chunk-IFVMCECG.js → chunk-7KPU4VDE.js} +1 -1
  26. data/website/assets/chunks/{chunk-FBK4QOLY.js → chunk-A5S7PJ2Q.js} +1 -1
  27. data/website/assets/chunks/{chunk-YPZM5QAW.js → chunk-BNFQ6YYK.js} +1 -1
  28. data/website/assets/chunks/{chunk-MGH5TWGB.js → chunk-DR3UYLVK.js} +1 -1
  29. data/website/assets/chunks/{chunk-MMD2CHZ4.js → chunk-EB5GI6TX.js} +1 -1
  30. data/website/assets/chunks/chunk-GPIO2QPP.js +1 -0
  31. data/website/assets/chunks/{chunk-ELAEHAWT.js → chunk-I5CHBHZT.js} +1 -1
  32. data/website/assets/chunks/{chunk-IEWJFRV2.js → chunk-KFCEUT4I.js} +1 -1
  33. data/website/assets/chunks/{chunk-GFG7Q2HN.js → chunk-KJTG2HC3.js} +1 -1
  34. data/website/assets/chunks/{chunk-KOVRICJQ.js → chunk-LUJIS6FY.js} +1 -1
  35. data/website/assets/chunks/chunk-MKLMFEY4.js +1 -0
  36. data/website/assets/chunks/{chunk-ODUIGMTT.js → chunk-NSER5MRF.js} +1 -1
  37. data/website/assets/chunks/{chunk-PHW75MPZ.js → chunk-ODZW2LAZ.js} +1 -1
  38. data/website/assets/chunks/chunk-TZRTKK7O.js +1 -0
  39. data/website/assets/chunks/{chunk-XPCWLWWI.js → chunk-USR7LCIV.js} +1 -1
  40. data/website/assets/chunks/{chunk-QV32QYTD.js → chunk-V3AAEOUZ.js} +1 -1
  41. data/website/assets/chunks/{classDiagram-v2-4MYWR3UA-TBKN4UUY.js → classDiagram-v2-4MYWR3UA-ZY57RKXZ.js} +1 -1
  42. data/website/assets/chunks/{cose-bilkent-JH36ORCC-L6EPO3KG.js → cose-bilkent-JH36ORCC-WIVS7FPC.js} +1 -1
  43. data/website/assets/chunks/{cynefinDiagram-WF24UDRP-NQI7F564.js → cynefinDiagram-WF24UDRP-MLC22WFH.js} +1 -1
  44. data/website/assets/chunks/{dagre-NK4GIZVX-JD2M5C6I.js → dagre-NK4GIZVX-4LFK4F5D.js} +1 -1
  45. data/website/assets/chunks/{diagram-CBK3MWTC-D4ZSERBO.js → diagram-CBK3MWTC-2SSL2APM.js} +1 -1
  46. data/website/assets/chunks/{diagram-I5XIIV2D-HIOQ6A3G.js → diagram-I5XIIV2D-64DRXMM6.js} +1 -1
  47. data/website/assets/chunks/{diagram-ODIL2UCW-MSREDQ6B.js → diagram-ODIL2UCW-XK4IEKYC.js} +1 -1
  48. data/website/assets/chunks/{diagram-PFBEJUXE-JPKSKRIC.js → diagram-PFBEJUXE-KKVC77DE.js} +1 -1
  49. data/website/assets/chunks/{diagram-RJA3I4VV-IQ6632CB.js → diagram-RJA3I4VV-LNQEDK46.js} +1 -1
  50. data/website/assets/chunks/{diagram-TYUNFSNR-P5IKS3A3.js → diagram-TYUNFSNR-QVOLMEC4.js} +1 -1
  51. data/website/assets/chunks/{ebnfDiagram-V4P3TTPT-VCZMC4YS.js → ebnfDiagram-V4P3TTPT-CXZTWZZY.js} +1 -1
  52. data/website/assets/chunks/{elk-QONTBCTQ-7AW4R5PK.js → elk-QONTBCTQ-ASERRRNS.js} +1 -1
  53. data/website/assets/chunks/{erDiagram-KYQIGQAA-V4LOTM3S.js → erDiagram-KYQIGQAA-NEFXHTDF.js} +1 -1
  54. data/website/assets/chunks/flowDiagram-IUGLLWBU-GKBFQNDP.js +1 -0
  55. data/website/assets/chunks/{ganttDiagram-R7GPNTJY-AEVHODOA.js → ganttDiagram-R7GPNTJY-Y2KSJYS4.js} +1 -1
  56. data/website/assets/chunks/{gitGraphDiagram-PDYL7XHY-LKBXIKVR.js → gitGraphDiagram-PDYL7XHY-EX3ERW5D.js} +1 -1
  57. data/website/assets/chunks/infoDiagram-MVDRKAX5-AUCEX7FP.js +2 -0
  58. data/website/assets/chunks/{ishikawaDiagram-HPEHV2GE-JSVZLZDP.js → ishikawaDiagram-HPEHV2GE-CCJUQRNA.js} +1 -1
  59. data/website/assets/chunks/{journeyDiagram-BOSHW7O7-JVAKMGRK.js → journeyDiagram-BOSHW7O7-ZS3BH6WM.js} +1 -1
  60. data/website/assets/chunks/{kanban-definition-FNSA4HC5-7RQQNTOF.js → kanban-definition-FNSA4HC5-VFJSTQMF.js} +1 -1
  61. data/website/assets/chunks/{mindmap-definition-6OY57UG3-NRMVR6UI.js → mindmap-definition-6OY57UG3-KHVZR6MO.js} +1 -1
  62. data/website/assets/chunks/{pegDiagram-ECIUJNBX-BUG53OMT.js → pegDiagram-ECIUJNBX-4DCYWOTB.js} +1 -1
  63. data/website/assets/chunks/{pieDiagram-GNMPY74T-KK6VNPAE.js → pieDiagram-GNMPY74T-MSSPA6BG.js} +1 -1
  64. data/website/assets/chunks/{quadrantDiagram-D57K4MC3-6R7AY2OK.js → quadrantDiagram-D57K4MC3-AOYUYY4I.js} +1 -1
  65. data/website/assets/chunks/{railroadDiagram-Y72NRBL7-G6YI4UOP.js → railroadDiagram-Y72NRBL7-2F7VDY63.js} +1 -1
  66. data/website/assets/chunks/{requirementDiagram-EQYSW5RA-FGXZYHEV.js → requirementDiagram-EQYSW5RA-VWA3RAXW.js} +1 -1
  67. data/website/assets/chunks/{sankeyDiagram-SY24JHO5-7JCOYDKS.js → sankeyDiagram-SY24JHO5-2555YRTO.js} +1 -1
  68. data/website/assets/chunks/{sequenceDiagram-BLEHNHQU-R5TBDEQR.js → sequenceDiagram-BLEHNHQU-42EPBSFI.js} +1 -1
  69. data/website/assets/chunks/{stateDiagram-v2-A6IESKWZ-PS2LTOBE.js → stateDiagram-v2-A6IESKWZ-BUWAZBMT.js} +1 -1
  70. data/website/assets/chunks/{swimlanes-B3ENRKFQ-T4ANUYE5.js → swimlanes-B3ENRKFQ-YVQZM2ZV.js} +1 -1
  71. data/website/assets/chunks/swimlanesDiagram-AYQRV4AK-PIM5CPGV.js +8 -0
  72. data/website/assets/chunks/{timeline-definition-JXYKGLGB-NKTZVLAN.js → timeline-definition-JXYKGLGB-L4XK4IA2.js} +1 -1
  73. data/website/assets/chunks/{usecaseDiagram-WPOLBNNX-23KYIREC.js → usecaseDiagram-WPOLBNNX-JIQPEJGT.js} +1 -1
  74. data/website/assets/chunks/{vennDiagram-Q3Y3IDCW-7K3XRLKC.js → vennDiagram-Q3Y3IDCW-ZL36EB3C.js} +1 -1
  75. data/website/assets/chunks/{wardleyDiagram-IVAIDKWA-FBDWJFKS.js → wardleyDiagram-IVAIDKWA-6NNJBKAT.js} +1 -1
  76. data/website/assets/chunks/{xychartDiagram-4URNHDU4-OY3ZRRWP.js → xychartDiagram-4URNHDU4-ZBQDSFFT.js} +1 -1
  77. data/website/assets/docs-7YBVH7A3.css +1 -0
  78. data/website/assets/docs-PCBXSG6K.js +1 -0
  79. data/website/assets/docs-navigation-SQPXOH42.js +1 -0
  80. data/website/assets/favorite-controls-7CQOGEEJ.js +1 -0
  81. data/website/assets/graph-QFPKHVGP.js +1 -0
  82. data/website/assets/manifest.json +163 -151
  83. data/website/assets/{mermaid-DLWPGV5J.js → mermaid-47XTJG37.js} +2 -2
  84. data/website/assets/minimal-JBOFMENV.css +1 -0
  85. data/website/assets/minimal-YEVXPLLM.js +1 -0
  86. data/website/assets/{previews-MG7MTTYB.js → previews-MS2IAQAO.js} +1 -1
  87. data/website/assets/search-4HE3SQVR.js +1 -0
  88. data/website/lib/jekyll_obsidian/adapter.rb +16 -4
  89. data/website/lib/jekyll_obsidian/built_in_themes.rb +36 -16
  90. data/website/lib/jekyll_obsidian/content_policy.rb +30 -1
  91. data/website/lib/jekyll_obsidian/diagnostics.rb +14 -0
  92. data/website/lib/jekyll_obsidian/footer_links.rb +73 -0
  93. data/website/lib/jekyll_obsidian/front_matter.rb +36 -12
  94. data/website/lib/jekyll_obsidian/localized_compiler.rb +184 -40
  95. data/website/lib/jekyll_obsidian/markdown_options.rb +37 -0
  96. data/website/lib/jekyll_obsidian/ofm_scanner.rb +11 -6
  97. data/website/lib/jekyll_obsidian/output_text.rb +5 -0
  98. data/website/lib/jekyll_obsidian/paged_archive.rb +1 -1
  99. data/website/lib/jekyll_obsidian/published_markdown.rb +55 -2
  100. data/website/lib/jekyll_obsidian/reading_time.rb +54 -0
  101. data/website/lib/jekyll_obsidian/robots.rb +11 -0
  102. data/website/lib/jekyll_obsidian/site_compilation.rb +10 -99
  103. data/website/lib/jekyll_obsidian/tag_policy.rb +4 -2
  104. data/website/lib/jekyll_obsidian/value_objects.rb +4 -1
  105. data/website/lib/jekyll_obsidian/vault_compiler.rb +243 -155
  106. data/website/lib/jekyll_obsidian/version.rb +1 -1
  107. data/website/lib/jekyll_obsidian.rb +5 -0
  108. data/website/scripts/verify-site-urls.rb +2 -1
  109. metadata +79 -70
  110. data/website/assets/chunks/chunk-7UNR26CO.js +0 -12
  111. data/website/assets/chunks/flowDiagram-IUGLLWBU-4HYSLWMD.js +0 -1
  112. data/website/assets/chunks/infoDiagram-MVDRKAX5-IIV27ROL.js +0 -2
  113. data/website/assets/chunks/swimlanesDiagram-AYQRV4AK-CMBJIT6P.js +0 -8
  114. data/website/assets/docs-E2KRT3NI.js +0 -1
  115. data/website/assets/docs-YTJN5WJC.css +0 -1
  116. data/website/assets/docs-navigation-PT5X44HW.js +0 -1
  117. data/website/assets/graph-F3JLZWW5.js +0 -1
  118. data/website/assets/minimal-KTFDX3OT.css +0 -1
  119. data/website/assets/minimal-NEM6YCGV.js +0 -1
  120. data/website/assets/search-7PCXY7J6.js +0 -1
  121. /data/website/assets/chunks/{chunk-7UAUSQAK.js → chunk-UNVUNKH6.js} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c11e15e11052a976f2df428f2e9aededf413b04913f74119971422b851e5f002
4
- data.tar.gz: 7b3eb3de37c73c25bb4c9466a90a770794c0ec2d849a7e7290d85fe5cdfa39c7
3
+ metadata.gz: 7f9d91405141a83604332d9d3ae64c3e3538e3a1d8d94d0cb4e0301effa7445c
4
+ data.tar.gz: a14c690ad7ad6033d94ce1140c5908cf00b23b5071c3bf07cc1162cf21f42a6e
5
5
  SHA512:
6
- metadata.gz: 78dd8b1ad15cd01084ad34c03e17b6938136a7a66151e2a017617bd0805848c594218c62e895cf68c798469349dc7b5242f61f32d1cd9141e8b88fc8571ce1e0
7
- data.tar.gz: 42d8f4022ccfc4e3b3bbe2db55fd87271e802d5220f8017ec6fc5fdf44ae6c59a193f9ec4e8db2991a607d10fbdedd6cd96dbdf521331e1454de2a11184b3200
6
+ metadata.gz: 77a426ca377292092e9d34af6a6b2afe22e42438a7e5f32371f71715cb67f7ffdd24d8a5a1b5c9980f5cd50d7a3cb4fe93415d9b325496894fbbd96a83889e3d
7
+ data.tar.gz: ec7dd1f4417e7f061ace9795839a6ebc6f8bd669f58c7779db2806c63bdb104d4eaf8bfdf14dc9ebc1959678450f1b1b6f470fc85430b6be996dbe1f5c9b1daf
data/README.md CHANGED
@@ -2,39 +2,28 @@
2
2
 
3
3
  English | [简体中文](README.zh-CN.md)
4
4
 
5
- `jekyll-obsidian` turns a Markdown folder, including an Obsidian vault, into a blog or documentation site. Keep writing in your editor and push to GitHub; Actions builds and publishes the site. Add a configuration file and a workflow to your repository. The implementation is installed as the `jekyll-obsidian-site` Ruby gem.
5
+ Turn a Markdown folder or Obsidian vault into a blog or documentation site. Keep writing in your editor and push to GitHub; Actions builds and publishes the site using the [jekyll-obsidian-site](https://rubygems.org/gems/jekyll-obsidian-site) Ruby gem.
6
6
 
7
7
  Live preview: [sinputer.top/jekyll-obsidian](https://sinputer.top/jekyll-obsidian/)
8
8
 
9
- Choose one built-in theme for each build:
9
+ Choose a built-in theme:
10
10
 
11
- - `minimal` combines an authored Home page with recent posts, a full Blog, documentation, and explicit custom sections for personal or organization sites.
12
- - `docs` provides a document tree and previous or next links.
11
+ - `minimal` (default): an authored home page, recent posts, a blog, documentation, and project portfolios or custom sections.
12
+ - `docs`: a document tree with previous and next links.
13
13
 
14
- Both themes enable search, wiki-link reading previews, the page outline, note relations, and an interactive local graph by default. A note participating in a link or embed relation with another public note keeps its local graph at the top of the right-hand context rail; isolated and self-link-only notes omit it. Its two controls open the complete public graph or an expanded view of the current note's neighbourhood. The complete graph still contains every public note, and `/graph/` is not a generated route.
14
+ Both themes include search, wiki-link previews, page outlines, note relations, and interactive graphs. They support media embeds, translations, and GitHub Discussions comments, with canonical metadata, a sitemap, and Markdown downloads.
15
15
 
16
- Switching themes does not change note URLs.
17
- Both themes use compact header icons with accessible names and hover hints. Supported local files and HTTPS media embed in notes, including native audio/video, PDFs, YouTube, Bilibili, Vimeo and X. See [Syntax](website/jekyll-obsidian-docs/docs/Syntax.md) for formats and examples. Paged archives show up to five nearby page links and accept a page number for direct navigation.
18
- The default build and deployment theme is `minimal`. Both themes can publish locale overlays from `_translations/<locale>/` and attach GitHub Discussions comments to posts. When the corresponding mapping is present and omits `enabled`, localization defaults on only for `docs`, while comments default on only for `minimal`.
16
+ ## Publish with GitHub Pages
19
17
 
20
- See [Localization](website/jekyll-obsidian-docs/docs/Localization.md) for locale manifests, which content controls site structure, fallback pages, and SEO behavior.
18
+ The workflow installs the build tools, so you do not need Ruby or Node.js locally. [Public repositories can use GitHub Pages on GitHub Free](https://docs.github.com/en/pages/quickstart#who-can-use-this-feature).
21
19
 
22
- Minimal also provides Blog, tags, Atom feeds, contacts, source actions, and an automatically detected Portfolio with project cards. A project wrapper can use a public GitHub Markdown file as its body. Both themes generate Search and Graph data, canonical metadata, a sitemap, a 404 page, and frontmatter-free Markdown resources. Optional traffic measurement supports either Cloudflare Web Analytics or Google Analytics and stays off until configured.
20
+ Publication settings control the generated site, not access to committed files. Anyone who can read the repository can read unpublished notes too. Keep private material out of public repositories, and inspect linked Canvas and Bases files before publishing them as downloads.
23
21
 
24
- ## Before you publish
22
+ **Already have a Gemfile?** Follow [Host Integration](website/jekyll-obsidian-docs/docs/Integration.md#use-bundler) first: the Action requires both `Gemfile` and `Gemfile.lock`, with the builder version matching the Action release.
25
23
 
26
- Deploying with GitHub Pages does not require Ruby, Node.js, Bundler, npm, or a browser on your computer. The generated GitHub Actions workflow installs the build toolchain.
27
-
28
- [GitHub Pages is available for public repositories on GitHub Free](https://docs.github.com/en/pages/quickstart#who-can-use-this-feature), so a public `jekyll-obsidian` site needs no paid hosting.
29
-
30
- The publication policy controls what enters the generated site. It does not make other committed files private. Anyone who can read the repository can read unpublished notes too, so do not commit secrets, personal records, or other private material.
31
-
32
- Canvas and Bases files become downloads when a public note links to them. Inspect them before committing because they can contain excerpts or references to unpublished material.
33
-
34
- ## Add it to your repository
35
-
36
- 1. Create `.github/jekyll-obsidian.yml`, using [the example configuration](examples/jekyll-obsidian.yml):
24
+ 1. Create `.github/jekyll-obsidian.yml` using [the example configuration](examples/jekyll-obsidian.yml):
37
25
 
26
+ <!-- example:site-config -->
38
27
  ```yaml
39
28
  title: My Site
40
29
  website:
@@ -43,97 +32,66 @@ website:
43
32
  ```
44
33
 
45
34
  2. Copy [the Pages workflow](examples/pages.yml) to `.github/workflows/pages.yml`.
46
- 3. Put a Markdown note with `publish: true` in `docs/`, then select **Settings > Pages > Build and deployment > Source > GitHub Actions** and push.
35
+ 3. Create `docs/index.md`:
47
36
 
48
- The content directory can also be `website/docs/` or another repository-relative directory. Edit `website.source` to select it. No local Ruby, Node.js, or build command is needed for Actions.
37
+ <!-- example:public-note -->
38
+ ```markdown
39
+ ---
40
+ publish: true
41
+ title: Welcome
42
+ ---
49
43
 
50
- For local initialization, install Ruby 4.0.x and run:
44
+ # Welcome
51
45
 
52
- ```sh
53
- gem install jekyll-obsidian-site
54
- jekyll-obsidian init --source docs
46
+ My first public note.
55
47
  ```
56
48
 
57
- `init` creates the same configuration and workflow. It adds a public welcome note only when the content directory is absent or empty. Existing conflicting files are left unchanged. See [Host Integration](website/jekyll-obsidian-docs/docs/Integration.md) for Bundler, updates, and existing repositories.
58
-
59
- ## Preview the deployed site
60
-
61
- Wait for the **Build and deploy Pages** workflow on the default branch to succeed. GitHub reports the deployed URL in the workflow's `deploy` job and in **Settings → Pages**.
49
+ 4. Select **Settings > Pages > Build and deployment > Source > GitHub Actions**, then commit and push to the default branch.
62
50
 
63
- Without a custom domain, the expected URL is:
51
+ After **Build and deploy Pages** succeeds, find the URL in the `deploy` job or **Settings > Pages**. Project sites normally use `https://<owner>.github.io/<repository>/`; repositories named `<owner>.github.io` use the domain root. The workflow also reads custom-domain settings automatically. See [Deployment](website/jekyll-obsidian-docs/docs/Deployment.md).
64
52
 
65
- - `https://<owner>.github.io/<repository>/` for a normal project repository.
66
- - `https://<owner>.github.io/` when the repository itself is named `<owner>.github.io`.
53
+ ## Configure and update
67
54
 
68
- If you configure a custom domain, use the URL shown in **Settings → Pages**. The workflow reads GitHub Pages metadata and builds links for that URL automatically. See [Deployment](website/jekyll-obsidian-docs/docs/Deployment.md) for the workflow and custom-domain details.
55
+ Edit `.github/jekyll-obsidian.yml`. Site identity fields (`title`, `description`, `lang`, `url`, `baseurl`) belong at the YAML root; content, theme, and feature settings belong under `website`. Set `website.source` to a repository-relative content directory and `website.theme` to `minimal` or `docs`. Changes take effect on the next build.
69
56
 
70
- ## Configure and publish
57
+ By default, only notes whose frontmatter has the YAML boolean `publish: true` enter the site. To publish folders recursively, list content-relative paths under `website.content.publish_by_default`; `.` selects the whole content tree. Use `publish: false` to exclude a note. Quoted strings such as `"true"` are not booleans. Obsidian's `.obsidian/` and `.trash/` directories are excluded.
71
58
 
72
- Edit `.github/jekyll-obsidian.yml` to configure the title, language, content directory, theme, and features. All entries are directly editable. Changing `website.source` or `website.theme` takes effect on the next build; the workflow does not need to be regenerated.
59
+ A home page is optional: without one, the site can open a section or another public note. At least one public note is required. See [Customization](website/jekyll-obsidian-docs/docs/Customization.md#content-and-navigation) for index selection and navigation.
73
60
 
74
- The configuration interface is the root `website:` mapping.
61
+ Switching themes preserves the URLs of notes that remain published. For multilingual sites, set `website.i18n.enabled: true` explicitly to keep translations enabled across theme changes. See [Localization](website/jekyll-obsidian-docs/docs/Localization.md).
75
62
 
76
- Both themes can store post comments in GitHub Discussions through Giscus. Comments use the publication repository by default and can point at a separate public repository. When `website.comments` exists and omits `enabled`, `minimal` enables comments by default; `docs` requires `website.comments.enabled: true`. Enabling comments before Discussions or the Giscus App is ready does not fail the build; incomplete Giscus configuration produces a warning and a non-interactive fallback. See [Comments](website/jekyll-obsidian-docs/docs/Comments.md) for repository setup, thread identity, privacy boundaries, and troubleshooting.
63
+ See [theme defaults](website/jekyll-obsidian-docs/docs/Customization.md#site-themes) for feature, localization, and comment settings.
77
64
 
78
- Open your content directory in Obsidian or any Markdown editor. By default, a note enters the site only when its frontmatter contains the YAML boolean `publish: true`:
79
-
80
- ```yaml
81
- ---
82
- publish: true
83
- title: A public note
84
- tags:
85
- - example
86
- ---
87
- ```
88
-
89
- The strings `"true"` and `"yes"` are not accepted. To publish a whole folder recursively, list its path under `website.content.publish_by_default`; use `.` to select the complete content tree. A note can opt out of either default with the YAML boolean `publish: false`. Obsidian's `.obsidian/` state and `.trash/` are excluded from the content snapshot.
90
-
91
- `index.md` is optional at the content root and in every nested folder. When a folder has no physical `index.md`, a published sibling named exactly `README.md` becomes its index. A physical `index.md` keeps priority even when it is unpublished; in that case, `README.md` remains an ordinary note. A selected README keeps its source path and source actions but publishes at the folder route. Minimal places the selected public root index above the six most recent posts on Home; without one, Home can still show the post stream. A folder without a public selected index links to its first ordered public page. A content directory with no public notes still fails the build.
92
-
93
- Trusted standalone HTML slides can also publish at explicit routes without a theme or Liquid pass. Map one `.html` file or a directory bundle containing `index.html`; a bundle publishes its regular files with their relative structure intact, except Markdown and compiler locale manifests such as `_locale.yml`:
94
-
95
- ```yaml
96
- website:
97
- html:
98
- slides/product-tour: /slides/product-tour/
99
- ```
100
-
101
- HTML mappings are an explicit publication boundary independent of Markdown defaults. Raw pages stay out of navigation, Search, Graph, feeds, and sitemap, and they execute as trusted same-origin code. Review the complete bundle before publishing. See [Customization](website/jekyll-obsidian-docs/docs/Customization.md#standalone-html-slides) and the [working slide source](website/jekyll-obsidian-docs/slides/jekyll-obsidian/index.html).
102
-
103
- Update the Action version in your workflow to use a new release. For a local gem installation, run `gem update jekyll-obsidian-site`; for Bundler, run `bundle update jekyll-obsidian-site` and commit the lockfile. Your content and configuration remain in your repository.
65
+ To upgrade, change the Action release in the workflow. If you use Bundler, update the Gemfile constraint to the same version, run `bundle update jekyll-obsidian-site`, and commit both dependency files with the workflow. For a standalone local installation, run `gem update jekyll-obsidian-site`.
104
66
 
105
67
  ## Optional local preview
106
68
 
107
- With Ruby 4.0.x on macOS, Linux, or WSL:
69
+ With Ruby 4.0.x on macOS, Linux, or WSL, run from your repository root:
108
70
 
109
71
  ```sh
110
72
  gem install jekyll-obsidian-site
111
73
  jekyll-obsidian dev
112
74
  ```
113
75
 
114
- Open `http://127.0.0.1:58000/`. Content and configuration changes trigger a complete rebuild. A failed rebuild leaves the last successful site available. Run `jekyll-obsidian dev --help` for host, port, base path, and theme options.
115
-
116
- Build for another host with `jekyll-obsidian build --url https://example.com --baseurl /project`. Output is written to `.jekyll-obsidian-cache/site/`. `jekyll-obsidian clean` removes this project's cache and output. The gem includes frontend assets, so local use does not require Node.js.
117
-
118
- ## Guides
76
+ Open `http://127.0.0.1:58000/`. Content and configuration changes trigger a rebuild; failures preserve the last successful site. Run `jekyll-obsidian dev --help` for host, port, base path, and theme options. The gem includes frontend assets, so Node.js is not required.
119
77
 
120
- - [Host Integration](website/jekyll-obsidian-docs/docs/Integration.md) covers installation and updates in another repository.
121
- - [Getting Started](website/jekyll-obsidian-docs/docs/Getting%20Started.md) covers GitHub Actions publishing, authoring, and optional local preview.
122
- - [Syntax](website/jekyll-obsidian-docs/docs/Syntax.md) documents the supported Obsidian-flavored Markdown.
123
- - [Customization](website/jekyll-obsidian-docs/docs/Customization.md) covers site identity, themes, navigation, and features.
124
- - [Portfolio](website/jekyll-obsidian-docs/docs/Portfolio.md) covers project collections and public GitHub Markdown bodies.
125
- - [Analytics](website/jekyll-obsidian-docs/docs/Analytics.md) covers optional Cloudflare and Google traffic measurement.
126
- - [Comments](website/jekyll-obsidian-docs/docs/Comments.md) covers GitHub Discussions setup and privacy boundaries.
127
- - [Localization](website/jekyll-obsidian-docs/docs/Localization.md) covers translations, fallback pages, and localized SEO.
128
- - [Deployment](website/jekyll-obsidian-docs/docs/Deployment.md) covers GitHub Pages, URL paths, and custom domains.
78
+ To create the configuration and workflow locally, run `jekyll-obsidian init --source docs`. It adds a public welcome note only when the content directory is absent or empty, and reports conflicting files without overwriting them. For Bundler commands, see [Host Integration](website/jekyll-obsidian-docs/docs/Integration.md).
129
79
 
130
- Contributors can continue with the [Developer Guide](website/jekyll-obsidian-docs/docs/development/index.md).
80
+ For another host, run `jekyll-obsidian build --url https://example.com --baseurl /project` and upload `.jekyll-obsidian-cache/site/`. `jekyll-obsidian clean` removes this project's cache and output.
131
81
 
132
- Native Windows contributors can use RubyInstaller Ruby+Devkit 4.0.6, Bundler 4.0.16 and Node 26. The Developer Guide includes PowerShell build and archive-test commands. The full Ruby suite runs with `bundle exec rake test`. Directory-link tests use junctions when Windows symbolic-link privileges are unavailable; only file-link tests and filenames unsupported by Windows are skipped, with explicit reasons. Preview tests isolate and stop their own child process.
82
+ ## Guides and contributing
133
83
 
134
- ## Recommendations and collection archives
84
+ - [Host Integration](website/jekyll-obsidian-docs/docs/Integration.md): installation, Bundler, and upgrades.
85
+ - [Getting Started](website/jekyll-obsidian-docs/docs/Getting%20Started.md): publishing and authoring.
86
+ - [Syntax](website/jekyll-obsidian-docs/docs/Syntax.md): Obsidian-flavored Markdown and media embeds.
87
+ - [Customization](website/jekyll-obsidian-docs/docs/Customization.md): themes, navigation, archive tabs, recommendations, and trusted HTML slides.
88
+ - [Portfolio](website/jekyll-obsidian-docs/docs/Portfolio.md): project collections and public GitHub Markdown bodies.
89
+ - [Analytics](website/jekyll-obsidian-docs/docs/Analytics.md): optional Cloudflare or Google traffic measurement.
90
+ - [Comments](website/jekyll-obsidian-docs/docs/Comments.md): GitHub Discussions setup and privacy.
91
+ - [Localization](website/jekyll-obsidian-docs/docs/Localization.md): translations, fallback pages, and SEO.
92
+ - [Deployment](website/jekyll-obsidian-docs/docs/Deployment.md): hosting, URL paths, and custom domains.
135
93
 
136
- Supply expiring article recommendations through a vault-root `_recommendations.json`, or declare an archive tab with `tab.layout: archive` for scoped dates, topics, and pagination. See [Customization](website/jekyll-obsidian-docs/docs/Customization.md#expiring-recommendations) for the recommendation format and [Custom tabs](website/jekyll-obsidian-docs/docs/Customization.md#custom-tabs) for archive settings.
94
+ For development setup and native Windows PowerShell commands, read the [Developer Guide](website/jekyll-obsidian-docs/docs/development/index.md). On macOS, Linux, or WSL, run `website/bin/test` from the repository root. It builds frontend assets and packages the gem before running the Ruby, TypeScript, frontend, and Node checks. If running Ruby tests separately from `website/`, first run `npm run build` and `bundle exec ruby scripts/package.rb --skip-assets`, then `bundle exec rake test`; the suite tests an actual installed gem.
137
95
 
138
96
  ## License
139
97
 
@@ -2,6 +2,6 @@
2
2
  <ul class="blog-ledger__topics" aria-label="{{ ui.sources | default: 'Sources' | escape }} / {{ ui.topics | default: 'Topics' | escape }}">
3
3
  {% for tag in include.post.archive_facets %}<li><a href="{{ blog_url | escape }}?{{ tag.facet | url_encode }}={{ tag.id | url_encode }}" data-archive-facet="{{ tag.facet | escape }}" data-archive-value="{{ tag.id | escape }}">{{ tag.name | escape }}</a></li>{% endfor %}
4
4
  </ul>
5
- {% if include.post.source_url %}<a class="archive-source-url" href="{{ include.post.source_url | escape }}" rel="noopener noreferrer">{{ include.post.source_url | escape }}</a>{% endif %}
5
+ {% if include.post.source_url %}<a class="archive-source-url" href="{{ include.post.source_url | escape }}" rel="noopener noreferrer">{{ include.post.source_title | default: include.post.source_url | escape }}</a>{% endif %}
6
6
  {% if include.post.date_basis == 'observed' %}<small>{{ ui.first_observed | default: 'First observed' | escape }}</small>{% endif %}
7
7
  </footer>
@@ -4,12 +4,15 @@
4
4
  <div class="archive-pagination__navigation">
5
5
  <button type="button" data-archive-page="prev" aria-label="{{ ui.previous | default: 'Previous' | escape }}" title="{{ ui.previous | default: 'Previous' | escape }}" disabled>{% include website/action-icon.html name='previous' class='archive-pagination__arrow' %}<span>{{ ui.previous | default: 'Previous' | escape }}</span></button>
6
6
  <div class="archive-pagination__numbers" data-archive-page-numbers></div>
7
- <button type="button" data-archive-page="next" aria-label="{{ ui.next | default: 'Next' | escape }}" title="{{ ui.next | default: 'Next' | escape }}"{% if archive_total <= page.website.theme_data.archive.page_size %} disabled{% endif %}>{% include website/action-icon.html name='next' class='archive-pagination__arrow' %}<span>{{ ui.next | default: 'Next' | escape }}</span></button>
7
+ <button type="button" data-archive-page="next" aria-label="{{ ui.next | default: 'Next' | escape }}" title="{{ ui.next | default: 'Next' | escape }}" disabled>{% include website/action-icon.html name='next' class='archive-pagination__arrow' %}<span>{{ ui.next | default: 'Next' | escape }}</span></button>
8
8
  </div>
9
9
  <form class="archive-pagination__jump" data-archive-page-jump hidden>
10
10
  <label><span class="visually-hidden">{{ ui.page_input | default: 'Page number' | escape }}</span><input type="number" inputmode="numeric" min="1" step="1" required disabled></label>
11
11
  <button type="submit">{{ ui.page_go | default: 'Go' | escape }}</button>
12
12
  </form>
13
13
  </nav>
14
- <p role="status" aria-live="polite" data-archive-status data-loading="{{ ui.archive_loading | default: 'Loading selected entries…' | escape }}" data-unavailable="{{ ui.archive_unavailable | default: 'Selected entries could not be loaded. Retry or clear the filters.' | escape }}" data-refresh-error="{{ ui.archive_refresh_error | escape }}"></p>
14
+ <p role="status" aria-live="polite" data-archive-status data-module-unavailable="{{ ui.archive_module_unavailable | escape }}" data-loading="{{ ui.archive_loading | default: 'Loading selected entries…' | escape }}" data-unavailable="{{ ui.archive_unavailable | default: 'Selected entries could not be loaded. Retry or clear the filters.' | escape }}" data-refresh-error="{{ ui.archive_refresh_error | escape }}"></p>
15
15
  <button type="button" data-archive-retry hidden>{{ ui.retry | default: 'Retry' | escape }}</button>
16
+ {% unless page.website.theme_data.favorites %}{% if archive_total > page.website.theme_data.archive.page_size %}
17
+ <noscript><p>{{ ui.archive_requires_js | default: 'The first page is shown. Enable JavaScript to browse all entries.' | escape }}</p></noscript>
18
+ {% endif %}{% endunless %}
@@ -1,14 +1,14 @@
1
1
  {% case include.icon %}
2
- {% when 'email' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="5" width="18" height="14" rx="2"></rect><path d="m3 7 9 6 9-6"></path></svg>
3
- {% when 'phone' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 2 .7 2.9a2 2 0 0 1-.4 2.1L8.1 10a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.9.6 2.9.7a2 2 0 0 1 1.6 1.9Z"></path></svg>
4
- {% when 'github' %}{% include website/github-icon.html class='minimal-contact__icon minimal-contact__icon--brand' %}
5
- {% when 'linkedin' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="3" width="18" height="18" rx="2"></rect><path d="M8 10v7M8 7v.01M12 17v-7M12 13a4 4 0 0 1 8 0v4"></path></svg>
6
- {% when 'x' %}<svg class="minimal-contact__icon minimal-contact__icon--brand" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18.24 2.25h3.31l-7.23 8.26 8.51 11.24h-6.66l-5.21-6.82-5.97 6.82H1.68l7.73-8.84L1.25 2.25h6.83l4.71 6.23 5.45-6.23Zm-1.16 17.52h1.84L7.08 4.13H5.12l11.96 15.64Z"></path></svg>
7
- {% when 'mastodon' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 17V9a4 4 0 0 1 7-2.6A4 4 0 0 1 19 9v6c0 4-3 6-7 6-2.2 0-4-.5-5.2-1.5"></path><path d="M9 15V9.5a1.5 1.5 0 0 1 3 0V15M12 9.5a1.5 1.5 0 0 1 3 0V15"></path></svg>
8
- {% when 'bluesky' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 11c-1.7-3-5.8-6-7.6-4.7-1.7 1.3-.7 5.7 2 7.3 1.2.7 2.7.7 4 .2-2.1.4-4.2 1.7-3.5 3.7.8 2.4 3.9 1.3 5.1-.9 1.2 2.2 4.3 3.3 5.1.9.7-2-1.4-3.3-3.5-3.7 1.3.5 2.8.5 4-.2 2.7-1.6 3.7-6 2-7.3C17.8 5 13.7 8 12 11Z"></path></svg>
9
- {% when 'instagram' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="3" width="18" height="18" rx="5"></rect><circle cx="12" cy="12" r="4"></circle><path d="M17.5 6.5h.01"></path></svg>
10
- {% when 'youtube' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M21 8.2a2.8 2.8 0 0 0-2-2C17.2 5.7 12 5.7 12 5.7s-5.2 0-7 .5a2.8 2.8 0 0 0-2 2A29 29 0 0 0 2.5 12 29 29 0 0 0 3 15.8a2.8 2.8 0 0 0 2 2c1.8.5 7 .5 7 .5s5.2 0 7-.5a2.8 2.8 0 0 0 2-2 29 29 0 0 0 .5-3.8 29 29 0 0 0-.5-3.8Z"></path><path d="m10 9 5 3-5 3Z"></path></svg>
11
- {% when 'telegram' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m21 4-3 16-6-4-3 3-1-5-5-2Z"></path><path d="m8 14 9-7-6 9"></path></svg>
12
- {% when 'rss' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="5" cy="19" r="1"></circle><path d="M4 11a9 9 0 0 1 9 9M4 4a16 16 0 0 1 16 16"></path></svg>
13
- {% when 'website' %}<svg class="minimal-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"></circle><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"></path></svg>
2
+ {% when 'email' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="5" width="18" height="14" rx="2"></rect><path d="m3 7 9 6 9-6"></path></svg>
3
+ {% when 'phone' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 2 .7 2.9a2 2 0 0 1-.4 2.1L8.1 10a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.9.6 2.9.7a2 2 0 0 1 1.6 1.9Z"></path></svg>
4
+ {% when 'github' %}{% include website/github-icon.html class='site-contact__icon site-contact__icon--brand' %}
5
+ {% when 'linkedin' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="3" width="18" height="18" rx="2"></rect><path d="M8 10v7M8 7v.01M12 17v-7M12 13a4 4 0 0 1 8 0v4"></path></svg>
6
+ {% when 'x' %}<svg class="site-contact__icon site-contact__icon--brand" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18.24 2.25h3.31l-7.23 8.26 8.51 11.24h-6.66l-5.21-6.82-5.97 6.82H1.68l7.73-8.84L1.25 2.25h6.83l4.71 6.23 5.45-6.23Zm-1.16 17.52h1.84L7.08 4.13H5.12l11.96 15.64Z"></path></svg>
7
+ {% when 'mastodon' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 17V9a4 4 0 0 1 7-2.6A4 4 0 0 1 19 9v6c0 4-3 6-7 6-2.2 0-4-.5-5.2-1.5"></path><path d="M9 15V9.5a1.5 1.5 0 0 1 3 0V15M12 9.5a1.5 1.5 0 0 1 3 0V15"></path></svg>
8
+ {% when 'bluesky' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 11c-1.7-3-5.8-6-7.6-4.7-1.7 1.3-.7 5.7 2 7.3 1.2.7 2.7.7 4 .2-2.1.4-4.2 1.7-3.5 3.7.8 2.4 3.9 1.3 5.1-.9 1.2 2.2 4.3 3.3 5.1.9.7-2-1.4-3.3-3.5-3.7 1.3.5 2.8.5 4-.2 2.7-1.6 3.7-6 2-7.3C17.8 5 13.7 8 12 11Z"></path></svg>
9
+ {% when 'instagram' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="3" width="18" height="18" rx="5"></rect><circle cx="12" cy="12" r="4"></circle><path d="M17.5 6.5h.01"></path></svg>
10
+ {% when 'youtube' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M21 8.2a2.8 2.8 0 0 0-2-2C17.2 5.7 12 5.7 12 5.7s-5.2 0-7 .5a2.8 2.8 0 0 0-2 2A29 29 0 0 0 2.5 12 29 29 0 0 0 3 15.8a2.8 2.8 0 0 0 2 2c1.8.5 7 .5 7 .5s5.2 0 7-.5a2.8 2.8 0 0 0 2-2 29 29 0 0 0 .5-3.8 29 29 0 0 0-.5-3.8Z"></path><path d="m10 9 5 3-5 3Z"></path></svg>
11
+ {% when 'telegram' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m21 4-3 16-6-4-3 3-1-5-5-2Z"></path><path d="m8 14 9-7-6 9"></path></svg>
12
+ {% when 'rss' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="5" cy="19" r="1"></circle><path d="M4 11a9 9 0 0 1 9 9M4 4a16 16 0 0 1 16 16"></path></svg>
13
+ {% when 'website' %}<svg class="site-contact__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"></circle><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"></path></svg>
14
14
  {% endcase %}
@@ -1,14 +1,14 @@
1
1
  {% assign ui = page.website.i18n.messages %}
2
2
  {% if page.website.theme_data.archive %}{% include website/archive-export.html %}{% endif %}
3
3
  {% if page.website.features.search %}
4
- <dialog class="website-dialog" data-dialog="search" aria-labelledby="search-dialog-title"{% if ui.search_loading %} data-search-loading="{{ ui.search_loading | escape }}"{% endif %}{% if ui.search_prompt %} data-search-prompt="{{ ui.search_prompt | escape }}"{% endif %}{% if ui.search_unavailable %} data-search-unavailable="{{ ui.search_unavailable | escape }}"{% endif %}{% if ui.search_no_results %} data-search-no-results="{{ ui.search_no_results | escape }}"{% endif %}{% if ui.search_result_one %} data-search-result-one="{{ ui.search_result_one | escape }}"{% endif %}{% if ui.search_result_many %} data-search-result-many="{{ ui.search_result_many | escape }}"{% endif %}>
4
+ <dialog class="website-dialog" data-dialog="search" aria-labelledby="search-dialog-title"{% if ui.search_loading %} data-search-loading="{{ ui.search_loading | escape }}"{% endif %}{% if ui.search_prompt %} data-search-prompt="{{ ui.search_prompt | escape }}"{% endif %}{% if ui.search_retry %} data-search-retry="{{ ui.search_retry | escape }}"{% endif %}{% if ui.search_unavailable %} data-search-unavailable="{{ ui.search_unavailable | escape }}"{% endif %}{% if ui.search_no_results %} data-search-no-results="{{ ui.search_no_results | escape }}"{% endif %}{% if ui.search_result_one %} data-search-result-one="{{ ui.search_result_one | escape }}"{% endif %}{% if ui.search_result_many %} data-search-result-many="{{ ui.search_result_many | escape }}"{% endif %}>
5
5
  <div class="website-dialog__sheet">
6
6
  <header class="website-dialog__header">
7
7
  <h2 class="website-dialog__title" id="search-dialog-title">{{ ui.search_title | default: 'Search this site' | escape }}</h2>
8
8
  <button class="website-dialog__close" type="button" data-dialog-close aria-label="{{ ui.close_search | default: 'Close search' | escape }}">&times;</button>
9
9
  </header>
10
10
  <div class="website-dialog__body">
11
- <label class="search-box"><span aria-hidden="true">⌕</span><span class="visually-hidden">{{ ui.search_pages | default: 'Search pages' | escape }}</span><input type="search" inputmode="search" autocomplete="off" placeholder="{{ ui.search_placeholder | default: 'Title, tag, or phrase' | escape }}" data-search-input><kbd>⌘K</kbd></label>
11
+ <label class="search-box"><span aria-hidden="true">⌕</span><span class="visually-hidden">{{ ui.search_pages | default: 'Search pages' | escape }}</span><input type="search" inputmode="search" autocomplete="off" placeholder="{{ ui.search_placeholder | default: 'Title, tag, or phrase' | escape }}" data-search-input autofocus><kbd>Ctrl/⌘ K</kbd></label>
12
12
  {% if page.website.navigation.size > 0 %}
13
13
  <nav class="search-navigation" aria-label="{{ ui.primary_navigation | default: 'Primary navigation' | escape }}" data-search-navigation>
14
14
  <ul class="search-navigation__list">
@@ -1,5 +1,5 @@
1
1
  {% if page.website.features.favorites %}
2
- <div data-favorites-ui data-save="{{ ui.favorite_save | default: 'Save' | escape }}" data-remove="{{ ui.favorite_remove | default: 'Remove favorite' | escape }}" data-saved="{{ ui.favorite_saved | default: 'Saved' | escape }}" data-empty="{{ ui.favorites_empty | default: 'No favorites yet. Save an entry to find it here.' | escape }}" data-error="{{ ui.favorite_storage_error | escape }}" data-damaged="{{ ui.favorite_storage_damaged | escape }}" data-unreadable="{{ ui.favorite_storage_unreadable | escape }}" data-unsupported="{{ ui.favorite_storage_unsupported | escape }}" data-quota="{{ ui.favorite_storage_quota | escape }}" data-blocked="{{ ui.favorite_storage_blocked | escape }}" data-removed="{{ ui.favorite_removed_article | escape }}" data-refresh-error="{{ ui.favorites_refresh_error | escape }}" data-undated="{{ ui.undated | default: 'Undated' | escape }}" data-recovery-restored="{{ ui.favorite_recovery_restored | escape }}" data-recovery-cleared="{{ ui.favorite_recovery_cleared | escape }}" data-recovery-required="{{ ui.favorite_recovery_required | escape }}"></div>
2
+ <div data-favorites-ui data-module-unavailable="{{ ui.favorites_module_unavailable | escape }}" data-save="{{ ui.favorite_save | default: 'Save' | escape }}" data-remove="{{ ui.favorite_remove | default: 'Remove favorite' | escape }}" data-saved="{{ ui.favorite_saved | default: 'Saved' | escape }}" data-empty="{{ ui.favorites_empty | default: 'No favorites yet. Save an entry to find it here.' | escape }}" data-error="{{ ui.favorite_storage_error | escape }}" data-damaged="{{ ui.favorite_storage_damaged | escape }}" data-unreadable="{{ ui.favorite_storage_unreadable | escape }}" data-unsupported="{{ ui.favorite_storage_unsupported | escape }}" data-quota="{{ ui.favorite_storage_quota | escape }}" data-blocked="{{ ui.favorite_storage_blocked | escape }}" data-removed="{{ ui.favorite_removed_article | escape }}" data-refresh-error="{{ ui.favorites_refresh_error | escape }}" data-undated="{{ ui.undated | default: 'Undated' | escape }}" data-recovery-restored="{{ ui.favorite_recovery_restored | escape }}" data-recovery-cleared="{{ ui.favorite_recovery_cleared | escape }}" data-recovery-required="{{ ui.favorite_recovery_required | escape }}"></div>
3
3
  <p class="favorite-status" role="status" aria-live="polite" data-favorite-status></p>
4
4
  <details class="favorites-recovery" data-favorites-recovery hidden>
5
5
  <summary>{{ ui.favorite_recovery_title | default: 'Recovery copies' | escape }}</summary>
@@ -1,6 +1,30 @@
1
1
  <footer class="site-footer">
2
2
  {% assign ui = page.website.i18n.messages %}
3
+ {% assign footer = page.website.footer %}
3
4
  <div class="site-footer__inner">
5
+ {% if footer.contacts.size > 0 or footer.links.size > 0 %}
6
+ <div class="site-footer__main">
7
+ {% if footer.contacts.size > 0 %}
8
+ <nav class="site-footer__section" aria-labelledby="footer-contact-title">
9
+ <h2 id="footer-contact-title" class="site-footer__heading">{{ ui.contact | default: 'Contact' | escape }}</h2>
10
+ <ul class="site-footer__contacts">
11
+ {% for contact in footer.contacts %}
12
+ <li>{% if contact.icon %}<a class="site-contact site-contact--icon" href="{{ contact.url | escape }}" rel="me" aria-label="{{ contact.label | escape }}" title="{{ contact.label | escape }}">{% include website/contact-icon.html icon=contact.icon %}</a>{% else %}<a class="site-contact site-contact--text" href="{{ contact.url | escape }}" rel="me">{{ contact.label | escape }}</a>{% endif %}</li>
13
+ {% endfor %}
14
+ </ul>
15
+ </nav>
16
+ {% endif %}
17
+ {% if footer.links.size > 0 %}
18
+ <nav class="site-footer__section" aria-labelledby="footer-sites-title">
19
+ <h2 id="footer-sites-title" class="site-footer__heading">{{ ui.footer_sites | default: 'Sites' | escape }}</h2>
20
+ <ul class="site-footer__links">
21
+ {% for link in footer.links %}<li><a href="{{ link.url | escape }}">{{ link.label | escape }}</a></li>{% endfor %}
22
+ </ul>
23
+ </nav>
24
+ {% endif %}
25
+ </div>
26
+ {% endif %}
27
+ <div class="site-footer__credit">
4
28
  <span>{{ ui.built_by | default: 'Built by' | escape }}</span>
5
29
  <a class="site-footer__github" href="https://github.com/wowfun/jekyll-obsidian" aria-label="{{ ui.project_on_github | default: 'Jekyll Obsidian on GitHub' | escape }}">
6
30
  {% include website/github-icon.html %}
@@ -10,5 +34,6 @@
10
34
  <span>MIT License</span>
11
35
  <span aria-hidden="true">·</span>
12
36
  <time datetime="{{ site.time | date: "%Y" }}">{{ site.time | date: "%Y" }}</time>
37
+ </div>
13
38
  </div>
14
39
  </footer>
@@ -15,6 +15,7 @@
15
15
  <div class="graph-view graph-view--compact" data-graph-view data-graph-mode="compact" data-current-note-id="{{ local_graph.current_id | escape }}"{% if ui.graph_loading %} data-graph-loading="{{ ui.graph_loading | escape }}"{% endif %}{% if ui.graph_unavailable %} data-graph-unavailable="{{ ui.graph_unavailable | escape }}"{% endif %}{% if ui.graph_summary %} data-graph-summary="{{ ui.graph_summary | escape }}"{% endif %}{% if ui.graph_node_label %} data-graph-node-label="{{ ui.graph_node_label | escape }}"{% endif %}{% if ui.graph_title %} data-graph-title="{{ ui.graph_title | escape }}"{% endif %}{% if ui.graph_description %} data-graph-description="{{ ui.graph_description | escape }}"{% endif %}>
16
16
  <p class="graph-status" data-graph-status aria-live="polite">{{ ui.graph_loading | default: 'Loading graph…' | escape }}</p>
17
17
  </div>
18
+ <p class="local-graph__hint">{{ ui.graph_zoom_hint | default: 'Ctrl/⌘ + scroll to zoom' | escape }}</p>
18
19
  <template data-local-graph-data>
19
20
  {% for node in local_graph.nodes %}<i data-graph-node data-node-id="{{ node.id | escape }}" data-node-title="{{ node.title | escape }}" data-node-url="{{ node.url | escape }}" data-node-degree="{{ node.degree }}"></i>{% endfor %}
20
21
  {% for edge in local_graph.edges %}<i data-graph-edge data-edge-source="{{ edge.source | escape }}" data-edge-target="{{ edge.target | escape }}" data-edge-kind="{{ edge.kind | escape }}" data-edge-count="{{ edge.count }}"></i>{% endfor %}
@@ -23,6 +23,10 @@
23
23
  <span class="note-meta__topics" aria-label="{{ ui.topics | default: 'Topics' | escape }}" lang="{{ page.website.i18n.locale | default: site.lang | default: 'en' | escape }}" dir="{{ page.website.i18n.dir | default: 'ltr' | escape }}">{% for topic in page.website.topic_links %}<a class="tag-chip" href="{{ blog_url | escape }}?topic={{ topic.anchor | url_encode }}" lang="{{ page.website.i18n.content_lang | default: page.website.i18n.locale | default: site.lang | default: 'en' | escape }}" dir="{{ page.website.i18n.content_dir | default: page.website.i18n.dir | default: 'ltr' | escape }}">{{ topic.name | escape }}</a>{% endfor %}</span>
24
24
  {% endif %}
25
25
  {% if page.website.updated %}<time datetime="{{ page.website.updated | escape }}">{{ ui.updated | default: 'Updated' | escape }} {{ page.website.updated | date: "%Y-%m-%d" }}</time>{% endif %}
26
+ {% if page.website.features.reading_time and page.website.directory_index != true and page.website.reading_time_minutes > 2 %}
27
+ {% assign reading_time_label = ui.reading_time | default: 'About {minutes} min read' | replace: '{minutes}', page.website.reading_time_minutes %}
28
+ <span class="note-reading-time" lang="{{ page.website.i18n.reading_time_language.lang | default: 'en' | escape }}" dir="{{ page.website.i18n.reading_time_language.dir | default: 'ltr' | escape }}">{{ reading_time_label | escape }}</span>
29
+ {% endif %}
26
30
  {% if page.website.features.tags and page.website.archive_item != true %}
27
31
  {% unless page.website.theme == 'minimal' and page.website.content_type == 'post' %}
28
32
  {% if page.website.theme == 'minimal' %}{% assign tags_url = page.website.routes.blog %}{% unless tags_url %}{% assign tags_url = '/blog/' | relative_url %}{% endunless %}{% else %}{% assign tags_url = page.website.routes.tags %}{% unless tags_url %}{% assign tags_url = '/tags/' | relative_url %}{% endunless %}{% endif %}
@@ -1 +1 @@
1
- {% if page.website.source_url %}<p class="archive-source-url note-source-url"><a href="{{ page.website.source_url | escape }}" rel="noopener noreferrer">{{ page.website.source_url | escape }}</a></p>{% endif %}
1
+ {% if page.website.source_url %}<p class="archive-source-url note-source-url"><a href="{{ page.website.source_url | escape }}" rel="noopener noreferrer">{{ page.website.source_title | default: page.website.source_url | escape }}</a></p>{% endif %}
@@ -17,7 +17,6 @@
17
17
  </div>
18
18
  </section>
19
19
  {% endif %}
20
- {% if page.website.theme_data.contacts.size > 0 %}<nav class="minimal-contacts" aria-label="{{ ui.contact | default: 'Contact' | escape }}">{% for contact in page.website.theme_data.contacts %}{% if contact.icon %}<a class="minimal-contact minimal-contact--icon" href="{{ contact.url | escape }}" rel="me" aria-label="{{ contact.label | escape }}" title="{{ contact.label | escape }}">{% include website/contact-icon.html icon=contact.icon %}</a>{% else %}<a class="minimal-contact minimal-contact--text" href="{{ contact.url | escape }}" rel="me">{{ contact.label | escape }}</a>{% endif %}{% endfor %}</nav>{% endif %}
21
20
  {% when 'portfolio-index' %}
22
21
  {% include website/portfolio-grid.html index=true %}
23
22
  {% when 'blog-index' %}
@@ -8,5 +8,5 @@
8
8
  {% for topic in include.summaries %}<li><a href="{{ filter_url | escape }}?topic={{ topic.anchor | url_encode }}" data-topic-filter-option data-topic-anchor="{{ topic.anchor | escape }}"><span class="context-tag__name">{{ topic.name | escape }}</span><span class="context-tag__count">{{ topic.count }}</span></a></li>{% endfor %}
9
9
  </ul>
10
10
  </nav>
11
- <p class="filter-empty" data-filter-empty hidden>{{ ui.no_matching_entries | default: 'No entries match these filters.' | escape }}</p>
11
+ <p class="filter-empty" data-filter-empty role="status" data-module-unavailable="{{ ui.archive_module_unavailable | escape }}" hidden>{{ ui.no_matching_entries | default: 'No entries match these filters.' | escape }}</p>
12
12
  {% endif %}
@@ -9,7 +9,7 @@
9
9
  {% if page.website.kind == 'home' and page.website.id %}{% assign is_authored_home = true %}{% endif %}
10
10
  {% assign has_home_modules = false %}
11
11
  {% if is_authored_home %}
12
- {% if page.website.theme_data.recent_posts.size > 0 or page.website.theme_data.contacts.size > 0 %}{% assign has_home_modules = true %}{% endif %}
12
+ {% if page.website.theme_data.recent_posts.size > 0 %}{% assign has_home_modules = true %}{% endif %}
13
13
  {% endif %}
14
14
  {% assign has_mobile_context = false %}
15
15
  {% if page.website.kind == 'home' %}
@@ -25,7 +25,7 @@
25
25
  {% include website/header.html theme='minimal' %}
26
26
  {% include website/favorites-ui.html %}
27
27
 
28
- <main class="minimal-shell{% if page.website.archive_item %} minimal-shell--archive-item{% endif %}{% unless page.website.kind == 'note' %} minimal-shell--system{% endunless %}{% if is_authored_home %} minimal-shell--authored-home{% endif %}{% if is_docs_page %} minimal-shell--docs{% endif %}{% if page.website.kind == 'blog-index' %} minimal-shell--blog{% endif %}" id="main-content" tabindex="-1"{% if page.website.kind == 'blog-index' %} data-ledger-current-year="{{ page.website.theme_data.ledger_current_year }}"{% endif %}{% if page.website.kind == 'blog-index' %} data-ledger-group-by="{{ page.website.theme_data.ledger_group_by | default: 'year' | escape }}"{% endif %}{% if page.website.theme_data.favorites %} data-favorites-page data-sources-label="{{ ui.sources | escape }}" data-topics-label="{{ ui.topics | escape }}" data-all-label="{{ ui.all | escape }}"{% endif %}{% if page.website.kind == 'blog-index' %} data-filter-page{% if page.website.theme_data.archive %} data-paged-archive data-archive-url="{{ page.website.theme_data.archive.url | escape }}" data-archive-current-url="{{ page.website.theme_data.archive.current_url | escape }}" data-observed-label="{{ ui.first_observed | default: 'First observed' | escape }}"{% endif %}{% endif %}>
28
+ <main class="minimal-shell{% if page.website.archive_item %} minimal-shell--archive-item{% endif %}{% unless page.website.kind == 'note' %} minimal-shell--system{% endunless %}{% if is_authored_home %} minimal-shell--authored-home{% endif %}{% if is_docs_page %} minimal-shell--docs{% endif %}{% if page.website.kind == 'blog-index' %} minimal-shell--blog{% endif %}" id="main-content" tabindex="-1"{% if page.website.kind == 'blog-index' %} data-ledger-current-year="{{ page.website.theme_data.ledger_current_year }}"{% endif %}{% if page.website.kind == 'blog-index' %} data-ledger-group-by="{{ page.website.theme_data.ledger_group_by | default: 'year' | escape }}"{% endif %}{% if page.website.theme_data.favorites %} data-favorites-page data-sources-label="{{ ui.sources | escape }}" data-topics-label="{{ ui.topics | escape }}" data-all-label="{{ ui.all | escape }}"{% endif %}{% if page.website.kind == 'blog-index' %} data-filter-page data-module-unavailable="{{ ui.archive_module_unavailable | escape }}"{% if page.website.theme_data.archive %} data-paged-archive data-archive-url="{{ page.website.theme_data.archive.url | escape }}" data-archive-current-url="{{ page.website.theme_data.archive.current_url | escape }}" data-observed-label="{{ ui.first_observed | default: 'First observed' | escape }}"{% endif %}{% endif %}>
29
29
  {% if is_docs_page %}
30
30
  <aside class="minimal-docs-sidebar">
31
31
  <nav class="docs-tree" aria-label="{{ ui.documentation | default: 'Documentation' | escape }}" data-docs-navigation>
@@ -0,0 +1,12 @@
1
+ import{a as fe,b as Ce,c as Z,d as ae,e as _e,f as pe,g as ie,h as He,i as Fe,j as W,k as he,l as ke,m as Pe,n as Y,o as oe,p as qe,q as Oe}from"./chunks/chunk-MKLMFEY4.js";import{b as re}from"./chunks/chunk-TZRTKK7O.js";import{a as Me}from"./chunks/chunk-DR3UYLVK.js";import"./chunks/chunk-D6FURU6X.js";import{b as xe,c as ne,d as Te,f as V}from"./chunks/chunk-KJTG2HC3.js";import"./chunks/chunk-PHKIAKHS.js";function Re(e,r,t,n){return r.getAll(t).includes(n)||!e.default_view||r.get("include_tabs")==="1"?!0:!!e.default_view.facets[t]?.[n]}function ot(e,r){if(e.default_view&&r.get("include_tabs")!=="1")return e.default_view;let t=n=>Object.fromEntries(Object.entries(n).map(([u,[c,f]])=>[u,f-c]));return{total:e.total,facets:Object.fromEntries(Object.entries(e.facets).map(([n,u])=>[n,Object.fromEntries(u.map(c=>[c.id,c.count]))])),years:t(e.years),months:t(e.months),days:t(e.days)}}function se(e,r,t,n){return!n||r.getAll(t).includes(n)?!0:!Re(e,r,t,n)||t==="source"&&e.tab_sources?.includes(n)&&r.get("include_tabs")!=="1"?!1:r.getAll("show_hidden").includes(t)||!e.hidden_tags?.includes(e.prefixes[t]+n)}function ce(e,r,t,n){if(r==="show_hidden"){let c=new Set(e.getAll(r));c.has(n)?c.delete(n):c.add(n),e.delete(r),[...c].sort().forEach(f=>e.append(r,f));return}let u=V(t,e.toString()).parameters.get(r)==="1";if(u?e.delete(r):e.set(r,"1"),r==="include_tabs"&&(e.delete("page"),u)){let c=[...new Set(e.getAll("source").map(f=>ne(f,t.prefixes.source||"source/",t.aliases)))].filter(f=>!t.tab_sources?.includes(f));e.delete("source"),c.forEach(f=>e.append("source",f))}}function Q(){return document.querySelector("[data-archive-visibility-ui]")?.dataset||{}}function ge(e,r,t,n={},u){let c=e.facets[t]?.some(l=>e.hidden_tags?.includes(e.prefixes[t]+l.id)&&Re(e,r,t,l.id));return[...t==="source"&&e.facets[t]?.some(l=>e.tab_sources?.includes(l.id))?["include_tabs"]:[],...c?["show_hidden"]:[]].map(l=>{let d=l==="show_hidden"?r.getAll(l).includes(t):r.get(l)==="1",a=document.createElement("button");return a.type="button",a.className="archive-visibility",a.dataset.archiveVisibility=l,a.dataset.archiveVisibilityFacet=t,a.setAttribute("aria-expanded",String(d)),u&&a.setAttribute("aria-controls",u),a.textContent=l==="include_tabs"?d?n.hideTabs||"Hide tab sources":n.includeTabs||"Include tab sources":t==="topic"?d?n.hideTopics||"Hide hidden topics":n.showTopics||"Show hidden topics":d?n.hideTags||"Hide hidden tags":n.showTags||"Show hidden tags",a})}var De=new WeakMap;function me(e,r){e&&e.textContent!==r&&(e.textContent=r)}function Ie(e,r){e.hidden!==r&&(e.hidden=r)}function Ue(e,r,t){let n=De.get(e),u=!!(r.hidden_tags?.length||r.tab_sources?.length);if(!u&&!n?.governed)return;let c=t.get("include_tabs")==="1",f=JSON.stringify([t.getAll("show_hidden"),Object.keys(r.facets).map(a=>t.getAll(a))]);if(n?.data===r&&n.scope===c&&n.selection===f)return;let l=n?.data!==r||n.scope!==c?ot(r,t):void 0,d=Q();for(let a of e.querySelectorAll(".archive-facet")){let i=a.querySelector(".archive-facet-heading"),o=a.querySelector("[data-archive-facet]")?.dataset.archiveFacet;if(!o)continue;let h=a.querySelector("ul");h.id||(h.id=`archive-options-${o}`);let m=new Map([...i.querySelectorAll("[data-archive-visibility]")].map(g=>[g.dataset.archiveVisibility,g]));for(let g of ge(r,t,o,d,h.id)){let E=m.get(g.dataset.archiveVisibility);if(E){me(E,g.textContent);for(let x of["aria-expanded","aria-controls"])E.getAttribute(x)!==g.getAttribute(x)&&E.setAttribute(x,g.getAttribute(x));m.delete(g.dataset.archiveVisibility)}else i.append(g)}m.forEach(g=>g.remove());for(let g of a.querySelectorAll("[data-archive-facet]")){let E=g.dataset.archiveValue,x=g.querySelector("span");Ie(g.closest("li"),!se(r,t,o,E)),l&&me(x,String(E?l.facets[o]?.[E]||0:l.total))}}if(l)for(let a of["year","month","day"]){let i=l[`${a}s`];for(let o of document.querySelectorAll(`[data-timeline-nav] [data-${a}-filter-option]`)){let h=i[o.getAttribute(`data-filter-${a}`)]||0,m=o.querySelector(".archive-timeline__count");me(m,String(h));let g=o.closest(a==="year"?"section":"li");g&&Ie(g,h===0)}}De.set(e,{data:r,selection:f,scope:c,governed:u})}var $e=864e5;function le(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return;let r=Date.parse(e+"T00:00:00Z");if(!(!Number.isFinite(r)||new Date(r).toISOString().slice(0,10)!==e))return r/$e}function ye(e,r,t){if(!e||!r)return"required";let n=le(e),u=le(r);return n===void 0||u===void 0?"invalid":n>u?"order":u-n+1>t?"limit":null}function be(e,r,t){let n=new URLSearchParams(r).get("day");if(n&&le(n)!==void 0)return[n,n];let u=t[0],c=u===void 0?void 0:Object.keys(e.days).find(s=>u>=e.days[s][0]&&u<e.days[s][1]);return c?[new Date((le(c)-e.export_max_days+1)*$e).toISOString().slice(0,10),c]:["",""]}function Ne(e,r,t,n){if(ye(t,n,e.export_max_days))throw new Error("Invalid export date range");let u=new URLSearchParams(r);for(let s of["day","month","year","page"])u.delete(s);let c=V(e,u.toString()),f=Object.entries(e.days).filter(([s])=>s>=t&&s<=n).map(([,s])=>s);return c.query.range=f.length?[Math.min(...f.map(s=>s[0])),Math.max(...f.map(s=>s[1]))]:[0,0],c}function ve(e){return e.replace(/[\t\r\n\u2028\u2029]+/g," ").replace(/[\\`*_[\]{}<>#!|~]/g,"\\$&")}function Be(e,r,t,n){let u=a=>a==="source"?n.source:a==="topic"?n.topic:a,c=(a,i)=>i.map(o=>ve(r.labels[r.prefixes[a]+o]||o)).join(", "),f=a=>`<${Z(a,!0).href.replace(/</g,"%3C").replace(/>/g,"%3E")}>`,s=a=>{let i=e.filters.getAll(a);return a==="source"&&!i.length&&r.tab_sources?.length&&e.filters.get("include_tabs")!=="1"?n.allWithoutTabs:c(a,i)||n.all},d=[["# "+ve(e.site),`${n.dates}: ${e.start} \u2014 ${e.end}`,...Object.keys(r.prefixes).map(a=>`${u(a)}: ${s(a)}`),`${n.entries}: ${e.cards.length}`].join(`
2
+
3
+ `)];for(let a of e.cards){let i=t.get(a.id);if(i===void 0)throw new Error("Incomplete export");let o=[`${n.date}: ${a.display_date||""}`,...Object.entries(a.facets).map(([h,m])=>`${u(h)}: ${c(h,m)}`),...a.source_url?[`${n.original}: ${a.source_title?`[${ve(a.source_title)}](${f(a.source_url)})`:f(a.source_url)}`]:[],`${n.article}: ${f(a.url)}`].join(`
4
+ `);d.push(`
5
+
6
+ ---
7
+
8
+ `,o,`
9
+
10
+ `,i.replace(/\r\n?/g,`
11
+ `).trimEnd())}return d.push(`
12
+ `),d}function je(e){let r=e.site.toLowerCase().replace(/[^\p{L}\p{N}_-]+/gu,"-").replace(/^-+|-+$/g,"")||"archive",t=e.locale.replace(/[^a-zA-Z0-9-]/g,"")||"en";return`${r}-${t}-${e.start}_${e.end}.md`}function Ve(e){let r=document.querySelector("[data-archive-export-open]"),t=document.querySelector('[data-dialog="export"]');if(!r||!t)return()=>{};let n=t.querySelector("[data-export-start]"),u=t.querySelector("[data-export-end]"),c=t.querySelector("[data-export-fields]"),f=t.querySelector("[data-export-facets]"),s=t.querySelector("[data-export-status]"),l=t.querySelector("[data-export-download]"),d=t.querySelector("[data-export-retry]"),a=t.querySelector("[data-export-cancel]"),i=t.querySelector("[data-export-progress]"),o=v=>t.dataset[v]||"",h,m=new URLSearchParams,g=[],E=new AbortController,x=new AbortController,L,I,b=!1,S=(v,p)=>o(v).replace("{count}",String(p));function H(v){I=v,d.hidden=!v}function M(){L?.controller.abort(),L=void 0,H(),c.disabled=!1,a.hidden=!0,i.hidden=!0}function T(){f.replaceChildren();let v=Q();for(let[p,A]of Object.entries(h.facets)){let y=document.createElement("fieldset"),w=document.createElement("legend");y.dataset.exportFacetGroup=p,w.textContent=p==="source"?o("sources"):p==="topic"?o("topics"):p,y.append(w);let D=document.createElement("div");D.className="archive-export__choices",D.id=`export-options-${p}`,y.append(...ge(h,m,p,v,D.id));let U=m.getAll(p),G=[...A,...U.filter(P=>!A.some(R=>R.id===P)).map(P=>({id:P,name:P}))],k=document.createElement("button");k.type="button",k.textContent=o("all"),k.className="tag-chip",k.dataset.exportAll=p,k.setAttribute("aria-label",`${w.textContent}: ${o("all")}`),k.setAttribute("aria-pressed",String(U.length===0)),D.append(k);for(let P of G){if(!se(h,m,p,P.id))continue;let R=document.createElement("label");R.className="archive-export__choice";let B=document.createElement("input");B.type="checkbox",B.dataset.exportFacet=p,B.value=P.id,B.checked=U.includes(P.id);let Se=document.createElement("span");Se.textContent=P.name,R.append(B,Se),D.append(R)}y.append(D),f.append(y)}}async function C(v){let p=await e.manifest(v);return v.throwIfAborted(),p.generation===h?.generation?!0:(await j(),!b&&t.open&&(s.textContent=`${o("updated")} ${s.textContent}`),!1)}async function q(v=!1){x.abort(),x=new AbortController;let p=AbortSignal.any([E.signal,x.signal]);if(g=[],l.disabled=!0,M(),!h)return;let A=ye(n.value,u.value,h.export_max_days);if(A){s.textContent=o(A).replace("{days}",String(h.export_max_days));return}if(s.textContent=o("calculating"),v&&await new Promise(y=>{let w=()=>{clearTimeout(D),p.removeEventListener("abort",w),y()},D=setTimeout(w,180);p.addEventListener("abort",w,{once:!0})}),!p.aborted)try{if(!await C(p))return;let y=await e.select(Ne(h,m,n.value,u.value),"all",p,5e3);if(p.aborted||b)return;if(y.count>5e3){s.textContent=S("tooMany",y.count).replace("{limit}",String(5e3));return}g=y.ordinals,s.textContent=y.count?S("matches",y.count):o("empty"),l.disabled=y.count===0}catch{p.aborted||(s.textContent=o("unavailable"),H(()=>{q()}))}}async function j(){E.abort(),x.abort(),E=new AbortController;let v=E.signal,p=location.search;h=void 0,g=[],M(),f.replaceChildren(),n.value=u.value="",l.disabled=!0,c.disabled=!0,s.textContent=o("calculating"),Me("export");let A=document.activeElement;try{let y=await e.manifest(v);if(v.aborted)return;h=y;let w=V(h,p);if(m=new URLSearchParams(w.parameters),[n.value,u.value]=be(h,p,[]),!n.value){let D=await e.select(w,"first",v);if(v.aborted)return;[n.value,u.value]=be(h,p,D.ordinals)}for(let D of["day","month","year","page"])m.delete(D);T(),c.disabled=!1,document.activeElement===A&&n.focus(),t.querySelector("[data-export-limit]").textContent=o("limitHint").replace("{days}",String(h.export_max_days)),await q()}catch{v.aborted||(s.textContent=o("unavailable"),H(()=>{j()}))}}async function $(){if(!h||!g.length||L?.status==="running")return;x.abort();let v=new AbortController;L??={snapshot:{site:o("site"),locale:document.documentElement.lang,start:n.value,end:u.value,filters:new URLSearchParams(m),cards:[]},ordinals:[...g],bodies:new Map,budget:new Ce,controller:v,status:"running"};let p=L;p.controller=v,p.status="running";let A=AbortSignal.any([E.signal,p.controller.signal]),{snapshot:y,bodies:w}=p;l.disabled=!0,c.disabled=!0,H(),a.hidden=!1,i.hidden=!1,i.max=p.ordinals.length;let D=()=>{i.value=w.size,s.textContent=o("progress").replace("{done}",String(w.size)).replace("{count}",String(p.ordinals.length))};D();try{if(!await C(A))return;y.cards.length||(i.removeAttribute("value"),s.textContent=o("loadingCards"),y.cards=await e.cards(p.ordinals,A),A.throwIfAborted(),D());let U=0;if(await ae(y.cards.filter(R=>!w.has(R.id)),async R=>{try{let B=await e.markdown(R,A,p.budget);A.throwIfAborted(),w.set(R.id,B),D()}catch(B){if(A.aborted||B instanceof fe)throw B;U++}},A),A.throwIfAborted(),U){p.status="failed",s.textContent=S("failed",U),H(()=>{$()});return}let G=Be(y,h,w,{dates:o("dates"),source:o("sources"),topic:o("topics"),all:o("all"),allWithoutTabs:o("allWithoutTabs"),entries:o("entries"),date:o("date"),original:o("original"),article:o("article")}),k=URL.createObjectURL(new Blob(G,{type:"text/markdown;charset=utf-8"})),P=document.createElement("a");P.href=k,P.download=je(y),document.body.append(P),P.click(),P.remove(),setTimeout(()=>URL.revokeObjectURL(k),1e3),s.textContent=S("complete",y.cards.length),p.status="complete"}catch(U){U instanceof fe&&!A.aborted?(p.status="limited",p.controller.abort(),w.clear(),s.textContent=o("tooLarge")):A.aborted||(p.status="failed",s.textContent=o("unavailable"),H(()=>{$()}))}finally{L===p&&(c.disabled=!1,a.hidden=!0,i.hidden=!0,l.disabled=p.status!=="complete")}}function z(v){if(!(L?.status==="running"||!h)){for(let p of Object.keys(h.facets))m.delete(p);for(let p of f.querySelectorAll("input:checked"))m.append(p.dataset.exportFacet,p.value);m=V(h,m.toString()).parameters;for(let p of f.querySelectorAll("[data-export-all]"))p.setAttribute("aria-pressed",String(!m.has(p.dataset.exportAll)));for(let p of f.querySelectorAll("[data-export-facet]")){let A=p.closest("label");if(A.hidden=!se(h,m,p.dataset.exportFacet,p.value),A.hidden&&document.activeElement===p){let y=p.dataset.exportFacet==="source"&&h.tab_sources?.includes(p.value)&&m.get("include_tabs")!=="1"?"include_tabs":"show_hidden",w=p.closest("fieldset");(w?.querySelector(`[data-archive-visibility="${y}"]`)||w?.querySelector("[data-export-all]"))?.focus()}}q(v?.target===n||v?.target===u)}}function J(v){if(!(v.target instanceof Element))return;let p=v.target.closest("[data-archive-visibility]");if(p&&h&&L?.status!=="running"){let y=p.dataset.archiveVisibility,w=p.closest("[data-export-facet-group]").dataset.exportFacetGroup;ce(m,y,h,w),T(),f.querySelector(`[data-export-facet-group="${w}"] [data-archive-visibility="${y}"]`)?.focus(),y==="include_tabs"&&q();return}let A=v.target.closest("[data-export-all]");if(!(!A||L?.status==="running")){for(let y of f.querySelectorAll("input"))y.dataset.exportFacet===A.dataset.exportAll&&(y.checked=!1);z()}}function ee(){M(),l.disabled=!g.length,s.textContent=o("cancelled")}function K(){E.abort(),x.abort(),M()}function X(){K(),b||r.focus()}function te(v){(v.target===t||v.target instanceof Element&&v.target.closest("[data-dialog-close]"))&&K()}function N(){I?.()}let O=()=>{j()},F=()=>{$()};return r.hidden=!1,r.addEventListener("click",O),t.addEventListener("close",X),t.addEventListener("cancel",K),t.addEventListener("click",te),c.addEventListener("input",z),f.addEventListener("click",J),l.addEventListener("click",F),d.addEventListener("click",N),a.addEventListener("click",ee),()=>{b=!0,X(),t.open&&t.close(),r.removeEventListener("click",O),t.removeEventListener("close",X),c.removeEventListener("input",z),f.removeEventListener("click",J),t.removeEventListener("cancel",K),t.removeEventListener("click",te),l.removeEventListener("click",F),d.removeEventListener("click",N),a.removeEventListener("click",ee)}}var st=new Set("A ABBR B BLOCKQUOTE BR CODE DD DEL DETAILS DIV DL DT EM FIGCAPTION FIGURE H1 H2 H3 H4 H5 H6 HR I IMG KBD LI MARK OL P PRE S SECTION SMALL SPAN STRONG SUB SUMMARY SUP TABLE TBODY TD TFOOT TH THEAD TR UL".split(" ")),ct=new Set("SCRIPT STYLE IFRAME OBJECT EMBED FORM INPUT BUTTON SELECT TEXTAREA TEMPLATE NOSCRIPT SVG MATH".split(" "));function lt(e,r,t){let n=new URL(r),u=n.origin+n.pathname+n.search,c=document.createElement("template");c.innerHTML=e;let f=c.content.querySelector(".note-content");if(!f)throw new Error("Article body is missing");let s=new Map(Array.from(f.querySelectorAll("[id]"),(a,i)=>[a.id,`${t}-${i}`]));function l(a){if(a.nodeType===Node.TEXT_NODE)return document.createTextNode(a.textContent||"");if(!(a instanceof Element)||ct.has(a.tagName))return null;let i=document.createDocumentFragment();for(let m of a.childNodes){let g=l(m);g&&i.append(g)}if(!st.has(a.tagName))return i;let o=document.createElement(a.tagName.toLowerCase());a.id&&(o.id=s.get(a.id));for(let m of["title","lang","dir","alt","colspan","rowspan","scope","start"]){let g=a.getAttribute(m);g!==null&&o.setAttribute(m,g)}a.tagName==="CODE"&&(o.className=[...a.classList].filter(m=>/^language-[\w+-]+$/.test(m)).join(" "));let h=a.tagName==="A"?"href":a.tagName==="IMG"?"src":null;if(h){let m=a.getAttribute(h);if(m)try{let g=new URL(m,n);if(/^https?:$/.test(g.protocol)||h==="href"&&g.protocol==="mailto:"){let E;try{E=s.get(decodeURIComponent(g.hash.slice(1)))}catch{}o.setAttribute(h,E&&g.origin+g.pathname+g.search===u?`#${E}`:g.href)}}catch{}}return a.tagName==="A"&&o.setAttribute("rel","noopener noreferrer"),a.tagName==="IMG"&&(o.setAttribute("loading","lazy"),!o.hasAttribute("src"))?null:(o.append(i),o)}let d=document.createDocumentFragment();for(let a of f.childNodes){let i=l(a);i&&d.append(i)}return d}function Ke(e,r){let t=document.querySelector("[data-archive-reading-toggle]");if(!t)return{refresh(){},dispose(){}};let n=!1,u=!1,c=new AbortController,f=0,s,l=new WeakMap,d=new Map,a=0;try{n=localStorage.getItem("website-archive-reading")==="true"}catch{}t.hidden=!1;function i(){t.setAttribute("aria-checked",String(n)),t.title=n?t.dataset.enabled||"Read in full: on":t.dataset.disabled||"Read in full: off"}function o(b){let S=b.cloneNode(!0),H=new Map,M=`archive-article-${++f}`;for(let[T,C]of[...S.querySelectorAll("[id]")].entries()){let q=`${M}-${T}`;H.set(C.id,q),C.id=q}for(let T of S.querySelectorAll('a[href^="#"]')){let C=H.get(T.getAttribute("href").slice(1));C&&T.setAttribute("href","#"+C)}return S}async function h(b,S){let H=b.querySelector("a.blog-ledger__main"),M=b.querySelector(".blog-ledger__content");if(!H||!M||!m(b)||b.dataset.readingLoaded||l.get(b)===S)return;l.set(b,S);let T=M.querySelector(".archive-reading__body");T||(T=document.createElement("div"),T.className="archive-reading__body note-content",M.append(T)),T.textContent=t.dataset.loading||"Loading article\u2026",T.setAttribute("aria-busy","true");try{let C=d.get(H.href);if(C)d.delete(H.href),d.set(H.href,C);else{let q=await r.article(H.href,S);for(S.throwIfAborted(),C={body:lt(q.html,q.url,"archive-template"),weight:q.html.length*2},d.set(H.href,C),a+=C.weight;d.size>100||a>4*1024*1024;){let j=d.keys().next().value;a-=d.get(j).weight,d.delete(j)}}S.throwIfAborted(),T.replaceChildren(o(C.body)),b.dataset.readingLoaded="true"}catch{if(S.aborted)return;let C=document.createElement("p");C.textContent=t.dataset.unavailable||"Article could not be loaded.";let q=document.createElement("button");q.type="button",q.dataset.readingRetry="",q.textContent=t.dataset.retry||"Retry",T.replaceChildren(C,q)}finally{l.get(b)===S&&l.delete(b),S.aborted||T.removeAttribute("aria-busy")}}function m(b){return!b.closest("[hidden], details[data-ledger-day]:not([open])")}function g(b=e){if(!n||u)return;let S=c.signal,H=Array.from(b.querySelectorAll("[data-filter-item]"));if(s)for(let M of H)m(M)?!M.dataset.readingLoaded&&l.get(M)!==S&&s.observe(M):s.unobserve(M);else ae(H.filter(m),M=>h(M,S),S).catch(()=>{})}function E(){if(s?.disconnect(),s=void 0,c.abort(),c=new AbortController,e.classList.toggle("archive-reading",n),i(),!n||u)return;let b=c.signal;typeof IntersectionObserver=="function"&&(s=new IntersectionObserver((S,H)=>{if(!b.aborted)for(let M of S)M.isIntersecting&&m(M.target)&&(H.unobserve(M.target),h(M.target,b))},{rootMargin:"400px 0px"})),g()}function x(){n=!n;try{localStorage.setItem("website-archive-reading",String(n))}catch{}E()}function L(b){if(!n||u||!(b.target instanceof Element)||!b.target.closest("[data-reading-retry]"))return;let S=b.target.closest("[data-filter-item]");S&&h(S,c.signal)}t.addEventListener("click",x),e.addEventListener("click",L);let I=b=>{b.target instanceof HTMLDetailsElement&&b.target.hasAttribute("data-ledger-day")&&g(b.target)};return e.addEventListener("toggle",I,!0),i(),{refresh:E,dispose(){u=!0,s?.disconnect(),c.abort(),d.clear(),a=0,t.removeEventListener("click",x),e.removeEventListener("click",L),e.removeEventListener("toggle",I,!0)}}}var Ge=new WeakMap;function We(e){let r=Ge.get(e);if(!r){let t=e.querySelector("[data-ledger-day-ui]").dataset;r={year:e.dataset.ledgerCurrentYear,date:t.date,dateYear:t.dateYear,months:t.months.split("|"),weekdays:t.weekdays.split("|"),entry:t.entry,entries:t.entries,undated:t.undated},Ge.set(e,r)}return r}function dt(e,r){return(r===1?e.entry:e.entries).replaceAll("{count}",String(r))}function Ye(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return;let r=new Date(`${e}T00:00:00Z`);if(!(!Number.isFinite(r.valueOf())||r.toISOString().slice(0,10)!==e))return{year:e.slice(0,4),month:r.getUTCMonth(),day:r.getUTCDate(),weekday:r.getUTCDay()}}function ut(e,r){let t=We(e),n=Ye(r),u=n?.year===t.year?t.date:t.dateYear,c=n&&{month:t.months[n.month],day:String(n.day),year:n.year};return{date:c?u.replace(/\{(month|day|year)\}/g,(f,s)=>c[s]):t.undated,weekday:n?t.weekdays[n.weekday]:"",dated:!!n}}function ze(e,r){let t=document.createElement("details");t.className="archive-day",t.dataset.ledgerDay=r;let n=document.createElement("summary"),u=document.createElement("h2"),c=ut(e,r),f=document.createElement(c.dated?"time":"span");f.textContent=c.date,f instanceof HTMLTimeElement&&(f.dateTime=r),u.append(f);let s=document.createElement("span");s.className="archive-day__arrow",s.setAttribute("aria-hidden","true");let l=document.createElement("span");if(l.className="archive-day__meta",c.weekday){let a=document.createElement("span");a.textContent=c.weekday,l.append(a," \xB7 ")}let d=document.createElement("span");return d.dataset.ledgerDayCount="",l.append(d),n.append(u,s,l),t.append(n),t}function de(e){let r=new Map,t=new WeakMap,n=()=>Array.from(e.querySelectorAll("details[data-ledger-day]"));for(let s of n())t.set(s,s.hasAttribute("data-ledger-default-open")?s.dataset.ledgerDefaultOpen==="true":s.open);function u(s=n()){for(let l of s){let d=t.get(l);d!==void 0&&d!==l.open&&r.set(l.dataset.ledgerDay,l.open),t.set(l,l.open)}}function c(){let s=n();u(s);let l=s.filter(a=>!a.closest("[data-filter-group][hidden]")),d;for(let a of l){let i=a.dataset.ledgerDay;Ye(i)&&(!d||i>d)&&(d=i)}d||=l[0]?.dataset.ledgerDay;for(let a of l){let i=a.dataset.ledgerDay,o=r.get(i)??i===d;t.set(a,o),a.open!==o&&(a.open=o);let h=a.querySelector("[data-ledger-day-count]");h&&(h.textContent=dt(We(e),a.querySelectorAll("[data-filter-item]:not([hidden])").length))}}let f=s=>{s.target instanceof HTMLDetailsElement&&s.target.hasAttribute("data-ledger-day")&&u([s.target])};return c(),e.addEventListener("toggle",f,!0),{replace(s){u(),s(),c()},refresh:c,dispose(){e.removeEventListener("toggle",f,!0),r.clear()}}}function _(e,r,t){let n=document.createElement(e);return n.textContent=r,t&&(n.className=t),n}function Je(e,r,t,n){let u=t.ledger_group_by||e.dataset.ledgerGroupBy||"year";e.dataset.ledgerGroupBy=u;let c=document.createDocumentFragment(),f=u==="day",s=Y(),l=!!document.querySelector("[data-favorites-ui]"),d,a;for(let i of r){let o=(f?i.display_date:i.year)||s.undated||"Undated";if(o!==d){d=o;let L=document.createElement("section");L.dataset.filterGroup="";let I=i.display_date||"Undated",b=f?ze(e,I):L;f||L.append(_("h2",d));let S=_("section","","blog-ledger");a=document.createElement("ol"),S.append(a),b.append(S),f&&L.append(b),c.append(L)}let h=document.createElement("li");if(h.dataset.filterItem="",!f){let L=_("div","","blog-ledger__meta"),I=_("time",i.display_date||"");I.dateTime=i.published_at||"",L.append(I),h.append(L)}let m=_("div","","blog-ledger__content"),g=i.unavailable?_("div","","blog-ledger__main"):_("a","","blog-ledger__main");if(g instanceof HTMLAnchorElement&&(g.href=Z(i.url).href),g.append(_("strong",i.title)),i.snapshot_locale&&(g.lang=i.snapshot_locale),i.summary&&g.append(_("span",i.summary,"blog-ledger__description")),l){let L=_("div","","blog-ledger__heading");L.append(g,qe({...i,favorite_labels:He(i,t)})),m.append(L)}else m.append(g);let E=_("footer","","archive-card-footer"),x=_("ul","","blog-ledger__topics");for(let[L,I]of Object.entries(i.facets))for(let b of I){let S=ie(i,L,b,t),H=_("a",S);H.dataset.archiveFacet=L,H.dataset.archiveValue=b;let M=new URL(window.location.href),T=new Set(M.searchParams.getAll(L));T.has(b)?T.delete(b):T.add(b),M.searchParams.delete("page"),M.searchParams.delete(L),[...T].sort().forEach(q=>M.searchParams.append(L,q)),H.href=M.pathname+M.search;let C=document.createElement("li");C.append(H),x.append(C)}if(E.append(x),i.source_url){let L=_("a",i.source_title||i.source_url,"archive-source-url");L.href=Z(i.source_url,!0).href,L.rel="noopener noreferrer",E.append(L)}i.date_basis==="observed"&&E.append(_("small",e.dataset.observedLabel||"First observed")),i.unavailable&&(h.dataset.favoriteUnavailable="",E.append(_("small",s.removed||"This article is no longer published. Your saved summary and original link are kept."))),m.append(E),h.append(m),a.append(h)}e.querySelector("[data-filter-list]").replaceChildren(c),Oe(n)}function ft(){try{let e=JSON.parse(Q().hiddenTags||"[]");return Array.isArray(e)&&e.every(r=>typeof r=="string"&&r.length>0)?e:[]}catch{return[]}}function pt(e,r){let t=Object.create(null),n=Object.assign(Object.create(null),r?.prefixes||{source:"source/",topic:"topics/"}),u={...r?.labels},c={},f={},s={},l=new Map;for(let d of Object.keys(r?.prefixes||{source:"source/",topic:"topics/"}))t[d]=[];e.forEach((d,a)=>{for(let[i,o]of Object.entries(d.facets)){Object.hasOwn(n,i)||(n[i]=pe(n,i)),t[i]||=[];for(let h of o){let m=n[i]+h;u[m]||=ie(d,i,h,r);let g=l.get(i);g||(g=new Map,l.set(i,g));let E=g.get(h);E||(E={id:h,name:u[m],count:0},g.set(h,E),t[i].push(E)),E.count++}}for(let[i,o]of[[c,d.year],[f,d.month],[s,d.display_date]])o&&(i[o]||=[a,a],i[o][1]=a+1)});for(let d of Object.values(t))d.sort((a,i)=>i.count-a.count||a.id.localeCompare(i.id));return{total:e.length,page_size:50,hidden_tags:r?.hidden_tags||ft(),facets:t,prefixes:n,labels:u,aliases:r?.aliases||{},years:c,months:f,days:s,ledger_group_by:"day"}}function Le(e,r){return Object.hasOwn(e.snapshots,r)?r:Object.keys(e.snapshots)[0]}function we(e,r){let t=Le(e,r);return{...e.snapshots[t],snapshot_locale:t}}function ht(e,r){return r&&Object.keys(r.aliases).length&&(e=e.map(t=>({...t,facets:Object.fromEntries(Object.entries(t.facets).map(([n,u])=>[n,[...new Set(u.map(c=>ne(c,pe(r.prefixes,n),r.aliases)))]]))}))),e.sort((t,n)=>(t.display_date||"")>(n.display_date||"")?-1:(t.display_date||"")<(n.display_date||"")?1:t.id<n.id?-1:t.id>n.id?1:0)}function Ee(e,r){return new Map([...e].map(([t,n])=>[t,n.snapshots[Le(n,r)]]))}function Ze(e,r,t,n,u,c){let f=new Map(e.map(d=>[d.id,d])),s=Ee(r.entries,c),l=ht([...t.entries.values()].map(d=>{let a=f.get(d.id),i=d.snapshots[Le(d,c)];return a&&ke(i,s.get(d.id))?a:{...we(d,c),unavailable:!!a?.unavailable}}),n);return{cards:l,manifest:pt(l,n),refreshFailed:u&&l.length>0,sourceManifest:n,snapshots:Ee(t.entries,c),revision:t.revision}}async function Qe(e,r,t){try{return e.length?await Pe(e,t,r.entries):W()}catch(n){oe(n);try{return W()}catch{return r}}}async function mt(e,r,t){let n=document.documentElement.lang||"en";try{t||=W()}catch(l){throw oe(l),l}let u=t,c=[...t.entries.values()].map(l=>we(l,n)),f,s=!1;try{f=await e.manifest(r);let l=c.length?await e.lookup(c.map(d=>d.id),r):new Map;r.throwIfAborted(),c=c.map(d=>l.has(d.id)?{...he(l.get(d.id),f),snapshot_locale:n}:{...d,unavailable:!0}),u=await Qe(c.filter(d=>!d.unavailable),t,n)}catch{r.throwIfAborted(),s=!0}return Ze(c,t,u,f,s,n)}async function gt(e,r,t,n=W()){let u=document.documentElement.lang||"en",c=Ee(n.entries,u),f=new Map(e.cards.map(i=>[i.id,i])),s=[],l=n,d=[...n.entries.values()].map(i=>{let o=f.get(i.id);return o&&c.get(i.id)===e.snapshots.get(i.id)?o:(o||s.push(i.id),{...!Object.hasOwn(i.snapshots,u)&&o?.snapshot_locale===u?o:we(i,u),unavailable:!!o?.unavailable})}),a=e.refreshFailed;if(s.length)try{let i=await r.lookup(s,t);t.throwIfAborted();let o=[...i.values()].map(m=>he(m,e.sourceManifest)),h=new Map(o.map(m=>[m.id,m]));d=d.map(m=>h.has(m.id)?{...h.get(m.id),snapshot_locale:u}:m),l=await Qe(o,n,u)}catch{t.throwIfAborted(),a=!0}return Ze(d,n,l,e.sourceManifest,a,u)}async function et(e,r,t){let n;try{n=W()}catch(u){throw oe(u),u}return t?t.revision===n.revision?t:gt(t,e,r,n):mt(e,r,n)}var Xe=new WeakMap;function tt(e,r,t){let n=Xe.get(e);n||(n=new Map,Xe.set(e,n));let u=new Set(t.keys.filter(f=>!n.has(f)));for(let f of u)n.set(f,new Uint8Array(Math.ceil(e.length/8)));u.size&&e.forEach((f,s)=>{for(let[l,d]of Object.entries(f.facets))for(let a of d){let i=l+"/"+a;u.has(i)&&(n.get(i)[s>>3]|=1<<(s&7))}});let c=Object.fromEntries(t.keys.map(f=>[f,n.get(f)]));for(;n.size>20;)n.delete(n.keys().next().value);return Te(e.length,r.page_size,t.query,c)}function rt(e,r){let t=e.querySelector("[data-favorites-facets]"),n=new Map([["source",e.dataset.sourcesLabel||"Sources"],["topic",e.dataset.topicsLabel||"Topics"]]);t.replaceChildren();for(let[c,f]of Object.entries(r.facets)){let s=_("nav","","tag-filter archive-facet"),l=_("h2",n.get(c)||c,"archive-facet-label"),d=_("ul","","tag-filter__list");s.setAttribute("aria-label",l.textContent);for(let i of[{id:"",name:e.dataset.allLabel||"All",count:r.total},...f]){let o=_("button","","tag-chip");o.type="button",o.dataset.archiveFacet=c,o.dataset.archiveValue=i.id,o.append(document.createTextNode(i.name+" "),_("span",String(i.count)));let h=document.createElement("li");h.append(o),d.append(h)}let a=_("div","","archive-facet-heading");a.append(l),s.append(a,d),t.append(s)}for(let c of document.querySelectorAll("[data-timeline-nav]")){let f=c.querySelector("h2");c.replaceChildren(),f&&c.append(f);for(let s of Object.keys(r.years).filter(l=>l!=="Undated").sort().reverse()){let l=_("section","","archive-timeline__year archive-timeline__year--days"),d=_("h3",""),a=_("ul",""),i=(h,m,g,E)=>{let x=_("a","");return x.href=`${location.pathname}?${h}=${encodeURIComponent(m)}`,x.setAttribute(`data-${h}-filter-option`,""),x.setAttribute(`data-filter-${h}`,m),x.append(_("span",g),_("span",String(E),"archive-timeline__count")),x},o=r.years[s];d.append(i("year",s,s,o[1]-o[0]));for(let h of Object.keys(r.days).filter(m=>m.startsWith(s)).sort().reverse()){let m=r.days[h],g=document.createElement("li");g.append(i("day",h,h.slice(5),m[1]-m[0])),a.append(g)}l.append(d,a),c.append(l)}c.hidden=!Object.keys(r.days).length}for(let c of document.querySelectorAll('[data-dialog-open="context"]'))c.hidden=!Object.keys(r.days).length;let u=e.querySelector("[data-archive-empty]");r.total||u.replaceChildren(document.createTextNode(Y().empty||"No favorites yet. Save an entry to find it here."))}function vt(e,r){let t=Math.min(5,r),n=Math.max(1,Math.min(e-2,r-t+1));return Array.from({length:t},(u,c)=>n+c)}function nt(e,r,t,n){let u=e.dataset.pageLabel||"Page {page} of {pages}",c=e.dataset.resultLabel||"{count} entries";e.querySelector("[data-archive-page-status]").textContent=`${c.replace("{count}",String(n))} \xB7 ${u.replace("{page}",String(r)).replace("{pages}",String(t))}`,e.querySelector("[data-archive-page=prev]").disabled=r<=1,e.querySelector("[data-archive-page=next]").disabled=r>=t;let f=e.querySelector("[data-archive-page-numbers]");f.replaceChildren(),f.hidden=t<=1;for(let d of vt(r,t)){let a=document.createElement("a"),i=new URL(location.href);d===1?i.searchParams.delete("page"):i.searchParams.set("page",String(d)),a.href=i.pathname+i.search,a.dataset.archivePage=String(d),a.textContent=String(d),a.setAttribute("aria-label",(e.dataset.numberLabel||"Page {page}").replace("{page}",String(d))),d===r&&a.setAttribute("aria-current","page"),f.append(a)}let s=e.querySelector("[data-archive-page-jump]"),l=s.querySelector("input");(document.activeElement!==l||e.dataset.currentPage!==String(r))&&(l.value=String(r)),e.dataset.currentPage=String(r),l.max=String(t),l.disabled=n===0,document.activeElement!==l&&l.setCustomValidity(""),s.hidden=t<=1}function at(e){return re(r=>{let t=_e(e.dataset.archiveUrl);r(()=>t.dispose());let n=e.hasAttribute("data-favorites-page"),u=e.querySelector("[data-archive-status]"),c=e.querySelector("[data-archive-retry]"),f=e.querySelector("[data-archive-empty]"),s=[...f.childNodes].map(O=>O.cloneNode(!0)),l=e.querySelector("[data-archive-pagination]"),d=l.querySelector("[data-archive-page=prev]"),a=l.querySelector("[data-archive-page=next]"),i=new AbortController;r(()=>i.abort());let o=de(e);r(()=>o.dispose());let h=Ke(e,t);r(()=>h.dispose()),n||r(Ve(t));let m=0,g=!0;r(()=>{g=!1});let E,x,L,I=!0,b,S=async()=>{throw new Error("Current deployment could not be verified")},H={manifest:S,lookup:S},M,T={ordinals:[],count:0,page:1,pages:1};async function C(O=!1){let F=window.location.search;if(E===F)return;E=F;let v=++m;u.textContent=u.dataset.loading||"Loading\u2026",c.hidden=!0,e.setAttribute("aria-busy","true"),d.disabled=!0,a.disabled=!0;try{if(O&&!b&&(x=void 0,I=!1,b=t.revalidateCurrent(e.dataset.archiveCurrentUrl,i.signal).then(()=>{I=!0}).catch(()=>{i.signal.throwIfAborted()}).finally(()=>{b=void 0})),await b,!g||v!==m)return;let p;n&&(p=await et(I?t:H,i.signal,x));let A=p?.manifest||await t.manifest(i.signal);if(!g||v!==m)return;p&&(x=p);let y=V(A,window.location.search),w=p?tt(p.cards,A,y):await t.select(y,"page",i.signal);if(!g||v!==m)return;let D=p?w.ordinals.map(k=>p.cards[k]):await t.cards(w.ordinals,i.signal);if(!g||v!==m)return;p&&L!==A&&(f.replaceChildren(...s.map(k=>k.cloneNode(!0))),rt(e,A),L=A),o.replace(()=>Je(e,D,A,p?new Set(p.snapshots.keys()):void 0)),h.refresh(),T=w,M=A,Ue(e,A,y.parameters),w.page>1?y.parameters.set("page",String(w.page)):y.parameters.delete("page");let U=y.parameters.toString();history.replaceState(null,"",window.location.pathname+(U?`?${U}`:""));for(let k of e.querySelectorAll("button[data-archive-facet]")){let P=k.dataset.archiveFacet,R=k.dataset.archiveValue;k.setAttribute("aria-pressed",String(R?y.parameters.getAll(P).includes(R):!y.parameters.getAll(P).length))}for(let k of["year","month","day"])for(let P of document.querySelectorAll(`[data-timeline-nav] [data-${k}-filter-option]`))y.parameters.get(k)===P.getAttribute(`data-filter-${k}`)?P.setAttribute("aria-current","page"):P.removeAttribute("aria-current");nt(l,w.page,w.pages,w.count);let G=p?p.refreshFailed:!I;f.hidden=w.count!==0,u.textContent=G?p?Y().refreshError||"Could not refresh articles. Your saved summaries are shown. Retry to continue.":u.dataset.refreshError||"Could not check for updates. Previously loaded entries remain available. Retry to check again.":"",c.hidden=!G,e.removeAttribute("aria-busy")}catch{g&&v===m&&(u.textContent=u.dataset.unavailable||"Entries could not be loaded.",c.hidden=!1,e.removeAttribute("aria-busy"),h.refresh())}finally{v===m&&(E=void 0)}}function q(O){if(!(O.target instanceof Element)||O.button!==0||O.metaKey||O.ctrlKey||O.shiftKey||O.altKey)return;let F=O.target.closest("[data-archive-visibility], [data-archive-facet], [data-year-filter-option], [data-month-filter-option], [data-day-filter-option], [data-archive-page], [data-archive-clear], [data-archive-retry]");if(!F||!e.contains(F)&&!F.closest("[data-timeline-nav]"))return;if(O.preventDefault(),F.hasAttribute("data-archive-retry")){C(!0);return}if(e.hasAttribute("aria-busy")&&F.hasAttribute("data-archive-page"))return;let v=new URL(window.location.href);if(F.dataset.archiveVisibility){if(!M)return;ce(v.searchParams,F.dataset.archiveVisibility,M,F.dataset.archiveVisibilityFacet)}else if(F.hasAttribute("data-archive-clear"))v.search="";else if(F.dataset.archivePage){let p=F.dataset.archivePage,A=p==="next"?T.page+1:p==="prev"?T.page-1:Number(p);if(!Number.isSafeInteger(A))return;v.searchParams.set("page",String(Math.max(1,Math.min(T.pages,A))))}else if(v.searchParams.delete("page"),F.dataset.archiveFacet){let p=F.dataset.archiveFacet,A=F.dataset.archiveValue||"",y=new Set(v.searchParams.getAll(p));A?y.has(A)?y.delete(A):y.add(A):y.clear(),v.searchParams.delete(p),[...y].sort().forEach(w=>v.searchParams.append(p,w))}else{let p=F.hasAttribute("data-year-filter-option")?"year":F.hasAttribute("data-month-filter-option")?"month":"day",A=F.getAttribute(`data-filter-${p}`);for(let y of["year","month","day"])y!==p&&v.searchParams.delete(y);v.searchParams.get(p)===A?v.searchParams.delete(p):v.searchParams.set(p,A)}v.search!==window.location.search&&history.pushState(null,"",v.pathname+v.search),C()}let j=l.querySelector("[data-archive-page-jump]"),$=j.querySelector("input"),z=()=>{$.setCustomValidity("")},J=()=>{$.setCustomValidity((l.dataset.jumpError||"Enter a whole number from 1 to {pages}.").replace("{pages}",String(T.pages)))};function ee(O){if(O.preventDefault(),e.hasAttribute("aria-busy"))return;let F=xe($.value);if(F===void 0||F>T.pages){J(),$.reportValidity();return}let v=new URL(location.href);F===1?v.searchParams.delete("page"):v.searchParams.set("page",String(F)),v.search!==location.search&&history.pushState(null,"",v.pathname+v.search),C()}let K=()=>{n&&(E=void 0,C())},X=()=>{C()},te=O=>{O.persisted&&(E=void 0,C(!0))},N={signal:i.signal};window.addEventListener(Fe,K,N),j.addEventListener("submit",ee,N),$.addEventListener("input",z,N),$.addEventListener("invalid",J,N),document.addEventListener("click",q,N),window.addEventListener("popstate",X,N),window.addEventListener("pageshow",te,N),C()})}function ue(e,r,t,n){let u=e.get(r)??"";return t.some(c=>c.dataset[n]===u)?u:""}function it(e){let r=new URLSearchParams(window.location.search),t=Array.from(document.querySelectorAll("[data-topic-filter-nav] [data-topic-filter-option]")),n=Array.from(document.querySelectorAll("[data-year-filter-option]")),u=Array.from(document.querySelectorAll("[data-month-filter-option]")),c=Array.from(document.querySelectorAll("[data-day-filter-option]")),f=ue(r,"topic",t,"topicAnchor"),s=ue(r,"day",c,"filterDay"),l=s?"":ue(r,"month",u,"filterMonth"),d=s||l?"":ue(r,"year",n,"filterYear");for(let o of t)o.dataset.topicAnchor===f?o.setAttribute("aria-current","page"):o.removeAttribute("aria-current");for(let o of n)d&&o.dataset.filterYear===d?o.setAttribute("aria-current","page"):o.removeAttribute("aria-current");for(let o of u)l&&o.dataset.filterMonth===l?o.setAttribute("aria-current","page"):o.removeAttribute("aria-current");for(let o of c)s&&o.dataset.filterDay===s?o.setAttribute("aria-current","page"):o.removeAttribute("aria-current");let a=Array.from(e.querySelectorAll("[data-filter-item]"));for(let o of a){let h=(o.dataset.topicAnchors??"").split(/\s+/).filter(Boolean),m=o.dataset.filterMonth??"";o.hidden=!!(f&&!h.includes(f)||d&&!m.startsWith(`${d}-`)||l&&m!==l||s&&o.dataset.filterDay!==s)}for(let o of e.querySelectorAll("[data-filter-group]"))o.hidden=!o.querySelector("[data-filter-item]:not([hidden])");let i=e.querySelector("[data-filter-empty]");i&&(i.hidden=a.some(o=>!o.hidden))}function dr(){return re(e=>{Array.from(document.querySelectorAll("[data-paged-archive]")).forEach(s=>e(at(s)));let t=Array.from(document.querySelectorAll("[data-filter-page]:not([data-paged-archive])"));if(t.length===0)return;let n=t.map(s=>{it(s);let l=de(s);return e(()=>l.dispose()),l}),u=()=>t.forEach((s,l)=>{it(s),n[l].refresh()}),c=s=>{let l=s.target;if(!(l instanceof Element))return;let d=l.closest("a[data-topic-filter-option], a[data-year-filter-option], a[data-month-filter-option], a[data-day-filter-option]");if(!d)return;let a=new URL(d.href,window.location.href);if(a.origin!==window.location.origin||a.pathname!==window.location.pathname)return;s.preventDefault();let i=new URL(window.location.href);if(i.pathname=a.pathname,d.hasAttribute("data-topic-filter-option")){let o=d.dataset.topicAnchor??"";o?i.searchParams.set("topic",o):i.searchParams.delete("topic")}else{let o=d.hasAttribute("data-year-filter-option")?"year":d.hasAttribute("data-month-filter-option")?"month":"day",h=d.getAttribute(`data-filter-${o}`)??"";d.getAttribute("aria-current")==="page"?i.searchParams.delete(o):i.searchParams.set(o,h);for(let m of["year","month","day"])m!==o&&i.searchParams.delete(m)}window.history.pushState(null,"",`${i.pathname}${i.search}`),u()},f=new AbortController;e(()=>f.abort()),document.addEventListener("click",c,{signal:f.signal}),window.addEventListener("popstate",u,{signal:f.signal}),window.addEventListener("pageshow",u,{signal:f.signal})})}export{dr as initialiseArchiveFilters};
@@ -1 +1 @@
1
- import{d as o}from"./chunks/chunk-GFG7Q2HN.js";import"./chunks/chunk-PHKIAKHS.js";var e=new Map,a;globalThis.addEventListener("message",c=>{let{id:d,generation:n,total:u,size:l,query:i,bitmaps:m,mode:g,limit:p}=c.data;a!==n&&(e.clear(),a=n);for(let[t,r]of Object.entries(m))e.set(t,r);let s=Object.create(null);for(let t of[...i.groups.flat(),...i.excluded||[]]){let r=e.get(t);r&&(s[t]=r,e.delete(t),e.set(t,r))}for(;e.size>20;)e.delete(e.keys().next().value);globalThis.postMessage({id:d,...o(u,l,i,s,g,p)})});
1
+ import{d as o}from"./chunks/chunk-KJTG2HC3.js";import"./chunks/chunk-PHKIAKHS.js";var e=new Map,a;globalThis.addEventListener("message",c=>{let{id:d,generation:n,total:u,size:l,query:i,bitmaps:m,mode:g,limit:p}=c.data;a!==n&&(e.clear(),a=n);for(let[t,r]of Object.entries(m))e.set(t,r);let s=Object.create(null);for(let t of[...i.groups.flat(),...i.excluded||[]]){let r=e.get(t);r&&(s[t]=r,e.delete(t),e.set(t,r))}for(;e.size>20;)e.delete(e.keys().next().value);globalThis.postMessage({id:d,...o(u,l,i,s,g,p)})});
@@ -1 +1 @@
1
- import{a,b as u,c as f}from"./chunk-P2OPVFT2.js";import{a as m}from"./chunk-NCOVM3YF.js";import{b as p}from"./chunk-7UAUSQAK.js";import{b as l}from"./chunk-6UFWKTSA.js";import"./chunk-ATQQWCXO.js";import"./chunk-TPW5CADB.js";import"./chunk-TMMWB6NQ.js";import"./chunk-TWGPYWIY.js";import"./chunk-T3FZWEYV.js";import"./chunk-FBC3PYSO.js";import"./chunk-4W4OQ3QY.js";import"./chunk-RV7WQMNL.js";import"./chunk-WGMEMLED.js";import"./chunk-KNYDPLLK.js";import"./chunk-HP75Y56I.js";import"./chunk-TSOLLCID.js";import"./chunk-76QEHT4T.js";import"./chunk-A7665WVC.js";import"./chunk-L465623K.js";import"./chunk-IFVMCECG.js";import"./chunk-GTVNUHF4.js";import{b as s}from"./chunk-YM6ZMZQI.js";import{a as t}from"./chunk-EIBFAW37.js";import"./chunk-5CCFYMCF.js";import"./chunk-PHKIAKHS.js";var v=l().RailroadAbnf.parser.LangiumParser,i=t(e=>{let r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=t(e=>{let r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=t(e=>{if(e.includes("*")){let[n,o]=e.split("*"),c=n?parseInt(n,10):0,d=o?parseInt(o,10):1/0;return{min:c,max:d}}let r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=t(e=>{let r=A(e.primary);if(!e.repeat)return r;let{min:n,max:o}=b(e.repeat);return n===0&&o===1?{type:"optional",element:r}:{type:"repetition",element:r,min:n,max:o}},"transformElement"),A=t(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=t(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=t(e=>{m(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:t(e=>{a.clear(),s.debug("[ABNF Parser] Starting Langium parse");let r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new p(r);let n=r.value;s.debug("[ABNF Parser] Parsed rules:",n.rules.length),h(n),s.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},I={parser:R,db:a,renderer:f,styles:u};export{I as diagram};
1
+ import{a,b as u,c as f}from"./chunk-7AU45BWK.js";import{a as m}from"./chunk-NCOVM3YF.js";import{b as p}from"./chunk-UNVUNKH6.js";import"./chunk-HP75Y56I.js";import"./chunk-TSOLLCID.js";import{b as l}from"./chunk-6UFWKTSA.js";import"./chunk-ATQQWCXO.js";import"./chunk-TPW5CADB.js";import"./chunk-TMMWB6NQ.js";import"./chunk-TWGPYWIY.js";import"./chunk-76QEHT4T.js";import"./chunk-A7665WVC.js";import"./chunk-T3FZWEYV.js";import"./chunk-FBC3PYSO.js";import"./chunk-4W4OQ3QY.js";import"./chunk-RV7WQMNL.js";import"./chunk-WGMEMLED.js";import"./chunk-KNYDPLLK.js";import"./chunk-L465623K.js";import"./chunk-7KPU4VDE.js";import"./chunk-GTVNUHF4.js";import{b as s}from"./chunk-YM6ZMZQI.js";import"./chunk-5CCFYMCF.js";import{a as t}from"./chunk-EIBFAW37.js";import"./chunk-PHKIAKHS.js";var v=l().RailroadAbnf.parser.LangiumParser,i=t(e=>{let r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=t(e=>{let r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=t(e=>{if(e.includes("*")){let[n,o]=e.split("*"),c=n?parseInt(n,10):0,d=o?parseInt(o,10):1/0;return{min:c,max:d}}let r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=t(e=>{let r=A(e.primary);if(!e.repeat)return r;let{min:n,max:o}=b(e.repeat);return n===0&&o===1?{type:"optional",element:r}:{type:"repetition",element:r,min:n,max:o}},"transformElement"),A=t(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=t(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=t(e=>{m(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:t(e=>{a.clear(),s.debug("[ABNF Parser] Starting Langium parse");let r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new p(r);let n=r.value;s.debug("[ABNF Parser] Parsed rules:",n.rules.length),h(n),s.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},I={parser:R,db:a,renderer:f,styles:u};export{I as diagram};