@jant/core 0.6.11 → 0.6.12

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 (72) hide show
  1. package/bin/commands/import-site.js +45 -20
  2. package/dist/app-B5P1b4TF.js +6 -0
  3. package/dist/{app-CpmficmQ.js → app-D-zAhayc.js} +331 -55
  4. package/dist/client/.vite/manifest.json +3 -3
  5. package/dist/client/_assets/client-BUxR-E8O.css +2 -0
  6. package/dist/client/_assets/{client-Dd9U383b.js → client-S1cdvulk.js} +1 -1
  7. package/dist/client/_assets/{client-auth-DkpSdIDz.js → client-auth-YW92ZH7u.js} +116 -55
  8. package/dist/{export-Ba7NJImL.js → export-Ckwh4BiE.js} +4 -4
  9. package/dist/{github-sync-BD4w2m8-.js → github-sync-BMmK3JZ0.js} +2 -2
  10. package/dist/{github-sync-Cb4_6_i7.js → github-sync-Dl9wQMar.js} +1 -1
  11. package/dist/index.js +3 -3
  12. package/dist/node.js +4 -4
  13. package/package.json +1 -1
  14. package/src/__tests__/import-site-command.test.ts +75 -0
  15. package/src/__tests__/vite-dev-plugins.test.ts +34 -0
  16. package/src/client/__tests__/compose-launch.test.ts +50 -1
  17. package/src/client/__tests__/compose-shortcuts.test.ts +74 -18
  18. package/src/client/components/__tests__/jant-command-palette.test.ts +63 -0
  19. package/src/client/components/__tests__/jant-compose-dialog.test.ts +33 -0
  20. package/src/client/components/__tests__/jant-compose-editor-rehost-notice.test.ts +20 -1
  21. package/src/client/components/__tests__/jant-nav-manager.test.ts +77 -1
  22. package/src/client/components/__tests__/jant-settings-avatar.test.ts +6 -0
  23. package/src/client/components/__tests__/jant-settings-general.test.ts +71 -0
  24. package/src/client/components/jant-command-palette.ts +67 -2
  25. package/src/client/components/jant-compose-dialog.ts +8 -2
  26. package/src/client/components/jant-nav-manager.ts +142 -2
  27. package/src/client/components/jant-settings-general.ts +56 -0
  28. package/src/client/components/nav-manager-types.ts +14 -0
  29. package/src/client/components/settings-types.ts +30 -0
  30. package/src/client/compose-launch.ts +30 -0
  31. package/src/client/compose-shortcuts.ts +46 -3
  32. package/src/client/tiptap/__tests__/rehost-images.test.ts +66 -13
  33. package/src/client/tiptap/rehost-images.ts +5 -1
  34. package/src/i18n/__tests__/fallback.test.ts +24 -0
  35. package/src/i18n/locales/public/zh-Hans.po +2 -2
  36. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  37. package/src/i18n/locales/public/zh-Hant.po +2 -2
  38. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  39. package/src/i18n/locales/settings/en.po +54 -0
  40. package/src/i18n/locales/settings/en.ts +1 -1
  41. package/src/i18n/locales/settings/zh-Hans.po +64 -10
  42. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  43. package/src/i18n/locales/settings/zh-Hant.po +56 -2
  44. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  45. package/src/lib/__tests__/feed.test.ts +96 -10
  46. package/src/lib/feed.ts +63 -3
  47. package/src/lib/post-display.ts +14 -8
  48. package/src/preset.css +60 -18
  49. package/src/routes/dash/settings.tsx +41 -2
  50. package/src/routes/pages/__tests__/draft-about-edit.test.ts +65 -0
  51. package/src/routes/pages/page.tsx +44 -12
  52. package/src/services/__tests__/about-page.test.ts +116 -0
  53. package/src/services/__tests__/navigation.test.ts +190 -1
  54. package/src/services/__tests__/post-timeline.test.ts +119 -2
  55. package/src/services/about-page.ts +143 -0
  56. package/src/services/export-theme/layouts/_default/rss.xml +2 -1
  57. package/src/services/export-theme/layouts/partials/feed-post-content.xml +25 -1
  58. package/src/services/export-theme/styles/main.css +46 -14
  59. package/src/services/index.ts +27 -17
  60. package/src/services/navigation.ts +155 -1
  61. package/src/services/post.ts +24 -7
  62. package/src/styles/components.css +20 -0
  63. package/src/styles/tokens.css +26 -8
  64. package/src/styles/ui.css +149 -7
  65. package/src/types/views.ts +13 -0
  66. package/src/ui/dash/appearance/NavigationContent.tsx +57 -0
  67. package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +19 -0
  68. package/src/ui/dash/settings/GeneralContent.tsx +44 -0
  69. package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +8 -0
  70. package/src/ui/feed/__tests__/timeline-cards.test.ts +162 -1
  71. package/dist/app-DqKkZenB.js +0 -6
  72. package/dist/client/_assets/client-BhHHVvSY.css +0 -2
@@ -18,6 +18,11 @@ msgstr ""
18
18
  msgid "/* Your custom CSS here */"
19
19
  msgstr "/* 在此放入您的自訂 CSS */"
20
20
 
21
+ #. @context: Compact conflict message when /about is occupied
22
+ #: src/ui/dash/settings/GeneralContent.tsx
23
+ msgid "/about is already used. Rename that item before creating an About page."
24
+ msgstr "/about 已被佔用。重新命名該項目後再建立 About 頁面。"
25
+
21
26
  #. @context: GitHub sync picker — entry at the bottom of the owner dropdown that starts a new install flow
22
27
  #: src/routes/dash/settings.tsx
23
28
  msgid "+ Install on another account"
@@ -48,6 +53,11 @@ msgstr "顯示在您的主頁上的簡短介紹。"
48
53
  msgid "A warmer look, like slightly aged paper."
49
54
  msgstr "更暖一些,像略舊的紙。"
50
55
 
56
+ #. @context: Link label for editing or creating the About page
57
+ #: src/ui/dash/settings/GeneralContent.tsx
58
+ msgid "About page"
59
+ msgstr "About 頁面"
60
+
51
61
  #. @context: Settings form field for site description
52
62
  #: src/ui/dash/settings/GeneralContent.tsx
53
63
  msgid "About this blog"
@@ -86,6 +96,11 @@ msgstr "目前的工作階段"
86
96
  msgid "Active Tokens"
87
97
  msgstr "已啟用的權杖"
88
98
 
99
+ #. @context: Button to add a suggested nav link
100
+ #: src/ui/dash/appearance/NavigationContent.tsx
101
+ msgid "Add"
102
+ msgstr "新增"
103
+
89
104
  #. @context: Description in link popover form
90
105
  #: src/ui/dash/appearance/NavigationContent.tsx
91
106
  msgid "Add a custom link to any URL"
@@ -101,6 +116,11 @@ msgstr "新增選集"
101
116
  msgid "Add collection to navigation"
102
117
  msgstr "新增選集到導覽"
103
118
 
119
+ #. @context: Description for suggested nav links
120
+ #: src/ui/dash/appearance/NavigationContent.tsx
121
+ msgid "Add common destinations that already exist on your site."
122
+ msgstr "新增網站中已經存在的常用入口。"
123
+
104
124
  #. @context: Custom CSS settings description
105
125
  #: src/ui/dash/appearance/AdvancedContent.tsx
106
126
  msgid "Add custom CSS to override any styles. Use data attributes like [data-page], [data-post], [data-format] to target specific elements."
@@ -182,8 +202,10 @@ msgstr "套用於整個網站, 包括管理頁面. 選擇一個調色盤, 然後
182
202
 
183
203
  #. @context: Custom URL target type badge for an archive view
184
204
  #. @context: Custom URL type option for filtered archive view
205
+ #. @context: Suggested navigation link target type
185
206
  #: src/routes/dash/custom-urls.tsx
186
207
  #: src/routes/dash/custom-urls.tsx
208
+ #: src/ui/dash/appearance/NavigationContent.tsx
187
209
  msgid "Archive"
188
210
  msgstr "封存"
189
211
 
@@ -358,8 +380,10 @@ msgstr "選集"
358
380
 
359
381
  #. @context: Custom URL target type badge for a collection
360
382
  #. @context: Custom URL type option
383
+ #. @context: Suggested navigation link target type
361
384
  #: src/routes/dash/custom-urls.tsx
362
385
  #: src/routes/dash/custom-urls.tsx
386
+ #: src/ui/dash/appearance/NavigationContent.tsx
363
387
  msgid "Collection"
364
388
  msgstr "選集"
365
389
 
@@ -537,6 +561,11 @@ msgstr "在 GitHub 建立新儲存庫"
537
561
  msgid "Create a post with curl:"
538
562
  msgstr "使用 curl 建立貼文:"
539
563
 
564
+ #. @context: Button to create the standard About page
565
+ #: src/ui/dash/settings/GeneralContent.tsx
566
+ msgid "Create About page"
567
+ msgstr "建立 About 頁面"
568
+
540
569
  #. @context: Button to save new custom URL
541
570
  #: src/routes/dash/custom-urls.tsx
542
571
  msgid "Create Custom URL"
@@ -754,6 +783,11 @@ msgstr "例如 iOS 捷徑"
754
783
  msgid "Edit"
755
784
  msgstr "編輯"
756
785
 
786
+ #. @context: Link to edit the standard About page
787
+ #: src/ui/dash/settings/GeneralContent.tsx
788
+ msgid "Edit About page"
789
+ msgstr "編輯 About 頁面"
790
+
757
791
  #. @context: GitHub sync picker — shown when the selected repo has no commits
758
792
  #: src/routes/dash/settings.tsx
759
793
  msgid "Empty repository. Ready to connect."
@@ -1030,7 +1064,12 @@ msgstr "連結"
1030
1064
  #. @context: Post format badge - link
1031
1065
  #: src/ui/dash/FormatBadge.tsx
1032
1066
  msgid "Link"
