@jant/core 0.3.7 → 0.3.8

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 (241) hide show
  1. package/dist/app.js +4 -0
  2. package/dist/client.js +1 -0
  3. package/dist/db/schema.js +13 -0
  4. package/dist/i18n/locales/en.js +1 -1
  5. package/dist/i18n/locales/zh-Hans.js +1 -1
  6. package/dist/i18n/locales/zh-Hant.js +1 -1
  7. package/dist/lib/image.js +3 -3
  8. package/dist/lib/media-helpers.js +43 -0
  9. package/dist/lib/nav-reorder.js +27 -0
  10. package/dist/lib/navigation.js +35 -0
  11. package/dist/lib/theme-components.js +49 -0
  12. package/dist/routes/api/timeline.js +115 -0
  13. package/dist/routes/api/upload.js +9 -5
  14. package/dist/routes/dash/navigation.js +274 -0
  15. package/dist/routes/pages/archive.js +14 -27
  16. package/dist/routes/pages/collection.js +10 -19
  17. package/dist/routes/pages/home.js +83 -126
  18. package/dist/routes/pages/page.js +19 -38
  19. package/dist/routes/pages/post.js +38 -51
  20. package/dist/routes/pages/search.js +13 -26
  21. package/dist/services/index.js +3 -1
  22. package/dist/services/media.js +1 -1
  23. package/dist/services/navigation.js +115 -0
  24. package/dist/services/post.js +26 -1
  25. package/dist/theme/components/PostList.js +5 -0
  26. package/dist/theme/components/index.js +2 -0
  27. package/dist/theme/components/timeline/ArticleCard.js +50 -0
  28. package/dist/theme/components/timeline/ImageCard.js +86 -0
  29. package/dist/theme/components/timeline/LinkCard.js +62 -0
  30. package/dist/theme/components/timeline/NoteCard.js +37 -0
  31. package/dist/theme/components/timeline/QuoteCard.js +51 -0
  32. package/dist/theme/components/timeline/ThreadPreview.js +52 -0
  33. package/dist/theme/components/timeline/TimelineFeed.js +43 -0
  34. package/dist/theme/components/timeline/TimelineItem.js +25 -0
  35. package/dist/theme/components/timeline/index.js +8 -0
  36. package/dist/theme/layouts/DashLayout.js +8 -0
  37. package/dist/theme/layouts/SiteLayout.js +160 -0
  38. package/dist/theme/layouts/index.js +1 -0
  39. package/dist/types/sortablejs.d.js +5 -0
  40. package/package.json +3 -2
  41. package/src/__tests__/helpers/db.ts +10 -0
  42. package/src/app.tsx +4 -0
  43. package/src/client.ts +1 -0
  44. package/src/db/migrations/0003_add_navigation_links.sql +8 -0
  45. package/src/db/migrations/meta/0003_snapshot.json +821 -0
  46. package/src/db/migrations/meta/_journal.json +14 -0
  47. package/src/db/schema.ts +13 -0
  48. package/src/i18n/locales/en.po +100 -32
  49. package/src/i18n/locales/en.ts +1 -1
  50. package/src/i18n/locales/zh-Hans.po +102 -55
  51. package/src/i18n/locales/zh-Hans.ts +1 -1
  52. package/src/i18n/locales/zh-Hant.po +102 -55
  53. package/src/i18n/locales/zh-Hant.ts +1 -1
  54. package/src/index.ts +5 -0
  55. package/src/lib/__tests__/theme-components.test.ts +107 -0
  56. package/src/lib/image.ts +3 -3
  57. package/src/lib/media-helpers.ts +54 -0
  58. package/src/lib/nav-reorder.ts +26 -0
  59. package/src/lib/navigation.ts +46 -0
  60. package/src/lib/theme-components.ts +76 -0
  61. package/src/routes/api/__tests__/posts.test.ts +8 -8
  62. package/src/routes/api/__tests__/timeline.test.ts +242 -0
  63. package/src/routes/api/timeline.tsx +145 -0
  64. package/src/routes/api/upload.ts +9 -5
  65. package/src/routes/dash/navigation.tsx +306 -0
  66. package/src/routes/pages/archive.tsx +15 -23
  67. package/src/routes/pages/collection.tsx +8 -15
  68. package/src/routes/pages/home.tsx +111 -122
  69. package/src/routes/pages/page.tsx +17 -30
  70. package/src/routes/pages/post.tsx +33 -42
  71. package/src/routes/pages/search.tsx +18 -22
  72. package/src/services/__tests__/media.test.ts +34 -7
  73. package/src/services/__tests__/navigation.test.ts +213 -0
  74. package/src/services/__tests__/post-timeline.test.ts +220 -0
  75. package/src/services/index.ts +7 -0
  76. package/src/services/media.ts +2 -1
  77. package/src/services/navigation.ts +165 -0
  78. package/src/services/post.ts +48 -1
  79. package/src/styles/components.css +59 -0
  80. package/src/theme/components/PostList.tsx +7 -0
  81. package/src/theme/components/index.ts +12 -0
  82. package/src/theme/components/timeline/ArticleCard.tsx +57 -0
  83. package/src/theme/components/timeline/ImageCard.tsx +80 -0
  84. package/src/theme/components/timeline/LinkCard.tsx +66 -0
  85. package/src/theme/components/timeline/NoteCard.tsx +41 -0
  86. package/src/theme/components/timeline/QuoteCard.tsx +55 -0
  87. package/src/theme/components/timeline/ThreadPreview.tsx +49 -0
  88. package/src/theme/components/timeline/TimelineFeed.tsx +52 -0
  89. package/src/theme/components/timeline/TimelineItem.tsx +39 -0
  90. package/src/theme/components/timeline/index.ts +8 -0
  91. package/src/theme/layouts/DashLayout.tsx +10 -0
  92. package/src/theme/layouts/SiteLayout.tsx +184 -0
  93. package/src/theme/layouts/index.ts +1 -0
  94. package/src/types/sortablejs.d.ts +23 -0
  95. package/src/types.ts +61 -0
  96. package/dist/app.d.ts +0 -38
  97. package/dist/app.d.ts.map +0 -1
  98. package/dist/auth.d.ts +0 -25
  99. package/dist/auth.d.ts.map +0 -1
  100. package/dist/db/index.d.ts +0 -10
  101. package/dist/db/index.d.ts.map +0 -1
  102. package/dist/db/schema.d.ts +0 -1543
  103. package/dist/db/schema.d.ts.map +0 -1
  104. package/dist/i18n/Trans.d.ts +0 -25
  105. package/dist/i18n/Trans.d.ts.map +0 -1
  106. package/dist/i18n/context.d.ts +0 -69
  107. package/dist/i18n/context.d.ts.map +0 -1
  108. package/dist/i18n/detect.d.ts +0 -20
  109. package/dist/i18n/detect.d.ts.map +0 -1
  110. package/dist/i18n/i18n.d.ts +0 -32
  111. package/dist/i18n/i18n.d.ts.map +0 -1
  112. package/dist/i18n/index.d.ts +0 -41
  113. package/dist/i18n/index.d.ts.map +0 -1
  114. package/dist/i18n/locales/en.d.ts +0 -3
  115. package/dist/i18n/locales/en.d.ts.map +0 -1
  116. package/dist/i18n/locales/zh-Hans.d.ts +0 -3
  117. package/dist/i18n/locales/zh-Hans.d.ts.map +0 -1
  118. package/dist/i18n/locales/zh-Hant.d.ts +0 -3
  119. package/dist/i18n/locales/zh-Hant.d.ts.map +0 -1
  120. package/dist/i18n/locales.d.ts +0 -11
  121. package/dist/i18n/locales.d.ts.map +0 -1
  122. package/dist/i18n/middleware.d.ts +0 -21
  123. package/dist/i18n/middleware.d.ts.map +0 -1
  124. package/dist/index.d.ts +0 -16
  125. package/dist/index.d.ts.map +0 -1
  126. package/dist/lib/config.d.ts +0 -83
  127. package/dist/lib/config.d.ts.map +0 -1
  128. package/dist/lib/constants.d.ts +0 -37
  129. package/dist/lib/constants.d.ts.map +0 -1
  130. package/dist/lib/image.d.ts +0 -73
  131. package/dist/lib/image.d.ts.map +0 -1
  132. package/dist/lib/index.d.ts +0 -9
  133. package/dist/lib/index.d.ts.map +0 -1
  134. package/dist/lib/markdown.d.ts +0 -60
  135. package/dist/lib/markdown.d.ts.map +0 -1
  136. package/dist/lib/schemas.d.ts +0 -130
  137. package/dist/lib/schemas.d.ts.map +0 -1
  138. package/dist/lib/sqid.d.ts +0 -60
  139. package/dist/lib/sqid.d.ts.map +0 -1
  140. package/dist/lib/sse.d.ts +0 -192
  141. package/dist/lib/sse.d.ts.map +0 -1
  142. package/dist/lib/theme.d.ts +0 -44
  143. package/dist/lib/theme.d.ts.map +0 -1
  144. package/dist/lib/time.d.ts +0 -90
  145. package/dist/lib/time.d.ts.map +0 -1
  146. package/dist/lib/url.d.ts +0 -82
  147. package/dist/lib/url.d.ts.map +0 -1
  148. package/dist/middleware/auth.d.ts +0 -24
  149. package/dist/middleware/auth.d.ts.map +0 -1
  150. package/dist/middleware/onboarding.d.ts +0 -26
  151. package/dist/middleware/onboarding.d.ts.map +0 -1
  152. package/dist/routes/api/posts.d.ts +0 -13
  153. package/dist/routes/api/posts.d.ts.map +0 -1
  154. package/dist/routes/api/search.d.ts +0 -13
  155. package/dist/routes/api/search.d.ts.map +0 -1
  156. package/dist/routes/api/upload.d.ts +0 -16
  157. package/dist/routes/api/upload.d.ts.map +0 -1
  158. package/dist/routes/dash/collections.d.ts +0 -13
  159. package/dist/routes/dash/collections.d.ts.map +0 -1
  160. package/dist/routes/dash/index.d.ts +0 -15
  161. package/dist/routes/dash/index.d.ts.map +0 -1
  162. package/dist/routes/dash/media.d.ts +0 -16
  163. package/dist/routes/dash/media.d.ts.map +0 -1
  164. package/dist/routes/dash/pages.d.ts +0 -15
  165. package/dist/routes/dash/pages.d.ts.map +0 -1
  166. package/dist/routes/dash/posts.d.ts +0 -13
  167. package/dist/routes/dash/posts.d.ts.map +0 -1
  168. package/dist/routes/dash/redirects.d.ts +0 -13
  169. package/dist/routes/dash/redirects.d.ts.map +0 -1
  170. package/dist/routes/dash/settings.d.ts +0 -15
  171. package/dist/routes/dash/settings.d.ts.map +0 -1
  172. package/dist/routes/feed/rss.d.ts +0 -13
  173. package/dist/routes/feed/rss.d.ts.map +0 -1
  174. package/dist/routes/feed/sitemap.d.ts +0 -13
  175. package/dist/routes/feed/sitemap.d.ts.map +0 -1
  176. package/dist/routes/pages/archive.d.ts +0 -15
  177. package/dist/routes/pages/archive.d.ts.map +0 -1
  178. package/dist/routes/pages/collection.d.ts +0 -13
  179. package/dist/routes/pages/collection.d.ts.map +0 -1
  180. package/dist/routes/pages/home.d.ts +0 -13
  181. package/dist/routes/pages/home.d.ts.map +0 -1
  182. package/dist/routes/pages/page.d.ts +0 -15
  183. package/dist/routes/pages/page.d.ts.map +0 -1
  184. package/dist/routes/pages/post.d.ts +0 -13
  185. package/dist/routes/pages/post.d.ts.map +0 -1
  186. package/dist/routes/pages/search.d.ts +0 -13
  187. package/dist/routes/pages/search.d.ts.map +0 -1
  188. package/dist/services/collection.d.ts +0 -32
  189. package/dist/services/collection.d.ts.map +0 -1
  190. package/dist/services/index.d.ts +0 -28
  191. package/dist/services/index.d.ts.map +0 -1
  192. package/dist/services/media.d.ts +0 -34
  193. package/dist/services/media.d.ts.map +0 -1
  194. package/dist/services/post.d.ts +0 -31
  195. package/dist/services/post.d.ts.map +0 -1
  196. package/dist/services/redirect.d.ts +0 -15
  197. package/dist/services/redirect.d.ts.map +0 -1
  198. package/dist/services/search.d.ts +0 -26
  199. package/dist/services/search.d.ts.map +0 -1
  200. package/dist/services/settings.d.ts +0 -18
  201. package/dist/services/settings.d.ts.map +0 -1
  202. package/dist/theme/color-themes.d.ts +0 -30
  203. package/dist/theme/color-themes.d.ts.map +0 -1
  204. package/dist/theme/components/ActionButtons.d.ts +0 -43
  205. package/dist/theme/components/ActionButtons.d.ts.map +0 -1
  206. package/dist/theme/components/CrudPageHeader.d.ts +0 -23
  207. package/dist/theme/components/CrudPageHeader.d.ts.map +0 -1
  208. package/dist/theme/components/DangerZone.d.ts +0 -36
  209. package/dist/theme/components/DangerZone.d.ts.map +0 -1
  210. package/dist/theme/components/EmptyState.d.ts +0 -27
  211. package/dist/theme/components/EmptyState.d.ts.map +0 -1
  212. package/dist/theme/components/ListItemRow.d.ts +0 -15
  213. package/dist/theme/components/ListItemRow.d.ts.map +0 -1
  214. package/dist/theme/components/MediaGallery.d.ts +0 -13
  215. package/dist/theme/components/MediaGallery.d.ts.map +0 -1
  216. package/dist/theme/components/PageForm.d.ts +0 -14
  217. package/dist/theme/components/PageForm.d.ts.map +0 -1
  218. package/dist/theme/components/Pagination.d.ts +0 -46
  219. package/dist/theme/components/Pagination.d.ts.map +0 -1
  220. package/dist/theme/components/PostForm.d.ts +0 -16
  221. package/dist/theme/components/PostForm.d.ts.map +0 -1
  222. package/dist/theme/components/PostList.d.ts +0 -10
  223. package/dist/theme/components/PostList.d.ts.map +0 -1
  224. package/dist/theme/components/ThreadView.d.ts +0 -15
  225. package/dist/theme/components/ThreadView.d.ts.map +0 -1
  226. package/dist/theme/components/TypeBadge.d.ts +0 -12
  227. package/dist/theme/components/TypeBadge.d.ts.map +0 -1
  228. package/dist/theme/components/VisibilityBadge.d.ts +0 -12
  229. package/dist/theme/components/VisibilityBadge.d.ts.map +0 -1
  230. package/dist/theme/components/index.d.ts +0 -14
  231. package/dist/theme/components/index.d.ts.map +0 -1
  232. package/dist/theme/index.d.ts +0 -21
  233. package/dist/theme/index.d.ts.map +0 -1
  234. package/dist/theme/layouts/BaseLayout.d.ts +0 -23
  235. package/dist/theme/layouts/BaseLayout.d.ts.map +0 -1
  236. package/dist/theme/layouts/DashLayout.d.ts +0 -17
  237. package/dist/theme/layouts/DashLayout.d.ts.map +0 -1
  238. package/dist/theme/layouts/index.d.ts +0 -3
  239. package/dist/theme/layouts/index.d.ts.map +0 -1
  240. package/dist/types.d.ts +0 -237
  241. package/dist/types.d.ts.map +0 -1
