@jant/core 0.3.35 → 0.3.37

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 (307) hide show
  1. package/bin/commands/export.js +1 -1
  2. package/bin/commands/import-site.js +529 -0
  3. package/bin/commands/reset-password.js +3 -2
  4. package/dist/client/assets/heic-to-DIRPI3VF.js +1 -0
  5. package/dist/client/assets/module-RjUF93sV.js +716 -0
  6. package/dist/client/assets/native-48B9X9Wg.js +1 -0
  7. package/dist/client/assets/url-FWFqPJPb.js +1 -0
  8. package/dist/client/client.css +1 -1
  9. package/dist/client/client.js +4564 -3013
  10. package/dist/index.js +12885 -8161
  11. package/package.json +23 -6
  12. package/src/__tests__/helpers/app.ts +10 -10
  13. package/src/__tests__/helpers/db.ts +91 -87
  14. package/src/app.tsx +157 -31
  15. package/src/auth.ts +20 -2
  16. package/src/client/archive-nav.js +187 -0
  17. package/src/client/audio-player.ts +478 -0
  18. package/src/client/audio-processor.ts +84 -0
  19. package/src/{lib → client}/avatar-upload.ts +4 -3
  20. package/src/{lib → client}/collection-form-bridge.ts +2 -2
  21. package/src/{ui → client}/components/__tests__/jant-collection-form.test.ts +26 -9
  22. package/src/client/components/__tests__/jant-compose-dialog.test.ts +1140 -0
  23. package/src/client/components/__tests__/jant-compose-editor.test.ts +504 -0
  24. package/src/{ui → client}/components/__tests__/jant-post-form.test.ts +37 -17
  25. package/src/{ui → client}/components/__tests__/jant-settings-avatar.test.ts +2 -2
  26. package/src/{ui → client}/components/__tests__/jant-settings-general.test.ts +3 -3
  27. package/src/client/components/collection-sidebar-types.ts +43 -0
  28. package/src/{ui → client}/components/collection-types.ts +3 -4
  29. package/src/client/components/compose-types.ts +174 -0
  30. package/src/client/components/jant-collection-form.ts +667 -0
  31. package/src/client/components/jant-collection-sidebar.ts +805 -0
  32. package/src/client/components/jant-compose-dialog.ts +2161 -0
  33. package/src/client/components/jant-compose-editor.ts +1813 -0
  34. package/src/client/components/jant-compose-fullscreen.ts +283 -0
  35. package/src/client/components/jant-media-lightbox.ts +259 -0
  36. package/src/{ui → client}/components/jant-nav-manager.ts +97 -298
  37. package/src/{ui → client}/components/jant-post-form.ts +141 -12
  38. package/src/client/components/jant-post-menu.ts +1019 -0
  39. package/src/{ui → client}/components/jant-settings-avatar.ts +3 -3
  40. package/src/{ui → client}/components/jant-settings-general.ts +38 -4
  41. package/src/client/components/jant-text-preview.ts +232 -0
  42. package/src/{ui → client}/components/nav-manager-types.ts +6 -18
  43. package/src/{ui → client}/components/post-form-template.ts +137 -38
  44. package/src/{ui → client}/components/post-form-types.ts +15 -4
  45. package/src/client/compose-bridge.ts +583 -0
  46. package/src/{lib → client}/image-processor.ts +26 -8
  47. package/src/client/lazy-slugify.ts +51 -0
  48. package/src/client/media-metadata.ts +247 -0
  49. package/src/client/multipart-upload.ts +160 -0
  50. package/src/{lib → client}/nav-manager-bridge.ts +1 -1
  51. package/src/{lib → client}/post-form-bridge.ts +53 -2
  52. package/src/{lib → client}/settings-bridge.ts +3 -15
  53. package/src/client/thread-context.ts +140 -0
  54. package/src/client/tiptap/bubble-menu.ts +205 -0
  55. package/src/client/tiptap/create-editor.ts +86 -0
  56. package/src/client/tiptap/exitable-marks.ts +73 -0
  57. package/src/client/tiptap/extensions.ts +65 -0
  58. package/src/client/tiptap/image-node.ts +482 -0
  59. package/src/client/tiptap/link-toolbar.ts +371 -0
  60. package/src/client/tiptap/more-break.ts +50 -0
  61. package/src/client/tiptap/paste-image.ts +129 -0
  62. package/src/client/tiptap/slash-commands.ts +438 -0
  63. package/src/{lib → client}/toast.ts +101 -3
  64. package/src/client/types/sortablejs.d.ts +44 -0
  65. package/src/client/upload-with-metadata.ts +54 -0
  66. package/src/client/video-processor.ts +207 -0
  67. package/src/client.ts +27 -17
  68. package/src/db/__tests__/migrations.test.ts +118 -0
  69. package/src/db/index.ts +52 -0
  70. package/src/db/migrations/0000_baseline.sql +269 -0
  71. package/src/db/migrations/0001_fts_setup.sql +31 -0
  72. package/src/db/migrations/meta/0000_snapshot.json +703 -119
  73. package/src/db/migrations/meta/0001_snapshot.json +1337 -0
  74. package/src/db/migrations/meta/_journal.json +4 -39
  75. package/src/db/schema.ts +409 -140
  76. package/src/i18n/__tests__/detect.test.ts +115 -0
  77. package/src/i18n/context.tsx +2 -2
  78. package/src/i18n/detect.ts +85 -1
  79. package/src/i18n/i18n.ts +1 -1
  80. package/src/i18n/index.ts +2 -1
  81. package/src/i18n/locales/en.po +783 -1087
  82. package/src/i18n/locales/en.ts +1 -1
  83. package/src/i18n/locales/zh-Hans.po +867 -812
  84. package/src/i18n/locales/zh-Hans.ts +1 -1
  85. package/src/i18n/locales/zh-Hant.po +878 -823
  86. package/src/i18n/locales/zh-Hant.ts +1 -1
  87. package/src/i18n/middleware.ts +6 -0
  88. package/src/index.ts +5 -7
  89. package/src/lib/__tests__/blurhash-placeholder.test.ts +75 -0
  90. package/src/lib/__tests__/constants.test.ts +0 -1
  91. package/src/lib/__tests__/markdown-to-tiptap.test.ts +358 -0
  92. package/src/lib/__tests__/nanoid.test.ts +26 -0
  93. package/src/lib/__tests__/resolve-config.test.ts +2 -2
  94. package/src/lib/__tests__/schemas.test.ts +186 -65
  95. package/src/lib/__tests__/slug.test.ts +126 -0
  96. package/src/lib/__tests__/sse.test.ts +6 -6
  97. package/src/lib/__tests__/summary.test.ts +264 -0
  98. package/src/lib/__tests__/theme.test.ts +1 -1
  99. package/src/lib/__tests__/timeline.test.ts +33 -30
  100. package/src/lib/__tests__/tiptap-to-markdown.test.ts +346 -0
  101. package/src/lib/__tests__/url.test.ts +2 -2
  102. package/src/lib/__tests__/view.test.ts +140 -65
  103. package/src/lib/blurhash-placeholder.ts +102 -0
  104. package/src/lib/constants.ts +3 -1
  105. package/src/lib/emoji-catalog.ts +963 -0
  106. package/src/lib/errors.ts +11 -8
  107. package/src/lib/feed.ts +77 -31
  108. package/src/lib/html.ts +2 -1
  109. package/src/lib/icon-catalog.ts +5033 -1
  110. package/src/lib/icons.ts +3 -2
  111. package/src/lib/index.ts +0 -1
  112. package/src/lib/markdown-to-tiptap.ts +286 -0
  113. package/src/lib/media-helpers.ts +22 -12
  114. package/src/lib/nanoid.ts +29 -0
  115. package/src/lib/navigation.ts +1 -1
  116. package/src/lib/render.tsx +24 -5
  117. package/src/lib/resolve-config.ts +13 -2
  118. package/src/lib/schemas.ts +226 -58
  119. package/src/lib/search-snippet.ts +34 -0
  120. package/src/lib/slug.ts +96 -0
  121. package/src/lib/sse.ts +6 -6
  122. package/src/lib/storage.ts +115 -7
  123. package/src/lib/summary.ts +158 -0
  124. package/src/lib/theme.ts +11 -8
  125. package/src/lib/timeline.ts +76 -34
  126. package/src/lib/tiptap-render.ts +191 -0
  127. package/src/lib/tiptap-to-markdown.ts +305 -0
  128. package/src/lib/upload.ts +263 -14
  129. package/src/lib/url.ts +37 -22
  130. package/src/lib/view.ts +236 -55
  131. package/src/middleware/__tests__/auth.test.ts +191 -11
  132. package/src/middleware/__tests__/onboarding.test.ts +12 -10
  133. package/src/middleware/auth.ts +63 -9
  134. package/src/middleware/error-handler.ts +3 -3
  135. package/src/middleware/onboarding.ts +1 -1
  136. package/src/middleware/secure-headers.ts +40 -0
  137. package/src/preset.css +83 -2
  138. package/src/routes/__tests__/compose.test.ts +17 -24
  139. package/src/routes/api/__tests__/collections.test.ts +109 -61
  140. package/src/routes/api/__tests__/nav-items.test.ts +46 -29
  141. package/src/routes/api/__tests__/posts.test.ts +132 -68
  142. package/src/routes/api/__tests__/search.test.ts +15 -2
  143. package/src/routes/api/__tests__/upload-multipart.test.ts +534 -0
  144. package/src/routes/api/collections.ts +57 -31
  145. package/src/routes/api/custom-urls.ts +80 -0
  146. package/src/routes/api/export.ts +31 -0
  147. package/src/routes/api/nav-items.ts +23 -19
  148. package/src/routes/api/posts.ts +81 -62
  149. package/src/routes/api/search.ts +3 -4
  150. package/src/routes/api/upload-multipart.ts +245 -0
  151. package/src/routes/api/upload.ts +92 -24
  152. package/src/routes/auth/__tests__/setup.test.ts +20 -60
  153. package/src/routes/auth/reset.tsx +5 -4
  154. package/src/routes/auth/setup.tsx +39 -31
  155. package/src/routes/auth/signin.tsx +13 -14
  156. package/src/routes/compose.tsx +27 -63
  157. package/src/routes/dash/__tests__/settings-avatar.test.ts +44 -9
  158. package/src/routes/dash/custom-urls.tsx +414 -0
  159. package/src/routes/dash/settings.tsx +475 -99
  160. package/src/routes/feed/__tests__/rss.test.ts +22 -23
  161. package/src/routes/feed/rss.ts +6 -2
  162. package/src/routes/feed/sitemap.ts +2 -12
  163. package/src/routes/pages/__tests__/collections.test.ts +5 -6
  164. package/src/routes/pages/__tests__/featured.test.ts +36 -18
  165. package/src/routes/pages/archive.tsx +177 -37
  166. package/src/routes/pages/collection.tsx +43 -14
  167. package/src/routes/pages/collections.tsx +11 -2
  168. package/src/routes/pages/featured.tsx +27 -3
  169. package/src/routes/pages/home.tsx +15 -14
  170. package/src/routes/pages/latest.tsx +1 -11
  171. package/src/routes/pages/new.tsx +39 -0
  172. package/src/routes/pages/page.tsx +95 -49
  173. package/src/routes/pages/search.tsx +1 -1
  174. package/src/services/__tests__/api-token.test.ts +135 -0
  175. package/src/services/__tests__/collection.test.ts +275 -227
  176. package/src/services/__tests__/custom-url.test.ts +213 -0
  177. package/src/services/__tests__/media.test.ts +162 -22
  178. package/src/services/__tests__/navigation.test.ts +109 -68
  179. package/src/services/__tests__/post-timeline.test.ts +205 -32
  180. package/src/services/__tests__/post.test.ts +800 -230
  181. package/src/services/__tests__/search.test.ts +67 -10
  182. package/src/services/__tests__/settings.test.ts +3 -3
  183. package/src/services/api-token.ts +166 -0
  184. package/src/services/auth.ts +17 -2
  185. package/src/services/collection.ts +397 -131
  186. package/src/services/custom-url.ts +188 -0
  187. package/src/services/export.ts +802 -0
  188. package/src/services/index.ts +26 -19
  189. package/src/services/media.ts +100 -22
  190. package/src/services/navigation.ts +158 -47
  191. package/src/services/path.ts +339 -0
  192. package/src/services/post.ts +764 -172
  193. package/src/services/search.ts +161 -74
  194. package/src/services/settings.ts +6 -2
  195. package/src/styles/components.css +293 -62
  196. package/src/styles/tokens.css +93 -5
  197. package/src/styles/ui.css +4349 -766
  198. package/src/types/bindings.ts +8 -0
  199. package/src/types/config.ts +34 -4
  200. package/src/types/constants.ts +17 -2
  201. package/src/types/entities.ts +83 -37
  202. package/src/types/operations.ts +20 -27
  203. package/src/types/props.ts +52 -17
  204. package/src/types/views.ts +48 -24
  205. package/src/ui/color-themes.ts +133 -23
  206. package/src/ui/compose/ComposeDialog.tsx +255 -16
  207. package/src/ui/compose/ComposePrompt.tsx +1 -1
  208. package/src/ui/dash/CrudPageHeader.tsx +1 -1
  209. package/src/ui/dash/ListItemRow.tsx +1 -1
  210. package/src/ui/dash/StatusBadge.tsx +12 -2
  211. package/src/ui/dash/appearance/AdvancedContent.tsx +71 -59
  212. package/src/ui/dash/appearance/ColorThemeContent.tsx +48 -33
  213. package/src/ui/dash/appearance/FontThemeContent.tsx +65 -73
  214. package/src/ui/dash/appearance/NavigationContent.tsx +106 -135
  215. package/src/ui/dash/index.ts +0 -3
  216. package/src/ui/dash/settings/AccountContent.tsx +87 -146
  217. package/src/ui/dash/settings/AccountMenuContent.tsx +147 -0
  218. package/src/ui/dash/settings/ApiTokensContent.tsx +232 -0
  219. package/src/ui/dash/settings/AvatarContent.tsx +78 -0
  220. package/src/ui/dash/settings/GeneralContent.tsx +3 -62
  221. package/src/ui/dash/settings/SessionsContent.tsx +159 -0
  222. package/src/ui/dash/settings/SettingsRootContent.tsx +266 -0
  223. package/src/ui/feed/LinkCard.tsx +89 -40
  224. package/src/ui/feed/NoteCard.tsx +39 -25
  225. package/src/ui/feed/PostStatusBadges.tsx +67 -0
  226. package/src/ui/feed/QuoteCard.tsx +38 -23
  227. package/src/ui/feed/ThreadPreview.tsx +90 -26
  228. package/src/ui/feed/TimelineFeed.tsx +3 -2
  229. package/src/ui/feed/TimelineItem.tsx +15 -6
  230. package/src/ui/feed/__tests__/thread-preview.test.ts +107 -0
  231. package/src/ui/feed/thread-preview-state.ts +61 -0
  232. package/src/ui/font-themes.ts +2 -2
  233. package/src/ui/layouts/BaseLayout.tsx +2 -2
  234. package/src/ui/layouts/SiteLayout.tsx +116 -103
  235. package/src/ui/pages/ArchivePage.tsx +923 -95
  236. package/src/ui/pages/CollectionPage.tsx +6 -35
  237. package/src/ui/pages/CollectionsPage.tsx +2 -1
  238. package/src/ui/pages/ComposePage.tsx +54 -0
  239. package/src/ui/pages/FeaturedPage.tsx +2 -1
  240. package/src/ui/pages/HomePage.tsx +1 -1
  241. package/src/ui/pages/PostPage.tsx +30 -45
  242. package/src/ui/pages/SearchPage.tsx +182 -38
  243. package/src/ui/shared/AdminBreadcrumb.tsx +29 -0
  244. package/src/ui/shared/CollectionsSidebar.tsx +239 -4
  245. package/src/ui/shared/MediaGallery.tsx +475 -41
  246. package/src/ui/shared/PostFooter.tsx +204 -0
  247. package/src/ui/shared/StarRating.tsx +27 -0
  248. package/src/ui/shared/__tests__/format-chars.test.ts +35 -0
  249. package/src/ui/shared/index.ts +0 -1
  250. package/src/db/migrations/0000_square_wallflower.sql +0 -118
  251. package/src/db/migrations/0001_add_search_fts.sql +0 -34
  252. package/src/db/migrations/0002_add_media_attachments.sql +0 -3
  253. package/src/db/migrations/0003_add_navigation_links.sql +0 -8
  254. package/src/db/migrations/0004_add_storage_provider.sql +0 -3
  255. package/src/db/migrations/0005_v2_schema_migration.sql +0 -268
  256. package/src/db/migrations/0006_rename_slug_to_path.sql +0 -5
  257. package/src/db/migrations/0007_post_collections_m2m.sql +0 -94
  258. package/src/db/migrations/0008_add_collection_dividers.sql +0 -8
  259. package/src/db/migrations/0009_drop_collection_show_divider.sql +0 -2
  260. package/src/db/migrations/0010_add_performance_indexes.sql +0 -16
  261. package/src/db/migrations/0011_add_path_registry.sql +0 -23
  262. package/src/db/migrations/meta/0003_snapshot.json +0 -821
  263. package/src/lib/__tests__/sqid.test.ts +0 -65
  264. package/src/lib/collections-reorder.ts +0 -28
  265. package/src/lib/compose-bridge.ts +0 -280
  266. package/src/lib/media-upload.ts +0 -148
  267. package/src/lib/sqid.ts +0 -79
  268. package/src/routes/api/__tests__/pages.test.ts +0 -218
  269. package/src/routes/api/pages.ts +0 -73
  270. package/src/routes/dash/__tests__/pages.test.ts +0 -226
  271. package/src/routes/dash/appearance.tsx +0 -240
  272. package/src/routes/dash/collections.tsx +0 -211
  273. package/src/routes/dash/index.tsx +0 -103
  274. package/src/routes/dash/media.tsx +0 -132
  275. package/src/routes/dash/pages.tsx +0 -239
  276. package/src/routes/dash/posts.tsx +0 -334
  277. package/src/routes/dash/redirects.tsx +0 -257
  278. package/src/routes/pages/post.tsx +0 -59
  279. package/src/services/__tests__/page.test.ts +0 -298
  280. package/src/services/__tests__/path-registry.test.ts +0 -165
  281. package/src/services/__tests__/redirect.test.ts +0 -159
  282. package/src/services/page.ts +0 -203
  283. package/src/services/path-registry.ts +0 -160
  284. package/src/services/redirect.ts +0 -97
  285. package/src/types/sortablejs.d.ts +0 -29
  286. package/src/ui/components/__tests__/jant-compose-dialog.test.ts +0 -512
  287. package/src/ui/components/__tests__/jant-compose-editor.test.ts +0 -272
  288. package/src/ui/components/compose-types.ts +0 -75
  289. package/src/ui/components/jant-collection-form.ts +0 -512
  290. package/src/ui/components/jant-compose-dialog.ts +0 -495
  291. package/src/ui/components/jant-compose-editor.ts +0 -814
  292. package/src/ui/dash/PageForm.tsx +0 -185
  293. package/src/ui/dash/PostList.tsx +0 -95
  294. package/src/ui/dash/appearance/AppearanceNav.tsx +0 -60
  295. package/src/ui/dash/collections/CollectionForm.tsx +0 -166
  296. package/src/ui/dash/collections/CollectionsListContent.tsx +0 -146
  297. package/src/ui/dash/collections/IconPickerGrid.tsx +0 -50
  298. package/src/ui/dash/collections/ViewCollectionContent.tsx +0 -103
  299. package/src/ui/dash/media/MediaListContent.tsx +0 -201
  300. package/src/ui/dash/media/ViewMediaContent.tsx +0 -208
  301. package/src/ui/dash/pages/PagesContent.tsx +0 -74
  302. package/src/ui/dash/posts/PostForm.tsx +0 -248
  303. package/src/ui/dash/settings/SettingsNav.tsx +0 -52
  304. package/src/ui/layouts/DashLayout.tsx +0 -165
  305. package/src/ui/pages/SinglePage.tsx +0 -23
  306. package/src/ui/shared/ThreadView.tsx +0 -136
  307. /package/src/{ui → client}/components/settings-types.ts +0 -0
