@jant/core 0.3.25 → 0.3.26

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 (131) hide show
  1. package/dist/app.js +67 -562
  2. package/dist/client.js +1 -0
  3. package/dist/i18n/locales/en.js +1 -1
  4. package/dist/i18n/locales/zh-Hans.js +1 -1
  5. package/dist/i18n/locales/zh-Hant.js +1 -1
  6. package/dist/lib/avatar-upload.js +134 -0
  7. package/dist/lib/config.js +39 -0
  8. package/dist/lib/constants.js +10 -10
  9. package/dist/lib/favicon.js +102 -0
  10. package/dist/lib/image.js +13 -17
  11. package/dist/lib/media-helpers.js +2 -2
  12. package/dist/lib/navigation.js +23 -3
  13. package/dist/lib/render.js +10 -1
  14. package/dist/lib/schemas.js +31 -0
  15. package/dist/lib/timezones.js +388 -0
  16. package/dist/lib/view.js +1 -1
  17. package/dist/routes/api/posts.js +1 -1
  18. package/dist/routes/api/upload.js +3 -3
  19. package/dist/routes/auth/reset.js +221 -0
  20. package/dist/routes/auth/setup.js +194 -0
  21. package/dist/routes/auth/signin.js +176 -0
  22. package/dist/routes/dash/collections.js +23 -415
  23. package/dist/routes/dash/media.js +12 -392
  24. package/dist/routes/dash/pages.js +7 -330
  25. package/dist/routes/dash/redirects.js +18 -12
  26. package/dist/routes/dash/settings.js +198 -577
  27. package/dist/routes/feed/rss.js +2 -1
  28. package/dist/routes/feed/sitemap.js +4 -2
  29. package/dist/routes/pages/featured.js +5 -1
  30. package/dist/routes/pages/home.js +26 -1
  31. package/dist/routes/pages/latest.js +45 -0
  32. package/dist/services/post.js +30 -50
  33. package/dist/types/bindings.js +3 -0
  34. package/dist/types/config.js +147 -0
  35. package/dist/types/constants.js +27 -0
  36. package/dist/types/entities.js +3 -0
  37. package/dist/types/operations.js +3 -0
  38. package/dist/types/props.js +3 -0
  39. package/dist/types/views.js +5 -0
  40. package/dist/types.js +8 -111
  41. package/dist/ui/color-themes.js +33 -33
  42. package/dist/ui/compose/ComposeDialog.js +36 -21
  43. package/dist/ui/dash/PageForm.js +21 -15
  44. package/dist/ui/dash/PostForm.js +22 -16
  45. package/dist/ui/dash/collections/CollectionForm.js +152 -0
  46. package/dist/ui/dash/collections/CollectionsListContent.js +68 -0
  47. package/dist/ui/dash/collections/ViewCollectionContent.js +96 -0
  48. package/dist/ui/dash/media/MediaListContent.js +166 -0
  49. package/dist/ui/dash/media/ViewMediaContent.js +212 -0
  50. package/dist/ui/dash/pages/LinkFormContent.js +130 -0
  51. package/dist/ui/dash/pages/UnifiedPagesContent.js +193 -0
  52. package/dist/ui/dash/settings/AccountContent.js +209 -0
  53. package/dist/ui/dash/settings/AppearanceContent.js +259 -0
  54. package/dist/ui/dash/settings/GeneralContent.js +536 -0
  55. package/dist/ui/dash/settings/SettingsNav.js +41 -0
  56. package/dist/ui/font-themes.js +36 -0
  57. package/dist/ui/layouts/BaseLayout.js +24 -2
  58. package/dist/ui/layouts/SiteLayout.js +47 -19
  59. package/package.json +1 -1
  60. package/src/app.tsx +93 -553
  61. package/src/client.ts +1 -0
  62. package/src/i18n/locales/en.po +240 -175
  63. package/src/i18n/locales/en.ts +1 -1
  64. package/src/i18n/locales/zh-Hans.po +240 -175
  65. package/src/i18n/locales/zh-Hans.ts +1 -1
  66. package/src/i18n/locales/zh-Hant.po +240 -175
  67. package/src/i18n/locales/zh-Hant.ts +1 -1
  68. package/src/lib/__tests__/config.test.ts +192 -0
  69. package/src/lib/__tests__/favicon.test.ts +151 -0
  70. package/src/lib/__tests__/image.test.ts +2 -6
  71. package/src/lib/__tests__/timezones.test.ts +61 -0
  72. package/src/lib/__tests__/view.test.ts +2 -2
  73. package/src/lib/avatar-upload.ts +165 -0
  74. package/src/lib/config.ts +47 -0
  75. package/src/lib/constants.ts +19 -11
  76. package/src/lib/favicon.ts +115 -0
  77. package/src/lib/image.ts +13 -21
  78. package/src/lib/media-helpers.ts +2 -2
  79. package/src/lib/navigation.ts +33 -2
  80. package/src/lib/render.tsx +15 -1
  81. package/src/lib/schemas.ts +39 -0
  82. package/src/lib/timezones.ts +325 -0
  83. package/src/lib/view.ts +1 -1
  84. package/src/routes/api/posts.ts +1 -1
  85. package/src/routes/api/upload.ts +2 -3
  86. package/src/routes/auth/reset.tsx +239 -0
  87. package/src/routes/auth/setup.tsx +189 -0
  88. package/src/routes/auth/signin.tsx +163 -0
  89. package/src/routes/dash/__tests__/settings-avatar.test.ts +89 -0
  90. package/src/routes/dash/collections.tsx +17 -366
  91. package/src/routes/dash/media.tsx +12 -414
  92. package/src/routes/dash/pages.tsx +8 -348
  93. package/src/routes/dash/redirects.tsx +20 -14
  94. package/src/routes/dash/settings.tsx +243 -534
  95. package/src/routes/feed/__tests__/rss.test.ts +141 -0
  96. package/src/routes/feed/rss.ts +3 -1
  97. package/src/routes/feed/sitemap.ts +4 -2
  98. package/src/routes/pages/featured.tsx +7 -1
  99. package/src/routes/pages/home.tsx +25 -2
  100. package/src/routes/pages/latest.tsx +59 -0
  101. package/src/services/post.ts +34 -66
  102. package/src/styles/components.css +0 -65
  103. package/src/styles/tokens.css +1 -1
  104. package/src/styles/ui.css +24 -40
  105. package/src/types/bindings.ts +30 -0
  106. package/src/types/config.ts +183 -0
  107. package/src/types/constants.ts +26 -0
  108. package/src/types/entities.ts +109 -0
  109. package/src/types/operations.ts +88 -0
  110. package/src/types/props.ts +115 -0
  111. package/src/types/views.ts +172 -0
  112. package/src/types.ts +8 -644
  113. package/src/ui/__tests__/font-themes.test.ts +34 -0
  114. package/src/ui/color-themes.ts +34 -34
  115. package/src/ui/compose/ComposeDialog.tsx +40 -21
  116. package/src/ui/dash/PageForm.tsx +25 -19
  117. package/src/ui/dash/PostForm.tsx +26 -20
  118. package/src/ui/dash/collections/CollectionForm.tsx +153 -0
  119. package/src/ui/dash/collections/CollectionsListContent.tsx +85 -0
  120. package/src/ui/dash/collections/ViewCollectionContent.tsx +92 -0
  121. package/src/ui/dash/media/MediaListContent.tsx +201 -0
  122. package/src/ui/dash/media/ViewMediaContent.tsx +208 -0
  123. package/src/ui/dash/pages/LinkFormContent.tsx +119 -0
  124. package/src/ui/dash/pages/UnifiedPagesContent.tsx +203 -0
  125. package/src/ui/dash/settings/AccountContent.tsx +176 -0
  126. package/src/ui/dash/settings/AppearanceContent.tsx +254 -0
  127. package/src/ui/dash/settings/GeneralContent.tsx +533 -0
  128. package/src/ui/dash/settings/SettingsNav.tsx +56 -0
  129. package/src/ui/font-themes.ts +54 -0
  130. package/src/ui/layouts/BaseLayout.tsx +17 -0
  131. package/src/ui/layouts/SiteLayout.tsx +45 -31
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Unified pages list - navigation items + other pages
3
+ */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
4
+ import { useLingui as $_useLingui } from "@jant/core/i18n";
5
+ import { ListItemRow, ActionButtons, CrudPageHeader } from "../index.js";
6
+ export function UnifiedPagesContent({ navItems, otherPages }) {
7
+ const { i18n: $__i18n, _: $__ } = $_useLingui();
8
+ return /*#__PURE__*/ _jsxs(_Fragment, {
9
+ children: [
10
+ /*#__PURE__*/ _jsx(CrudPageHeader, {
11
+ title: $__i18n._({
12
+ id: "wRR604",
13
+ message: "Pages"
14
+ }),
15
+ children: /*#__PURE__*/ _jsxs("div", {
16
+ class: "flex gap-2",
17
+ children: [
18
+ /*#__PURE__*/ _jsx("a", {
19
+ href: "/dash/pages/links/new",
20
+ class: "btn-outline",
21
+ children: $__i18n._({
22
+ id: "V4WsyL",
23
+ message: "Add Link"
24
+ })
25
+ }),
26
+ /*#__PURE__*/ _jsx("a", {
27
+ href: "/dash/pages/new",
28
+ class: "btn",
29
+ children: $__i18n._({
30
+ id: "GrZ6fH",
31
+ message: "New Page"
32
+ })
33
+ })
34
+ ]
35
+ })
36
+ }),
37
+ /*#__PURE__*/ _jsxs("section", {
38
+ class: "mb-8",
39
+ children: [
40
+ /*#__PURE__*/ _jsx("h2", {
41
+ class: "text-lg font-medium mb-3",
42
+ children: $__i18n._({
43
+ id: "GTPbOX",
44
+ message: "Your site navigation"
45
+ })
46
+ }),
47
+ navItems.length === 0 ? /*#__PURE__*/ _jsx("p", {
48
+ class: "text-sm text-muted-foreground py-4",
49
+ children: $__i18n._({
50
+ id: "vh0C9b",
51
+ message: "No navigation links yet. Add pages to navigation or create links."
52
+ })
53
+ }) : /*#__PURE__*/ _jsx("div", {
54
+ id: "nav-links-list",
55
+ class: "flex flex-col divide-y",
56
+ children: navItems.map((item)=>/*#__PURE__*/ _jsx(ListItemRow, {
57
+ actions: item.type === "page" ? /*#__PURE__*/ _jsxs(_Fragment, {
58
+ children: [
59
+ /*#__PURE__*/ _jsx(ActionButtons, {
60
+ editHref: item.pageId ? `/dash/pages/${item.pageId}/edit` : undefined,
61
+ editLabel: $__i18n._({
62
+ id: "ePK91l",
63
+ message: "Edit"
64
+ })
65
+ }),
66
+ /*#__PURE__*/ _jsx("button", {
67
+ type: "button",
68
+ class: "btn-sm-ghost",
69
+ "data-on:click__prevent": `@post('/dash/pages/${item.pageId}/remove-from-nav')`,
70
+ children: $__i18n._({
71
+ id: "g3mKmM",
72
+ message: "Un-nav"
73
+ })
74
+ })
75
+ ]
76
+ }) : /*#__PURE__*/ _jsx(_Fragment, {
77
+ children: /*#__PURE__*/ _jsx(ActionButtons, {
78
+ editHref: `/dash/pages/links/${item.id}/edit`,
79
+ editLabel: $__i18n._({
80
+ id: "ePK91l",
81
+ message: "Edit"
82
+ }),
83
+ deleteAction: `/dash/pages/links/${item.id}/delete`,
84
+ deleteLabel: $__i18n._({
85
+ id: "cnGeoo",
86
+ message: "Delete"
87
+ })
88
+ })
89
+ }),
90
+ children: /*#__PURE__*/ _jsxs("div", {
91
+ class: "flex items-center gap-3 cursor-grab",
92
+ "data-id": item.id,
93
+ children: [
94
+ /*#__PURE__*/ _jsx("span", {
95
+ class: "text-muted-foreground select-none",
96
+ children: "⠿"
97
+ }),
98
+ /*#__PURE__*/ _jsxs("div", {
99
+ class: "flex items-center gap-2",
100
+ children: [
101
+ /*#__PURE__*/ _jsx("span", {
102
+ class: "font-medium",
103
+ children: item.label
104
+ }),
105
+ /*#__PURE__*/ _jsx("code", {
106
+ class: "text-sm text-muted-foreground bg-muted px-1 rounded",
107
+ children: item.url
108
+ }),
109
+ /*#__PURE__*/ _jsx("span", {
110
+ class: "badge-secondary",
111
+ children: item.type === "page" ? $__i18n._({
112
+ id: "MnbH31",
113
+ message: "page"
114
+ }) : $__i18n._({
115
+ id: "LdyooL",
116
+ message: "link"
117
+ })
118
+ })
119
+ ]
120
+ })
121
+ ]
122
+ })
123
+ }, item.id))
124
+ })
125
+ ]
126
+ }),
127
+ /*#__PURE__*/ _jsxs("section", {
128
+ children: [
129
+ /*#__PURE__*/ _jsx("h2", {
130
+ class: "text-lg font-medium mb-3",
131
+ children: $__i18n._({
132
+ id: "Y75ho6",
133
+ message: "Other pages"
134
+ })
135
+ }),
136
+ otherPages.length === 0 ? /*#__PURE__*/ _jsx("p", {
137
+ class: "text-sm text-muted-foreground py-4",
138
+ children: $__i18n._({
139
+ id: "/rkqRV",
140
+ message: "All pages are in your navigation."
141
+ })
142
+ }) : /*#__PURE__*/ _jsx("div", {
143
+ class: "flex flex-col divide-y",
144
+ children: otherPages.map((page)=>/*#__PURE__*/ _jsxs(ListItemRow, {
145
+ actions: /*#__PURE__*/ _jsxs(_Fragment, {
146
+ children: [
147
+ /*#__PURE__*/ _jsx("button", {
148
+ type: "button",
149
+ class: "btn-sm-outline",
150
+ "data-on:click__prevent": `@post('/dash/pages/${page.id}/add-to-nav')`,
151
+ children: $__i18n._({
152
+ id: "+MH6k9",
153
+ message: "Add to nav"
154
+ })
155
+ }),
156
+ /*#__PURE__*/ _jsx(ActionButtons, {
157
+ editHref: `/dash/pages/${page.id}/edit`,
158
+ editLabel: $__i18n._({
159
+ id: "ePK91l",
160
+ message: "Edit"
161
+ }),
162
+ viewHref: page.status !== "draft" ? `/${page.slug}` : undefined,
163
+ viewLabel: $__i18n._({
164
+ id: "jpctdh",
165
+ message: "View"
166
+ })
167
+ })
168
+ ]
169
+ }),
170
+ children: [
171
+ /*#__PURE__*/ _jsx("a", {
172
+ href: `/dash/pages/${page.id}`,
173
+ class: "font-medium hover:underline",
174
+ children: page.title || $__i18n._({
175
+ id: "wja8aL",
176
+ message: "Untitled"
177
+ })
178
+ }),
179
+ /*#__PURE__*/ _jsxs("p", {
180
+ class: "text-sm text-muted-foreground mt-1",
181
+ children: [
182
+ "/",
183
+ page.slug
184
+ ]
185
+ })
186
+ ]
187
+ }, page.id))
188
+ })
189
+ ]
190
+ })
191
+ ]
192
+ });
193
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Account settings: profile + password change forms
3
+ */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
4
+ import { useLingui as $_useLingui } from "@jant/core/i18n";
5
+ import { SettingsNav } from "./SettingsNav.js";
6
+ export function AccountContent({ userName }) {
7
+ const { i18n: $__i18n, _: $__ } = $_useLingui();
8
+ const profileSignals = JSON.stringify({
9
+ userName
10
+ }).replace(/</g, "\\u003c");
11
+ return /*#__PURE__*/ _jsxs(_Fragment, {
12
+ children: [
13
+ /*#__PURE__*/ _jsx("h1", {
14
+ class: "text-2xl font-semibold mb-2",
15
+ children: $__i18n._({
16
+ id: "Tz0i8g",
17
+ message: "Settings"
18
+ })
19
+ }),
20
+ /*#__PURE__*/ _jsx(SettingsNav, {
21
+ currentTab: "account"
22
+ }),
23
+ /*#__PURE__*/ _jsxs("div", {
24
+ class: "flex flex-col gap-6 max-w-lg",
25
+ children: [
26
+ /*#__PURE__*/ _jsxs("form", {
27
+ "data-signals": profileSignals,
28
+ "data-on:submit__prevent": "@post('/dash/settings/account')",
29
+ "data-indicator": "_profileLoading",
30
+ children: [
31
+ /*#__PURE__*/ _jsxs("div", {
32
+ class: "card",
33
+ children: [
34
+ /*#__PURE__*/ _jsx("header", {
35
+ children: /*#__PURE__*/ _jsx("h2", {
36
+ children: $__i18n._({
37
+ id: "vERlcd",
38
+ message: "Profile"
39
+ })
40
+ })
41
+ }),
42
+ /*#__PURE__*/ _jsx("section", {
43
+ class: "flex flex-col gap-4",
44
+ children: /*#__PURE__*/ _jsxs("div", {
45
+ class: "field",
46
+ children: [
47
+ /*#__PURE__*/ _jsx("label", {
48
+ class: "label",
49
+ children: $__i18n._({
50
+ id: "6YtxFj",
51
+ message: "Name"
52
+ })
53
+ }),
54
+ /*#__PURE__*/ _jsx("input", {
55
+ type: "text",
56
+ "data-bind": "userName",
57
+ class: "input",
58
+ required: true
59
+ })
60
+ ]
61
+ })
62
+ })
63
+ ]
64
+ }),
65
+ /*#__PURE__*/ _jsxs("button", {
66
+ type: "submit",
67
+ class: "btn mt-4",
68
+ "data-attr:disabled": "$_profileLoading",
69
+ children: [
70
+ /*#__PURE__*/ _jsx("svg", {
71
+ "data-show": "$_profileLoading",
72
+ style: "display:none",
73
+ class: "animate-spin size-4",
74
+ xmlns: "http://www.w3.org/2000/svg",
75
+ viewBox: "0 0 24 24",
76
+ fill: "none",
77
+ stroke: "currentColor",
78
+ "stroke-width": "2",
79
+ "stroke-linecap": "round",
80
+ "stroke-linejoin": "round",
81
+ role: "status",
82
+ children: /*#__PURE__*/ _jsx("path", {
83
+ d: "M21 12a9 9 0 1 1-6.219-8.56"
84
+ })
85
+ }),
86
+ $__i18n._({
87
+ id: "ssqvZi",
88
+ message: "Save Profile"
89
+ })
90
+ ]
91
+ })
92
+ ]
93
+ }),
94
+ /*#__PURE__*/ _jsxs("form", {
95
+ "data-signals": "{currentPassword: '', newPassword: '', confirmPassword: ''}",
96
+ "data-on:submit__prevent": "@post('/dash/settings/password')",
97
+ "data-indicator": "_passwordLoading",
98
+ children: [
99
+ /*#__PURE__*/ _jsxs("div", {
100
+ class: "card",
101
+ children: [
102
+ /*#__PURE__*/ _jsx("header", {
103
+ children: /*#__PURE__*/ _jsx("h2", {
104
+ children: $__i18n._({
105
+ id: "VhMDMg",
106
+ message: "Change Password"
107
+ })
108
+ })
109
+ }),
110
+ /*#__PURE__*/ _jsxs("section", {
111
+ class: "flex flex-col gap-4",
112
+ children: [
113
+ /*#__PURE__*/ _jsxs("div", {
114
+ class: "field",
115
+ children: [
116
+ /*#__PURE__*/ _jsx("label", {
117
+ class: "label",
118
+ children: $__i18n._({
119
+ id: "DCKkhU",
120
+ message: "Current Password"
121
+ })
122
+ }),
123
+ /*#__PURE__*/ _jsx("input", {
124
+ type: "password",
125
+ "data-bind": "currentPassword",
126
+ class: "input",
127
+ required: true,
128
+ autocomplete: "current-password"
129
+ })
130
+ ]
131
+ }),
132
+ /*#__PURE__*/ _jsxs("div", {
133
+ class: "field",
134
+ children: [
135
+ /*#__PURE__*/ _jsx("label", {
136
+ class: "label",
137
+ children: $__i18n._({
138
+ id: "7vhWI8",
139
+ message: "New Password"
140
+ })
141
+ }),
142
+ /*#__PURE__*/ _jsx("input", {
143
+ type: "password",
144
+ "data-bind": "newPassword",
145
+ class: "input",
146
+ required: true,
147
+ minlength: 8,
148
+ autocomplete: "new-password"
149
+ })
150
+ ]
151
+ }),
152
+ /*#__PURE__*/ _jsxs("div", {
153
+ class: "field",
154
+ children: [
155
+ /*#__PURE__*/ _jsx("label", {
156
+ class: "label",
157
+ children: $__i18n._({
158
+ id: "yjkELF",
159
+ message: "Confirm New Password"
160
+ })
161
+ }),
162
+ /*#__PURE__*/ _jsx("input", {
163
+ type: "password",
164
+ "data-bind": "confirmPassword",
165
+ class: "input",
166
+ required: true,
167
+ minlength: 8,
168
+ autocomplete: "new-password"
169
+ })
170
+ ]
171
+ })
172
+ ]
173
+ })
174
+ ]
175
+ }),
176
+ /*#__PURE__*/ _jsxs("button", {
177
+ type: "submit",
178
+ class: "btn mt-4",
179
+ "data-attr:disabled": "$_passwordLoading",
180
+ children: [
181
+ /*#__PURE__*/ _jsx("svg", {
182
+ "data-show": "$_passwordLoading",
183
+ style: "display:none",
184
+ class: "animate-spin size-4",
185
+ xmlns: "http://www.w3.org/2000/svg",
186
+ viewBox: "0 0 24 24",
187
+ fill: "none",
188
+ stroke: "currentColor",
189
+ "stroke-width": "2",
190
+ "stroke-linecap": "round",
191
+ "stroke-linejoin": "round",
192
+ role: "status",
193
+ children: /*#__PURE__*/ _jsx("path", {
194
+ d: "M21 12a9 9 0 1 1-6.219-8.56"
195
+ })
196
+ }),
197
+ $__i18n._({
198
+ id: "VhMDMg",
199
+ message: "Change Password"
200
+ })
201
+ ]
202
+ })
203
+ ]
204
+ })
205
+ ]
206
+ })
207
+ ]
208
+ });
209
+ }
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Appearance settings: color theme picker + custom CSS form
3
+ */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
4
+ import { useLingui as $_useLingui } from "@jant/core/i18n";
5
+ import { SettingsNav } from "./SettingsNav.js";
6
+ function ThemeCard({ theme, selected }) {
7
+ const expr = `$theme === '${theme.id}'`;
8
+ const { preview } = theme;
9
+ return /*#__PURE__*/ _jsx("label", {
10
+ class: `block cursor-pointer rounded-lg border overflow-hidden transition-colors ${selected ? "border-primary" : "border-border"}`,
11
+ "data-class:border-primary": expr,
12
+ "data-class:border-border": `$theme !== '${theme.id}'`,
13
+ children: /*#__PURE__*/ _jsxs("div", {
14
+ class: "grid grid-cols-2",
15
+ children: [
16
+ /*#__PURE__*/ _jsxs("div", {
17
+ class: "p-5",
18
+ style: `background-color:${preview.lightBg};color:${preview.lightText}`,
19
+ children: [
20
+ /*#__PURE__*/ _jsx("input", {
21
+ type: "radio",
22
+ name: "theme",
23
+ value: theme.id,
24
+ "data-bind": "theme",
25
+ checked: selected || undefined,
26
+ class: "mb-1"
27
+ }),
28
+ /*#__PURE__*/ _jsx("h3", {
29
+ class: "font-bold text-lg",
30
+ children: theme.name
31
+ }),
32
+ /*#__PURE__*/ _jsxs("p", {
33
+ class: "text-sm mt-2 leading-relaxed",
34
+ children: [
35
+ "This is the ",
36
+ theme.name,
37
+ " theme in light mode. Links",
38
+ " ",
39
+ /*#__PURE__*/ _jsx("a", {
40
+ tabIndex: -1,
41
+ class: "underline",
42
+ style: `color:${preview.lightLink}`,
43
+ children: "look like this"
44
+ }),
45
+ ". We'll show the correct light or dark mode based on your visitor's settings."
46
+ ]
47
+ })
48
+ ]
49
+ }),
50
+ /*#__PURE__*/ _jsxs("div", {
51
+ class: "p-5",
52
+ style: `background-color:${preview.darkBg};color:${preview.darkText}`,
53
+ children: [
54
+ /*#__PURE__*/ _jsx("h3", {
55
+ class: "font-bold text-lg",
56
+ children: theme.name
57
+ }),
58
+ /*#__PURE__*/ _jsxs("p", {
59
+ class: "text-sm mt-2 leading-relaxed",
60
+ children: [
61
+ "This is the ",
62
+ theme.name,
63
+ " theme in dark mode. Links",
64
+ " ",
65
+ /*#__PURE__*/ _jsx("a", {
66
+ tabIndex: -1,
67
+ class: "underline",
68
+ style: `color:${preview.darkLink}`,
69
+ children: "look like this"
70
+ }),
71
+ ". We'll show the correct light or dark mode based on your visitor's settings."
72
+ ]
73
+ })
74
+ ]
75
+ })
76
+ ]
77
+ })
78
+ });
79
+ }
80
+ export function AppearanceContent({ themes, currentThemeId, fontThemes, currentFontThemeId, customCSS }) {
81
+ const { i18n: $__i18n, _: $__ } = $_useLingui();
82
+ const themeSignals = JSON.stringify({
83
+ theme: currentThemeId
84
+ }).replace(/</g, "\\u003c");
85
+ const cssSignals = JSON.stringify({
86
+ customCSS
87
+ }).replace(/</g, "\\u003c");
88
+ return /*#__PURE__*/ _jsxs(_Fragment, {
89
+ children: [
90
+ /*#__PURE__*/ _jsx("h1", {
91
+ class: "text-2xl font-semibold mb-2",
92
+ children: $__i18n._({
93
+ id: "Tz0i8g",
94
+ message: "Settings"
95
+ })
96
+ }),
97
+ /*#__PURE__*/ _jsx(SettingsNav, {
98
+ currentTab: "appearance"
99
+ }),
100
+ /*#__PURE__*/ _jsx("div", {
101
+ "data-signals": themeSignals,
102
+ "data-on:change": "@post('/dash/settings/appearance')",
103
+ class: "max-w-3xl mb-8",
104
+ children: /*#__PURE__*/ _jsxs("fieldset", {
105
+ children: [
106
+ /*#__PURE__*/ _jsx("legend", {
107
+ class: "text-lg font-semibold",
108
+ children: $__i18n._({
109
+ id: "rFmBG3",
110
+ message: "Color theme"
111
+ })
112
+ }),
113
+ /*#__PURE__*/ _jsx("p", {
114
+ class: "text-sm text-muted-foreground mb-4",
115
+ children: $__i18n._({
116
+ id: "07Epll",
117
+ message: "This will theme both your site and your dashboard. All color themes support dark mode."
118
+ })
119
+ }),
120
+ /*#__PURE__*/ _jsx("div", {
121
+ class: "flex flex-col gap-4",
122
+ children: themes.map((theme)=>/*#__PURE__*/ _jsx(ThemeCard, {
123
+ theme: theme,
124
+ selected: theme.id === currentThemeId
125
+ }, theme.id))
126
+ })
127
+ ]
128
+ })
129
+ }),
130
+ /*#__PURE__*/ _jsx("div", {
131
+ "data-signals": JSON.stringify({
132
+ fontTheme: currentFontThemeId
133
+ }).replace(/</g, "\\u003c"),
134
+ "data-on:change": "@post('/dash/settings/font-theme')",
135
+ class: "max-w-3xl",
136
+ children: /*#__PURE__*/ _jsxs("fieldset", {
137
+ children: [
138
+ /*#__PURE__*/ _jsx("legend", {
139
+ class: "text-lg font-semibold",
140
+ children: $__i18n._({
141
+ id: "M2kIWU",
142
+ message: "Font theme"
143
+ })
144
+ }),
145
+ /*#__PURE__*/ _jsx("p", {
146
+ class: "text-sm text-muted-foreground mb-4",
147
+ children: $__i18n._({
148
+ id: "3SAro+",
149
+ message: "Choose a font for your site. All options use system fonts for fast loading."
150
+ })
151
+ }),
152
+ /*#__PURE__*/ _jsx("div", {
153
+ class: "flex flex-col gap-2",
154
+ children: fontThemes.map((ft)=>/*#__PURE__*/ _jsxs("label", {
155
+ class: `flex items-start gap-3 p-3 rounded-lg border cursor-pointer transition-colors ${ft.id === currentFontThemeId ? "border-primary" : "border-border"}`,
156
+ "data-class:border-primary": `$fontTheme === '${ft.id}'`,
157
+ "data-class:border-border": `$fontTheme !== '${ft.id}'`,
158
+ children: [
159
+ /*#__PURE__*/ _jsx("input", {
160
+ type: "radio",
161
+ name: "fontTheme",
162
+ value: ft.id,
163
+ "data-bind": "fontTheme",
164
+ checked: ft.id === currentFontThemeId || undefined,
165
+ class: "mt-1"
166
+ }),
167
+ /*#__PURE__*/ _jsxs("div", {
168
+ children: [
169
+ /*#__PURE__*/ _jsx("div", {
170
+ class: "font-medium",
171
+ children: ft.name
172
+ }),
173
+ /*#__PURE__*/ _jsx("div", {
174
+ class: "text-sm text-muted-foreground",
175
+ children: ft.description
176
+ }),
177
+ /*#__PURE__*/ _jsxs("div", {
178
+ class: "mt-1 text-sm",
179
+ style: `font-family:${ft.fontFamily}`,
180
+ children: [
181
+ "The quick brown fox jumps over the lazy dog.",
182
+ " ",
183
+ "敏捷的棕色狐狸跳过了懒狗。"
184
+ ]
185
+ })
186
+ ]
187
+ })
188
+ ]
189
+ }, ft.id))
190
+ })
191
+ ]
192
+ })
193
+ }),
194
+ /*#__PURE__*/ _jsxs("form", {
195
+ "data-signals": cssSignals,
196
+ "data-on:submit__prevent": "@post('/dash/settings/custom-css')",
197
+ "data-indicator": "_cssLoading",
198
+ class: "max-w-3xl mt-8",
199
+ children: [
200
+ /*#__PURE__*/ _jsxs("fieldset", {
201
+ children: [
202
+ /*#__PURE__*/ _jsx("legend", {
203
+ class: "text-lg font-semibold",
204
+ children: $__i18n._({
205
+ id: "9+vGLh",
206
+ message: "Custom CSS"
207
+ })
208
+ }),
209
+ /*#__PURE__*/ _jsx("p", {
210
+ class: "text-sm text-muted-foreground mb-4",
211
+ children: $__i18n._({
212
+ id: "vmQmHx",
213
+ message: "Add custom CSS to override any styles. Use data attributes like [data-page], [data-post], [data-format] to target specific elements."
214
+ })
215
+ }),
216
+ /*#__PURE__*/ _jsx("textarea", {
217
+ "data-bind": "customCSS",
218
+ class: "textarea font-mono text-sm min-h-32",
219
+ rows: 8,
220
+ placeholder: $__i18n._({
221
+ id: "wc+17X",
222
+ message: "/* Your custom CSS here */"
223
+ }),
224
+ children: customCSS
225
+ })
226
+ ]
227
+ }),
228
+ /*#__PURE__*/ _jsxs("button", {
229
+ type: "submit",
230
+ class: "btn mt-4",
231
+ "data-attr:disabled": "$_cssLoading",
232
+ children: [
233
+ /*#__PURE__*/ _jsx("svg", {
234
+ "data-show": "$_cssLoading",
235
+ style: "display:none",
236
+ class: "animate-spin size-4",
237
+ xmlns: "http://www.w3.org/2000/svg",
238
+ viewBox: "0 0 24 24",
239
+ fill: "none",
240
+ stroke: "currentColor",
241
+ "stroke-width": "2",
242
+ "stroke-linecap": "round",
243
+ "stroke-linejoin": "round",
244
+ role: "status",
245
+ children: /*#__PURE__*/ _jsx("path", {
246
+ d: "M21 12a9 9 0 1 1-6.219-8.56"
247
+ })
248
+ }),
249
+ $__i18n._({
250
+ id: "NU2Fqi",
251
+ message: "Save CSS"
252
+ })
253
+ ]
254
+ })
255
+ ]
256
+ })
257
+ ]
258
+ });
259
+ }