@@ -23,13 +23,6 @@ msgstr "{count} 條回覆"
23
23
  msgid "← Back to Collections"
24
24
  msgstr "← 返回收藏夾"
25
25
 
26
- #. @context: Navigation link
27
- #. @context: Navigation link
28
- #: src/routes/pages/collection.tsx:76
29
- #: src/routes/pages/post.tsx:63
30
- msgid "← Back to home"
31
- msgstr "← 返回首頁"
32
-
33
26
  #. @context: Archive post reply indicator - single
34
27
  #: src/routes/pages/archive.tsx:175
35
28
  msgid "1 reply"
@@ -53,7 +46,7 @@ msgstr "帳戶"
53
46
  #. @context: Button to open media picker
54
47
  #: src/theme/components/PostForm.tsx:178
55
48
  msgid "Add Media"
56
- msgstr ""
49
+ msgstr "添加媒體"
57
50
 
58
51
  #. @context: Archive filter - all types
59
52
  #: src/routes/pages/archive.tsx:115
@@ -66,12 +59,15 @@ msgid "Appearance"
66
59
  msgstr "外觀"
67
60
 
68
61
  #. @context: Archive page title
69
- #. @context: Navigation link to archive page
70
62
  #: src/routes/pages/archive.tsx:102
71
- #: src/routes/pages/home.tsx:40
72
63
  msgid "Archive"