@@ -2,20 +2,32 @@
2
2
  * View Model Types (render-ready, for theme components)
3
3
  */
4
4
 
5
- import type { Format, Status, NavItemType } from "./constants.js";
5
+ import type { Format, Status, Visibility, NavItemType } from "./constants.js";
6
6
  import type { Post, Collection } from "./entities.js";
7
7
 
8
+ /**
9
+ * Render-ready collection tag for display in post footers.
10
+ * Pre-computed at the viewmodel layer -- no lib/ imports needed.
11
+ */
12
+ export interface CollectionTagView {
13
+ slug: string;
14
+ title: string;
15
+ /** Pre-rendered icon HTML (SVG or emoji span) */
16
+ iconHtml?: string;
17
+ }
18
+
8
19
  /**
9
20
  * Render-ready post data for theme components.
10
21
  * All fields are pre-computed -- no lib/ imports needed.
11
22
  */
12
23
  export interface PostView {
13
24
  // Identity
14
- id: number;
15
- /** Pre-computed permalink: "/{path}" if path set, otherwise "/p/{sqid}" */
25
+ /** UUIDv7 identifier */
26
+ id: string;
27
+ /** Pre-computed permalink: "/{slug}" */
16
28
  permalink: string;
17
- /** Custom URL path, if set. Supports multi-level paths (e.g. "2024/my-post") */
18
- path?: string;
29
+ /** Post slug */
30
+ slug: string;
19
31
 
20
32
  // Content
21
33
  title?: string;
@@ -35,8 +47,9 @@ export interface PostView {
35
47
  // Metadata
36
48
  format: Format;
37
49
  status: Status;
38
- featured: boolean;
50
+ visibility: Visibility;
39
51
  pinned: boolean;
52
+ featured: boolean;
40
53
  rating?: number;
41
54
 
42
55
  // Time -- pre-formatted
@@ -54,27 +67,23 @@ export interface PostView {
54
67
  // Media -- URLs pre-computed
55
68
  media: MediaView[];
56
69
 
70
+ // Collections this post belongs to
71
+ collections: CollectionTagView[];
72
+
57
73
  // Thread context
58
- replyToId?: number;
59
- threadRootId?: number;
74
+ /** UUIDv7 of the parent post */
75
+ replyToId?: string;
76
+ /** UUIDv7 of the thread root post */
77
+ threadRootId?: string;
78
+ /** Permalink of the thread root post (for "in thread" link on featured replies) */
79
+ threadRootPermalink?: string;
80
+ /** Whether this post is the last (most recent) in its thread. Controls reply button visibility. */
81
+ isLastInThread: boolean;
60
82
 
61
83
  // Raw content (for forms/editing, not typical theme use)
62
84
  body?: string;
63
85
  }
64
86
 
65
- /**
66
- * Render-ready page data for theme components.
67
- */
68
- export interface PageView {
69
- id: number;
70
- slug: string;
71
- title?: string;
72
- bodyHtml?: string;
73
- status: Status;
74
- createdAt: string;
75
- updatedAt: string;
76
- }
77
-
78
87
  /**
79
88
  * Render-ready media data for theme components.
80
89
  * URLs are pre-computed -- no lib/ imports needed.
@@ -90,6 +99,12 @@ export interface MediaView {
90
99
  width?: number;
91
100
  height?: number;
92
101
  size?: number;
102
+ blurhash?: string;
103
+ waveform?: string;
104
+ posterUrl?: string;
105
+ originalName?: string;
106
+ summary?: string;
107
+ chars?: number;
93
108
  }
94
109
 
95
110
  /**
@@ -97,11 +112,11 @@ export interface MediaView {
97
112
  * Active/external state pre-computed.
98
113
  */
99
114
  export interface NavItemView {
100
- id: number;
115
+ /** UUIDv7 identifier */
116
+ id: string;
101
117
  type: NavItemType;
102
118
  label: string;
103
119
  url: string;
104
- pageId?: number;
105
120
  /** Pre-computed based on currentPath */
106
121
  isActive: boolean;
107
122
  /** Pre-computed: starts with http(s):// */
@@ -125,7 +140,12 @@ export interface SearchResult {
125
140
  export interface SearchResultView {
126
141
  post: PostView;
127
142
  rank: number;
143
+ /** FTS5 snippet from body_text column with <mark> tags */
128
144
  snippet?: string;
145
+ /** Title with matched query terms wrapped in <mark> */
146
+ titleHighlighted?: string;
147
+ /** quoteText (truncated) with matched query terms wrapped in <mark> */
148
+ quoteHighlighted?: string;
129
149
  }
130
150
 
131
151
  /**
@@ -134,7 +154,8 @@ export interface SearchResultView {
134
154
  export interface TimelineItemView {
135
155
  post: PostView;
136
156
  threadPreview?: {
137
- replies: PostView[];
157
+ latestReply: PostView;
158
+ parentReply?: PostView;
138
159
  totalReplyCount: number;
139
160
  };
140
161
  }
@@ -167,4 +188,7 @@ export interface SiteLayoutProps {
167
188
  showHeaderAvatar?: boolean;
168
189
  siteFooterHtml?: string;
169
190
  sidebar?: import("hono/jsx").Child;
191
+ uploadMaxFileSize?: number;
192
+ showComposeDialog?: boolean;
193
+ showHeader?: boolean;
170
194
  }
@@ -15,7 +15,7 @@ export interface ColorTheme {
15
15
  name: string;
16
16
  /** CSS variable overrides for :root (light mode) */
17
17
  light: Record<string, string>;
18
- /** CSS variable overrides for .dark (dark mode) */
18
+ /** CSS variable overrides for dark mode (prefers-color-scheme: dark) */
19
19
  dark: Record<string, string>;
20
20
  /** Preview colors (hex) for theme picker cards */
21
21
  preview: {
@@ -28,32 +28,55 @@ export interface ColorTheme {
28
28
  };
29
29
  }
30
30
 
31
+ interface ThemeModeColors {
32
+ bg: string;
33
+ fg: string;
34
+ primary: string;
35
+ primaryFg: string;
36
+ muted: string;
37
+ mutedFg: string;
38
+ border: string;
39
+ /** Destructive action color (defaults to BaseCoat red) */
40
+ destructive?: string;
41
+ /** Success indicator color (defaults to preset green) */
42
+ success?: string;
43
+ /** Search highlight background */
44
+ searchMarkBg?: string;
45
+ /** Search highlight text color */
46
+ searchMarkColor?: string;
47
+ /** Admin dashboard background */
48
+ dashBg?: string;
49
+ }
50
+
51
+ /** Default destructive/success colors that harmonize with most themes */
52
+ const DEFAULTS = {
53
+ light: {
54
+ destructive: "oklch(0.577 0.245 27.325)",
55
+ success: "oklch(0.518 0.16 145.071)",
56
+ searchMarkBg: "oklch(0.92 0.14 90 / 0.55)",
57
+ searchMarkColor: "oklch(0.35 0.09 70)",
58
+ dashBg: "oklch(0.97 0.005 80)",
59
+ },
60
+ dark: {
61
+ destructive: "oklch(0.704 0.191 22.216)",
62
+ success: "oklch(0.627 0.194 149.214)",
63
+ searchMarkBg: "oklch(0.45 0.1 85 / 0.5)",
64
+ searchMarkColor: "oklch(0.92 0.08 90)",
65
+ dashBg: "oklch(0.2 0.005 80)",
66
+ },
67
+ };
68
+
31
69
  /**
32
70
  * Create a comprehensive color theme from key colors.
33
71
  * Derives card, popover, muted, secondary, accent, and sidebar variables.
72
+ * Also sets --destructive, --success, --search-mark-*, and --dash-bg.
34
73
  */
35
74
  function defineTheme(opts: {
36
75
  id: string;
37
76
  name: string;
38
77
  preview: ColorTheme["preview"];
39
- light: {
40
- bg: string;
41
- fg: string;
42
- primary: string;
43
- primaryFg: string;
44
- muted: string;
45
- mutedFg: string;
46
- border: string;
47
- };
48
- dark: {
49
- bg: string;
50
- fg: string;
51
- primary: string;
52
- primaryFg: string;
53
- muted: string;
54
- mutedFg: string;
55
- border: string;
56
- };
78
+ light: ThemeModeColors;
79
+ dark: ThemeModeColors;
57
80
  }): ColorTheme {
58
81
  const { light, dark } = opts;
59
82
  return {
@@ -75,6 +98,8 @@ function defineTheme(opts: {
75
98
  "--muted-foreground": light.mutedFg,
76
99
  "--accent": light.muted,
77
100
  "--accent-foreground": light.fg,
101
+ "--destructive": light.destructive ?? DEFAULTS.light.destructive,
102
+ "--success": light.success ?? DEFAULTS.light.success,
78
103
  "--border": light.border,
79
104
  "--input": light.border,
80
105
  "--ring": light.primary,
@@ -86,6 +111,10 @@ function defineTheme(opts: {
86
111
  "--sidebar-accent-foreground": light.fg,
87
112
  "--sidebar-border": light.border,
88
113
  "--sidebar-ring": light.primary,
114
+ "--search-mark-bg": light.searchMarkBg ?? DEFAULTS.light.searchMarkBg,
115
+ "--search-mark-color":
116
+ light.searchMarkColor ?? DEFAULTS.light.searchMarkColor,
117
+ "--dash-bg": light.dashBg ?? DEFAULTS.light.dashBg,
89
118
  },
90
119
  dark: {
91
120
  "--background": dark.bg,
@@ -102,6 +131,8 @@ function defineTheme(opts: {
102
131
  "--muted-foreground": dark.mutedFg,
103
132
  "--accent": dark.muted,
104
133
  "--accent-foreground": dark.fg,
134
+ "--destructive": dark.destructive ?? DEFAULTS.dark.destructive,
135
+ "--success": dark.success ?? DEFAULTS.dark.success,
105
136
  "--border": dark.border,
106
137
  "--input": dark.border,
107
138
  "--ring": dark.primary,
@@ -113,6 +144,10 @@ function defineTheme(opts: {
113
144
  "--sidebar-accent-foreground": dark.fg,
114
145
  "--sidebar-border": dark.border,
115
146
  "--sidebar-ring": dark.primary,
147
+ "--search-mark-bg": dark.searchMarkBg ?? DEFAULTS.dark.searchMarkBg,
148
+ "--search-mark-color":
149
+ dark.searchMarkColor ?? DEFAULTS.dark.searchMarkColor,
150
+ "--dash-bg": dark.dashBg ?? DEFAULTS.dark.dashBg,
116
151
  },
117
152
  };
118
153
  }
@@ -137,6 +172,9 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
137
172
  muted: "oklch(0.94 0.022 95)",
138
173
  mutedFg: "oklch(0.52 0 0)",
139
174
  border: "oklch(0.88 0.025 95)",
175
+ destructive: "oklch(0.55 0.22 25)",
176
+ success: "oklch(0.5 0.14 150)",
177
+ dashBg: "oklch(0.96 0.015 95)",
140
178
  },
141
179
  dark: {
142
180
  bg: "oklch(0.2 0.02 90)",
@@ -146,6 +184,9 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
146
184
  muted: "oklch(0.26 0.018 90)",
147
185
  mutedFg: "oklch(0.62 0.012 95)",
148
186
  border: "oklch(0.32 0.018 90)",
187
+ destructive: "oklch(0.68 0.19 22)",
188
+ success: "oklch(0.62 0.15 150)",
189
+ dashBg: "oklch(0.18 0.015 90)",
149
190
  },
150
191
  }),
151
192
 
@@ -168,6 +209,11 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
168
209
  muted: "oklch(0.93 0.02 75)",
169
210
  mutedFg: "oklch(0.5 0.025 55)",
170
211
  border: "oklch(0.88 0.025 75)",
212
+ destructive: "oklch(0.5 0.2 15)",
213
+ success: "oklch(0.5 0.14 155)",
214
+ searchMarkBg: "oklch(0.88 0.12 75 / 0.6)",
215
+ searchMarkColor: "oklch(0.3 0.06 55)",
216
+ dashBg: "oklch(0.95 0.012 75)",
171
217
  },
172
218
  dark: {
173
219
  bg: "oklch(0.16 0.03 50)",
@@ -177,14 +223,17 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
177
223
  muted: "oklch(0.22 0.025 50)",
178
224
  mutedFg: "oklch(0.62 0.02 75)",
179
225
  border: "oklch(0.28 0.025 50)",
226
+ destructive: "oklch(0.65 0.2 15)",
227
+ success: "oklch(0.62 0.15 155)",
228
+ searchMarkBg: "oklch(0.42 0.1 60 / 0.55)",
229
+ searchMarkColor: "oklch(0.9 0.06 75)",
230
+ dashBg: "oklch(0.14 0.025 50)",
180
231
  },
181
232
  }),
182
233
 
183
- {
234
+ defineTheme({
184
235
  id: "panda",
185
236
  name: "Panda",
186
- light: {},
187
- dark: {},
188
237
  preview: {
189
238
  lightBg: "#ffffff",
190
239
  lightText: "#1e1e1e",
@@ -193,7 +242,31 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
193
242
  darkText: "#fafafa",
194
243
  darkLink: "#eaeaea",
195
244
  },
196
- },
245
+ light: {
246
+ bg: "oklch(1 0 0)",
247
+ fg: "oklch(0.2 0 0)",
248
+ primary: "oklch(0.2 0 0)",
249
+ primaryFg: "oklch(1 0 0)",
250
+ muted: "oklch(0.96 0 0)",
251
+ mutedFg: "oklch(0.5 0 0)",
252
+ border: "oklch(0.9 0 0)",
253
+ destructive: "oklch(0.55 0.22 25)",
254
+ success: "oklch(0.5 0.15 145)",
255
+ dashBg: "oklch(0.97 0 0)",
256
+ },
257
+ dark: {
258
+ bg: "oklch(0.21 0 0)",
259
+ fg: "oklch(0.98 0 0)",
260
+ primary: "oklch(0.93 0 0)",
261
+ primaryFg: "oklch(0.15 0 0)",
262
+ muted: "oklch(0.27 0 0)",
263
+ mutedFg: "oklch(0.65 0 0)",
264
+ border: "oklch(0.33 0 0)",
265
+ destructive: "oklch(0.68 0.18 22)",
266
+ success: "oklch(0.62 0.16 150)",
267
+ dashBg: "oklch(0.18 0 0)",
268
+ },
269
+ }),
197
270
 
198
271
  defineTheme({
199
272
  id: "beach",
@@ -214,6 +287,9 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
214
287
  muted: "oklch(0.93 0.015 85)",
215
288
  mutedFg: "oklch(0.52 0.015 65)",
216
289
  border: "oklch(0.88 0.018 85)",
290
+ destructive: "oklch(0.52 0.2 22)",
291
+ success: "oklch(0.5 0.12 170)",
292
+ dashBg: "oklch(0.95 0.008 85)",
217
293
  },
218
294
  dark: {
219
295
  bg: "oklch(0.27 0.03 210)",
@@ -223,6 +299,9 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
223
299
  muted: "oklch(0.33 0.025 210)",
224
300
  mutedFg: "oklch(0.65 0.015 80)",
225
301
  border: "oklch(0.38 0.02 210)",
302
+ destructive: "oklch(0.68 0.18 20)",
303
+ success: "oklch(0.65 0.12 170)",
304
+ dashBg: "oklch(0.24 0.025 210)",
226
305
  },
227
306
  }),
228
307
 
@@ -245,6 +324,12 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
245
324
  muted: "oklch(0.83 0.035 130)",
246
325
  mutedFg: "oklch(0.48 0.03 140)",
247
326
  border: "oklch(0.79 0.035 130)",
327
+ destructive: "oklch(0.52 0.18 25)",
328
+ // Use blue-teal to differentiate from the green primary
329
+ success: "oklch(0.48 0.1 220)",
330
+ searchMarkBg: "oklch(0.8 0.06 100 / 0.6)",
331
+ searchMarkColor: "oklch(0.3 0.04 130)",
332
+ dashBg: "oklch(0.85 0.028 130)",
248
333
  },
249
334
  dark: {
250
335
  bg: "oklch(0.18 0.02 140)",
@@ -254,6 +339,11 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
254
339
  muted: "oklch(0.24 0.02 140)",
255
340
  mutedFg: "oklch(0.58 0.02 130)",
256
341
  border: "oklch(0.3 0.02 140)",
342
+ destructive: "oklch(0.65 0.17 22)",
343
+ success: "oklch(0.6 0.1 220)",
344
+ searchMarkBg: "oklch(0.4 0.06 110 / 0.55)",
345
+ searchMarkColor: "oklch(0.88 0.04 130)",
346
+ dashBg: "oklch(0.16 0.018 140)",
257
347
  },
258
348
  }),
259
349
 
@@ -276,6 +366,11 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
276
366
  muted: "oklch(0.92 0 0)",
277
367
  mutedFg: "oklch(0.55 0 0)",
278
368
  border: "oklch(0.87 0 0)",
369
+ destructive: "oklch(0.55 0.22 25)",
370
+ success: "oklch(0.5 0.15 145)",
371
+ searchMarkBg: "oklch(0.88 0 0 / 0.7)",
372
+ searchMarkColor: "oklch(0.25 0 0)",
373
+ dashBg: "oklch(0.94 0 0)",
279
374
  },