1033
- msgstr "連結 (Jant 的貼文格式之一。)"
1067
+ msgstr "連結"
1068
+
1069
+ #. @context: Toast after adding a suggested nav link
1070
+ #: src/ui/dash/appearance/NavigationContent.tsx
1071
+ msgid "Link added to navigation."
1072
+ msgstr "連結已新增到導覽。"
1034
1073
 
1035
1074
  #. @context: Label for list posts curl example
1036
1075
  #: src/ui/dash/settings/ApiTokensContent.tsx
@@ -1275,6 +1314,11 @@ msgstr "帶橘調的底色。最暖的一套。"
1275
1314
  msgid "owner/repo"
1276
1315
  msgstr "owner/repo"
1277
1316
 
1317
+ #. @context: Suggested navigation link target type
1318
+ #: src/ui/dash/appearance/NavigationContent.tsx
1319
+ msgid "Page"
1320
+ msgstr "頁面"
1321
+
1278
1322
  #. @context: Bone color theme preview body
1279
1323
  #: src/ui/dash/appearance/ColorThemeContent.tsx
1280
1324
  msgid "Pale bone-white with a muted green accent."
@@ -1407,7 +1451,7 @@ msgstr "查詢參數"
1407
1451
  #. @context: Post format badge - quote
1408
1452
  #: src/ui/dash/FormatBadge.tsx
1409
1453
  msgid "Quote"
1410
- msgstr "引用 (Jant 的貼文格式之一。)"
1454
+ msgstr "引用"
1411
1455
 
1412
1456
  #. @context: Lead text before a live <html lang> preview of the content language
1413
1457
  #: src/ui/dash/settings/GeneralContent.tsx
@@ -1675,6 +1719,11 @@ msgstr "柔象牙白"
1675
1719
  msgid "Stop accepting posts from Telegram. Your existing notes stay published."
1676
1720
  msgstr "停止接受來自 Telegram 的貼文。您現有的筆記會保持已發佈。"
1677
1721
 
1722
+ #. @context: Section heading for suggested nav links
1723
+ #: src/ui/dash/appearance/NavigationContent.tsx
1724
+ msgid "Suggested links"
1725
+ msgstr "建議新增的連結"
1726
+
1678
1727
  #. @context: Button to trigger a full content push to GitHub on GitHub Sync settings
1679
1728
  #: src/ui/dash/settings/GitHubSyncContent.tsx
1680
1729
  msgid "Sync Now"
@@ -1946,6 +1995,11 @@ msgstr "檢視"
1946
1995
  msgid "Want more control?"
1947
1996
  msgstr "想要更細緻的控制?"
1948
1997
 
1998
+ #. @context: Prompt shown below the short site description, before the About page action
1999
+ #: src/ui/dash/settings/GeneralContent.tsx
2000
+ msgid "Want to write a fuller introduction?"
2001
+ msgstr "想寫更完整的介紹?"
2002
+
1949
2003
  #. @context: Dune color theme preview help line
1950
2004
  #: src/ui/dash/appearance/ColorThemeContent.tsx
1951
2005
  msgid "Warm and earthy, but still light."