73
64
  msgstr "檔案館"
74
65
 
66
+ #. @context: Confirmation dialog when deleting a post from the list
67
+ #: src/theme/components/PostList.tsx:56
68
+ msgid "Are you sure you want to delete this post? This cannot be undone."
69
+ msgstr ""
70
+
75
71
  #. @context: Post type badge - article
76
72
  #. @context: Post type label - article
77
73
  #. @context: Post type option
@@ -89,29 +85,22 @@ msgstr "文章"
89
85
  #. @context: Hint for image post type media requirement
90
86
  #: src/theme/components/PostForm.tsx:130
91
87
  msgid "At least 1 image required for image posts."
92
- msgstr ""
88
+ msgstr "至少需要 1 張圖片才能發佈圖片帖子。"
93
89
 
94
90
  #. @context: Button to go back to media list
95
91
  #: src/routes/dash/media.tsx:245
96
92
  msgid "Back"
97
93
  msgstr "返回"
98
94
 
99
- #. @context: Navigation link back to home page
100
- #. @context: Navigation link back to home page
101
- #. @context: Navigation link back to home page
102
- #: src/routes/pages/archive.tsx:209
103
- #: src/routes/pages/page.tsx:37
104
- #: src/routes/pages/search.tsx:144
105
- msgid "Back to home"
106
- msgstr "回到首頁"
107
-
108
95
  #. @context: Button to cancel and go back
109
96
  #. @context: Button to cancel form
110
97
  #. @context: Button to cancel form
111
98
  #. @context: Button to cancel form
112
99
  #. @context: Button to cancel form
100
+ #. @context: Button to cancel form
113
101
  #: src/routes/dash/collections.tsx:176
114
102
  #: src/routes/dash/collections.tsx:345
103
+ #: src/routes/dash/navigation.tsx:182
115
104
  #: src/routes/dash/redirects.tsx:167
116
105
  #: src/theme/components/PageForm.tsx:161
117
106
  #: src/theme/components/PostForm.tsx:312
@@ -140,7 +129,7 @@ msgstr "收藏夾"
140
129
  #. @context: Post form field - assign to collections
141
130
  #: src/theme/components/PostForm.tsx:261
142
131
  msgid "Collections (optional)"
143
- msgstr ""
132
+ msgstr "收藏(可選)"
144
133
 
145
134
  #. @context: Appearance settings heading
146
135
  #: src/routes/dash/settings.tsx:301
@@ -148,7 +137,7 @@ msgid "Color theme"
148
137
  msgstr "顏色主題"
149
138
 
150
139
  #. @context: Setup form submit button
151
- #: src/app.tsx:245
140
+ #: src/app.tsx:248
152
141
  msgid "Complete Setup"
153
142
  msgstr "完成設置"
154
143
 
@@ -158,7 +147,7 @@ msgid "Confirm New Password"
158
147
  msgstr "確認新密碼"
159
148
 
160
149
  #. @context: Password reset form field
161
- #: src/app.tsx:487
150
+ #: src/app.tsx:490
162
151
  msgid "Confirm Password"
163
152
  msgstr "確認密碼"
164
153
 
@@ -181,6 +170,11 @@ msgstr "複製"
181
170
  msgid "Create Collection"
182
171
  msgstr "創建收藏夾"
183
172
 
173
+ #. @context: Button to save new navigation link
174
+ #: src/routes/dash/navigation.tsx:176
175
+ msgid "Create Link"
176
+ msgstr "建立連結"
177
+
184
178
  #. @context: Button to create new page
185
179
  #: src/theme/components/PageForm.tsx:155
186
180
  msgid "Create Page"
@@ -192,7 +186,7 @@ msgid "Create Redirect"
192
186
  msgstr "建立重定向"
193
187
 
194
188
  #. @context: Setup page description
195
- #: src/app.tsx:187
189
+ #: src/app.tsx:190
196
190
  msgid "Create your admin account."
197
191
  msgstr "建立您的管理員帳戶。"
198
192
 
@@ -229,7 +223,9 @@ msgid "Dashboard"
229
223
  msgstr "儀表板"
230
224
 
231
225
  #. @context: Button to delete item
226
+ #. @context: Button to delete navigation link
232
227
  #. @context: Button to delete redirect
228
+ #: src/routes/dash/navigation.tsx:66
233
229
  #: src/routes/dash/redirects.tsx:60
234
230
  #: src/theme/components/ActionButtons.tsx:80
235
231
  msgid "Delete"
@@ -256,7 +252,7 @@ msgid "Deleting this media will remove it permanently from storage."
256
252
  msgstr "刪除此媒體將永久從存儲中移除它。"
257
253
 
258
254
  #. @context: Hint shown on signin page when demo credentials are pre-filled
259
- #: src/app.tsx:336
255
+ #: src/app.tsx:339
260
256
  msgid "Demo account pre-filled. Just click Sign In."
261
257
  msgstr "示範帳戶已預填。只需點擊登入。"
262
258
 
@@ -267,10 +263,15 @@ msgstr "示範帳戶已預填。只需點擊登入。"
267
263
  msgid "Description (optional)"
268
264
  msgstr "描述(可選)"
269
265
 
266
+ #. @context: Navigation label help text
267
+ #: src/routes/dash/navigation.tsx:139
268
+ msgid "Display text for the link"
269
+ msgstr "顯示連結的文字"
270
+
270
271
  #. @context: Close media picker button
271
272
  #: src/theme/components/PostForm.tsx:334
272
273
  msgid "Done"
273
- msgstr ""
274
+ msgstr "完成"
274
275
 
275
276
  #. @context: Page status option - draft
276
277
  #. @context: Post visibility badge - draft
@@ -289,17 +290,19 @@ msgstr "草稿"
289
290
  #. @context: Source name placeholder
290
291
  #: src/theme/components/PostForm.tsx:214
291
292
  msgid "e.g. The Verge, John Doe"
292
- msgstr ""
293
+ msgstr "例如:The Verge,約翰·多伊"
293
294
 
294
295
  #. @context: Button to edit collection
295
296
  #. @context: Button to edit collection
296
297
  #. @context: Button to edit item
298
+ #. @context: Button to edit navigation link
297
299
  #. @context: Button to edit page
298
300
  #. @context: Button to edit page
299
301
  #. @context: Button to edit post
300
302
  #. @context: Button to edit post
301
303
  #: src/routes/dash/collections.tsx:66