280
375
  dark: {
281
376
  bg: "oklch(0.18 0 0)",
@@ -285,6 +380,11 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
285
380
  muted: "oklch(0.24 0 0)",
286
381
  mutedFg: "oklch(0.6 0 0)",
287
382
  border: "oklch(0.3 0 0)",
383
+ destructive: "oklch(0.68 0.18 22)",
384
+ success: "oklch(0.62 0.16 150)",
385
+ searchMarkBg: "oklch(0.35 0 0 / 0.6)",
386
+ searchMarkColor: "oklch(0.9 0 0)",
387
+ dashBg: "oklch(0.16 0 0)",
288
388
  },
289
389
  }),
290
390
 
@@ -307,6 +407,11 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
307
407
  muted: "oklch(0.93 0.016 325)",
308
408
  mutedFg: "oklch(0.52 0.015 310)",
309
409
  border: "oklch(0.88 0.016 325)",
410
+ destructive: "oklch(0.55 0.2 15)",
411
+ success: "oklch(0.5 0.14 155)",
412
+ searchMarkBg: "oklch(0.9 0.08 310 / 0.45)",
413
+ searchMarkColor: "oklch(0.3 0.04 300)",
414
+ dashBg: "oklch(0.95 0.01 325)",
310
415
  },
311
416
  dark: {
312
417
  bg: "oklch(0.18 0.025 300)",
@@ -316,6 +421,11 @@ export const BUILTIN_COLOR_THEMES: ColorTheme[] = [
316
421
  muted: "oklch(0.24 0.022 300)",
317
422
  mutedFg: "oklch(0.62 0.012 325)",
318
423
  border: "oklch(0.3 0.022 300)",
424
+ destructive: "oklch(0.68 0.18 18)",
425
+ success: "oklch(0.62 0.15 155)",
426
+ searchMarkBg: "oklch(0.38 0.08 290 / 0.5)",
427
+ searchMarkColor: "oklch(0.9 0.04 325)",
428
+ dashBg: "oklch(0.16 0.02 300)",
319
429
  },
320
430
  }),
321
431
  ];