@@ -1 +1 @@
1
- /*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"++YsxG\":[\"讀者和搜尋引擎看到的是\"],\"+4Z6iP\":[\"先在 GitHub 上建立儲存庫 — 可以是空的。\"],\"+9JI/F\":[\"連線後會將您的網站同步到 \",[\"repo\"],\" 的預設分支,並疊加在其現有歷史之上。Jant 管理路徑外的既有檔案會保留。此操作無法復原。\"],\"+AXdXp\":[\"標籤與 URL 為必填\"],\"+K0AvT\":[\"解除連線\"],\"+wgt7C\":[\"低飽和的紅棕底,溫暖、有泥土感。\"],\"+zy2Nq\":[\"類型\"],\"/3H2/s\":[\"此託管網站透過 \",[\"providerLabel\"],\" 登入。請在該處管理密碼與託管存取權限。\"],\"/JnyjR\":[\"切換內建導覽項目。它們的順序決定頁首顯示哪些項目,以及首頁會先開啟哪一個 feed。\"],\"/PXXBT\":[\"近乎純白,帶一點暖意。\"],\"/zOUxl\":[\"連結至 Telegram 機器人的 QR 碼\"],\"0OGSSc\":[\"頭像顯示已更新.\"],\"0UzCUX\":[\"更新您用來登入的密碼\"],\"0bdA9b\":[\"開啟 Telegram 以連線\"],\"0uIjy/\":[\"淺鼠尾草綠底,配同色系的綠。\"],\"10UtuM\":[\"CJK 字體\"],\"1F6Mzc\":[\"目前尚無導覽項目。請新增連結或在下方啟用系統項目。\"],\"1H7gng\":[\"後台語言\"],\"1mbBbL\":[\"手動連接\"],\"1njn7W\":[\"淺色\"],\"1qGdnL\":[\"預設主題。沉靜,適合長時間閱讀。\"],\"2B7t+s\":[\"工作階段與密碼\"],\"2DoBvq\":[\"訂閱來源\"],\"2FYpfJ\":[\"更多\"],\"2Ithfh\":[\"傳送任何文字給機器人,該文字會作為筆記已發佈。\"],\"2PTjMB\":[\"我想刪除 \",[\"siteName\"]],\"2cFU6q\":[\"網站頁尾\"],\"2fPEPI\":[\"沉靜、偏冷的底色。\"],\"2lkk2l\":[\"微黃的紙底,配橄欖綠。\"],\"2oWZo7\":[\"最近一次提交\"],\"2uuy4H\":[\"已透過個人存取權杖連線\"],\"35x8eZ\":[\"顯示 \",[\"shown\"],\" 共 \",[\"total\"]],\"39QGku\":[\"開啟機器人並傳送綁定碼,之後你傳給它的任何訊息都會成為筆記。\"],\"3Cw1AI\":[\"新增選集\"],\"3VrybB\":[\"重新導向\"],\"3Yvsaz\":[\"302 (暫時)\"],\"3n0zbB\":[\"在示範模式中已停用工作階段管理。請改用共用示範工作階段。\"],\"3sYJi5\":[\"下載與 Hugo 相容的封存 — 以靜態方式託管或移轉到另一個 Jant\"],\"3wKq0C\":[\"無法儲存。請稍後再試。\"],\"49Bsal\":[\"Feed 設定已更新。\"],\"4Jge8E\":[\"目前的工作階段\"],\"4KIa+q\":[\"已下載匯出檔案。\"],\"4cEClj\":[\"工作階段\"],\"4yyXWu\":[\"淺骨白底,配低飽和的綠。\"],\"4zGJ5E\":[\"永久刪除帳戶\"],\"5QlUIt\":[\"倉庫為空。準備連線。\"],\"5VQnR3\":[\"當你想要一個永遠不會改變的 feed URL 時,請使用這些。\"],\"5dpcN1\":[\"輸入以搜尋全部\"],\"5f1Wo9\":[\"已以 \",[\"account\"],\" 連線\"],\"5o8R81\":[\"極淺的象牙底,配淡淡的茶綠。\"],\"6ArdBh\":[\"將精選文章用於 /feed.\"],\"6DjeBT\":[\"示範網站會始終對搜尋引擎保持隱藏。\"],\"6E3aK4\":[\"管理託管\"],\"6FFB7q\":[\"使用最新的公開貼文作為 /feed。\"],\"6K1Vef\":[\"確定要永久刪除此部落格嗎?此動作無法復原。\"],\"6NpNLc\":[\"此儲存庫已有內容。\"],\"6V3Ea3\":[\"已複製\"],\"71WIgc\":[\"取得新代碼\"],\"746NHh\":[\"此部落格\"],\"7811AW\":[\"此儲存庫已在備份本網站。\"],\"7FCZPo\":[\"內容語言\"],\"7FaY4u\":[\"用法\"],\"7G9YLi\":[\"允許搜尋引擎收錄我的網站\"],\"7GISOt\":[\"儲存機器人權杖\"],\"7MZxzw\":[\"密碼已變更.\"],\"7vhWI8\":[\"新密碼\"],\"81nFIS\":[\"密碼不符。請確認兩個欄位相同。\"],\"87a/t/\":[\"標籤\"],\"89Upyo\":[\"該主題目前不可用。請選擇其他主題。\"],\"8BfEpW\":[\"託管帳號\"],\"8N/Mcp\":[\"封存篩選參數 (例如 format=note&view=list)\"],\"8T46pB\":[\"機器人權杖\"],\"8U2Z7f\":[\"新增自訂 URL\"],\"8ZsakT\":[\"密碼\"],\"8gEghq\":[\"明亮的暖白底,配苔綠點綴。\"],\"9+vGLh\":[\"自訂 CSS\"],\"9As8Nu\":[\"在 GitHub 上建立一個\"],\"9EjI4j\":[\"暖沙色\"],\"9Lsvt5\":[\"已於 \",[\"date\"],\" 登入\"],\"9T7Cwm\":[\"重新導向、自訂路徑與網址控制\"],\"9aUyym\":[\"查看您在哪裡已登入,並撤銷舊的工作階段\"],\"A1taO8\":[\"搜尋\"],\"AeXO77\":[\"帳戶\"],\"AnY+O9\":[\"在首頁底部顯示「Build with Jant」\"],\"ApZDMk\":[\"此圖會用於您的 favicon 和 apple-touch-icon。為達最佳效果,請上傳至少 512x512 像素、背景為純色的正方形 PNG。\"],\"B495Gs\":[\"封存\"],\"B4ESok\":[\"API 參考\"],\"BzEFor\":[\"或\"],\"CDAdlf\":[\"移除機器人\"],\"CTAEes\":[\"選擇儲存庫\"],\"CjZZgz\":[\"此儲存庫已有提交紀錄\"],\"D8k2s6\":[\"連接 Telegram\"],\"DCKkhU\":[\"目前密碼\"],\"DKKKeF\":[\"在 \",[\"providerLabel\"],\" 管理密碼與託管存取\"],\"DVFXa6\":[\"最乾淨、最中性的一檔。\"],\"EO3I6h\":[\"上傳未成功. 請稍後再試.\"],\"Eax/et\":[\"強調色\"],\"Enslfm\":[\"目標網址\"],\"F53UDu\":[\"冷白\"],\"F7FKwe\":[\"你在此處貼上的任何內容都能完全存取訪客的瀏覽器。僅使用來自你信任來源的程式碼。\"],\"F8SNqr\":[\"暖橘\"],\"Fk3SSD\":[\"平靜自然,看著舒服。\"],\"FkMol5\":[\"精選\"],\"G/1oP+\":[\"移除 webhook 並停止同步。您的儲存庫內容不會被刪除。\"],\"G0qJsQ\":[\"找不到安全權杖。請重新整理頁面後再試一次。\"],\"G39wnK\":[\"將內容備份並與 GitHub 儲存庫同步\"],\"GMMWcy\":[\"名稱, 中繼資料, 語言, 和 搜尋預設值\"],\"GXsAby\":[\"撤銷\"],\"GxkJXS\":[\"上傳中...\"],\"GzKzUa\":[\"試用限制\"],\"H4x7Sk\":[\"後台介面顯示的語言。可選 English、简体中文 和 繁體中文。\"],\"HCNlq3\":[\"乾淨、高對比,接近純白。\"],\"HHDyGw\":[\"柔綠\"],\"HKH+W+\":[\"資料\"],\"Hp1l6f\":[\"目前\"],\"HxlY7t\":[\"變更此設定會更新訂閱者從 /feed 取得的內容。\"],\"HxuOlm\":[\"網站頁首\"],\"I4HRxU\":[\"已發布的全部貼文,包括從 Latest 中隱藏的那些。\"],\"I6gXOa\":[\"路徑\"],\"I76CzF\":[\"中性灰\"],\"ID38tA\":[\"示範模式下帳號刪除已停用。共用示範會另行重置。\"],\"IF9tPu\":[\"何時使用網站匯出、資料庫備份與復原演練。\"],\"IW5PBo\":[\"複製權杖\"],\"IagCbF\":[\"URL\"],\"IfB3m6\":[\"你撰寫內容所用的語言。透過 HTML lang 和 RSS 向讀者與搜尋引擎宣告。支援任意 BCP 47 標籤。\"],\"IreQBq\":[\"儲存庫\"],\"J6bLeg\":[\"新增自訂連結到任何 URL\"],\"JL7LF5\":[\"可用的 CSS 變數、data 屬性與範例.\"],\"JTviaO\":[\"管理登入安全、匯出,以及不可逆的操作。\"],\"JcD7qf\":[\"更多操作\"],\"JjX0OO\":[\"請立即複製您的權杖 — 它不會再顯示。\"],\"JrFTcr\":[\"連線中…\"],\"JuN5GC\":[\"未選取檔案。請選擇要上傳的檔案。\"],\"KDw4GX\":[\"重試\"],\"KSgo21\":[\"選擇一個儲存庫\"],\"KVVYBh\":[\"新增選集到導覽\"],\"KiJn9B\":[\"筆記\"],\"KwOLJF\":[\"Jant 最初的配色,日常穩妥之選。\"],\"L3DEwT\":[\"移除這個頭像?您的 favicon 與頁首圖示會回復為預設。\"],\"L4t4/q\":[\"3月14日\"],\"LdyooL\":[\"連結\"],\"M/D8PK\":[\"+ 安裝到其他帳戶\"],\"M/haSd\":[\"永遠顯示主題的淺色版本。\"],\"M2kIWU\":[\"字型主題\"],\"M6CbAU\":[\"切換編輯面板\"],\"MaYYE6\":[\"透過向 Telegram 機器人傳送訊息來發佈筆記\"],\"Me5t5H\":[\"連接 GitHub 倉庫,自動將你的文章備份為 Markdown 檔案。GitHub 上的編輯會同步回你的網站。\"],\"Mr4QPw\":[\"要斷開 Telegram?您可以隨時使用新的綁定代碼重新連接。\"],\"MtENL9\":[\"調整您的網站外觀、可讀性與執行效能。\"],\"N/8NPV\":[\"在刪除前,請先下載網站匯出檔案。刪除後無法恢復此帳號。\"],\"N7UNHY\":[\"精選 RSS 來源\"],\"NHnUHF\":[\"頁首上的網站圖示與個人標記\"],\"NU2Fqi\":[\"儲存 CSS\"],\"NVjhde\":[\"暖羊皮紙\"],\"Nldjdr\":[\"尚未有自訂 URL。建立一個自訂 URL 以為文章新增重新導向或自訂路徑。\"],\"O7rgs6\":[\"頁首 RSS 指向你的 \",[\"feed\"],\" 訂閱 (/feed)。在「一般」中變更 /feed 回傳的內容。\"],\"OSJXFg\":[\"套用於整個網站, 包括管理頁面. 選擇一個調色盤, 然後決定它是跟隨系統還是維持固定.\"],\"Ox3+3h\":[\"無相符結果。\"],\"PEUV5I\":[\"程式碼注入已更新。\"],\"PHh52z\":[\"暖而厚重,棕調明顯。\"],\"PXj9lw\":[\"停止接受來自 Telegram 的貼文。您現有的筆記會保持已發佈。\"],\"PZ7HJ8\":[\"部落格大頭貼\"],\"Pwqkdw\":[\"載入中…\"],\"PxJ9W6\":[\"產生權杖\"],\"Q/6Y+2\":[\"需要在目標儲存庫上擁有 Contents(讀/寫)和 Webhooks(讀/寫)權限。\"],\"Q30z/l\":[\"要從導覽移除這個選集嗎?選集本身不會被刪除。\"],\"Q99OtV\":[\"將選集釘選到導覽列。最近 48 小時內更新的選集旁會顯示一個 * 號。\"],\"QCwsv1\":[\"暖白\"],\"QKvrmL\":[\"暖中性,適合長讀。\"],\"QZmz0H\":[\"內建連結\"],\"Qnrzvb\":[\"已啟用的權杖\"],\"R6Z4LE\":[\"下載失敗。請再試一次。\"],\"R9Khdg\":[\"自動\"],\"RcdDOS\":[\"在 Telegram 上向 @BotFather 發送訊息以建立機器人,然後貼上它提供給你的權杖\"],\"RdVIcf\":[\"奶油配深咖\"],\"RxsRD6\":[\"時區\"],\"SJmfuf\":[\"網站名稱\"],\"SKZhW9\":[\"權杖名稱 (API 權杖名稱欄位。)\"],\"SVQQPe\":[\"無法連線。請檢查錯誤並再試一次。\"],\"SchpMp\":[\"Telegram\"],\"SrGs4T\":[\"淺藍灰底,冷靜而均勻。\"],\"TpF3v+\":[\"在 </head> 之前注入。用於分析、自訂 meta 標籤,以及必須提前載入的樣式。\"],\"Tz0i8g\":[\"設定\"],\"UFK415\":[\"用於分析與小工具的網站全域 HTML\"],\"UTvFQq\":[\"開啟 \",[\"linkOpen\"],\"@\",[\"botUsername\"],[\"linkClose\"],\" 並傳送:\"],\"Uj/btJ\":[\"在我的網站頁首顯示大頭貼\"],\"UsODUn\":[\"選擇一個帳戶\"],\"UxKoFf\":[\"導覽\"],\"V+bhUy\":[\"安裝 GitHub App\"],\"V4WsyL\":[\"新增連結\"],\"V5pZwT\":[\"搜尋設定已更新。\"],\"VXUPla\":[\"使用 GitHub App 連線\"],\"VhMDMg\":[\"變更密碼\"],\"Vn3jYy\":[\"導覽項目\"],\"VoZYGU\":[\"這會永久刪除您所有的資料 — 文章、媒體、選集、設定,以及您的帳戶。您的部落格將被重設為初始設定狀態。此操作無法復原。\"],\"WUnFK2\":[\"偏冷的淺白底,配深靛藍文字。高對比。\"],\"Wa9q4P\":[\"純白\"],\"Weq9zb\":[\"一般\"],\"Wi9i06\":[\"依照每位訪客的系統偏好。\"],\"Wx1M8N\":[\"安裝 GitHub App,以授予存取權而無需管理個人權杖。權限以每個儲存庫為範圍,並可在 GitHub 上撤銷。\"],\"X+8FMk\":[\"目前的密碼不符。請再試一次。\"],\"X1G9eY\":[\"導覽預覽\"],\"X2Cbc2\":[\"封存 RSS 來源\"],\"X9Hujr\":[\"手動推送\"],\"XtBJV8\":[\"正在檢查儲存庫…\"],\"Xtc16w\":[\"重新整理儲存庫清單\"],\"Y/F35r\":[\"使用 curl 建立貼文:\"],\"Y/N5N7\":[\"柔和的奶油底,配低飽和的綠。\"],\"YF6zHf\":[\"網站設定已更新.\"],\"YdG2RF\":[\"匯出網站\"],\"YkgZi7\":[\"連接一個 Telegram 機器人,之後你傳給它的任何訊息都會以筆記形式已發佈。\"],\"YwhjRx\":[\"管理帳戶\"],\"Yxp859\":[\"暖奶油色\"],\"ZDY7Fy\":[\"同步中…\"],\"ZQKLI1\":[\"危險區域\"],\"ZS/CBL\":[\"刪除此導覽連結?訪客將不再在您的網站頁首看到它。\"],\"ZgZX+d\":[\"純白底配中性灰。不帶任何色偏。\"],\"ZhhOwV\":[\"引用 (Jant 的貼文格式之一。)\"],\"ZiooJI\":[\"API 權杖\"],\"Zm7Qb0\":[\"備份與還原指南\"],\"ZmUkwN\":[\"新增自訂連結到導覽\"],\"a14mj8\":[\"未知裝置\"],\"a1iEgy\":[\"暖奶油底,配深咖啡棕點綴。\"],\"a3LDKx\":[\"安全性\"],\"aAIQg2\":[\"外觀\"],\"aFkzVF\":[\"目標文章或選集的 slug\"],\"alKG0+\":[\"字型主題\"],\"anibOb\":[\"關於本部落格\"],\"any7NR\":[\"主題指南\"],\"b+/jO6\":[\"301 (永久)\"],\"bHOiy1\":[\"示範模式已停用變更密碼功能。請使用共用示範帳號登入。\"],\"bHYIks\":[\"登出\"],\"bV2vng\":[\"暖陶土色\"],\"bbR5vW\":[\"這套配色\"],\"bmrL08\":[\"示範模式會隱藏會話、密碼更改與帳號刪除。匯出功能仍可使用。\"],\"bviiKV\":[\"這個主題下的標題、正文和連結。\"],\"c3MN2z\":[\"所有可用的端點與請求格式。\"],\"cS7/bk\":[\"移除已儲存的機器人權杖?其 webhook 會被刪除,任何已連接的帳號將會被斷線。\"],\"cSDy01\":[\"自訂 CSS 已更新.\"],\"clzoNp\":[\"始終顯示深色主題。\"],\"cnGeoo\":[\"刪除\"],\"d3FRkY\":[\"無法複製. 請再試一次.\"],\"d5oGUo\":[\"在 GitHub 建立新儲存庫\"],\"dEgA5A\":[\"取消\"],\"dTXUY+\":[\"確認刪除帳號\"],\"dYKrp3\":[\"從最新中隱藏 (不出現在 Latest 中,但仍可透過固定連結和集合存取的狀態。)\"],\"dk7TCH\":[\"永久刪除所有資料並重設部落格\"],\"drodVV\":[\"目前還沒有選集。請先建立一個,然後將它加入您的導覽。\"],\"dsWkIw\":[\"要與 GitHub 斷開連線嗎? webhook 將會被移除。您的儲存庫內容不會被刪除。\"],\"e/tSI5\":[\"導覽順序已更新。\"],\"eOL7vn\":[\"色彩極少,干擾最小。\"],\"ePK91l\":[\"編輯\"],\"ebQKK7\":[\"網站\"],\"egK+Yy\":[\"供腳本與自動化使用的 Bearer 權杖\"],\"ehj/zN\":[\"重新導向類型\"],\"eneWvv\":[\"草稿\"],\"erTMh7\":[\"上次同步\"],\"f+m8jj\":[\"已複製訂閱網址。\"],\"f8fH8W\":[\"設計\"],\"fKRAwQ\":[\"沙色底,配綠色點綴。\"],\"fWYqkz\":[\"程式碼注入\"],\"fYXQnC\":[\"暖色裡最濃的一檔,溫馨。\"],\"gOWiTY\":[\"載入為中文、日文或韓文內容最佳化的襯線字型。\"],\"gZ5owP\":[\"搜尋儲存庫\"],\"gbqbh6\":[\"可以放心離開此頁面 — 同步會在背景繼續進行。\"],\"gkFvVN\":[\"在 </body> 之前注入。用於聊天小工具和不應阻塞頁面載入的腳本。\"],\"gtQsRO\":[\"建立自訂網址\"],\"hBO/y4\":[\"安全權杖已過期。請重新整理頁面並再試一次。\"],\"hGmyDl\":[\"權杖讓您從腳本, 捷徑和其他工具存取 API 無需登入\"],\"hIHkRy\":[\"已透過 GitHub 應用程式連線\"],\"hdSi1b\":[\"輸入 \",[\"repo\"],\" 以確認\"],\"he3ygx\":[\"複製\"],\"i0qMbr\":[\"首頁\"],\"iEUzMn\":[\"系統\"],\"iSLIjg\":[\"連接\"],\"iVOMRi\":[\"首頁設定已更新。\"],\"icB4Cv\":[\"將連結拖到此處以顯示於「更多」選單下方\"],\"id3vuh\":[\"已設定 Telegram,但無法連線到機器人。請檢查機器人權杖並再試一次。\"],\"ihn4zD\":[\"搜尋…\"],\"iiDXZc\":[\"顯示於所有文章與頁面的底部。\"],\"itS31B\":[\"更暖一些,像略舊的紙。\"],\"iwQZvS\":[\"冷藍灰\"],\"j4VrG6\":[\"下載匯出 ZIP\"],\"j5nQL2\":[\"例如 iOS 捷徑\"],\"jUV7CU\":[\"上傳大頭貼\"],\"jVUmOK\":[\"支援 Markdown\"],\"jdVYS8\":[\"選一個適合你文字的。\"],\"jgBjXJ\":[\"要撤銷這個權杖嗎?任何使用它的腳本都會停止運作。\"],\"jpctdh\":[\"檢視\"],\"k1ifdL\":[\"處理中...\"],\"kLw03Y\":[\"亮紙白\"],\"kMXclu\":[\"下載網站匯出檔案\"],\"kNiQp6\":[\"已釘選\"],\"kRhzWq\":[\"GitHub 同步\"],\"kVQs7s\":[\"細緻的樣式覆寫\"],\"ke1gWS\":[\"自訂 URL\"],\"kfcRb0\":[\"頭像\"],\"kxDZ2i\":[\"此程式碼會在您網站的每個頁面上執行。\"],\"l2Op2p\":[\"查詢參數\"],\"lLW3vJ\":[\"目標 slug\"],\"lV04bQ\":[\"溫暖、有泥土感,但不顯暗。\"],\"lYHJih\":[\"撤銷此工作階段?該裝置將需要重新登入。\"],\"mLOk1i\":[\"立即將所有文章推送到 GitHub,而不是等待下一次自動同步。\"],\"mSNmrX\":[\"列出貼文:\"],\"nG2qTk\":[\"示例連結\"],\"nK07ni\":[\"為您的網站選擇一種排版風格。每個主題會同時改變字體配對與閱讀節奏。\"],\"nbfdhU\":[\"第三方整合\"],\"ntJYyh\":[\"在 \",[\"providerLabel\"],\" 管理網域、方案和計費\"],\"o/vNDE\":[\"讓您覆寫任何主題變數。\"],\"oGC9uP\":[\"owner/repo\"],\"oH2JHg\":[\"我們會預先填入名稱 \",[\"name\"],\"。返回時清單會重新整理。\"],\"oKOOsY\":[\"色彩主題\"],\"oL535e\":[\"尚未同步\"],\"oNA4If\":[\"所有選集已經在您的導覽中。\"],\"oUn9Z7\":[\"近中性的淺灰,配鋼藍點綴。\"],\"ofdy2l\":[\"帶橘調的底色。最暖的一套。\"],\"pZq3aX\":[\"上傳失敗。請再試一次。\"],\"pgTIrt\":[\"選擇要與此網站同步的 GitHub 帳號和儲存庫.\"],\"psoxDF\":[\"該字型主題無法使用. 請選擇其他主題.\"],\"pvnfJD\":[\"深色\"],\"q+hNag\":[\"選集\"],\"qdcESc\":[\"建立新儲存庫\"],\"r5EW6f\":[\"此儲存庫已在備份另一個 Jant 網站 (\",[\"host\"],\"). 請選擇其他儲存庫.\"],\"rEspiY\":[\"導覽位置已更新。\"],\"rFmBG3\":[\"色彩主題\"],\"rlonmB\":[\"無法刪除。請稍後再試。\"],\"satWc6\":[\"主要 RSS 訂閱\"],\"sgr2wQ\":[\"選集\"],\"soRdOu\":[\"米白紙底,配深森綠。\"],\"sqxcaY\":[\"建立於 \",[\"date\"]],\"sxkWRg\":[\"進階\"],\"t/YqKh\":[\"移除\"],\"t3hvHq\":[\"立即同步\"],\"tJ4H0O\":[\"您的 Telegram 帳號\"],\"tfDRzk\":[\"儲存\"],\"tvgAq5\":[\"尚未授權任何帳戶\"],\"u1VTd3\":[\"調色盤、表面色調與整體氛圍\"],\"u3wRF+\":[\"已發佈\"],\"u6KOjV\":[\"想要更細緻的控制?\"],\"udPwLB\":[\"頁首\"],\"ui6aMF\":[\"這些裝置目前已登入您的帳號。撤銷任何您不認識的工作階段。\"],\"vBEKwo\":[\"在此管理本網站的活動工作階段。密碼與託管存取由 \",[\"providerLabel\"],\" 管理。\"],\"vRldcl\":[\"字體選擇與閱讀質感\"],\"vSYKYI\":[\"主要訂閱來源\"],\"vTuib7\":[\"這會控制 /feed 回傳的內容。\"],\"vmQmHx\":[\"新增自訂 CSS 以覆寫任何樣式。使用像 [data-page]、[data-post]、[data-format] 這類資料屬性來選取特定元素。\"],\"vzX5FB\":[\"刪除帳號\"],\"w8Rv8T\":[\"標籤為必填\"],\"wL3cK8\":[\"最新\"],\"wW6NCp\":[\"上次錯誤\"],\"wc+17X\":[\"/* 在此放入您的自訂 CSS */\"],\"wuLtXn\":[\"目前沒有任何活動中的工作階段。已登入的裝置會顯示在此處。\"],\"xCWek4\":[\"檔案儲存尚未設定。請檢查您的伺服器設定。\"],\"xHt036\":[\"個人存取權杖\"],\"xKeZ0l\":[\"更偏暖、偏土的色調。\"],\"xYbozN\":[\"柔象牙白\"],\"xqViCq\":[\"暖象牙白\"],\"xxaahd\":[\"想要更冷、更利落的觀感時。\"],\"y28hnO\":[\"文章\"],\"y8Md/V\":[\"語言與時間已更新。\"],\"yNCqOt\":[\"最新 RSS 來源\"],\"yQ3kNF\":[\"請輸入以下短語以確認:\"],\"ydq1k2\":[\"請先選擇一個帳戶\"],\"yjjCV8\":[\"固定的 RSS 檔案網址\"],\"yjkELF\":[\"確認新密碼\"],\"yzF66j\":[\"連結 (Jant 的貼文格式之一。)\"],\"z6wakA\":[\"顯示在您的主頁上的簡短介紹。\"],\"zEizrk\":[\"最後使用於 \",[\"date\"]],\"zSURJW\":[\"沒有符合的儲存庫.\"],\"zXH2jX\":[\"語言與時區\"],\"zlcDd2\":[\"刪除此自訂 URL?使用該 URL 的訪客將不會再被重新導向。\"],\"zwBp5t\":[\"私有\"],\"zxRN6H\":[\"頁首連結、首頁動態與更多選單\"]}")as Messages;
1
+ /*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"++YsxG\":[\"讀者和搜尋引擎看到的是\"],\"+4Z6iP\":[\"先在 GitHub 上建立儲存庫 — 可以是空的。\"],\"+9JI/F\":[\"連線後會將您的網站同步到 \",[\"repo\"],\" 的預設分支,並疊加在其現有歷史之上。Jant 管理路徑外的既有檔案會保留。此操作無法復原。\"],\"+AXdXp\":[\"標籤與 URL 為必填\"],\"+K0AvT\":[\"解除連線\"],\"+wgt7C\":[\"低飽和的紅棕底,溫暖、有泥土感。\"],\"+zy2Nq\":[\"類型\"],\"/3H2/s\":[\"此託管網站透過 \",[\"providerLabel\"],\" 登入。請在該處管理密碼與託管存取權限。\"],\"/JnyjR\":[\"切換內建導覽項目。它們的順序決定頁首顯示哪些項目,以及首頁會先開啟哪一個 feed。\"],\"/PXXBT\":[\"近乎純白,帶一點暖意。\"],\"/zOUxl\":[\"連結至 Telegram 機器人的 QR 碼\"],\"0OGSSc\":[\"頭像顯示已更新.\"],\"0UzCUX\":[\"更新您用來登入的密碼\"],\"0bdA9b\":[\"開啟 Telegram 以連線\"],\"0gECZD\":[\"想寫更完整的介紹?\"],\"0uIjy/\":[\"淺鼠尾草綠底,配同色系的綠。\"],\"10UtuM\":[\"CJK 字體\"],\"1F6Mzc\":[\"目前尚無導覽項目。請新增連結或在下方啟用系統項目。\"],\"1H7gng\":[\"後台語言\"],\"1mbBbL\":[\"手動連接\"],\"1njn7W\":[\"淺色\"],\"1qGdnL\":[\"預設主題。沉靜,適合長時間閱讀。\"],\"2B7t+s\":[\"工作階段與密碼\"],\"2DoBvq\":[\"訂閱來源\"],\"2FYpfJ\":[\"更多\"],\"2Ithfh\":[\"傳送任何文字給機器人,該文字會作為筆記已發佈。\"],\"2PTjMB\":[\"我想刪除 \",[\"siteName\"]],\"2cFU6q\":[\"網站頁尾\"],\"2fPEPI\":[\"沉靜、偏冷的底色。\"],\"2lkk2l\":[\"微黃的紙底,配橄欖綠。\"],\"2oWZo7\":[\"最近一次提交\"],\"2uuy4H\":[\"已透過個人存取權杖連線\"],\"2wK4BX\":[\"編輯 About 頁面\"],\"35x8eZ\":[\"顯示 \",[\"shown\"],\" 共 \",[\"total\"]],\"39QGku\":[\"開啟機器人並傳送綁定碼,之後你傳給它的任何訊息都會成為筆記。\"],\"3Cw1AI\":[\"新增選集\"],\"3VrybB\":[\"重新導向\"],\"3Yvsaz\":[\"302 (暫時)\"],\"3n0zbB\":[\"在示範模式中已停用工作階段管理。請改用共用示範工作階段。\"],\"3sYJi5\":[\"下載與 Hugo 相容的封存 — 以靜態方式託管或移轉到另一個 Jant\"],\"3wKq0C\":[\"無法儲存。請稍後再試。\"],\"49Bsal\":[\"Feed 設定已更新。\"],\"4Jge8E\":[\"目前的工作階段\"],\"4KIa+q\":[\"已下載匯出檔案。\"],\"4cEClj\":[\"工作階段\"],\"4yyXWu\":[\"淺骨白底,配低飽和的綠。\"],\"4zGJ5E\":[\"永久刪除帳戶\"],\"5QlUIt\":[\"倉庫為空。準備連線。\"],\"5VQnR3\":[\"當你想要一個永遠不會改變的 feed URL 時,請使用這些。\"],\"5dpcN1\":[\"輸入以搜尋全部\"],\"5f1Wo9\":[\"已以 \",[\"account\"],\" 連線\"],\"5o8R81\":[\"極淺的象牙底,配淡淡的茶綠。\"],\"6ArdBh\":[\"將精選文章用於 /feed.\"],\"6DjeBT\":[\"示範網站會始終對搜尋引擎保持隱藏。\"],\"6E3aK4\":[\"管理託管\"],\"6FFB7q\":[\"使用最新的公開貼文作為 /feed。\"],\"6K1Vef\":[\"確定要永久刪除此部落格嗎?此動作無法復原。\"],\"6NpNLc\":[\"此儲存庫已有內容。\"],\"6V3Ea3\":[\"已複製\"],\"6WdDG7\":[\"頁面\"],\"71WIgc\":[\"取得新代碼\"],\"746NHh\":[\"此部落格\"],\"7811AW\":[\"此儲存庫已在備份本網站。\"],\"7FCZPo\":[\"內容語言\"],\"7FaY4u\":[\"用法\"],\"7G9YLi\":[\"允許搜尋引擎收錄我的網站\"],\"7GISOt\":[\"儲存機器人權杖\"],\"7MZxzw\":[\"密碼已變更.\"],\"7vhWI8\":[\"新密碼\"],\"81nFIS\":[\"密碼不符。請確認兩個欄位相同。\"],\"87a/t/\":[\"標籤\"],\"89Upyo\":[\"該主題目前不可用。請選擇其他主題。\"],\"8BfEpW\":[\"託管帳號\"],\"8N/Mcp\":[\"封存篩選參數 (例如 format=note&view=list)\"],\"8T46pB\":[\"機器人權杖\"],\"8U2Z7f\":[\"新增自訂 URL\"],\"8ZsakT\":[\"密碼\"],\"8gEghq\":[\"明亮的暖白底,配苔綠點綴。\"],\"9+vGLh\":[\"自訂 CSS\"],\"9As8Nu\":[\"在 GitHub 上建立一個\"],\"9EjI4j\":[\"暖沙色\"],\"9J6wUO\":[\"建議新增的連結\"],\"9Lsvt5\":[\"已於 \",[\"date\"],\" 登入\"],\"9T7Cwm\":[\"重新導向、自訂路徑與網址控制\"],\"9aUyym\":[\"查看您在哪裡已登入,並撤銷舊的工作階段\"],\"A1taO8\":[\"搜尋\"],\"AeXO77\":[\"帳戶\"],\"AnY+O9\":[\"在首頁底部顯示「Build with Jant」\"],\"ApZDMk\":[\"此圖會用於您的 favicon 和 apple-touch-icon。為達最佳效果,請上傳至少 512x512 像素、背景為純色的正方形 PNG。\"],\"B495Gs\":[\"封存\"],\"B4ESok\":[\"API 參考\"],\"BTYdze\":[\"連結已新增到導覽。\"],\"BzEFor\":[\"或\"],\"CDAdlf\":[\"移除機器人\"],\"CTAEes\":[\"選擇儲存庫\"],\"CjZZgz\":[\"此儲存庫已有提交紀錄\"],\"D8k2s6\":[\"連接 Telegram\"],\"DCKkhU\":[\"目前密碼\"],\"DKKKeF\":[\"在 \",[\"providerLabel\"],\" 管理密碼與託管存取\"],\"DVFXa6\":[\"最乾淨、最中性的一檔。\"],\"EO3I6h\":[\"上傳未成功. 請稍後再試.\"],\"Eax/et\":[\"強調色\"],\"Enslfm\":[\"目標網址\"],\"F53UDu\":[\"冷白\"],\"F7FKwe\":[\"你在此處貼上的任何內容都能完全存取訪客的瀏覽器。僅使用來自你信任來源的程式碼。\"],\"F8SNqr\":[\"暖橘\"],\"Fk3SSD\":[\"平靜自然,看著舒服。\"],\"FkMol5\":[\"精選\"],\"G/1oP+\":[\"移除 webhook 並停止同步。您的儲存庫內容不會被刪除。\"],\"G0qJsQ\":[\"找不到安全權杖。請重新整理頁面後再試一次。\"],\"G39wnK\":[\"將內容備份並與 GitHub 儲存庫同步\"],\"GMMWcy\":[\"名稱, 中繼資料, 語言, 和 搜尋預設值\"],\"GXsAby\":[\"撤銷\"],\"GxkJXS\":[\"上傳中...\"],\"GzKzUa\":[\"試用限制\"],\"H4x7Sk\":[\"後台介面顯示的語言。可選 English、简体中文 和 繁體中文。\"],\"HCNlq3\":[\"乾淨、高對比,接近純白。\"],\"HHDyGw\":[\"柔綠\"],\"HKH+W+\":[\"資料\"],\"Hp1l6f\":[\"目前\"],\"HxlY7t\":[\"變更此設定會更新訂閱者從 /feed 取得的內容。\"],\"HxuOlm\":[\"網站頁首\"],\"I4HRxU\":[\"已發布的全部貼文,包括從 Latest 中隱藏的那些。\"],\"I6gXOa\":[\"路徑\"],\"I76CzF\":[\"中性灰\"],\"ID38tA\":[\"示範模式下帳號刪除已停用。共用示範會另行重置。\"],\"IF9tPu\":[\"何時使用網站匯出、資料庫備份與復原演練。\"],\"IW5PBo\":[\"複製權杖\"],\"IagCbF\":[\"URL\"],\"IfB3m6\":[\"你撰寫內容所用的語言。透過 HTML lang 和 RSS 向讀者與搜尋引擎宣告。支援任意 BCP 47 標籤。\"],\"IreQBq\":[\"儲存庫\"],\"J6bLeg\":[\"新增自訂連結到任何 URL\"],\"JL7LF5\":[\"可用的 CSS 變數、data 屬性與範例.\"],\"JTviaO\":[\"管理登入安全、匯出,以及不可逆的操作。\"],\"JcD7qf\":[\"更多操作\"],\"JjX0OO\":[\"請立即複製您的權杖 — 它不會再顯示。\"],\"JrFTcr\":[\"連線中…\"],\"JuN5GC\":[\"未選取檔案。請選擇要上傳的檔案。\"],\"KDw4GX\":[\"重試\"],\"KSgo21\":[\"選擇一個儲存庫\"],\"KVVYBh\":[\"新增選集到導覽\"],\"KiJn9B\":[\"筆記\"],\"KwOLJF\":[\"Jant 最初的配色,日常穩妥之選。\"],\"L3DEwT\":[\"移除這個頭像?您的 favicon 與頁首圖示會回復為預設。\"],\"L4t4/q\":[\"3月14日\"],\"LdyooL\":[\"連結\"],\"M/D8PK\":[\"+ 安裝到其他帳戶\"],\"M/haSd\":[\"永遠顯示主題的淺色版本。\"],\"M2kIWU\":[\"字型主題\"],\"M6CbAU\":[\"切換編輯面板\"],\"MaYYE6\":[\"透過向 Telegram 機器人傳送訊息來發佈筆記\"],\"Me5t5H\":[\"連接 GitHub 倉庫,自動將你的文章備份為 Markdown 檔案。GitHub 上的編輯會同步回你的網站。\"],\"Mr4QPw\":[\"要斷開 Telegram?您可以隨時使用新的綁定代碼重新連接。\"],\"MtENL9\":[\"調整您的網站外觀、可讀性與執行效能。\"],\"N/8NPV\":[\"在刪除前,請先下載網站匯出檔案。刪除後無法恢復此帳號。\"],\"N7UNHY\":[\"精選 RSS 來源\"],\"NHnUHF\":[\"頁首上的網站圖示與個人標記\"],\"NU2Fqi\":[\"儲存 CSS\"],\"NVjhde\":[\"暖羊皮紙\"],\"Nldjdr\":[\"尚未有自訂 URL。建立一個自訂 URL 以為文章新增重新導向或自訂路徑。\"],\"O7rgs6\":[\"頁首 RSS 指向你的 \",[\"feed\"],\" 訂閱 (/feed)。在「一般」中變更 /feed 回傳的內容。\"],\"OSJXFg\":[\"套用於整個網站, 包括管理頁面. 選擇一個調色盤, 然後決定它是跟隨系統還是維持固定.\"],\"Ox3+3h\":[\"無相符結果。\"],\"PEUV5I\":[\"程式碼注入已更新。\"],\"PHh52z\":[\"暖而厚重,棕調明顯。\"],\"PXj9lw\":[\"停止接受來自 Telegram 的貼文。您現有的筆記會保持已發佈。\"],\"PZ7HJ8\":[\"部落格大頭貼\"],\"Pwqkdw\":[\"載入中…\"],\"PxJ9W6\":[\"產生權杖\"],\"Q/6Y+2\":[\"需要在目標儲存庫上擁有 Contents(讀/寫)和 Webhooks(讀/寫)權限。\"],\"Q30z/l\":[\"要從導覽移除這個選集嗎?選集本身不會被刪除。\"],\"Q99OtV\":[\"將選集釘選到導覽列。最近 48 小時內更新的選集旁會顯示一個 * 號。\"],\"QCwsv1\":[\"暖白\"],\"QKvrmL\":[\"暖中性,適合長讀。\"],\"QZmz0H\":[\"內建連結\"],\"Qnrzvb\":[\"已啟用的權杖\"],\"R6Z4LE\":[\"下載失敗。請再試一次。\"],\"R9Khdg\":[\"自動\"],\"RcdDOS\":[\"在 Telegram 上向 @BotFather 發送訊息以建立機器人,然後貼上它提供給你的權杖\"],\"RdVIcf\":[\"奶油配深咖\"],\"RxsRD6\":[\"時區\"],\"SJmfuf\":[\"網站名稱\"],\"SKZhW9\":[\"權杖名稱 (API 權杖名稱欄位。)\"],\"SVQQPe\":[\"無法連線。請檢查錯誤並再試一次。\"],\"SchpMp\":[\"Telegram\"],\"SrGs4T\":[\"淺藍灰底,冷靜而均勻。\"],\"TpF3v+\":[\"在 </head> 之前注入。用於分析、自訂 meta 標籤,以及必須提前載入的樣式。\"],\"Tu6bMZ\":[\"建立 About 頁面\"],\"Tz0i8g\":[\"設定\"],\"UFK415\":[\"用於分析與小工具的網站全域 HTML\"],\"UTvFQq\":[\"開啟 \",[\"linkOpen\"],\"@\",[\"botUsername\"],[\"linkClose\"],\" 並傳送:\"],\"Uj/btJ\":[\"在我的網站頁首顯示大頭貼\"],\"UsODUn\":[\"選擇一個帳戶\"],\"UxKoFf\":[\"導覽\"],\"V+bhUy\":[\"安裝 GitHub App\"],\"V4WsyL\":[\"新增連結\"],\"V5pZwT\":[\"搜尋設定已更新。\"],\"VXUPla\":[\"使用 GitHub App 連線\"],\"VhMDMg\":[\"變更密碼\"],\"Vn3jYy\":[\"導覽項目\"],\"VoZYGU\":[\"這會永久刪除您所有的資料 — 文章、媒體、選集、設定,以及您的帳戶。您的部落格將被重設為初始設定狀態。此操作無法復原。\"],\"WUnFK2\":[\"偏冷的淺白底,配深靛藍文字。高對比。\"],\"Wa9q4P\":[\"純白\"],\"Wb7EHo\":[\"About 頁面\"],\"Weq9zb\":[\"一般\"],\"Wi9i06\":[\"依照每位訪客的系統偏好。\"],\"Wx1M8N\":[\"安裝 GitHub App,以授予存取權而無需管理個人權杖。權限以每個儲存庫為範圍,並可在 GitHub 上撤銷。\"],\"X+8FMk\":[\"目前的密碼不符。請再試一次。\"],\"X1G9eY\":[\"導覽預覽\"],\"X2Cbc2\":[\"封存 RSS 來源\"],\"X9Hujr\":[\"手動推送\"],\"XtBJV8\":[\"正在檢查儲存庫…\"],\"Xtc16w\":[\"重新整理儲存庫清單\"],\"Y/F35r\":[\"使用 curl 建立貼文:\"],\"Y/N5N7\":[\"柔和的奶油底,配低飽和的綠。\"],\"YF6zHf\":[\"網站設定已更新.\"],\"YdG2RF\":[\"匯出網站\"],\"YkgZi7\":[\"連接一個 Telegram 機器人,之後你傳給它的任何訊息都會以筆記形式已發佈。\"],\"YwhjRx\":[\"管理帳戶\"],\"Yxp859\":[\"暖奶油色\"],\"ZDY7Fy\":[\"同步中…\"],\"ZQKLI1\":[\"危險區域\"],\"ZS/CBL\":[\"刪除此導覽連結?訪客將不再在您的網站頁首看到它。\"],\"ZgZX+d\":[\"純白底配中性灰。不帶任何色偏。\"],\"ZhhOwV\":[\"引用\"],\"ZiooJI\":[\"API 權杖\"],\"Zm7Qb0\":[\"備份與還原指南\"],\"ZmUkwN\":[\"新增自訂連結到導覽\"],\"a14mj8\":[\"未知裝置\"],\"a1iEgy\":[\"暖奶油底,配深咖啡棕點綴。\"],\"a3LDKx\":[\"安全性\"],\"aAIQg2\":[\"外觀\"],\"aFkzVF\":[\"目標文章或選集的 slug\"],\"alKG0+\":[\"字型主題\"],\"anibOb\":[\"關於本部落格\"],\"any7NR\":[\"主題指南\"],\"b+/jO6\":[\"301 (永久)\"],\"bHOiy1\":[\"示範模式已停用變更密碼功能。請使用共用示範帳號登入。\"],\"bHYIks\":[\"登出\"],\"bV2vng\":[\"暖陶土色\"],\"bbR5vW\":[\"這套配色\"],\"bmrL08\":[\"示範模式會隱藏會話、密碼更改與帳號刪除。匯出功能仍可使用。\"],\"bviiKV\":[\"這個主題下的標題、正文和連結。\"],\"c3MN2z\":[\"所有可用的端點與請求格式。\"],\"cS7/bk\":[\"移除已儲存的機器人權杖?其 webhook 會被刪除,任何已連接的帳號將會被斷線。\"],\"cSDy01\":[\"自訂 CSS 已更新.\"],\"clzoNp\":[\"始終顯示深色主題。\"],\"cnGeoo\":[\"刪除\"],\"d3FRkY\":[\"無法複製. 請再試一次.\"],\"d5oGUo\":[\"在 GitHub 建立新儲存庫\"],\"dEgA5A\":[\"取消\"],\"dTXUY+\":[\"確認刪除帳號\"],\"dYKrp3\":[\"從最新中隱藏 (不出現在 Latest 中,但仍可透過固定連結和集合存取的狀態。)\"],\"dk7TCH\":[\"永久刪除所有資料並重設部落格\"],\"drodVV\":[\"目前還沒有選集。請先建立一個,然後將它加入您的導覽。\"],\"dsWkIw\":[\"要與 GitHub 斷開連線嗎? webhook 將會被移除。您的儲存庫內容不會被刪除。\"],\"e/tSI5\":[\"導覽順序已更新。\"],\"eOL7vn\":[\"色彩極少,干擾最小。\"],\"ePK91l\":[\"編輯\"],\"ebQKK7\":[\"網站\"],\"egK+Yy\":[\"供腳本與自動化使用的 Bearer 權杖\"],\"ehj/zN\":[\"重新導向類型\"],\"eneWvv\":[\"草稿\"],\"erTMh7\":[\"上次同步\"],\"f+m8jj\":[\"已複製訂閱網址。\"],\"f8fH8W\":[\"設計\"],\"fKRAwQ\":[\"沙色底,配綠色點綴。\"],\"fWYqkz\":[\"程式碼注入\"],\"fYXQnC\":[\"暖色裡最濃的一檔,溫馨。\"],\"gOWiTY\":[\"載入為中文、日文或韓文內容最佳化的襯線字型。\"],\"gZ5owP\":[\"搜尋儲存庫\"],\"gbqbh6\":[\"可以放心離開此頁面 — 同步會在背景繼續進行。\"],\"gkFvVN\":[\"在 </body> 之前注入。用於聊天小工具和不應阻塞頁面載入的腳本。\"],\"gtQsRO\":[\"建立自訂網址\"],\"hBO/y4\":[\"安全權杖已過期。請重新整理頁面並再試一次。\"],\"hGmyDl\":[\"權杖讓您從腳本, 捷徑和其他工具存取 API 無需登入\"],\"hIHkRy\":[\"已透過 GitHub 應用程式連線\"],\"hdSi1b\":[\"輸入 \",[\"repo\"],\" 以確認\"],\"he3ygx\":[\"複製\"],\"i0qMbr\":[\"首頁\"],\"iEUzMn\":[\"系統\"],\"iSLIjg\":[\"連接\"],\"iVOMRi\":[\"首頁設定已更新。\"],\"icB4Cv\":[\"將連結拖到此處以顯示於「更多」選單下方\"],\"id3vuh\":[\"已設定 Telegram,但無法連線到機器人。請檢查機器人權杖並再試一次。\"],\"ihn4zD\":[\"搜尋…\"],\"iiDXZc\":[\"顯示於所有文章與頁面的底部。\"],\"itS31B\":[\"更暖一些,像略舊的紙。\"],\"iwQZvS\":[\"冷藍灰\"],\"j4VrG6\":[\"下載匯出 ZIP\"],\"j5nQL2\":[\"例如 iOS 捷徑\"],\"jUV7CU\":[\"上傳大頭貼\"],\"jVUmOK\":[\"支援 Markdown\"],\"jdVYS8\":[\"選一個適合你文字的。\"],\"jgBjXJ\":[\"要撤銷這個權杖嗎?任何使用它的腳本都會停止運作。\"],\"jpctdh\":[\"檢視\"],\"k1ifdL\":[\"處理中...\"],\"kLw03Y\":[\"亮紙白\"],\"kMXclu\":[\"下載網站匯出檔案\"],\"kNiQp6\":[\"已釘選\"],\"kRhzWq\":[\"GitHub 同步\"],\"kVQs7s\":[\"細緻的樣式覆寫\"],\"ke1gWS\":[\"自訂 URL\"],\"kfcRb0\":[\"頭像\"],\"kxDZ2i\":[\"此程式碼會在您網站的每個頁面上執行。\"],\"l2Op2p\":[\"查詢參數\"],\"lLW3vJ\":[\"目標 slug\"],\"lV04bQ\":[\"溫暖、有泥土感,但不顯暗。\"],\"lYHJih\":[\"撤銷此工作階段?該裝置將需要重新登入。\"],\"m16xKo\":[\"新增\"],\"mLOk1i\":[\"立即將所有文章推送到 GitHub,而不是等待下一次自動同步。\"],\"mSNmrX\":[\"列出貼文:\"],\"n8+EXe\":[\"新增網站中已經存在的常用入口。\"],\"nG2qTk\":[\"示例連結\"],\"nK07ni\":[\"為您的網站選擇一種排版風格。每個主題會同時改變字體配對與閱讀節奏。\"],\"nbfdhU\":[\"第三方整合\"],\"ntJYyh\":[\"在 \",[\"providerLabel\"],\" 管理網域、方案和計費\"],\"o/vNDE\":[\"讓您覆寫任何主題變數。\"],\"oGC9uP\":[\"owner/repo\"],\"oH2JHg\":[\"我們會預先填入名稱 \",[\"name\"],\"。返回時清單會重新整理。\"],\"oKOOsY\":[\"色彩主題\"],\"oL535e\":[\"尚未同步\"],\"oNA4If\":[\"所有選集已經在您的導覽中。\"],\"oUn9Z7\":[\"近中性的淺灰,配鋼藍點綴。\"],\"ofdy2l\":[\"帶橘調的底色。最暖的一套。\"],\"pZq3aX\":[\"上傳失敗。請再試一次。\"],\"pgTIrt\":[\"選擇要與此網站同步的 GitHub 帳號和儲存庫.\"],\"psoxDF\":[\"該字型主題無法使用. 請選擇其他主題.\"],\"pt4OhQ\":[\"/about 已被佔用。重新命名該項目後再建立 About 頁面。\"],\"pvnfJD\":[\"深色\"],\"q+hNag\":[\"選集\"],\"qdcESc\":[\"建立新儲存庫\"],\"r5EW6f\":[\"此儲存庫已在備份另一個 Jant 網站 (\",[\"host\"],\"). 請選擇其他儲存庫.\"],\"rEspiY\":[\"導覽位置已更新。\"],\"rFmBG3\":[\"色彩主題\"],\"rlonmB\":[\"無法刪除。請稍後再試。\"],\"satWc6\":[\"主要 RSS 訂閱\"],\"sgr2wQ\":[\"選集\"],\"soRdOu\":[\"米白紙底,配深森綠。\"],\"sqxcaY\":[\"建立於 \",[\"date\"]],\"sxkWRg\":[\"進階\"],\"t/YqKh\":[\"移除\"],\"t3hvHq\":[\"立即同步\"],\"tJ4H0O\":[\"您的 Telegram 帳號\"],\"tfDRzk\":[\"儲存\"],\"tvgAq5\":[\"尚未授權任何帳戶\"],\"u1VTd3\":[\"調色盤、表面色調與整體氛圍\"],\"u3wRF+\":[\"已發佈\"],\"u6KOjV\":[\"想要更細緻的控制?\"],\"udPwLB\":[\"頁首\"],\"ui6aMF\":[\"這些裝置目前已登入您的帳號。撤銷任何您不認識的工作階段。\"],\"vBEKwo\":[\"在此管理本網站的活動工作階段。密碼與託管存取由 \",[\"providerLabel\"],\" 管理。\"],\"vRldcl\":[\"字體選擇與閱讀質感\"],\"vSYKYI\":[\"主要訂閱來源\"],\"vTuib7\":[\"這會控制 /feed 回傳的內容。\"],\"vmQmHx\":[\"新增自訂 CSS 以覆寫任何樣式。使用像 [data-page]、[data-post]、[data-format] 這類資料屬性來選取特定元素。\"],\"vzX5FB\":[\"刪除帳號\"],\"w8Rv8T\":[\"標籤為必填\"],\"wL3cK8\":[\"最新\"],\"wW6NCp\":[\"上次錯誤\"],\"wc+17X\":[\"/* 在此放入您的自訂 CSS */\"],\"wuLtXn\":[\"目前沒有任何活動中的工作階段。已登入的裝置會顯示在此處。\"],\"xCWek4\":[\"檔案儲存尚未設定。請檢查您的伺服器設定。\"],\"xHt036\":[\"個人存取權杖\"],\"xKeZ0l\":[\"更偏暖、偏土的色調。\"],\"xYbozN\":[\"柔象牙白\"],\"xqViCq\":[\"暖象牙白\"],\"xxaahd\":[\"想要更冷、更利落的觀感時。\"],\"y28hnO\":[\"文章\"],\"y8Md/V\":[\"語言與時間已更新。\"],\"yNCqOt\":[\"最新 RSS 來源\"],\"yQ3kNF\":[\"請輸入以下短語以確認:\"],\"ydq1k2\":[\"請先選擇一個帳戶\"],\"yjjCV8\":[\"固定的 RSS 檔案網址\"],\"yjkELF\":[\"確認新密碼\"],\"yzF66j\":[\"連結\"],\"z6wakA\":[\"顯示在您的主頁上的簡短介紹。\"],\"zEizrk\":[\"最後使用於 \",[\"date\"]],\"zSURJW\":[\"沒有符合的儲存庫.\"],\"zXH2jX\":[\"語言與時區\"],\"zlcDd2\":[\"刪除此自訂 URL?使用該 URL 的訪客將不會再被重新導向。\"],\"zwBp5t\":[\"私有\"],\"zxRN6H\":[\"頁首連結、首頁動態與更多選單\"]}")as Messages;
@@ -186,25 +186,17 @@ describe("feed renderers", () => {
186
186
  });