302
304
  #: src/routes/dash/collections.tsx:210
305
+ #: src/routes/dash/navigation.tsx:61
303
306
  #: src/routes/dash/pages.tsx:64
304
307
  #: src/routes/dash/pages.tsx:134
305
308
  #: src/routes/dash/posts.tsx:142
@@ -313,6 +316,11 @@ msgstr "編輯"
313
316
  msgid "Edit Collection"
314
317
  msgstr "編輯收藏集"
315
318
 
319
+ #. @context: Page heading
320
+ #: src/routes/dash/navigation.tsx:105
321
+ msgid "Edit Link"
322
+ msgstr "編輯連結"
323
+
316
324
  #. @context: Edit page main heading
317
325
  #: src/routes/dash/pages.tsx:176
318
326
  msgid "Edit Page"
@@ -325,20 +333,18 @@ msgstr "編輯文章"
325
333
 
326
334
  #. @context: Setup/signin form field - email
327
335
  #. @context: Setup/signin form field - email
328
- #: src/app.tsx:216
329
- #: src/app.tsx:350
336
+ #: src/app.tsx:219
337
+ #: src/app.tsx:353
330
338
  msgid "Email"
331
339
  msgstr "電子郵件"
332
340
 
333
341
  #. @context: Password reset page description
334
- #: src/app.tsx:457
342
+ #: src/app.tsx:460
335
343
  msgid "Enter your new password."
336
344
  msgstr "請輸入您的新密碼。"
337
345
 
338
- #. @context: Post visibility badge
339
346
  #. @context: Post visibility badge - featured
340
347
  #. @context: Post visibility option
341
- #: src/routes/pages/home.tsx:90
342
348
  #: src/theme/components/PostForm.tsx:237
343
349
  #: src/theme/components/VisibilityBadge.tsx:26
344
350
  msgid "Featured"
@@ -386,10 +392,15 @@ msgid "Images are automatically optimized: resized to max 1920px, converted to W
386
392
  msgstr "圖片會自動優化:調整大小至最大 1920 像素,轉換為 WebP 格式,並去除元數據。"
387
393
 
388
394
  #. @context: Password reset error heading
389
- #: src/app.tsx:522
395
+ #: src/app.tsx:525
390
396
  msgid "Invalid or Expired Link"
391
397
  msgstr "無效或已過期的連結"
392
398
 
399
+ #. @context: Navigation link form field
400
+ #: src/routes/dash/navigation.tsx:126
401
+ msgid "Label"
402
+ msgstr "標籤"
403
+
393
404
  #. @context: Settings form field
394
405
  #: src/routes/dash/settings.tsx:171
395
406
  msgid "Language"
@@ -409,15 +420,17 @@ msgstr "連結"
409
420
  msgid "Links"
410
421
  msgstr "連結"
411
422
 
423
+ #. @context: Button to load more posts in timeline
412
424
  #. @context: Pagination button - load more items
413
425
  #: src/theme/components/Pagination.tsx:103
426
+ #: src/theme/components/timeline/TimelineFeed.tsx:43
414
427
  msgid "Load more"
415
428
  msgstr "載入更多"
416
429
 
417
430
  #. @context: Loading state for media picker
418
431
  #: src/theme/components/PostForm.tsx:345
419
432
  msgid "Loading..."
420
- msgstr ""
433
+ msgstr "載入中..."
421
434
 
422
435
  #. @context: Page path validation message
423
436
  #: src/theme/components/PageForm.tsx:76
@@ -448,6 +461,13 @@ msgstr "我的收藏"
448
461
  msgid "Name"
449
462
  msgstr "名稱"
450
463
 
464
+ #. @context: Dashboard heading
465
+ #. @context: Dashboard navigation - navigation links management
466
+ #: src/routes/dash/navigation.tsx:29
467
+ #: src/theme/layouts/DashLayout.tsx:133
468
+ msgid "Navigation"
469
+ msgstr "導航"
470
+
451
471
  #. @context: Help text with link
452
472
  #: src/routes/dash/index.tsx:78
453
473
  msgid "Need help? Visit the <0>documentation</0>"
@@ -462,6 +482,15 @@ msgstr "需要幫助嗎?請訪問<0>文檔</0>。"
462
482
  msgid "New Collection"
463
483
  msgstr "新收藏集"
464
484
 
485
+ #. @context: Button to create new navigation link
486
+ #. @context: Button to create new navigation link
487
+ #. @context: Page heading
488
+ #: src/routes/dash/navigation.tsx:33
489
+ #: src/routes/dash/navigation.tsx:46
490
+ #: src/routes/dash/navigation.tsx:106
491
+ msgid "New Link"
492
+ msgstr "新連結"
493
+
465
494
  #. @context: Button to create new page
466
495
  #. @context: New page main heading
467
496
  #: src/routes/dash/pages.tsx:37
@@ -471,7 +500,7 @@ msgstr "新頁面"
471
500
 
472
501
  #. @context: Password form field
473
502
  #. @context: Password reset form field
474
- #: src/app.tsx:471
503
+ #: src/app.tsx:474
475
504
  #: src/routes/dash/settings.tsx:417
476
505
  msgid "New Password"
477
506
  msgstr "新密碼"
@@ -511,6 +540,11 @@ msgstr "尚未有任何收藏。"
511
540
  msgid "No media uploaded yet."
512
541
  msgstr "尚未上傳任何媒體。"
513
542
 
543
+ #. @context: Empty state message
544
+ #: src/routes/dash/navigation.tsx:42
545
+ msgid "No navigation links configured."
546
+ msgstr "未配置導航連結。"
547
+
514
548
  #. @context: Empty state message when no pages exist
515
549
  #: src/routes/dash/pages.tsx:46
516
550
  msgid "No pages yet."
@@ -530,7 +564,7 @@ msgstr "此集合中沒有帖子。"
530
564
 
531
565
  #. @context: Empty state message on home page
532
566
  #. @context: Empty state message when no posts exist
533
- #: src/routes/pages/home.tsx:54
567
+ #: src/routes/pages/home.tsx:42
534
568
  #: src/theme/components/PostList.tsx:25
535
569
  msgid "No posts yet."
536
570
  msgstr "尚未有帖子。"
@@ -594,8 +628,8 @@ msgstr "頁面"
594
628
 
595
629
  #. @context: Setup/signin form field - password
596
630
  #. @context: Setup/signin form field - password
597
- #: src/app.tsx:231
598
- #: src/app.tsx:359
631
+ #: src/app.tsx:234
632
+ #: src/app.tsx:362
599
633
  msgid "Password"
600
634
  msgstr "密碼"
601
635
 
@@ -604,9 +638,14 @@ msgstr "密碼"
604
638
  msgid "Path"
605
639
  msgstr "路徑"
606
640
 
641
+ #. @context: Navigation URL help text
642
+ #: src/routes/dash/navigation.tsx:161
643
+ msgid "Path (e.g. /archive) or full URL (e.g. https://example.com)"
644
+ msgstr "路徑(例如 /archive)或完整網址(例如 https://example.com)"
645
+
607
646
  #. @context: Link to individual post in thread
608
647
  #. @context: Link to permanent URL of post
609
- #: src/routes/pages/post.tsx:53
648
+ #: src/routes/pages/post.tsx:52
610
649
  #: src/theme/components/ThreadView.tsx:68
611
650
  msgid "Permalink"
612
651
  msgstr "永久鏈接"
@@ -717,11 +756,16 @@ msgstr "移除"
717
756
 
718
757
  #. @context: Password reset form submit button
719
758
  #. @context: Password reset page heading
720
- #: src/app.tsx:451
721
- #: src/app.tsx:502
759
+ #: src/app.tsx:454
760
+ #: src/app.tsx:505
722
761
  msgid "Reset Password"
723
762
  msgstr "重設密碼"
724
763
 
