@jant/core 0.3.27 → 0.3.28
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.
- package/dist/client/client.css +1 -0
- package/dist/client/client.js +31561 -0
- package/dist/index.js +15209 -15
- package/package.json +21 -15
- package/src/__tests__/helpers/app.ts +19 -3
- package/src/__tests__/helpers/db.ts +44 -0
- package/src/__tests__/helpers/lingui-core-macro-mock.ts +33 -0
- package/src/app.tsx +111 -174
- package/src/client.ts +13 -0
- package/src/db/migrations/0007_post_collections_m2m.sql +94 -0
- package/src/db/migrations/0008_add_collection_dividers.sql +8 -0
- package/src/db/migrations/0009_drop_collection_show_divider.sql +2 -0
- package/src/db/migrations/0010_add_performance_indexes.sql +16 -0
- package/src/db/schema.ts +24 -4
- package/src/i18n/locales/en.po +810 -385
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +733 -522
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +733 -522
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/i18n/middleware.ts +7 -11
- package/src/index.ts +1 -1
- package/src/lib/__tests__/icons.test.ts +178 -0
- package/src/lib/__tests__/resolve-config.test.ts +184 -0
- package/src/lib/__tests__/schemas.test.ts +12 -6
- package/src/lib/__tests__/theme.test.ts +62 -0
- package/src/lib/__tests__/timezones.test.ts +1 -1
- package/src/lib/__tests__/url.test.ts +12 -0
- package/src/lib/__tests__/view.test.ts +1 -5
- package/src/lib/avatar-upload.ts +18 -10
- package/src/lib/collection-form-bridge.ts +52 -0
- package/src/lib/collections-reorder.ts +28 -0
- package/src/lib/compose-bridge.ts +251 -0
- package/src/lib/errors.ts +116 -0
- package/src/lib/excerpt.ts +1 -1
- package/src/lib/favicon.ts +3 -5
- package/src/lib/html.ts +22 -0
- package/src/lib/icon-catalog.ts +181 -0
- package/src/lib/icons.ts +202 -0
- package/src/lib/navigation.ts +18 -33
- package/src/lib/pagination.ts +3 -2
- package/src/lib/post-form-bridge.ts +136 -0
- package/src/lib/render.tsx +11 -4
- package/src/lib/resolve-config.ts +157 -0
- package/src/lib/schemas.ts +76 -12
- package/src/lib/settings-bridge.ts +139 -0
- package/src/lib/storage.ts +37 -16
- package/src/lib/theme.ts +5 -7
- package/src/lib/timeline.ts +4 -8
- package/src/lib/toast.ts +134 -0
- package/src/lib/upload.ts +71 -0
- package/src/lib/url.ts +9 -1
- package/src/lib/version.ts +16 -0
- package/src/lib/view.ts +9 -10
- package/src/middleware/__tests__/auth.test.ts +6 -28
- package/src/middleware/__tests__/onboarding.test.ts +1 -1
- package/src/middleware/auth.ts +6 -12
- package/src/middleware/config.ts +51 -0
- package/src/middleware/error-handler.ts +56 -0
- package/src/middleware/onboarding.ts +1 -1
- package/src/preset.css +6 -0
- package/src/routes/__tests__/compose.test.ts +104 -17
- package/src/routes/api/__tests__/collections.test.ts +93 -2
- package/src/routes/api/__tests__/posts.test.ts +2 -1
- package/src/routes/api/__tests__/settings.test.ts +1 -1
- package/src/routes/api/collections.ts +64 -68
- package/src/routes/api/nav-items.ts +21 -59
- package/src/routes/api/pages.ts +18 -46
- package/src/routes/api/posts.ts +64 -86
- package/src/routes/api/search.ts +6 -4
- package/src/routes/api/settings.ts +8 -24
- package/src/routes/api/upload.ts +55 -53
- package/src/routes/auth/__tests__/setup.test.ts +118 -0
- package/src/routes/auth/reset.tsx +17 -66
- package/src/routes/auth/setup.tsx +67 -11
- package/src/routes/auth/signin.tsx +44 -8
- package/src/routes/compose.tsx +194 -0
- package/src/routes/dash/__tests__/font-theme.test.ts +110 -0
- package/src/routes/dash/__tests__/pages.test.ts +2 -2
- package/src/routes/dash/__tests__/settings-avatar.test.ts +23 -12
- package/src/routes/dash/appearance.tsx +173 -0
- package/src/routes/dash/collections.tsx +80 -14
- package/src/routes/dash/index.tsx +12 -14
- package/src/routes/dash/media.tsx +46 -49
- package/src/routes/dash/pages.tsx +85 -37
- package/src/routes/dash/posts.tsx +60 -23
- package/src/routes/dash/redirects.tsx +43 -33
- package/src/routes/dash/settings.tsx +234 -214
- package/src/routes/feed/__tests__/rss.test.ts +7 -3
- package/src/routes/feed/rss.ts +11 -16
- package/src/routes/feed/sitemap.ts +15 -9
- package/src/routes/pages/__tests__/collections.test.ts +9 -8
- package/src/routes/pages/archive.tsx +2 -2
- package/src/routes/pages/collection.tsx +76 -9
- package/src/routes/pages/collections.tsx +3 -1
- package/src/routes/pages/featured.tsx +2 -2
- package/src/routes/pages/home.tsx +3 -3
- package/src/routes/pages/latest.tsx +2 -2
- package/src/routes/pages/page.tsx +2 -2
- package/src/routes/pages/post.tsx +2 -2
- package/src/routes/pages/search.tsx +2 -2
- package/src/services/__tests__/collection.test.ts +324 -34
- package/src/services/__tests__/media.test.ts +1 -1
- package/src/services/__tests__/page.test.ts +116 -1
- package/src/services/auth.ts +88 -0
- package/src/services/collection.ts +169 -30
- package/src/services/index.ts +8 -3
- package/src/services/media.ts +39 -12
- package/src/services/navigation.ts +17 -5
- package/src/services/page.ts +24 -4
- package/src/services/post.ts +87 -19
- package/src/services/search.ts +0 -1
- package/src/services/settings.ts +21 -13
- package/src/style.css +3 -0
- package/src/styles/components.css +42 -1
- package/src/styles/tokens.css +4 -0
- package/src/styles/ui.css +902 -73
- package/src/types/app-context.ts +25 -0
- package/src/types/bindings.ts +1 -0
- package/src/types/config.ts +60 -23
- package/src/types/entities.ts +12 -2
- package/src/types/lingui-react-macro.d.ts +3 -3
- package/src/types/operations.ts +2 -4
- package/src/types/views.ts +1 -3
- package/src/ui/__tests__/font-themes.test.ts +27 -8
- package/src/ui/color-themes.ts +1 -1
- package/src/ui/components/__tests__/jant-collection-form.test.ts +153 -0
- package/src/ui/components/__tests__/jant-compose-dialog.test.ts +512 -0
- package/src/ui/components/__tests__/jant-compose-editor.test.ts +272 -0
- package/src/ui/components/__tests__/jant-post-form.test.ts +172 -0
- package/src/ui/components/__tests__/jant-settings-avatar.test.ts +235 -0
- package/src/ui/components/__tests__/jant-settings-general.test.ts +319 -0
- package/src/ui/components/collection-types.ts +45 -0
- package/src/ui/components/compose-types.ts +75 -0
- package/src/ui/components/jant-collection-form.ts +512 -0
- package/src/ui/components/jant-compose-dialog.ts +494 -0
- package/src/ui/components/jant-compose-editor.ts +799 -0
- package/src/ui/components/jant-post-form.ts +290 -0
- package/src/ui/components/jant-settings-avatar.ts +231 -0
- package/src/ui/components/jant-settings-general.ts +436 -0
- package/src/ui/components/post-form-template.ts +260 -0
- package/src/ui/components/post-form-types.ts +87 -0
- package/src/ui/components/settings-types.ts +62 -0
- package/src/ui/compose/ComposeDialog.tsx +141 -385
- package/src/ui/compose/ComposePrompt.tsx +3 -3
- package/src/ui/dash/PostList.tsx +55 -61
- package/src/ui/dash/appearance/AdvancedContent.tsx +80 -0
- package/src/ui/dash/appearance/AppearanceNav.tsx +56 -0
- package/src/ui/dash/appearance/ColorThemeContent.tsx +129 -0
- package/src/ui/dash/appearance/FontThemeContent.tsx +98 -0
- package/src/ui/dash/collections/CollectionForm.tsx +130 -117
- package/src/ui/dash/collections/CollectionsListContent.tsx +102 -41
- package/src/ui/dash/collections/IconPickerGrid.tsx +50 -0
- package/src/ui/dash/collections/ViewCollectionContent.tsx +14 -3
- package/src/ui/dash/index.ts +1 -1
- package/src/ui/dash/posts/PostForm.tsx +248 -0
- package/src/ui/dash/settings/AccountContent.tsx +69 -80
- package/src/ui/dash/settings/GeneralContent.tsx +159 -478
- package/src/ui/dash/settings/SettingsNav.tsx +4 -4
- package/src/ui/font-themes.ts +115 -32
- package/src/ui/layouts/BaseLayout.tsx +49 -19
- package/src/ui/layouts/DashLayout.tsx +14 -9
- package/src/ui/layouts/SiteLayout.tsx +38 -23
- package/src/ui/pages/CollectionPage.tsx +12 -2
- package/src/ui/pages/CollectionsPage.tsx +27 -27
- package/src/ui/pages/HomePage.tsx +15 -6
- package/src/ui/pages/SearchPage.tsx +1 -2
- package/src/ui/shared/CollectionsSidebar.tsx +59 -0
- package/src/ui/shared/Pagination.tsx +2 -2
- package/dist/app.js +0 -267
- package/dist/auth.js +0 -39
- package/dist/client.js +0 -13
- package/dist/db/index.js +0 -10
- package/dist/db/schema.js +0 -224
- package/dist/i18n/Trans.js +0 -24
- package/dist/i18n/context.js +0 -58
- package/dist/i18n/detect.js +0 -26
- package/dist/i18n/i18n.js +0 -49
- package/dist/i18n/index.js +0 -44
- package/dist/i18n/locales/en.js +0 -1
- package/dist/i18n/locales/zh-Hans.js +0 -1
- package/dist/i18n/locales/zh-Hant.js +0 -1
- package/dist/i18n/locales.js +0 -13
- package/dist/i18n/middleware.js +0 -30
- package/dist/lib/avatar-upload.js +0 -134
- package/dist/lib/config.js +0 -143
- package/dist/lib/constants.js +0 -50
- package/dist/lib/excerpt.js +0 -76
- package/dist/lib/favicon.js +0 -102
- package/dist/lib/feed.js +0 -123
- package/dist/lib/image-processor.js +0 -187
- package/dist/lib/image.js +0 -97
- package/dist/lib/index.js +0 -7
- package/dist/lib/markdown.js +0 -83
- package/dist/lib/media-helpers.js +0 -49
- package/dist/lib/media-upload.js +0 -104
- package/dist/lib/nav-reorder.js +0 -27
- package/dist/lib/navigation.js +0 -79
- package/dist/lib/pagination.js +0 -44
- package/dist/lib/render.js +0 -53
- package/dist/lib/schemas.js +0 -174
- package/dist/lib/sqid.js +0 -72
- package/dist/lib/sse.js +0 -218
- package/dist/lib/storage.js +0 -164
- package/dist/lib/theme.js +0 -65
- package/dist/lib/time.js +0 -159
- package/dist/lib/timeline.js +0 -95
- package/dist/lib/timezones.js +0 -388
- package/dist/lib/url.js +0 -89
- package/dist/lib/view.js +0 -217
- package/dist/middleware/auth.js +0 -52
- package/dist/middleware/onboarding.js +0 -41
- package/dist/routes/api/collections.js +0 -124
- package/dist/routes/api/nav-items.js +0 -104
- package/dist/routes/api/pages.js +0 -91
- package/dist/routes/api/posts.js +0 -218
- package/dist/routes/api/search.js +0 -48
- package/dist/routes/api/settings.js +0 -68
- package/dist/routes/api/upload.js +0 -246
- package/dist/routes/auth/reset.js +0 -221
- package/dist/routes/auth/setup.js +0 -194
- package/dist/routes/auth/signin.js +0 -176
- package/dist/routes/compose.js +0 -48
- package/dist/routes/dash/collections.js +0 -115
- package/dist/routes/dash/index.js +0 -118
- package/dist/routes/dash/media.js +0 -106
- package/dist/routes/dash/pages.js +0 -294
- package/dist/routes/dash/posts.js +0 -244
- package/dist/routes/dash/redirects.js +0 -257
- package/dist/routes/dash/settings.js +0 -379
- package/dist/routes/feed/rss.js +0 -62
- package/dist/routes/feed/sitemap.js +0 -49
- package/dist/routes/pages/archive.js +0 -62
- package/dist/routes/pages/collection.js +0 -34
- package/dist/routes/pages/collections.js +0 -28
- package/dist/routes/pages/featured.js +0 -36
- package/dist/routes/pages/home.js +0 -64
- package/dist/routes/pages/latest.js +0 -45
- package/dist/routes/pages/page.js +0 -68
- package/dist/routes/pages/post.js +0 -44
- package/dist/routes/pages/search.js +0 -54
- package/dist/services/collection.js +0 -109
- package/dist/services/index.js +0 -24
- package/dist/services/media.js +0 -117
- package/dist/services/navigation.js +0 -91
- package/dist/services/page.js +0 -84
- package/dist/services/post.js +0 -229
- package/dist/services/redirect.js +0 -48
- package/dist/services/search.js +0 -67
- package/dist/services/settings.js +0 -68
- package/dist/types/bindings.js +0 -3
- package/dist/types/config.js +0 -147
- package/dist/types/constants.js +0 -27
- package/dist/types/entities.js +0 -3
- package/dist/types/lingui-react-macro.d.js +0 -9
- package/dist/types/operations.js +0 -3
- package/dist/types/props.js +0 -3
- package/dist/types/sortablejs.d.js +0 -5
- package/dist/types/views.js +0 -5
- package/dist/types.js +0 -11
- package/dist/ui/color-themes.js +0 -268
- package/dist/ui/compose/ComposeDialog.js +0 -467
- package/dist/ui/compose/ComposePrompt.js +0 -55
- package/dist/ui/dash/ActionButtons.js +0 -46
- package/dist/ui/dash/CrudPageHeader.js +0 -22
- package/dist/ui/dash/DangerZone.js +0 -36
- package/dist/ui/dash/FormatBadge.js +0 -27
- package/dist/ui/dash/ListItemRow.js +0 -21
- package/dist/ui/dash/PageForm.js +0 -195
- package/dist/ui/dash/PostForm.js +0 -395
- package/dist/ui/dash/PostList.js +0 -83
- package/dist/ui/dash/StatusBadge.js +0 -46
- package/dist/ui/dash/collections/CollectionForm.js +0 -152
- package/dist/ui/dash/collections/CollectionsListContent.js +0 -68
- package/dist/ui/dash/collections/ViewCollectionContent.js +0 -96
- package/dist/ui/dash/index.js +0 -10
- package/dist/ui/dash/media/MediaListContent.js +0 -166
- package/dist/ui/dash/media/ViewMediaContent.js +0 -212
- package/dist/ui/dash/pages/LinkFormContent.js +0 -130
- package/dist/ui/dash/pages/UnifiedPagesContent.js +0 -193
- package/dist/ui/dash/settings/AccountContent.js +0 -209
- package/dist/ui/dash/settings/AppearanceContent.js +0 -259
- package/dist/ui/dash/settings/GeneralContent.js +0 -536
- package/dist/ui/dash/settings/SettingsNav.js +0 -41
- package/dist/ui/feed/LinkCard.js +0 -72
- package/dist/ui/feed/NoteCard.js +0 -58
- package/dist/ui/feed/QuoteCard.js +0 -63
- package/dist/ui/feed/ThreadPreview.js +0 -48
- package/dist/ui/feed/TimelineFeed.js +0 -41
- package/dist/ui/feed/TimelineItem.js +0 -27
- package/dist/ui/font-themes.js +0 -36
- package/dist/ui/layouts/BaseLayout.js +0 -153
- package/dist/ui/layouts/DashLayout.js +0 -141
- package/dist/ui/layouts/SiteLayout.js +0 -169
- package/dist/ui/pages/ArchivePage.js +0 -143
- package/dist/ui/pages/CollectionPage.js +0 -70
- package/dist/ui/pages/CollectionsPage.js +0 -76
- package/dist/ui/pages/FeaturedPage.js +0 -24
- package/dist/ui/pages/HomePage.js +0 -24
- package/dist/ui/pages/PostPage.js +0 -55
- package/dist/ui/pages/SearchPage.js +0 -122
- package/dist/ui/pages/SinglePage.js +0 -23
- package/dist/ui/shared/EmptyState.js +0 -27
- package/dist/ui/shared/MediaGallery.js +0 -35
- package/dist/ui/shared/Pagination.js +0 -195
- package/dist/ui/shared/ThreadView.js +0 -108
- package/dist/ui/shared/index.js +0 -5
- package/dist/vendor/datastar.js +0 -1606
- package/src/lib/__tests__/config.test.ts +0 -192
- package/src/lib/config.ts +0 -167
- package/src/routes/compose.ts +0 -63
- package/src/ui/dash/PostForm.tsx +0 -360
- package/src/ui/dash/settings/AppearanceContent.tsx +0 -254
package/src/ui/font-themes.ts
CHANGED
|
@@ -1,54 +1,137 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Built-in Font Themes
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Heading + body font pairings using system fonts only — no external font
|
|
5
|
+
* loading required. Each theme sets `--font-heading` and `--font-body`
|
|
6
|
+
* independently to enable classic editorial combinations.
|
|
7
|
+
*
|
|
8
|
+
* Name and description are MessageDescriptor objects for i18n support.
|
|
9
|
+
* Pass them to t() from useLingui() when rendering.
|
|
5
10
|
*/
|
|
6
11
|
|
|
12
|
+
import type { MessageDescriptor } from "@lingui/core";
|
|
13
|
+
|
|
7
14
|
/**
|
|
8
|
-
* A font theme definition with
|
|
15
|
+
* A font theme definition with heading + body pairing.
|
|
9
16
|
*/
|
|
10
17
|
export interface FontTheme {
|
|
11
|
-
/** Stored in DB settings, e.g. "
|
|
18
|
+
/** Stored in DB settings, e.g. "classic-editorial" */
|
|
12
19
|
id: string;
|
|
13
|
-
/** Display name
|
|
14
|
-
name:
|
|
15
|
-
/** CSS font-family stack */
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
|
|
20
|
+
/** Display name — pass to t() for translation */
|
|
21
|
+
name: MessageDescriptor;
|
|
22
|
+
/** CSS font-family stack for headings (h1-h6, site logo) */
|
|
23
|
+
headingFontFamily: string;
|
|
24
|
+
/** CSS font-family stack for body text */
|
|
25
|
+
bodyFontFamily: string;
|
|
26
|
+
/** Short description for the picker UI — pass to t() for translation */
|
|
27
|
+
description: MessageDescriptor;
|
|
19
28
|
}
|
|
20
29
|
|
|
30
|
+
/** System sans-serif stack */
|
|
31
|
+
const SANS =
|
|
32
|
+
'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Editorial serif stack
|
|
36
|
+
*
|
|
37
|
+
* ui-serif → New York (macOS 10.15+); Iowan Old Style (macOS/iOS);
|
|
38
|
+
* Charter (macOS); Cambria / Sitka Text (Windows); Georgia (universal)
|
|
39
|
+
*/
|
|
40
|
+
const EDITORIAL_SERIF =
|
|
41
|
+
'ui-serif, "Iowan Old Style", Charter, "Bitstream Charter", Cambria, "Sitka Text", Georgia, "Songti SC", "Noto Serif CJK SC", "STSong", "SimSun", serif';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Classical serif stack
|
|
45
|
+
*
|
|
46
|
+
* Palatino (macOS); Palatino Linotype / Book Antiqua (Windows);
|
|
47
|
+
* Old-style serif with calligraphic warmth
|
|
48
|
+
*/
|
|
49
|
+
const CLASSICAL_SERIF =
|
|
50
|
+
'Palatino, "Palatino Linotype", "Book Antiqua", "Songti SC", "Noto Serif CJK SC", "STSong", "SimSun", serif';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Geometric sans stack
|
|
54
|
+
*
|
|
55
|
+
* Futura (macOS); Century Gothic (Windows); clean geometric proportions
|
|
56
|
+
*/
|
|
57
|
+
const GEOMETRIC_SANS =
|
|
58
|
+
'Futura, "Century Gothic", "Noto Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif';
|
|
59
|
+
|
|
21
60
|
export const BUILTIN_FONT_THEMES: FontTheme[] = [
|
|
22
61
|
{
|
|
23
62
|
id: "default",
|
|
24
|
-
name:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
63
|
+
name: {
|
|
64
|
+
id: "System Default",
|
|
65
|
+
message: "System Default",
|
|
66
|
+
comment: "@context: Font theme name",
|
|
67
|
+
},
|
|
68
|
+
headingFontFamily: SANS,
|
|
69
|
+
bodyFontFamily: SANS,
|
|
70
|
+
description: {
|
|
71
|
+
id: "Matches your OS native font for consistent reading",
|
|
72
|
+
message: "Matches your OS native font for consistent reading",
|
|
73
|
+
comment: "@context: Font theme description",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
id: "modern-editorial",
|
|
79
|
+
name: {
|
|
80
|
+
id: "Modern Editorial",
|
|
81
|
+
message: "Modern Editorial",
|
|
82
|
+
comment: "@context: Font theme name",
|
|
83
|
+
},
|
|
84
|
+
headingFontFamily: SANS,
|
|
85
|
+
bodyFontFamily: EDITORIAL_SERIF,
|
|
86
|
+
description: {
|
|
87
|
+
id: "Clean sans-serif headings with elegant serif body text",
|
|
88
|
+
message: "Clean sans-serif headings with elegant serif body text",
|
|
89
|
+
comment: "@context: Font theme description",
|
|
90
|
+
},
|
|
29
91
|
},
|
|
30
92
|
{
|
|
31
|
-
id: "
|
|
32
|
-
name:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
93
|
+
id: "classic-editorial",
|
|
94
|
+
name: {
|
|
95
|
+
id: "Classic Editorial",
|
|
96
|
+
message: "Classic Editorial",
|
|
97
|
+
comment: "@context: Font theme name",
|
|
98
|
+
},
|
|
99
|
+
headingFontFamily: EDITORIAL_SERIF,
|
|
100
|
+
bodyFontFamily: SANS,
|
|
101
|
+
description: {
|
|
102
|
+
id: "Serif headings with clean sans-serif body text",
|
|
103
|
+
message: "Serif headings with clean sans-serif body text",
|
|
104
|
+
comment: "@context: Font theme description",
|
|
105
|
+
},
|
|
37
106
|
},
|
|
38
107
|
{
|
|
39
|
-
id: "
|
|
40
|
-
name:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
108
|
+
id: "literary",
|
|
109
|
+
name: {
|
|
110
|
+
id: "Literary",
|
|
111
|
+
message: "Literary",
|
|
112
|
+
comment: "@context: Font theme name",
|
|
113
|
+
},
|
|
114
|
+
headingFontFamily: CLASSICAL_SERIF,
|
|
115
|
+
bodyFontFamily: EDITORIAL_SERIF,
|
|
116
|
+
description: {
|
|
117
|
+
id: "Full serif pairing for immersive long-form reading",
|
|
118
|
+
message: "Full serif pairing for immersive long-form reading",
|
|
119
|
+
comment: "@context: Font theme description",
|
|
120
|
+
},
|
|
45
121
|
},
|
|
46
122
|
{
|
|
47
|
-
id: "
|
|
48
|
-
name:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
123
|
+
id: "geometric",
|
|
124
|
+
name: {
|
|
125
|
+
id: "Geometric",
|
|
126
|
+
message: "Geometric",
|
|
127
|
+
comment: "@context: Font theme name",
|
|
128
|
+
},
|
|
129
|
+
headingFontFamily: GEOMETRIC_SANS,
|
|
130
|
+
bodyFontFamily: SANS,
|
|
131
|
+
description: {
|
|
132
|
+
id: "Bold geometric headings with clean sans-serif body text",
|
|
133
|
+
message: "Bold geometric headings with clean sans-serif body text",
|
|
134
|
+
comment: "@context: Font theme description",
|
|
135
|
+
},
|
|
53
136
|
},
|
|
54
137
|
];
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* Provides the HTML shell with meta tags, styles, and scripts.
|
|
5
5
|
* If Context is provided, automatically wraps children with I18nProvider.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* In dev mode (Vite), serves assets via Vite's dev server.
|
|
8
|
+
* In production, serves pre-built assets with version cache-busting.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import type { FC, PropsWithChildren } from "hono/jsx";
|
|
11
12
|
import type { Context } from "hono";
|
|
12
|
-
import {
|
|
13
|
+
import { CORE_VERSION, IS_VITE_DEV } from "../../lib/version.js";
|
|
13
14
|
import { I18nProvider } from "../../i18n/index.js";
|
|
14
15
|
|
|
15
16
|
export interface ToastProps {
|
|
@@ -24,7 +25,9 @@ export interface BaseLayoutProps {
|
|
|
24
25
|
c?: Context;
|
|
25
26
|
toast?: ToastProps;
|
|
26
27
|
faviconUrl?: string;
|
|
28
|
+
faviconVersion?: string;
|
|
27
29
|
noindex?: boolean;
|
|
30
|
+
isAuthenticated?: boolean;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export const BaseLayout: FC<PropsWithChildren<BaseLayoutProps>> = ({
|
|
@@ -34,17 +37,21 @@ export const BaseLayout: FC<PropsWithChildren<BaseLayoutProps>> = ({
|
|
|
34
37
|
c,
|
|
35
38
|
toast,
|
|
36
39
|
faviconUrl,
|
|
40
|
+
faviconVersion,
|
|
37
41
|
noindex,
|
|
42
|
+
isAuthenticated = false,
|
|
38
43
|
children,
|
|
39
44
|
}) => {
|
|
40
45
|
// Read lang from Hono context if available, otherwise use prop or default
|
|
41
46
|
const resolvedLang = lang ?? (c ? c.get("lang") : "en");
|
|
42
47
|
|
|
43
|
-
// Read
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
+
// Read favicon/noindex from appConfig when not provided as prop
|
|
49
|
+
const appConfig = c ? c.get("appConfig") : undefined;
|
|
50
|
+
const resolvedFaviconUrl =
|
|
51
|
+
faviconUrl ?? (appConfig?.siteAvatarUrl || undefined);
|
|
52
|
+
const resolvedFaviconVersion =
|
|
53
|
+
faviconVersion ?? (appConfig?.faviconVersion || undefined);
|
|
54
|
+
const resolvedNoindex = noindex ?? appConfig?.noindex;
|
|
48
55
|
|
|
49
56
|
// Automatically wrap with I18nProvider if Context is provided
|
|
50
57
|
const content = c ? <I18nProvider c={c}>{children}</I18nProvider> : children;
|
|
@@ -52,11 +59,8 @@ export const BaseLayout: FC<PropsWithChildren<BaseLayoutProps>> = ({
|
|
|
52
59
|
// Read theme style from Hono context if available
|
|
53
60
|
const themeStyle = c ? c.get("themeStyle") : undefined;
|
|
54
61
|
|
|
55
|
-
// Read custom CSS from
|
|
56
|
-
const customCSS =
|
|
57
|
-
|
|
58
|
-
// Check authentication status for data attribute
|
|
59
|
-
const isAuthenticated = c ? c.get("isAuthenticated") : false;
|
|
62
|
+
// Read custom CSS from appConfig
|
|
63
|
+
const customCSS = appConfig?.customCSS || undefined;
|
|
60
64
|
|
|
61
65
|
return (
|
|
62
66
|
<html lang={resolvedLang}>
|
|
@@ -68,15 +72,41 @@ export const BaseLayout: FC<PropsWithChildren<BaseLayoutProps>> = ({
|
|
|
68
72
|
{resolvedNoindex && <meta name="robots" content="noindex, nofollow" />}
|
|
69
73
|
{resolvedFaviconUrl && (
|
|
70
74
|
<>
|
|
71
|
-
<link
|
|
72
|
-
|
|
75
|
+
<link
|
|
76
|
+
rel="icon"
|
|
77
|
+
href={
|
|
78
|
+
resolvedFaviconVersion
|
|
79
|
+
? `/favicon.ico?v=${resolvedFaviconVersion}`
|
|
80
|
+
: "/favicon.ico"
|
|
81
|
+
}
|
|
82
|
+
sizes="16x16 32x32"
|
|
83
|
+
/>
|
|
84
|
+
<link
|
|
85
|
+
rel="apple-touch-icon"
|
|
86
|
+
href={
|
|
87
|
+
resolvedFaviconVersion
|
|
88
|
+
? `/apple-touch-icon.png?v=${resolvedFaviconVersion}`
|
|
89
|
+
: "/apple-touch-icon.png"
|
|
90
|
+
}
|
|
91
|
+
sizes="180x180"
|
|
92
|
+
/>
|
|
73
93
|
</>
|
|
74
94
|
)}
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
95
|
+
{IS_VITE_DEV && <script type="module" src="/@vite/client" />}
|
|
96
|
+
<link
|
|
97
|
+
rel="stylesheet"
|
|
98
|
+
href={
|
|
99
|
+
IS_VITE_DEV ? "/src/style.css" : `/client.css?v=${CORE_VERSION}`
|
|
100
|
+
}
|
|
101
|
+
/>
|
|
102
|
+
{themeStyle && (
|
|
103
|
+
<style dangerouslySetInnerHTML={{ __html: themeStyle }} />
|
|
104
|
+
)}
|
|
105
|
+
{customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
|
|
106
|
+
<script
|
|
107
|
+
type="module"
|
|
108
|
+
src={IS_VITE_DEV ? "/src/client.ts" : `/client.js?v=${CORE_VERSION}`}
|
|
109
|
+
/>
|
|
80
110
|
</head>
|
|
81
111
|
<body
|
|
82
112
|
class="bg-background text-foreground antialiased"
|
|
@@ -41,7 +41,7 @@ function DashLayoutContent({
|
|
|
41
41
|
<div class="min-h-screen">
|
|
42
42
|
{/* Header */}
|
|
43
43
|
<header class="border-b bg-card">
|
|
44
|
-
<div class="container flex h-14 items-center justify-between">
|
|
44
|
+
<div class="container-sidebar flex h-14 items-center justify-between">
|
|
45
45
|
<a id="site-name" href="/dash" class="font-semibold">
|
|
46
46
|
{siteName}
|
|
47
47
|
</a>
|
|
@@ -70,9 +70,9 @@ function DashLayoutContent({
|
|
|
70
70
|
</header>
|
|
71
71
|
|
|
72
72
|
{/* Sidebar + Main */}
|
|
73
|
-
<div class="container
|
|
73
|
+
<div class="container-sidebar sidebar-layout py-8">
|
|
74
74
|
{/* Sidebar */}
|
|
75
|
-
<aside class="
|
|
75
|
+
<aside class="sidebar-nav">
|
|
76
76
|
<nav class="flex flex-col gap-1">
|
|
77
77
|
<a href="/dash" class={navClass("/dash", /^\/dash$/)}>
|
|
78
78
|
{t({
|
|
@@ -118,12 +118,12 @@ function DashLayoutContent({
|
|
|
118
118
|
})}
|
|
119
119
|
</a>
|
|
120
120
|
<a
|
|
121
|
-
href="/dash/
|
|
122
|
-
class={navClass("/dash/
|
|
121
|
+
href="/dash/appearance"
|
|
122
|
+
class={navClass("/dash/appearance", /^\/dash\/appearance/)}
|
|
123
123
|
>
|
|
124
124
|
{t({
|
|
125
|
-
message: "
|
|
126
|
-
comment: "@context: Dashboard navigation -
|
|
125
|
+
message: "Appearance",
|
|
126
|
+
comment: "@context: Dashboard navigation - appearance settings",
|
|
127
127
|
})}
|
|
128
128
|
</a>
|
|
129
129
|
<a
|
|
@@ -139,7 +139,7 @@ function DashLayoutContent({
|
|
|
139
139
|
</aside>
|
|
140
140
|
|
|
141
141
|
{/* Main content */}
|
|
142
|
-
<main class="
|
|
142
|
+
<main class="sidebar-main">{children}</main>
|
|
143
143
|
</div>
|
|
144
144
|
</div>
|
|
145
145
|
);
|
|
@@ -154,7 +154,12 @@ export const DashLayout: FC<PropsWithChildren<DashLayoutProps>> = ({
|
|
|
154
154
|
children,
|
|
155
155
|
}) => {
|
|
156
156
|
return (
|
|
157
|
-
<BaseLayout
|
|
157
|
+
<BaseLayout
|
|
158
|
+
title={`${title} - ${siteName}`}
|
|
159
|
+
c={c}
|
|
160
|
+
toast={toast}
|
|
161
|
+
isAuthenticated={true}
|
|
162
|
+
>
|
|
158
163
|
<DashLayoutContent siteName={siteName} currentPath={currentPath}>
|
|
159
164
|
{children}
|
|
160
165
|
</DashLayoutContent>
|
|
@@ -36,6 +36,7 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
36
36
|
siteAvatarUrl,
|
|
37
37
|
showHeaderAvatar,
|
|
38
38
|
siteFooterHtml,
|
|
39
|
+
sidebar,
|
|
39
40
|
children,
|
|
40
41
|
}) => {
|
|
41
42
|
const { t } = useLingui();
|
|
@@ -76,7 +77,7 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
76
77
|
|
|
77
78
|
return (
|
|
78
79
|
<div class="site-page">
|
|
79
|
-
<header class="site-header">
|
|
80
|
+
<header class={`site-header ${sidebar ? "site-header-sidebar" : ""}`}>
|
|
80
81
|
<div class="site-header-inner">
|
|
81
82
|
<div class="site-header-top site-header-top-bordered">
|
|
82
83
|
<a href="/" class="site-logo">
|
|
@@ -123,32 +124,46 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
123
124
|
</header>
|
|
124
125
|
|
|
125
126
|
<main class="site-main">
|
|
126
|
-
|
|
127
|
-
<div class="
|
|
128
|
-
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
key={link.href}
|
|
135
|
-
href={link.href}
|
|
136
|
-
class={`site-browse-link ${currentPath === link.href ? "site-browse-link-active" : ""}`}
|
|
137
|
-
>
|
|
138
|
-
{link.label}
|
|
139
|
-
</a>
|
|
140
|
-
</>
|
|
141
|
-
))}
|
|
142
|
-
</nav>
|
|
143
|
-
)}
|
|
144
|
-
{isHomePage && isAuthenticated && <ComposePrompt />}
|
|
145
|
-
{children}
|
|
127
|
+
{sidebar ? (
|
|
128
|
+
<div class="container-sidebar">
|
|
129
|
+
<div class="sidebar-layout">
|
|
130
|
+
<aside class="sidebar-nav">{sidebar}</aside>
|
|
131
|
+
<div class="sidebar-main">
|
|
132
|
+
<div class="site-content">{children}</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
146
135
|
</div>
|
|
147
|
-
|
|
136
|
+
) : (
|
|
137
|
+
<div class="site-container">
|
|
138
|
+
<div class="site-content">
|
|
139
|
+
{isHomePage && (
|
|
140
|
+
<nav class="site-browse-nav">
|
|
141
|
+
{browseLinks.map((link, i) => (
|
|
142
|
+
<>
|
|
143
|
+
{i > 0 && <span class="site-browse-sep">/</span>}
|
|
144
|
+
<a
|
|
145
|
+
key={link.href}
|
|
146
|
+
href={link.href}
|
|
147
|
+
class={`site-browse-link ${currentPath === link.href ? "site-browse-link-active" : ""}`}
|
|
148
|
+
>
|
|
149
|
+
{link.label}
|
|
150
|
+
</a>
|
|
151
|
+
</>
|
|
152
|
+
))}
|
|
153
|
+
</nav>
|
|
154
|
+
)}
|
|
155
|
+
{isHomePage && isAuthenticated && <ComposePrompt />}
|
|
156
|
+
{children}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
148
160
|
</main>
|
|
149
161
|
|
|
150
162
|
{siteFooterHtml && (
|
|
151
|
-
<footer
|
|
163
|
+
<footer
|
|
164
|
+
class={`site-footer ${sidebar ? "site-footer-sidebar" : ""}`}
|
|
165
|
+
data-footer
|
|
166
|
+
>
|
|
152
167
|
<div class="site-container">
|
|
153
168
|
<div
|
|
154
169
|
class="prose"
|
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Collection Page
|
|
3
3
|
*
|
|
4
|
-
* Collection header with divider-separated post list.
|
|
4
|
+
* Collection header with icon and divider-separated post list.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { FC } from "hono/jsx";
|
|
8
8
|
import { useLingui } from "@lingui/react/macro";
|
|
9
9
|
import type { CollectionPageProps } from "../../types.js";
|
|
10
|
+
import { renderCollectionIcon } from "../../lib/icons.js";
|
|
10
11
|
|
|
11
12
|
export const CollectionPage: FC<CollectionPageProps> = ({
|
|
12
13
|
collection,
|
|
13
14
|
posts,
|
|
14
15
|
}) => {
|
|
15
16
|
const { t } = useLingui();
|
|
17
|
+
const iconHtml = renderCollectionIcon(collection.icon, { size: 28 });
|
|
16
18
|
|
|
17
19
|
return (
|
|
18
20
|
<div class="py-6" data-page="collection">
|
|
19
21
|
<header class="mb-8">
|
|
20
|
-
<h1 class="text-2xl font-semibold">
|
|
22
|
+
<h1 class="text-2xl font-semibold flex items-center gap-3">
|
|
23
|
+
{iconHtml && (
|
|
24
|
+
<span
|
|
25
|
+
class="shrink-0"
|
|
26
|
+
dangerouslySetInnerHTML={{ __html: iconHtml }}
|
|
27
|
+
/>
|
|
28
|
+
)}
|
|
29
|
+
{collection.title}
|
|
30
|
+
</h1>
|
|
21
31
|
{collection.description && (
|
|
22
32
|
<p class="text-muted-foreground mt-2">{collection.description}</p>
|
|
23
33
|
)}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Collections Listing Page
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 2-column card grid of collections with icons and post counts.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { FC } from "hono/jsx";
|
|
8
8
|
import { useLingui } from "@lingui/react/macro";
|
|
9
9
|
import type { CollectionsPageProps } from "../../types.js";
|
|
10
|
+
import { renderCollectionIcon } from "../../lib/icons.js";
|
|
10
11
|
|
|
11
12
|
export const CollectionsPage: FC<CollectionsPageProps> = ({ collections }) => {
|
|
12
13
|
const { t } = useLingui();
|
|
@@ -31,38 +32,37 @@ export const CollectionsPage: FC<CollectionsPageProps> = ({ collections }) => {
|
|
|
31
32
|
})}
|
|
32
33
|
</p>
|
|
33
34
|
) : (
|
|
34
|
-
<div class="
|
|
35
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
35
36
|
{collections.map((collection) => (
|
|
36
37
|
<a
|
|
37
38
|
key={collection.id}
|
|
38
|
-
href={
|
|
39
|
-
class="
|
|
39
|
+
href={`/c/${collection.slug}`}
|
|
40
|
+
class="collection-card"
|
|
40
41
|
>
|
|
41
42
|
<div class="flex items-center gap-3">
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
</div>
|
|
53
|
-
<span class="text-sm text-muted-foreground shrink-0">
|
|
54
|
-
{collection.postCount}{" "}
|
|
55
|
-
{collection.postCount === 1
|
|
56
|
-
? t({
|
|
57
|
-
message: "post",
|
|
58
|
-
comment: "@context: Singular post count label",
|
|
59
|
-
})
|
|
60
|
-
: t({
|
|
61
|
-
message: "posts",
|
|
62
|
-
comment: "@context: Plural post count label",
|
|
63
|
-
})}
|
|
64
|
-
</span>
|
|
43
|
+
<span
|
|
44
|
+
class="collection-card-icon"
|
|
45
|
+
dangerouslySetInnerHTML={{
|
|
46
|
+
__html: renderCollectionIcon(collection.icon, {
|
|
47
|
+
size: 20,
|
|
48
|
+
fallback: true,
|
|
49
|
+
}),
|
|
50
|
+
}}
|
|
51
|
+
/>
|
|
52
|
+
<span class="font-medium">{collection.title}</span>
|
|
65
53
|
</div>
|
|
54
|
+
<p class="text-sm text-muted-foreground mt-1">
|
|
55
|
+
{collection.postCount}{" "}
|
|
56
|
+
{collection.postCount === 1
|
|
57
|
+
? t({
|
|
58
|
+
message: "entry",
|
|
59
|
+
comment: "@context: Singular entry count label",
|
|
60
|
+
})
|
|
61
|
+
: t({
|
|
62
|
+
message: "entries",
|
|
63
|
+
comment: "@context: Plural entry count label",
|
|
64
|
+
})}
|
|
65
|
+
</p>
|
|
66
66
|
</a>
|
|
67
67
|
))}
|
|
68
68
|
</div>
|
|
@@ -19,12 +19,21 @@ export const HomePage: FC<HomePageProps> = ({
|
|
|
19
19
|
return (
|
|
20
20
|
<div data-page="home">
|
|
21
21
|
{items.length === 0 ? (
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
<div data-feed>
|
|
23
|
+
<div id="timeline-feed">
|
|
24
|
+
<div id="timeline-items" class="flex flex-col">
|
|
25
|
+
<p
|
|
26
|
+
id="empty-timeline"
|
|
27
|
+
class="py-12 text-center text-muted-foreground"
|
|
28
|
+
>
|
|
29
|
+
{t({
|
|
30
|
+
message: "No posts yet.",
|
|
31
|
+
comment: "@context: Empty state message on home page",
|
|
32
|
+
})}
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
28
37
|
) : (
|
|
29
38
|
<TimelineFeed
|
|
30
39
|
items={items}
|
|
@@ -71,9 +71,8 @@ export const SearchPage: FC<SearchPageProps> = ({
|
|
|
71
71
|
comment: "@context: Search results count - single",
|
|
72
72
|
})
|
|
73
73
|
: t({
|
|
74
|
-
message:
|
|
74
|
+
message: `Found ${String(results.length)} results`,
|
|
75
75
|
comment: "@context: Search results count - multiple",
|
|
76
|
-
values: { count: String(results.length) },
|
|
77
76
|
})}
|
|
78
77
|
</p>
|
|
79
78
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collections Sidebar
|
|
3
|
+
*
|
|
4
|
+
* Shared sidebar navigation for public collection pages.
|
|
5
|
+
* Shows all collections with icons and active state.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { FC } from "hono/jsx";
|
|
9
|
+
import { useLingui } from "@lingui/react/macro";
|
|
10
|
+
import type { Collection } from "../../types.js";
|
|
11
|
+
import { renderCollectionIcon } from "../../lib/icons.js";
|
|
12
|
+
|
|
13
|
+
export interface CollectionsSidebarProps {
|
|
14
|
+
collections: Collection[];
|
|
15
|
+
activeSlug?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const CollectionsSidebar: FC<CollectionsSidebarProps> = ({
|
|
19
|
+
collections,
|
|
20
|
+
activeSlug,
|
|
21
|
+
}) => {
|
|
22
|
+
const { t } = useLingui();
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<nav class="flex flex-col gap-1 pt-6">
|
|
26
|
+
<h2 class="px-3 pb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
|
27
|
+
{t({
|
|
28
|
+
message: "Collections",
|
|
29
|
+
comment: "@context: Sidebar heading for collections nav",
|
|
30
|
+
})}
|
|
31
|
+
</h2>
|
|
32
|
+
{collections.map((col) => {
|
|
33
|
+
const isActive = col.slug === activeSlug;
|
|
34
|
+
return (
|
|
35
|
+
<a
|
|
36
|
+
key={col.id}
|
|
37
|
+
href={`/c/${col.slug}`}
|
|
38
|
+
class={`flex items-center gap-2.5 px-3 py-2 text-sm rounded-md truncate ${
|
|
39
|
+
isActive
|
|
40
|
+
? "bg-accent text-accent-foreground font-medium"
|
|
41
|
+
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
42
|
+
}`}
|
|
43
|
+
>
|
|
44
|
+
<span
|
|
45
|
+
class="flex items-center justify-center w-4 h-4 shrink-0"
|
|
46
|
+
dangerouslySetInnerHTML={{
|
|
47
|
+
__html: renderCollectionIcon(col.icon, {
|
|
48
|
+
size: 16,
|
|
49
|
+
fallback: true,
|
|
50
|
+
}),
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
<span class="truncate">{col.title}</span>
|
|
54
|
+
</a>
|
|
55
|
+
);
|
|
56
|
+
})}
|
|
57
|
+
</nav>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
@@ -224,10 +224,10 @@ export const PagePagination: FC<PagePaginationProps> = ({
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// Simple prev/next fallback when totalPages is unknown
|
|
227
|
+
const page = String(currentPage);
|
|
227
228
|
const pageText = t({
|
|
228
|
-
message:
|
|
229
|
+
message: `Page ${page}`,
|
|
229
230
|
comment: "@context: Pagination - current page indicator",
|
|
230
|
-
values: { page: String(currentPage) },
|
|
231
231
|
});
|
|
232
232
|
|
|
233
233
|
return (
|