187
187
 
188
188
  it("renders thread replies with hr separator and time element", () => {
189
- const reply: PostView = {
189
+ const reply = makePostView({
190
190
  id: "reply-1",
191
191
  permalink: "/reply-1",
192
192
  slug: "reply-1",
193
- format: "note",
194
- status: "published",
195
- visibility: "public",
196
- pinned: false,
197
- featured: false,
198
193
  publishedAt: "2026-03-19T12:00:00.000Z",
199
194
  publishedAtFormatted: "Mar 19, 2026",
200
195
  publishedAtTime: "12:00",
201
196
  publishedAtRelative: "now",
202
197
  updatedAt: "2026-03-19T12:00:00.000Z",
203
- media: [],
204
- collections: [],
205
- isLastInThread: true,
206
198
  bodyHtml: "<p>This is a reply</p>",
207
- };
199
+ });
208
200
 
209
201
  const xml = defaultFeedRenderer(
210
202
  makeFeedData(
@@ -222,6 +214,100 @@ describe("feed renderers", () => {
222
214
  expect(xml).toContain("<p>This is a reply</p>");
223
215
  });
224
216
 
217
+ it("renders note reply titles inline because replies do not get their own Atom entry title", () => {
218
+ const reply = makePostView({
219
+ id: "reply-1",
220
+ permalink: "/reply-1",
221
+ slug: "reply-1",
222
+ title: "Reply Article",
223
+ bodyHtml: "<p>Reply article body.</p>",
224
+ });
225
+
226
+ const xml = defaultFeedRenderer(
227
+ makeFeedData(
228
+ makePostView({
229
+ title: "Thread Root",
230
+ bodyHtml: "<p>Root content</p>",
231
+ threadReplies: [reply],
232
+ }),
233
+ ),
234
+ );
235
+
236
+ expect(xml).toContain(
237
+ '<h2><a href="https://example.com/reply-1">Reply Article</a></h2>',
238
+ );
239
+ expect(xml).toContain("<p>Reply article body.</p>");
240
+ });
241
+
242
+ it("renders link reply domain and title inline before commentary", () => {
243
+ const reply = makePostView({
244
+ id: "reply-1",
245
+ permalink: "/reply-1",
246
+ slug: "reply-1",
247
+ format: "link",
248
+ title: "test rss title",
249
+ url: "https://www.jant.me/test-rss-title",
250
+ bodyHtml: "<p>rss body</p>",
251
+ });
252
+
253
+ const xml = defaultFeedRenderer(
254
+ makeFeedData(
255
+ makePostView({
256
+ summary: "test rss",
257
+ bodyHtml: "<p>test rss</p>",
258
+ threadReplies: [reply],
259
+ }),
260
+ ),
261
+ );
262
+
263
+ expect(xml).toContain(
264
+ '<p><a href="https://www.jant.me/test-rss-title">jant.me</a></p>',
265
+ );
266
+ expect(xml).toContain(
267
+ '<h2><a href="https://www.jant.me/test-rss-title">test rss title</a></h2>',
268
+ );
269
+ expect(xml).toContain("<p>rss body</p>");
270
+ expect(xml).toContain(
271
+ '<a href="https://example.com/reply-1" title="Permalink">&nbsp;★&nbsp;</a>',
272
+ );
273
+ });
274
+
275
+ it("includes thread reply media as Atom enclosures on the combined entry", () => {
276
+ const reply = makePostView({
277
+ id: "reply-1",
278
+ permalink: "/reply-1",
279
+ slug: "reply-1",
280
+ bodyHtml: "<p>Reply with audio.</p>",
281
+ media: [
282
+ makeMediaView({
283
+ id: "reply-audio",
284
+ url: "https://example.com/media/reply.mp3",
285
+ thumbnailUrl: "https://example.com/media/reply.mp3",
286
+ mimeType: "audio/mpeg",
287
+ originalName: "reply.mp3",
288
+ size: 1024,
289
+ }),
290
+ ],
291
+ });
292
+
293
+ const xml = defaultFeedRenderer(
294
+ makeFeedData(
295
+ makePostView({
296
+ title: "Thread Root",
297
+ bodyHtml: "<p>Root content</p>",
298
+ threadReplies: [reply],
299
+ }),
300
+ ),
301
+ );
302
+
303
+ expect(xml).toContain(
304
+ '<link rel="enclosure" type="audio/mpeg" href="https://example.com/media/reply.mp3" length="1024" title="reply.mp3"',
305
+ );
306
+ expect(xml).toContain(
307
+ '<a href="https://example.com/media/reply.mp3">📎 [audio/mpeg] reply.mp3</a> (1 KB)',
308
+ );
309
+ });
310
+
225
311
  it("embeds image attachments as figures with alt text caption", () => {
226
312
  const post = makePostView({
227
313
  bodyHtml: "<p>Look at this.</p>",
package/src/lib/feed.ts CHANGED
@@ -92,6 +92,49 @@ function getAtomTitle(post: PostView): string {
92
92
  return post.title || "";
93
93
  }
94
94
 
95
+ interface SinglePostContentOptions {
96
+ /**
97
+ * Inline posts do not have their own Atom entry title/link, so their visible
98
+ * feed HTML must carry title and link metadata that top-level entries expose
99
+ * through Atom fields.
100
+ */
101
+ inline?: boolean;
102
+ }
103
+
104
+ function renderLinkedText(text: string, href?: string): string {
105
+ const label = escapeXml(text);
106
+ return href ? `<a href="${escapeXml(href)}">${label}</a>` : label;
107
+ }
108
+
109
+ function renderInlinePostHeader(
110
+ post: PostView,
111
+ permalinkUrl?: string,
112
+ ): string[] {
113
+ if (post.format === "quote") return [];
114
+
115
+ const parts: string[] = [];
116
+
117
+ if (post.format === "link") {
118
+ const linkUrl = post.url || "";
119
+ const domain = linkUrl ? extractDisplayDomain(linkUrl) || linkUrl : "";
120
+ if (domain) {
121
+ parts.push(`<p>${renderLinkedText(domain, linkUrl)}</p>`);
122
+ }
123
+ if (post.title) {
124
+ parts.push(
125
+ `<h2>${renderLinkedText(post.title, linkUrl || permalinkUrl)}</h2>`,
126
+ );
127
+ }
128
+ return parts;
129
+ }
130
+
131
+ if (post.title) {
132
+ parts.push(`<h2>${renderLinkedText(post.title, permalinkUrl)}</h2>`);
133
+ }
134
+
135
+ return parts;
136
+ }
137
+
95
138
  /**
96
139
  * Render a star rating as HTML for feed content.
97
140
  */
@@ -242,10 +285,19 @@ function renderMediaForFeed(
242
285
  *
243
286
  * @param post - Post view data
244
287
  * @param permalinkUrl - Absolute permalink URL back to the blog post
288
+ * @param options - Rendering options for top-level versus inline posts
245
289
  */
246
- function buildSinglePostContent(post: PostView, permalinkUrl?: string): string {
290
+ function buildSinglePostContent(
291
+ post: PostView,
292
+ permalinkUrl?: string,
293
+ options: SinglePostContentOptions = {},
294
+ ): string {
247
295
  const parts: string[] = [];
248
296
 
297
+ if (options.inline) {
298
+ parts.push(...renderInlinePostHeader(post, permalinkUrl));
299
+ }
300
+
249
301
  if (post.format === "quote" && post.quoteText) {
250
302
  const sourceName = post.title || "";
251
303
  const sourceUrl = post.url || "";
@@ -316,12 +368,20 @@ function buildFeedContent(
316
368
  parts.push(
317
369
  `<p><small><time datetime="${escapeXml(reply.publishedAt)}">${escapeXml(reply.publishedAtFormatted)}</time></small></p>`,
318
370
  );
319
- parts.push(buildSinglePostContent(reply, replyPermalink));
371
+ parts.push(buildSinglePostContent(reply, replyPermalink, { inline: true }));
320
372
  }
321
373
 
322
374
  return parts.join("\n");
323
375
  }
324
376
 
377
+ function getEntryMedia(post: FeedPostView): MediaView[] {
378
+ const media = [...post.media];
379
+ for (const reply of post.threadReplies ?? []) {
380
+ media.push(...reply.media);
381
+ }
382
+ return media;
383
+ }
384
+
325
385
  /**
326
386
  * Default Atom feed renderer.
327
387
  *
@@ -354,7 +414,7 @@ export function defaultFeedRenderer(data: FeedData): string {
354
414
  // One <link rel="enclosure"> per attachment so podcast/offline readers
355
415
  // can fetch them. Atom omits length when size is unknown; mimeType is
356
416
  // always known from the upload pipeline.
357
- const enclosureLinks = post.media
417
+ const enclosureLinks = getEntryMedia(post)
358
418
  .map((m) => {
359
419
  const lengthAttr =
360
420
  m.size != null && m.size > 0 ? ` length="${m.size}"` : "";
@@ -79,9 +79,17 @@ function resolvePostSocialImage(
79
79
  return undefined;
80
80
  }
81
81
 
82
- function canViewPost(post: Post, isAuthenticated: boolean): boolean {
82
+ interface PostDisplayOptions {
83
+ isAuthenticated?: boolean;
84
+ allowDraft?: boolean;
85
+ }
86
+
87
+ function canViewPost(post: Post, options: PostDisplayOptions = {}): boolean {
88
+ const isAuthenticated = options.isAuthenticated ?? false;
83
89
  if (post.status !== "published") {
84
- return false;
90
+ return Boolean(
91
+ post.status === "draft" && isAuthenticated && options.allowDraft,
92
+ );
85
93
  }
86
94
 
87
95
  if (post.visibility === "private" && !isAuthenticated) {
@@ -102,11 +110,10 @@ function canViewPost(post: Post, isAuthenticated: boolean): boolean {
102
110
  export async function assemblePostCardView(
103
111
  c: Context<Env>,
104
112
  postId: string,
105
- options?: { isAuthenticated?: boolean },
113
+ options?: PostDisplayOptions,
106
114
  ): Promise<PostView | null> {
107
115
  const post = await c.var.services.posts.getById(postId);
108
- const isAuthenticated = options?.isAuthenticated ?? false;
109
- if (!post || !canViewPost(post, isAuthenticated)) {
116
+ if (!post || !canViewPost(post, options)) {
110
117
  return null;
111
118
  }
112
119
 
@@ -149,15 +156,14 @@ export async function assemblePostCardView(
149
156
  export async function assemblePostPageDisplay(
150
157
  c: Context<Env>,
151
158
  postOrId: string | Post,
152
- options?: { isAuthenticated?: boolean },
159
+ options?: PostDisplayOptions,
153
160
  ): Promise<PostPageDisplayData | null> {
154
161
  const post =
155
162
  typeof postOrId === "string"
156
163
  ? await c.var.services.posts.getById(postOrId)
157
164
  : postOrId;
158
- const isAuthenticated = options?.isAuthenticated ?? false;
159
165
 
160
- if (!post || !canViewPost(post, isAuthenticated)) {
166
+ if (!post || !canViewPost(post, options)) {
161
167
  return null;
162
168
  }
163
169