764
+ #. @context: Button to save edited navigation link
765
+ #: src/routes/dash/navigation.tsx:172
766
+ msgid "Save Changes"
767
+ msgstr "保存更改"
768
+
725
769
  #. @context: Button to save profile
726
770
  #: src/routes/dash/settings.tsx:378
727
771
  msgid "Save Profile"
@@ -747,7 +791,7 @@ msgstr "搜尋帖子..."
747
791
  #. @context: Media picker dialog title
748
792
  #: src/theme/components/PostForm.tsx:324
749
793
  msgid "Select Media"
750
- msgstr ""
794
+ msgstr "選擇媒體"
751
795
 
752
796
  #. @context: Dashboard heading
753
797
  #. @context: Dashboard heading
@@ -756,14 +800,20 @@ msgstr ""
756
800
  #: src/routes/dash/settings.tsx:118
757
801
  #: src/routes/dash/settings.tsx:290
758
802
  #: src/routes/dash/settings.tsx:341
759
- #: src/theme/layouts/DashLayout.tsx:133
803
+ #: src/theme/layouts/DashLayout.tsx:143
760
804
  msgid "Settings"
761
805
  msgstr "設定"
762
806
 
807
+ #. @context: Link to show remaining thread replies
808
+ #. placeholder {0}: remainingCount === 1 ? "reply" : "replies"
809
+ #: src/theme/components/timeline/ThreadPreview.tsx:38
810
+ msgid "Show {remainingCount} more {0}"
811
+ msgstr "顯示 {remainingCount} 個更多 {0}"
812
+
763
813
  #. @context: Sign in form submit button
764
814
  #. @context: Sign in page heading
765
- #: src/app.tsx:327
766
- #: src/app.tsx:372
815
+ #: src/app.tsx:330
816
+ #: src/app.tsx:375
767
817
  msgid "Sign In"
768
818
  msgstr "登入"
769
819
 
@@ -792,7 +842,7 @@ msgstr "縮略名"
792
842
  #. @context: Post form field - name of the source website or author
793
843
  #: src/theme/components/PostForm.tsx:204
794
844
  msgid "Source Name (optional)"
795
- msgstr ""
845
+ msgstr "來源名稱(選填)"
796
846
 
797
847
  #. @context: Post form field
798
848
  #: src/theme/components/PostForm.tsx:188
@@ -820,7 +870,7 @@ msgid "The URL path for this page. Use lowercase letters, numbers, and hyphens."
820
870
  msgstr "此頁面的 URL 路徑。使用小寫字母、數字和連字符。"
821
871
 
822
872
  #. @context: Password reset error description
823
- #: src/app.tsx:530
873
+ #: src/app.tsx:533
824
874
  msgid "This password reset link is invalid or has expired. Please generate a new one."
825
875
  msgstr "此密碼重設連結無效或已過期。請生成一個新的連結。"
826
876
 
@@ -880,7 +930,7 @@ msgstr "不公開"
880
930
  #. @context: Default title for untitled page
881
931
  #. @context: Default title for untitled post
882
932
  #: src/routes/dash/pages.tsx:91
883
- #: src/theme/components/PostList.tsx:71
933
+ #: src/theme/components/PostList.tsx:78
884
934
  msgid "Untitled"
885
935
  msgstr "無標題"
886
936
 
@@ -915,7 +965,9 @@ msgid "Uploading..."
915
965
  msgstr "上傳中..."
916
966
 
917
967
  #. @context: Media detail section - URL
968
+ #. @context: Navigation link form field
918
969
  #: src/routes/dash/media.tsx:297
970
+ #: src/routes/dash/navigation.tsx:148
919
971
  msgid "URL"
920
972
  msgstr "網址"
921
973
 
@@ -946,11 +998,6 @@ msgstr "使用此 URL 將媒體嵌入到您的帖子中。"
946
998
  msgid "View"
947
999
  msgstr "查看"
948
1000
 
949
- #. @context: Link to view all posts on archive page
950
- #: src/routes/pages/home.tsx:109
951
- msgid "View all posts →"
952
- msgstr "查看所有文章 →"
953
-
954
1001
  #. @context: Dashboard header link to view the public site
955
1002
  #: src/theme/layouts/DashLayout.tsx:53
956
1003
  msgid "View Site"
@@ -962,7 +1009,7 @@ msgid "Visibility"
962
1009
  msgstr "可見性"
963
1010
 
964
1011
  #. @context: Setup page welcome heading
965
- #: src/app.tsx:181
1012
+ #: src/app.tsx:184
966
1013
  msgid "Welcome to Jant"
967
1014
  msgstr "歡迎來到 Jant"
968
1015
 
@@ -977,6 +1024,6 @@ msgid "What's this collection about?"
977
1024
  msgstr "這個收藏是關於什麼的?"
978
1025
 
979
1026
  #. @context: Setup form field - user name
980
- #: src/app.tsx:201
1027
+ #: src/app.tsx:204
981
1028
  msgid "Your Name"
982
1029
  msgstr "您的姓名"
@@ -1 +1 @@
1
- /*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"+7Wr2a\":[\"Edit: \",[\"title\"]],\"+MACwa\":[\"尚未有任何收藏。\"],\"+owNNn\":[\"文章\"],\"+zy2Nq\":[\"類型\"],\"/0D1Xp\":[\"編輯收藏集\"],\"/Rj5P4\":[\"您的姓名\"],\"07Epll\":[\"這將為您的網站和儀表板設置主題。所有顏色主題都支持深色模式。\"],\"0JkyS7\":[\"建立您的第一個頁面\"],\"0a6MpL\":[\"新重定向\"],\"1CU1Td\":[\"網址安全識別碼(小寫、數字、連字符)\"],\"1DBGsz\":[\"筆記\"],\"1o+wgo\":[\"e.g. The Verge, John Doe\"],\"2N0qpv\":[\"文章標題...\"],\"2fUwEY\":[\"Select Media\"],\"2q/Q7x\":[\"可見性\"],\"2rJGtU\":[\"頁面標題...\"],\"3Yvsaz\":[\"302(臨時)\"],\"4/SFQS\":[\"查看網站\"],\"40TVQj\":[\"自訂路徑(選填)\"],\"4KzVT6\":[\"刪除頁面\"],\"4b3oEV\":[\"內容\"],\"4mDPGp\":[\"此頁面的 URL 路徑。使用小寫字母、數字和連字符。\"],\"6WdDG7\":[\"頁面\"],\"6YtxFj\":[\"名稱\"],\"7G4SBz\":[\"頁面內容(支持Markdown)...\"],\"7Mk+/h\":[\"更新收藏集\"],\"7Q1KKN\":[\"來源路徑\"],\"7aECQB\":[\"無效或已過期的連結\"],\"7nGhhM\":[\"你在想什麼?\"],\"7p5kLi\":[\"儀表板\"],\"7vhWI8\":[\"新密碼\"],\"8ZsakT\":[\"密碼\"],\"90Luob\":[[\"count\"],\" 條回覆\"],\"A1taO8\":[\"搜尋\"],\"AeXO77\":[\"帳戶\"],\"AyHO4m\":[\"這個收藏是關於什麼的?\"],\"B373X+\":[\"編輯文章\"],\"B495Gs\":[\"檔案館\"],\"BjF0Jv\":[\"僅限小寫字母、數字和連字符\"],\"D9Oea+\":[\"永久鏈接\"],\"DCKkhU\":[\"當前密碼\"],\"DHhJ7s\":[\"上一頁\"],\"DPfwMq\":[\"Done\"],\"DoJzLz\":[\"收藏夾\"],\"E80cJw\":[\"刪除此媒體將永久從存儲中移除它。\"],\"EEYbdt\":[\"發佈\"],\"EGwzOK\":[\"完成設置\"],\"EkH9pt\":[\"更新\"],\"FGrimz\":[\"新帖子\"],\"FkMol5\":[\"精選\"],\"Fxf4jq\":[\"描述(可選)\"],\"GA5A5H\":[\"刪除收藏夾\"],\"GX2VMa\":[\"建立您的管理員帳戶。\"],\"GbVAnd\":[\"此密碼重設連結無效或已過期。請生成一個新的連結。\"],\"GorKul\":[\"歡迎來到 Jant\"],\"GrZ6fH\":[\"新頁面\"],\"GxkJXS\":[\"上傳中...\"],\"HfyyXl\":[\"My Blog\"],\"HiETwV\":[\"安靜(正常)\"],\"Hzi9AA\":[\"未找到任何帖子。\"],\"I6gXOa\":[\"路徑\"],\"I8hDlV\":[\"At least 1 image required for image posts.\"],\"IagCbF\":[\"網址\"],\"J4FNfC\":[\"此集合中沒有帖子。\"],\"JIBC/T\":[\"Supported formats: JPEG, PNG, GIF, WebP, SVG. Max size: 10MB.\"],\"Jed1wB\":[\"需要幫助嗎?請訪問<0>文檔</0>。\"],\"JiP4aa\":[\"已發佈的頁面可以通過其路徑訪問。草稿不可見。\"],\"K9NcLu\":[\"使用此 URL 將媒體嵌入到您的帖子中。\"],\"KbS2K9\":[\"重設密碼\"],\"KiJn9B\":[\"備註\"],\"L85WcV\":[\"縮略名\"],\"LkvLQe\":[\"尚未有頁面。\"],\"M1RvTd\":[\"點擊圖片以查看完整大小\"],\"M8kJqa\":[\"草稿\"],\"M9xgHy\":[\"重定向\"],\"MHrjPM\":[\"標題\"],\"MWBOxm\":[\"Collections (optional)\"],\"MZbQHL\":[\"未找到結果。\"],\"Mhf/H/\":[\"建立重定向\"],\"MqghUt\":[\"搜尋帖子...\"],\"N40H+G\":[\"所有\"],\"O3oNi5\":[\"電子郵件\"],\"OCNZaU\":[\"重定向來源的路徑\"],\"ODiSoW\":[\"尚未有帖子。\"],\"ONWvwQ\":[\"上傳\"],\"Pbm2/N\":[\"創建收藏夾\"],\"RDjuBN\":[\"Setup\"],\"Rj01Fz\":[\"連結\"],\"RwGhWy\":[\"包含 \",[\"count\"],\" 則帖子的主題\"],\"SJmfuf\":[\"網站名稱\"],\"ST+lN2\":[\"尚未上傳任何媒體。\"],\"Tt5T6+\":[\"文章\"],\"TxE+Mj\":[\"1 條回覆\"],\"Tz0i8g\":[\"設定\"],\"U5v6Gh\":[\"編輯頁面\"],\"UDMjsP\":[\"快速操作\"],\"UGT5vp\":[\"保存設定\"],\"VUSy8D\":[\"Search failed. Please try again.\"],\"VhMDMg\":[\"更改密碼\"],\"WDcQq9\":[\"不公開\"],\"Weq9zb\":[\"一般設定\"],\"WmZ/rP\":[\"到路徑\"],\"Y+7JGK\":[\"創建頁面\"],\"Z3FXyt\":[\"Loading...\"],\"ZQKLI1\":[\"危險區域\"],\"ZhhOwV\":[\"引用\"],\"aAIQg2\":[\"外觀\"],\"an5hVd\":[\"圖片\"],\"b+/jO6\":[\"301(永久)\"],\"bHYIks\":[\"登出\"],\"biOepV\":[\"← 返回首頁\"],\"cnGeoo\":[\"刪除\"],\"dEgA5A\":[\"取消\"],\"e6Jr7Q\":[\"← 返回收藏夾\"],\"ePK91l\":[\"編輯\"],\"eWLklq\":[\"引用\"],\"eneWvv\":[\"草稿\"],\"er8+x7\":[\"示範帳戶已預填。只需點擊登入。\"],\"f6e0Ry\":[\"文章\"],\"fG7BxZ\":[\"Upload images via the API: POST /api/upload with a file form field.\"],\"fttd2R\":[\"我的收藏\"],\"hG89Ed\":[\"圖片\"],\"hWOZIv\":[\"請輸入您的新密碼。\"],\"hXzOVo\":[\"下一頁\"],\"he3ygx\":[\"複製\"],\"iH8pgl\":[\"返回\"],\"ig4hg2\":[\"Let's set up your site.\"],\"jpctdh\":[\"查看\"],\"k1ifdL\":[\"處理中...\"],\"mTOYla\":[\"查看所有文章 →\"],\"n1ekoW\":[\"登入\"],\"oJFOZk\":[\"Source Name (optional)\"],\"oYPBa0\":[\"更新頁面\"],\"p2/GCq\":[\"確認密碼\"],\"pRhYH2\":[\"收藏中的帖子 (\",[\"count\"],\")\"],\"pZq3aX\":[\"上傳失敗。請再試一次。\"],\"qMyM2u\":[\"來源網址(選填)\"],\"qiXmlF\":[\"Add Media\"],\"r1MpXi\":[\"安靜\"],\"rFmBG3\":[\"顏色主題\"],\"rdUucN\":[\"預覽\"],\"rzNUSl\":[\"包含 1 則貼文的主題\"],\"sGajR7\":[\"線程開始\"],\"ssqvZi\":[\"保存個人資料\"],\"t/YqKh\":[\"移除\"],\"tfrt7B\":[\"未配置任何重定向。\"],\"tiq7kl\":[\"頁面 \",[\"page\"]],\"u2f7vd\":[\"網站描述\"],\"u3wRF+\":[\"已發佈\"],\"u6Hp4N\":[\"Markdown\"],\"uAQUqI\":[\"狀態\"],\"vERlcd\":[\"個人資料\"],\"vXIe7J\":[\"語言\"],\"vzU4k9\":[\"新收藏集\"],\"wEF6Ix\":[\"目的地路徑或 URL\"],\"wK4OTM\":[\"標題(選填)\"],\"wM5UXj\":[\"刪除媒體\"],\"wRR604\":[\"頁面\"],\"wja8aL\":[\"無標題\"],\"x+doid\":[\"圖片會自動優化:調整大小至最大 1920 像素,轉換為 WebP 格式,並去除元數據。\"],\"x0mzE0\":[\"創建你的第一篇帖子\"],\"x4RuFo\":[\"回到首頁\"],\"xYilR2\":[\"媒體\"],\"y28hnO\":[\"文章\"],\"yQ2kGp\":[\"載入更多\"],\"yjkELF\":[\"確認新密碼\"],\"yzF66j\":[\"連結\"],\"z8ajIE\":[\"找到 1 個結果\"],\"zH6KqE\":[\"找到 \",[\"count\"],\" 個結果\"]}")as Messages;
1
+ /*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"+7Wr2a\":[\"Edit: \",[\"title\"]],\"+MACwa\":[\"尚未有任何收藏。\"],\"+bHzpy\":[\"顯示連結的文字\"],\"+owNNn\":[\"文章\"],\"+zy2Nq\":[\"類型\"],\"/0D1Xp\":[\"編輯收藏集\"],\"/Rj5P4\":[\"您的姓名\"],\"07Epll\":[\"這將為您的網站和儀表板設置主題。所有顏色主題都支持深色模式。\"],\"0JkyS7\":[\"建立您的第一個頁面\"],\"0a6MpL\":[\"新重定向\"],\"1CU1Td\":[\"網址安全識別碼(小寫、數字、連字符)\"],\"1DBGsz\":[\"筆記\"],\"1o+wgo\":[\"例如:The Verge,約翰·多伊\"],\"2N0qpv\":[\"文章標題...\"],\"2fUwEY\":[\"選擇媒體\"],\"2q/Q7x\":[\"可見性\"],\"2rJGtU\":[\"頁面標題...\"],\"3Yvsaz\":[\"302(臨時)\"],\"4/SFQS\":[\"查看網站\"],\"40TVQj\":[\"自訂路徑(選填)\"],\"4KzVT6\":[\"刪除頁面\"],\"4b3oEV\":[\"內容\"],\"4mDPGp\":[\"此頁面的 URL 路徑。使用小寫字母、數字和連字符。\"],\"6WdDG7\":[\"頁面\"],\"6YtxFj\":[\"名稱\"],\"7G4SBz\":[\"頁面內容(支持Markdown)...\"],\"7Mk+/h\":[\"更新收藏集\"],\"7Q1KKN\":[\"來源路徑\"],\"7aECQB\":[\"無效或已過期的連結\"],\"7nGhhM\":[\"你在想什麼?\"],\"7p5kLi\":[\"儀表板\"],\"7vhWI8\":[\"新密碼\"],\"87a/t/\":[\"標籤\"],\"8ZsakT\":[\"密碼\"],\"90Luob\":[[\"count\"],\" 條回覆\"],\"A1taO8\":[\"搜尋\"],\"AeXO77\":[\"帳戶\"],\"AyHO4m\":[\"這個收藏是關於什麼的?\"],\"B373X+\":[\"編輯文章\"],\"B495Gs\":[\"檔案館\"],\"BjF0Jv\":[\"僅限小寫字母、數字和連字符\"],\"D9Oea+\":[\"永久鏈接\"],\"DCKkhU\":[\"當前密碼\"],\"DHhJ7s\":[\"上一頁\"],\"DPfwMq\":[\"完成\"],\"DoJzLz\":[\"收藏夾\"],\"E80cJw\":[\"刪除此媒體將永久從存儲中移除它。\"],\"EEYbdt\":[\"發佈\"],\"EGwzOK\":[\"完成設置\"],\"EkH9pt\":[\"更新\"],\"FGrimz\":[\"新帖子\"],\"FkMol5\":[\"精選\"],\"Fxf4jq\":[\"描述(可選)\"],\"GA5A5H\":[\"刪除收藏夾\"],\"GX2VMa\":[\"建立您的管理員帳戶。\"],\"GbVAnd\":[\"此密碼重設連結無效或已過期。請生成一個新的連結。\"],\"GorKul\":[\"歡迎來到 Jant\"],\"GrZ6fH\":[\"新頁面\"],\"GxkJXS\":[\"上傳中...\"],\"HfyyXl\":[\"My Blog\"],\"HiETwV\":[\"安靜(正常)\"],\"Hzi9AA\":[\"未找到任何帖子。\"],\"I6gXOa\":[\"路徑\"],\"I8hDlV\":[\"至少需要 1 張圖片才能發佈圖片帖子。\"],\"IUwGEM\":[\"保存更改\"],\"IagCbF\":[\"網址\"],\"J4FNfC\":[\"此集合中沒有帖子。\"],\"JIBC/T\":[\"Supported formats: JPEG, PNG, GIF, WebP, SVG. Max size: 10MB.\"],\"Jed1wB\":[\"需要幫助嗎?請訪問<0>文檔</0>。\"],\"JiP4aa\":[\"已發佈的頁面可以通過其路徑訪問。草稿不可見。\"],\"K9NcLu\":[\"使用此 URL 將媒體嵌入到您的帖子中。\"],\"KbS2K9\":[\"重設密碼\"],\"KiJn9B\":[\"備註\"],\"KmGXnO\":[\"Are you sure you want to delete this post? This cannot be undone.\"],\"L85WcV\":[\"縮略名\"],\"LkvLQe\":[\"尚未有頁面。\"],\"M1RvTd\":[\"點擊圖片以查看完整大小\"],\"M8kJqa\":[\"草稿\"],\"M9xgHy\":[\"重定向\"],\"MHrjPM\":[\"標題\"],\"MWBOxm\":[\"收藏(可選)\"],\"MZbQHL\":[\"未找到結果。\"],\"Mhf/H/\":[\"建立重定向\"],\"MqghUt\":[\"搜尋帖子...\"],\"N40H+G\":[\"所有\"],\"O3oNi5\":[\"電子郵件\"],\"OCNZaU\":[\"重定向來源的路徑\"],\"ODiSoW\":[\"尚未有帖子。\"],\"ONWvwQ\":[\"上傳\"],\"Pbm2/N\":[\"創建收藏夾\"],\"QEbNBb\":[\"路徑(例如 /archive)或完整網址(例如 https://example.com)\"],\"RDjuBN\":[\"Setup\"],\"Rj01Fz\":[\"連結\"],\"RwGhWy\":[\"包含 \",[\"count\"],\" 則帖子的主題\"],\"SJmfuf\":[\"網站名稱\"],\"ST+lN2\":[\"尚未上傳任何媒體。\"],\"Tt5T6+\":[\"文章\"],\"TxE+Mj\":[\"1 條回覆\"],\"Tz0i8g\":[\"設定\"],\"U5v6Gh\":[\"編輯頁面\"],\"UDMjsP\":[\"快速操作\"],\"UGT5vp\":[\"保存設定\"],\"UxKoFf\":[\"導航\"],\"VUSy8D\":[\"Search failed. Please try again.\"],\"VhMDMg\":[\"更改密碼\"],\"WDcQq9\":[\"不公開\"],\"Weq9zb\":[\"一般設定\"],\"WmZ/rP\":[\"到路徑\"],\"Y+7JGK\":[\"創建頁面\"],\"Z3FXyt\":[\"載入中...\"],\"ZQKLI1\":[\"危險區域\"],\"ZhhOwV\":[\"引用\"],\"aAIQg2\":[\"外觀\"],\"aaGV/9\":[\"新連結\"],\"an5hVd\":[\"圖片\"],\"b+/jO6\":[\"301(永久)\"],\"bHYIks\":[\"登出\"],\"biOepV\":[\"← Back to home\"],\"cnGeoo\":[\"刪除\"],\"dEgA5A\":[\"取消\"],\"e6Jr7Q\":[\"← 返回收藏夾\"],\"ePK91l\":[\"編輯\"],\"eWLklq\":[\"引用\"],\"eneWvv\":[\"草稿\"],\"er8+x7\":[\"示範帳戶已預填。只需點擊登入。\"],\"f6e0Ry\":[\"文章\"],\"fG7BxZ\":[\"Upload images via the API: POST /api/upload with a file form field.\"],\"fttd2R\":[\"我的收藏\"],\"gDx5MG\":[\"編輯連結\"],\"hG89Ed\":[\"圖片\"],\"hWOZIv\":[\"請輸入您的新密碼。\"],\"hXzOVo\":[\"下一頁\"],\"he3ygx\":[\"複製\"],\"iH8pgl\":[\"返回\"],\"ig4hg2\":[\"Let's set up your site.\"],\"jpctdh\":[\"查看\"],\"k1ifdL\":[\"處理中...\"],\"kd7eBB\":[\"建立連結\"],\"mTOYla\":[\"View all posts →\"],\"n1ekoW\":[\"登入\"],\"oJFOZk\":[\"來源名稱(選填)\"],\"oYPBa0\":[\"更新頁面\"],\"p2/GCq\":[\"確認密碼\"],\"pRhYH2\":[\"收藏中的帖子 (\",[\"count\"],\")\"],\"pZq3aX\":[\"上傳失敗。請再試一次。\"],\"qMyM2u\":[\"來源網址(選填)\"],\"qiXmlF\":[\"添加媒體\"],\"r1MpXi\":[\"安靜\"],\"rFmBG3\":[\"顏色主題\"],\"rdUucN\":[\"預覽\"],\"rzNUSl\":[\"包含 1 則貼文的主題\"],\"sGajR7\":[\"線程開始\"],\"smzF8S\":[\"顯示 \",[\"remainingCount\"],\" 個更多 \",[\"0\"]],\"ssqvZi\":[\"保存個人資料\"],\"t/YqKh\":[\"移除\"],\"tfrt7B\":[\"未配置任何重定向。\"],\"tiq7kl\":[\"頁面 \",[\"page\"]],\"u2f7vd\":[\"網站描述\"],\"u3wRF+\":[\"已發佈\"],\"u6Hp4N\":[\"Markdown\"],\"uAQUqI\":[\"狀態\"],\"vERlcd\":[\"個人資料\"],\"vXIe7J\":[\"語言\"],\"vzU4k9\":[\"新收藏集\"],\"wEF6Ix\":[\"目的地路徑或 URL\"],\"wK4OTM\":[\"標題(選填)\"],\"wM5UXj\":[\"刪除媒體\"],\"wRR604\":[\"頁面\"],\"wdGjkd\":[\"未配置導航連結。\"],\"wja8aL\":[\"無標題\"],\"x+doid\":[\"圖片會自動優化:調整大小至最大 1920 像素,轉換為 WebP 格式,並去除元數據。\"],\"x0mzE0\":[\"創建你的第一篇帖子\"],\"x4RuFo\":[\"Back to home\"],\"xYilR2\":[\"媒體\"],\"y28hnO\":[\"文章\"],\"yQ2kGp\":[\"載入更多\"],\"yjkELF\":[\"確認新密碼\"],\"yzF66j\":[\"連結\"],\"z8ajIE\":[\"找到 1 個結果\"],\"zH6KqE\":[\"找到 \",[\"count\"],\" 個結果\"]}")as Messages;
package/src/index.ts CHANGED
@@ -23,11 +23,16 @@ export type {
23
23
  PostCollection,
24
24
  Redirect,
25
25
  Setting,
26
+ NavigationLink,
26
27
  CreatePost,
27
28
  UpdatePost,
28
29
  JantConfig,
29
30
  JantTheme,
30
31
  ThemeComponents,
32
+ TimelineCardProps,
33
+ ThreadPreviewProps,
34
+ TimelineItemData,
35
+ TimelineFeedProps,
31
36
  } from "./types.js";
32
37
 
33
38
  export {
@@ -0,0 +1,107 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ resolveCardComponent,
4
+ resolveThreadPreview,
5
+ resolveTimelineFeed,
6
+ } from "../theme-components.js";
7
+ import type {
8
+ ThemeComponents,
9
+ TimelineCardProps,
10
+ ThreadPreviewProps,
11
+ TimelineFeedProps,
12
+ PostType,
13
+ } from "../../types.js";
14
+ import type { FC } from "hono/jsx";
15
+
16
+ // Create simple mock components for testing (avoids importing .tsx files with i18n)
17
+ const MockNoteCard: FC<TimelineCardProps> = () => null;
18
+ const MockArticleCard: FC<TimelineCardProps> = () => null;
19
+ const MockLinkCard: FC<TimelineCardProps> = () => null;
20
+ const MockQuoteCard: FC<TimelineCardProps> = () => null;
21
+ const MockImageCard: FC<TimelineCardProps> = () => null;
22
+ const MockThreadPreview: FC<ThreadPreviewProps> = () => null;
23
+ const MockTimelineFeed: FC<TimelineFeedProps> = () => null;
24
+
25
+ const DEFAULT_CARD_MAP: Record<PostType, FC<TimelineCardProps>> = {
26
+ note: MockNoteCard,
27
+ article: MockArticleCard,
28
+ link: MockLinkCard,
29
+ quote: MockQuoteCard,
30
+ image: MockImageCard,
31
+ page: MockNoteCard,
32
+ };
33
+
34
+ describe("theme-components", () => {
35
+ describe("resolveCardComponent", () => {
36
+ it("returns default NoteCard for note type", () => {
37
+ expect(resolveCardComponent("note", DEFAULT_CARD_MAP)).toBe(MockNoteCard);
38
+ });
39
+
40
+ it("returns default ArticleCard for article type", () => {
41
+ expect(resolveCardComponent("article", DEFAULT_CARD_MAP)).toBe(
42
+ MockArticleCard,
43
+ );
44
+ });
45
+
46
+ it("returns default LinkCard for link type", () => {
47
+ expect(resolveCardComponent("link", DEFAULT_CARD_MAP)).toBe(MockLinkCard);
48
+ });
49
+
50
+ it("returns default QuoteCard for quote type", () => {
51
+ expect(resolveCardComponent("quote", DEFAULT_CARD_MAP)).toBe(
52
+ MockQuoteCard,
53
+ );
54
+ });
55
+
56
+ it("returns default ImageCard for image type", () => {
57
+ expect(resolveCardComponent("image", DEFAULT_CARD_MAP)).toBe(
58
+ MockImageCard,
59
+ );
60
+ });
61
+
62
+ it("returns NoteCard as fallback for page type", () => {
63
+ expect(resolveCardComponent("page", DEFAULT_CARD_MAP)).toBe(MockNoteCard);
64
+ });
65
+
66
+ it("returns theme override when provided", () => {
67
+ const CustomNote: FC<TimelineCardProps> = () => null;
68
+ const overrides: ThemeComponents = { NoteCard: CustomNote };
69
+ expect(resolveCardComponent("note", DEFAULT_CARD_MAP, overrides)).toBe(
70
+ CustomNote,
71
+ );
72
+ });
73
+
74
+ it("returns default when theme has no override for type", () => {
75
+ const overrides: ThemeComponents = {};
76
+ expect(resolveCardComponent("article", DEFAULT_CARD_MAP, overrides)).toBe(
77
+ MockArticleCard,
78
+ );
79
+ });
80
+ });
81
+
82
+ describe("resolveThreadPreview", () => {
83
+ it("returns default ThreadPreview when no override", () => {
84
+ expect(resolveThreadPreview(MockThreadPreview)).toBe(MockThreadPreview);
85
+ });
86
+
87
+ it("returns theme override when provided", () => {
88
+ const Custom: FC<ThreadPreviewProps> = () => null;
89
+ expect(
90
+ resolveThreadPreview(MockThreadPreview, { ThreadPreview: Custom }),
91
+ ).toBe(Custom);
92
+ });
93
+ });
94
+
95
+ describe("resolveTimelineFeed", () => {
96
+ it("returns default TimelineFeed when no override", () => {
97
+ expect(resolveTimelineFeed(MockTimelineFeed)).toBe(MockTimelineFeed);
98
+ });
99
+
100
+ it("returns theme override when provided", () => {
101
+ const Custom: FC<TimelineFeedProps> = () => null;
102
+ expect(
103
+ resolveTimelineFeed(MockTimelineFeed, { TimelineFeed: Custom }),
104
+ ).toBe(Custom);
105
+ });
106
+ });
107
+ });
package/src/lib/image.ts CHANGED
@@ -85,12 +85,12 @@ export function getImageUrl(
85
85
  * @example
86
86
  * ```ts
87
87
  * // Without R2 public URL - uses UUID with extension
88
- * getMediaUrl("01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "uploads/file.webp");
88
+ * getMediaUrl("01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "media/2025/01/01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f.webp");
89
89
  * // Returns: "/media/01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f.webp"
90
90
  *
91
91
  * // With R2 public URL - uses direct CDN
92
- * getMediaUrl("01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "uploads/file.webp", "https://cdn.example.com");
93
- * // Returns: "https://cdn.example.com/uploads/file.webp"
92
+ * getMediaUrl("01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "media/2025/01/01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f.webp", "https://cdn.example.com");
93
+ * // Returns: "https://cdn.example.com/media/2025/01/01902a9f-1a2b-7c3d-8e4f-5a6b7c8d9e0f.webp"
94
94
  * ```
95
95
  */
96
96
  export function getMediaUrl(