@jant/core 0.3.34 → 0.3.36
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/assets/module-RjUF93sV.js +716 -0
- package/dist/client/assets/native-48B9X9Wg.js +1 -0
- package/dist/client/assets/url-8Dj-5CLW.js +1 -0
- package/dist/client/client.css +1 -1
- package/dist/client/client.js +3109 -2294
- package/dist/index.js +3327 -3031
- package/package.json +13 -4
- package/src/__tests__/helpers/app.ts +1 -1
- package/src/__tests__/helpers/db.ts +6 -0
- package/src/app.tsx +1 -5
- package/src/{lib → client}/avatar-upload.ts +1 -1
- package/src/{lib → client}/collection-form-bridge.ts +2 -2
- package/src/{ui → client}/components/__tests__/jant-collection-form.test.ts +26 -9
- package/src/{ui → client}/components/__tests__/jant-compose-dialog.test.ts +46 -14
- package/src/{ui → client}/components/__tests__/jant-compose-editor.test.ts +64 -24
- package/src/{ui → client}/components/__tests__/jant-post-form.test.ts +24 -14
- package/src/{ui → client}/components/__tests__/jant-settings-general.test.ts +3 -3
- package/src/client/components/collection-sidebar-types.ts +45 -0
- package/src/{ui → client}/components/collection-types.ts +3 -4
- package/src/{ui → client}/components/compose-types.ts +3 -1
- package/src/{ui → client}/components/jant-collection-form.ts +301 -182
- package/src/client/components/jant-collection-sidebar.ts +801 -0
- package/src/{ui → client}/components/jant-compose-dialog.ts +231 -1
- package/src/client/components/jant-compose-editor.ts +1249 -0
- package/src/client/components/jant-compose-fullscreen.ts +338 -0
- package/src/client/components/jant-media-lightbox.ts +257 -0
- package/src/{ui → client}/components/jant-nav-manager.ts +143 -84
- package/src/{ui → client}/components/jant-post-form.ts +57 -8
- package/src/{ui → client}/components/jant-settings-general.ts +2 -2
- package/src/{ui → client}/components/nav-manager-types.ts +3 -0
- package/src/{ui → client}/components/post-form-template.ts +35 -31
- package/src/{ui → client}/components/post-form-types.ts +7 -3
- package/src/{lib → client}/compose-bridge.ts +9 -7
- package/src/client/lazy-slugify.ts +51 -0
- package/src/{lib → client}/media-upload.ts +16 -3
- package/src/{lib → client}/nav-manager-bridge.ts +1 -1
- package/src/client/page-slug-bridge.ts +42 -0
- package/src/{lib → client}/post-form-bridge.ts +2 -2
- package/src/{lib → client}/settings-bridge.ts +3 -3
- package/src/client/tiptap/bubble-menu.ts +205 -0
- package/src/client/tiptap/create-editor.ts +40 -0
- package/src/client/tiptap/exitable-marks.ts +73 -0
- package/src/client/tiptap/extensions.ts +60 -0
- package/src/client/tiptap/image-node.ts +488 -0
- package/src/client/tiptap/link-toolbar.ts +371 -0
- package/src/client/tiptap/more-break.ts +50 -0
- package/src/client/tiptap/paste-image.ts +140 -0
- package/src/client/tiptap/slash-commands.ts +328 -0
- package/src/{types → client/types}/sortablejs.d.ts +1 -1
- package/src/client.ts +24 -17
- package/src/db/migrations/0012_add_tiptap_columns.sql +2 -0
- package/src/db/migrations/0013_replace_featured_with_visibility.sql +8 -0
- package/src/db/schema.ts +6 -1
- package/src/i18n/locales/en.po +641 -215
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +642 -204
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +642 -204
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/lib/__tests__/resolve-config.test.ts +2 -2
- package/src/lib/__tests__/schemas.test.ts +9 -6
- package/src/lib/__tests__/url.test.ts +2 -2
- package/src/lib/__tests__/view.test.ts +9 -9
- package/src/lib/emoji-catalog.ts +146 -0
- package/src/lib/feed.ts +1 -1
- package/src/lib/media-helpers.ts +10 -9
- package/src/lib/render.tsx +4 -3
- package/src/lib/resolve-config.ts +8 -1
- package/src/lib/schemas.ts +2 -3
- package/src/lib/summary.ts +92 -0
- package/src/lib/timeline.ts +2 -0
- package/src/lib/tiptap-render.ts +196 -0
- package/src/lib/upload.ts +97 -9
- package/src/lib/url.ts +7 -23
- package/src/lib/view.ts +33 -19
- package/src/middleware/error-handler.ts +3 -3
- package/src/preset.css +38 -0
- package/src/routes/api/collections.ts +20 -3
- package/src/routes/api/posts.ts +48 -33
- package/src/routes/api/upload.ts +7 -5
- package/src/routes/auth/reset.tsx +5 -4
- package/src/routes/auth/setup.tsx +26 -11
- package/src/routes/auth/signin.tsx +10 -7
- package/src/routes/compose.tsx +20 -11
- package/src/routes/dash/__tests__/settings-avatar.test.ts +43 -8
- package/src/routes/dash/index.tsx +7 -1
- package/src/routes/dash/media.tsx +3 -0
- package/src/routes/dash/pages.tsx +8 -2
- package/src/routes/dash/posts.tsx +6 -2
- package/src/routes/dash/redirects.tsx +15 -9
- package/src/routes/dash/settings.tsx +336 -32
- package/src/routes/feed/__tests__/rss.test.ts +245 -6
- package/src/routes/feed/rss.ts +70 -6
- package/src/routes/pages/__tests__/featured.test.ts +6 -7
- package/src/routes/pages/archive.tsx +11 -7
- package/src/routes/pages/collection.tsx +32 -15
- package/src/routes/pages/collections.tsx +11 -2
- package/src/routes/pages/featured.tsx +1 -1
- package/src/routes/pages/home.tsx +1 -1
- package/src/services/__tests__/post.test.ts +124 -33
- package/src/services/__tests__/settings.test.ts +3 -3
- package/src/services/page.ts +16 -3
- package/src/services/post.ts +96 -37
- package/src/services/search.ts +4 -2
- package/src/services/settings.ts +6 -2
- package/src/styles/components.css +240 -60
- package/src/styles/tokens.css +10 -0
- package/src/styles/ui.css +1157 -81
- package/src/types/bindings.ts +5 -0
- package/src/types/config.ts +23 -1
- package/src/types/constants.ts +3 -0
- package/src/types/entities.ts +9 -2
- package/src/types/operations.ts +9 -3
- package/src/types/props.ts +3 -3
- package/src/types/views.ts +3 -2
- package/src/ui/compose/ComposeDialog.tsx +24 -7
- package/src/ui/dash/PageForm.tsx +2 -0
- package/src/ui/dash/PostList.tsx +5 -5
- package/src/ui/dash/StatusBadge.tsx +13 -5
- package/src/ui/dash/appearance/AdvancedContent.tsx +52 -61
- package/src/ui/dash/appearance/ColorThemeContent.tsx +30 -35
- package/src/ui/dash/appearance/FontThemeContent.tsx +65 -73
- package/src/ui/dash/appearance/NavigationContent.tsx +107 -96
- package/src/ui/dash/media/MediaListContent.tsx +9 -4
- package/src/ui/dash/media/ViewMediaContent.tsx +2 -2
- package/src/ui/dash/pages/PagesContent.tsx +2 -1
- package/src/ui/dash/posts/PostForm.tsx +19 -7
- package/src/ui/dash/settings/AccountContent.tsx +133 -138
- package/src/ui/dash/settings/AvatarContent.tsx +70 -0
- package/src/ui/dash/settings/GeneralContent.tsx +3 -62
- package/src/ui/dash/settings/SettingsRootContent.tsx +236 -0
- package/src/ui/layouts/DashLayout.tsx +157 -75
- package/src/ui/layouts/SiteLayout.tsx +13 -13
- package/src/ui/pages/ArchivePage.tsx +10 -7
- package/src/ui/pages/CollectionPage.tsx +6 -35
- package/src/ui/pages/CollectionsPage.tsx +2 -1
- package/src/ui/pages/FeaturedPage.tsx +2 -1
- package/src/ui/pages/HomePage.tsx +1 -1
- package/src/ui/pages/SearchPage.tsx +1 -1
- package/src/ui/shared/CollectionsSidebar.tsx +228 -3
- package/src/ui/shared/MediaGallery.tsx +179 -41
- package/src/lib/collections-reorder.ts +0 -28
- package/src/routes/dash/appearance.tsx +0 -240
- package/src/routes/dash/collections.tsx +0 -211
- package/src/ui/components/jant-compose-editor.ts +0 -814
- package/src/ui/dash/appearance/AppearanceNav.tsx +0 -60
- package/src/ui/dash/collections/CollectionForm.tsx +0 -166
- package/src/ui/dash/collections/CollectionsListContent.tsx +0 -146
- package/src/ui/dash/collections/IconPickerGrid.tsx +0 -50
- package/src/ui/dash/collections/ViewCollectionContent.tsx +0 -103
- package/src/ui/dash/settings/SettingsNav.tsx +0 -52
- /package/src/{ui → client}/components/__tests__/jant-settings-avatar.test.ts +0 -0
- /package/src/{ui → client}/components/jant-settings-avatar.ts +0 -0
- /package/src/{ui → client}/components/settings-types.ts +0 -0
- /package/src/{lib → client}/image-processor.ts +0 -0
- /package/src/{lib → client}/toast.ts +0 -0
package/src/types/bindings.ts
CHANGED
|
@@ -27,6 +27,11 @@ export interface Bindings {
|
|
|
27
27
|
S3_SECRET_ACCESS_KEY?: string;
|
|
28
28
|
S3_REGION?: string;
|
|
29
29
|
S3_PUBLIC_URL?: string;
|
|
30
|
+
// Upload
|
|
31
|
+
UPLOAD_MAX_FILE_SIZE?: string;
|
|
32
|
+
// Summary extraction
|
|
33
|
+
SUMMARY_MAX_PARAGRAPHS?: string;
|
|
34
|
+
SUMMARY_MAX_CHARS?: string;
|
|
30
35
|
// RSS feed
|
|
31
36
|
RSS_FEED_LIMIT?: string;
|
|
32
37
|
}
|
package/src/types/config.ts
CHANGED
|
@@ -33,7 +33,7 @@ export const CONFIG_FIELDS = {
|
|
|
33
33
|
envOnly: false,
|
|
34
34
|
},
|
|
35
35
|
HEADER_NAV_MAX_VISIBLE: {
|
|
36
|
-
defaultValue: "
|
|
36
|
+
defaultValue: "2",
|
|
37
37
|
envOnly: false,
|
|
38
38
|
},
|
|
39
39
|
|
|
@@ -98,6 +98,18 @@ export const CONFIG_FIELDS = {
|
|
|
98
98
|
defaultValue: "",
|
|
99
99
|
envOnly: true,
|
|
100
100
|
},
|
|
101
|
+
UPLOAD_MAX_FILE_SIZE: {
|
|
102
|
+
defaultValue: "500",
|
|
103
|
+
envOnly: true,
|
|
104
|
+
},
|
|
105
|
+
SUMMARY_MAX_PARAGRAPHS: {
|
|
106
|
+
defaultValue: "5",
|
|
107
|
+
envOnly: true,
|
|
108
|
+
},
|
|
109
|
+
SUMMARY_MAX_CHARS: {
|
|
110
|
+
defaultValue: "500",
|
|
111
|
+
envOnly: true,
|
|
112
|
+
},
|
|
101
113
|
|
|
102
114
|
// Internal settings (DB-only, not configurable via env or dashboard)
|
|
103
115
|
THEME: {
|
|
@@ -195,6 +207,16 @@ export interface AppConfig {
|
|
|
195
207
|
s3PublicUrl: string;
|
|
196
208
|
imageTransformUrl: string;
|
|
197
209
|
|
|
210
|
+
// Upload (ENV only, parsed to number)
|
|
211
|
+
/** Max upload file size in MB. Defaults to 500. */
|
|
212
|
+
uploadMaxFileSize: number;
|
|
213
|
+
|
|
214
|
+
// Summary extraction (ENV only)
|
|
215
|
+
/** Max paragraphs to include in auto-extracted summary. Defaults to 5. */
|
|
216
|
+
summaryMaxParagraphs: number;
|
|
217
|
+
/** Max characters to include in auto-extracted summary. Defaults to 500. */
|
|
218
|
+
summaryMaxChars: number;
|
|
219
|
+
|
|
198
220
|
// Pagination/Feed (ENV only, parsed to number)
|
|
199
221
|
pageSize: number;
|
|
200
222
|
rssFeedLimit: number;
|
package/src/types/constants.ts
CHANGED
|
@@ -8,6 +8,9 @@ export type Format = (typeof FORMATS)[number];
|
|
|
8
8
|
export const STATUSES = ["draft", "published"] as const;
|
|
9
9
|
export type Status = (typeof STATUSES)[number];
|
|
10
10
|
|
|
11
|
+
export const VISIBILITIES = ["listed", "featured", "unlisted"] as const;
|
|
12
|
+
export type Visibility = (typeof VISIBILITIES)[number];
|
|
13
|
+
|
|
11
14
|
export const SORT_ORDERS = [
|
|
12
15
|
"newest",
|
|
13
16
|
"oldest",
|
package/src/types/entities.ts
CHANGED
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
* Entity Types (database-level models)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
Format,
|
|
7
|
+
Status,
|
|
8
|
+
Visibility,
|
|
9
|
+
SortOrder,
|
|
10
|
+
NavItemType,
|
|
11
|
+
} from "./constants.js";
|
|
6
12
|
|
|
7
13
|
export interface Post {
|
|
8
14
|
id: number;
|
|
9
15
|
format: Format;
|
|
10
16
|
status: Status;
|
|
11
|
-
|
|
17
|
+
visibility: Visibility;
|
|
12
18
|
pinned: number; // 0 | 1
|
|
13
19
|
path: string | null;
|
|
14
20
|
title: string | null;
|
|
@@ -16,6 +22,7 @@ export interface Post {
|
|
|
16
22
|
body: string | null;
|
|
17
23
|
bodyHtml: string | null;
|
|
18
24
|
quoteText: string | null;
|
|
25
|
+
summary: string | null;
|
|
19
26
|
rating: number | null;
|
|
20
27
|
replyToId: number | null;
|
|
21
28
|
threadId: number | null;
|
package/src/types/operations.ts
CHANGED
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
* Operation Types (create/update DTOs)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
Format,
|
|
7
|
+
Status,
|
|
8
|
+
Visibility,
|
|
9
|
+
SortOrder,
|
|
10
|
+
NavItemType,
|
|
11
|
+
} from "./constants.js";
|
|
6
12
|
|
|
7
13
|
export interface CreatePost {
|
|
8
14
|
format: Format;
|
|
9
15
|
status?: Status;
|
|
10
|
-
|
|
16
|
+
visibility?: Visibility;
|
|
11
17
|
pinned?: boolean;
|
|
12
18
|
path?: string;
|
|
13
19
|
title?: string;
|
|
@@ -24,7 +30,7 @@ export interface CreatePost {
|
|
|
24
30
|
export interface UpdatePost {
|
|
25
31
|
format?: Format;
|
|
26
32
|
status?: Status;
|
|
27
|
-
|
|
33
|
+
visibility?: Visibility;
|
|
28
34
|
pinned?: boolean;
|
|
29
35
|
path?: string | null;
|
|
30
36
|
title?: string | null;
|
package/src/types/props.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Page-Level Props & Feed Data Types
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { Format } from "./constants.js";
|
|
5
|
+
import type { Format, Visibility } from "./constants.js";
|
|
6
6
|
import type { Collection } from "./entities.js";
|
|
7
7
|
import type {
|
|
8
8
|
PostView,
|
|
@@ -45,7 +45,7 @@ export interface ArchivePageProps {
|
|
|
45
45
|
hasMore: boolean;
|
|
46
46
|
nextCursor?: number;
|
|
47
47
|
format?: Format;
|
|
48
|
-
|
|
48
|
+
visibility?: Visibility;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/** Props for the search page component */
|
|
@@ -60,7 +60,7 @@ export interface SearchPageProps {
|
|
|
60
60
|
/** Props for the single collection page component */
|
|
61
61
|
export interface CollectionPageProps {
|
|
62
62
|
collection: Collection;
|
|
63
|
-
|
|
63
|
+
items: TimelineItemView[];
|
|
64
64
|
hasMore: boolean;
|
|
65
65
|
nextCursor?: number;
|
|
66
66
|
}
|
package/src/types/views.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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
8
|
/**
|
|
@@ -35,7 +35,7 @@ export interface PostView {
|
|
|
35
35
|
// Metadata
|
|
36
36
|
format: Format;
|
|
37
37
|
status: Status;
|
|
38
|
-
|
|
38
|
+
visibility: Visibility;
|
|
39
39
|
pinned: boolean;
|
|
40
40
|
rating?: number;
|
|
41
41
|
|
|
@@ -167,4 +167,5 @@ export interface SiteLayoutProps {
|
|
|
167
167
|
showHeaderAvatar?: boolean;
|
|
168
168
|
siteFooterHtml?: string;
|
|
169
169
|
sidebar?: import("hono/jsx").Child;
|
|
170
|
+
uploadMaxFileSize?: number;
|
|
170
171
|
}
|
|
@@ -15,9 +15,13 @@ import { useLingui } from "@lingui/react/macro";
|
|
|
15
15
|
|
|
16
16
|
export interface ComposeDialogProps {
|
|
17
17
|
collections?: Collection[];
|
|
18
|
+
uploadMaxFileSize?: number;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
export const ComposeDialog: FC<ComposeDialogProps> = ({
|
|
21
|
+
export const ComposeDialog: FC<ComposeDialogProps> = ({
|
|
22
|
+
collections,
|
|
23
|
+
uploadMaxFileSize,
|
|
24
|
+
}) => {
|
|
21
25
|
const { t } = useLingui();
|
|
22
26
|
|
|
23
27
|
const labels = JSON.stringify({
|
|
@@ -90,9 +94,13 @@ export const ComposeDialog: FC<ComposeDialogProps> = ({ collections }) => {
|
|
|
90
94
|
message: "Media",
|
|
91
95
|
comment: "@context: Compose toolbar - media tooltip",
|
|
92
96
|
}),
|
|
93
|
-
|
|
94
|
-
message: "
|
|
95
|
-
comment: "@context: Compose toolbar -
|
|
97
|
+
rate: t({
|
|
98
|
+
message: "Rate",
|
|
99
|
+
comment: "@context: Compose toolbar - rate tooltip",
|
|
100
|
+
}),
|
|
101
|
+
emoji: t({
|
|
102
|
+
message: "Emoji",
|
|
103
|
+
comment: "@context: Compose toolbar - emoji picker tooltip",
|
|
96
104
|
}),
|
|
97
105
|
title: t({
|
|
98
106
|
message: "Title",
|
|
@@ -107,7 +115,7 @@ export const ComposeDialog: FC<ComposeDialogProps> = ({ collections }) => {
|
|
|
107
115
|
comment: "@context: Compose collection combobox search placeholder",
|
|
108
116
|
}),
|
|
109
117
|
noCollections: t({
|
|
110
|
-
message: "No collections
|
|
118
|
+
message: "No matching collections.",
|
|
111
119
|
comment: "@context: Compose collection combobox empty state",
|
|
112
120
|
}),
|
|
113
121
|
post: t({
|
|
@@ -127,7 +135,7 @@ export const ComposeDialog: FC<ComposeDialogProps> = ({ collections }) => {
|
|
|
127
135
|
comment: "@context: Alt text textarea placeholder",
|
|
128
136
|
}),
|
|
129
137
|
altHint: t({
|
|
130
|
-
message: "
|
|
138
|
+
message: "Helps screen readers describe the image",
|
|
131
139
|
comment: "@context: Hint text in alt text panel",
|
|
132
140
|
}),
|
|
133
141
|
addMore: t({
|
|
@@ -142,6 +150,11 @@ export const ComposeDialog: FC<ComposeDialogProps> = ({ collections }) => {
|
|
|
142
150
|
message: "Published!",
|
|
143
151
|
comment: "@context: Toast shown after successful deferred publish",
|
|
144
152
|
}),
|
|
153
|
+
retryAll: t({
|
|
154
|
+
message: "Click to retry all",
|
|
155
|
+
comment:
|
|
156
|
+
"@context: Tooltip hint on failed upload overlay, tells user clicking retries all failed uploads",
|
|
157
|
+
}),
|
|
145
158
|
}).replace(/</g, "\\u003c");
|
|
146
159
|
|
|
147
160
|
const collectionsJson = JSON.stringify(
|
|
@@ -158,7 +171,11 @@ export const ComposeDialog: FC<ComposeDialogProps> = ({ collections }) => {
|
|
|
158
171
|
class="compose-dialog"
|
|
159
172
|
onclick="event.target === this && this.close()"
|
|
160
173
|
>
|
|
161
|
-
<jant-compose-dialog
|
|
174
|
+
<jant-compose-dialog
|
|
175
|
+
collections={collectionsJson}
|
|
176
|
+
labels={labels}
|
|
177
|
+
upload-max-file-size={uploadMaxFileSize ?? 500}
|
|
178
|
+
>
|
|
162
179
|
{/* SSR fallback skeleton */}
|
|
163
180
|
<div class="compose-dialog-inner">
|
|
164
181
|
<div class="compose-dialog-header" />
|
package/src/ui/dash/PageForm.tsx
CHANGED
package/src/ui/dash/PostList.tsx
CHANGED
|
@@ -22,11 +22,12 @@ export const PostList: FC<PostListProps> = ({ posts }) => {
|
|
|
22
22
|
return (
|
|
23
23
|
<EmptyState
|
|
24
24
|
message={t({
|
|
25
|
-
message:
|
|
25
|
+
message:
|
|
26
|
+
"Nothing published yet. Write your first post to get started.",
|
|
26
27
|
comment: "@context: Empty state message when no posts exist",
|
|
27
28
|
})}
|
|
28
29
|
ctaText={t({
|
|
29
|
-
message: "
|
|
30
|
+
message: "Write your first post",
|
|
30
31
|
comment: "@context: Button in empty state to create first post",
|
|
31
32
|
})}
|
|
32
33
|
ctaHref="/dash/posts/new"
|
|
@@ -53,8 +54,7 @@ export const PostList: FC<PostListProps> = ({ posts }) => {
|
|
|
53
54
|
})}
|
|
54
55
|
deleteAction={`/dash/posts/${sqid.encode(post.id)}/delete`}
|
|
55
56
|
deleteConfirm={t({
|
|
56
|
-
message:
|
|
57
|
-
"Are you sure you want to delete this post? This cannot be undone.",
|
|
57
|
+
message: "Delete this post permanently? This can't be undone.",
|
|
58
58
|
comment:
|
|
59
59
|
"@context: Confirmation dialog when deleting a post from the list",
|
|
60
60
|
})}
|
|
@@ -65,7 +65,7 @@ export const PostList: FC<PostListProps> = ({ posts }) => {
|
|
|
65
65
|
<FormatBadge type={post.format} />
|
|
66
66
|
<StatusBadge
|
|
67
67
|
status={post.status}
|
|
68
|
-
|
|
68
|
+
visibility={post.visibility}
|
|
69
69
|
pinned={post.pinned}
|
|
70
70
|
/>
|
|
71
71
|
<span class="text-xs text-muted-foreground">
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Status Badge Component
|
|
3
3
|
*
|
|
4
|
-
* Displays badges for post status,
|
|
4
|
+
* Displays badges for post status, visibility, and pinned state.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { FC } from "hono/jsx";
|
|
8
8
|
import { useLingui } from "@lingui/react/macro";
|
|
9
|
-
import type { Status } from "../../types.js";
|
|
9
|
+
import type { Status, Visibility } from "../../types.js";
|
|
10
10
|
|
|
11
11
|
export interface StatusBadgeProps {
|
|
12
12
|
status: Status;
|
|
13
|
-
|
|
13
|
+
visibility?: Visibility;
|
|
14
14
|
pinned?: boolean;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export const StatusBadge: FC<StatusBadgeProps> = ({
|
|
18
18
|
status,
|
|
19
|
-
|
|
19
|
+
visibility,
|
|
20
20
|
pinned,
|
|
21
21
|
}) => {
|
|
22
22
|
const { t } = useLingui();
|
|
@@ -40,7 +40,7 @@ export const StatusBadge: FC<StatusBadgeProps> = ({
|
|
|
40
40
|
return (
|
|
41
41
|
<span class="flex items-center gap-1">
|
|
42
42
|
<span class={statusVariants[status]}>{statusLabels[status]}</span>
|
|
43
|
-
{featured && (
|
|
43
|
+
{visibility === "featured" && (
|
|
44
44
|
<span class="badge-primary">
|
|
45
45
|
{t({
|
|
46
46
|
message: "Featured",
|
|
@@ -48,6 +48,14 @@ export const StatusBadge: FC<StatusBadgeProps> = ({
|
|
|
48
48
|
})}
|
|
49
49
|
</span>
|
|
50
50
|
)}
|
|
51
|
+
{visibility === "unlisted" && (
|
|
52
|
+
<span class="badge-outline">
|
|
53
|
+
{t({
|
|
54
|
+
message: "Unlisted",
|
|
55
|
+
comment: "@context: Post badge - unlisted",
|
|
56
|
+
})}
|
|
57
|
+
</span>
|
|
58
|
+
)}
|
|
51
59
|
{pinned && (
|
|
52
60
|
<span class="badge-outline">
|
|
53
61
|
{t({
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { useLingui } from "@lingui/react/macro";
|
|
6
|
-
import { AppearanceNav } from "./AppearanceNav.js";
|
|
7
6
|
|
|
8
7
|
export function AdvancedContent({ customCSS }: { customCSS: string }) {
|
|
9
8
|
const { t } = useLingui();
|
|
@@ -11,67 +10,59 @@ export function AdvancedContent({ customCSS }: { customCSS: string }) {
|
|
|
11
10
|
const cssSignals = JSON.stringify({ customCSS }).replace(/</g, "\\u003c");
|
|
12
11
|
|
|
13
12
|
return (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class="
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})}
|
|
29
|
-
</legend>
|
|
30
|
-
<p class="text-sm text-muted-foreground mb-4">
|
|
31
|
-
{t({
|
|
32
|
-
message:
|
|
33
|
-
"Add custom CSS to override any styles. Use data attributes like [data-page], [data-post], [data-format] to target specific elements.",
|
|
34
|
-
comment: "@context: Custom CSS settings description",
|
|
35
|
-
})}
|
|
36
|
-
</p>
|
|
37
|
-
<textarea
|
|
38
|
-
data-bind="customCSS"
|
|
39
|
-
class="textarea font-mono text-sm min-h-32"
|
|
40
|
-
rows={8}
|
|
41
|
-
placeholder={t({
|
|
42
|
-
message: "/* Your custom CSS here */",
|
|
43
|
-
comment: "@context: Custom CSS textarea placeholder",
|
|
44
|
-
})}
|
|
45
|
-
>
|
|
46
|
-
{customCSS}
|
|
47
|
-
</textarea>
|
|
48
|
-
</fieldset>
|
|
49
|
-
<button
|
|
50
|
-
type="submit"
|
|
51
|
-
class="btn mt-4"
|
|
52
|
-
data-attr:disabled="$_cssLoading"
|
|
53
|
-
>
|
|
54
|
-
<svg
|
|
55
|
-
data-show="$_cssLoading"
|
|
56
|
-
style="display:none"
|
|
57
|
-
class="animate-spin size-4"
|
|
58
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
59
|
-
viewBox="0 0 24 24"
|
|
60
|
-
fill="none"
|
|
61
|
-
stroke="currentColor"
|
|
62
|
-
stroke-width="2"
|
|
63
|
-
stroke-linecap="round"
|
|
64
|
-
stroke-linejoin="round"
|
|
65
|
-
role="status"
|
|
66
|
-
>
|
|
67
|
-
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
68
|
-
</svg>
|
|
13
|
+
<form
|
|
14
|
+
data-signals={cssSignals}
|
|
15
|
+
data-on:submit__prevent="@post('/dash/settings/custom-css')"
|
|
16
|
+
data-indicator="_cssLoading"
|
|
17
|
+
class="max-w-3xl"
|
|
18
|
+
>
|
|
19
|
+
<fieldset>
|
|
20
|
+
<legend class="text-lg font-semibold">
|
|
21
|
+
{t({
|
|
22
|
+
message: "Custom CSS",
|
|
23
|
+
comment: "@context: Appearance settings heading for custom CSS",
|
|
24
|
+
})}
|
|
25
|
+
</legend>
|
|
26
|
+
<p class="text-sm text-muted-foreground mb-4">
|
|
69
27
|
{t({
|
|
70
|
-
message:
|
|
71
|
-
|
|
28
|
+
message:
|
|
29
|
+
"Add custom CSS to override any styles. Use data attributes like [data-page], [data-post], [data-format] to target specific elements.",
|
|
30
|
+
comment: "@context: Custom CSS settings description",
|
|
72
31
|
})}
|
|
73
|
-
</
|
|
74
|
-
|
|
75
|
-
|
|
32
|
+
</p>
|
|
33
|
+
<textarea
|
|
34
|
+
data-bind="customCSS"
|
|
35
|
+
class="textarea font-mono text-sm min-h-32"
|
|
36
|
+
rows={8}
|
|
37
|
+
placeholder={t({
|
|
38
|
+
message: "/* Your custom CSS here */",
|
|
39
|
+
comment: "@context: Custom CSS textarea placeholder",
|
|
40
|
+
})}
|
|
41
|
+
>
|
|
42
|
+
{customCSS}
|
|
43
|
+
</textarea>
|
|
44
|
+
</fieldset>
|
|
45
|
+
<button type="submit" class="btn mt-4" data-attr:disabled="$_cssLoading">
|
|
46
|
+
<svg
|
|
47
|
+
data-show="$_cssLoading"
|
|
48
|
+
style="display:none"
|
|
49
|
+
class="animate-spin size-4"
|
|
50
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
51
|
+
viewBox="0 0 24 24"
|
|
52
|
+
fill="none"
|
|
53
|
+
stroke="currentColor"
|
|
54
|
+
stroke-width="2"
|
|
55
|
+
stroke-linecap="round"
|
|
56
|
+
stroke-linejoin="round"
|
|
57
|
+
role="status"
|
|
58
|
+
>
|
|
59
|
+
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
60
|
+
</svg>
|
|
61
|
+
{t({
|
|
62
|
+
message: "Save CSS",
|
|
63
|
+
comment: "@context: Button to save custom CSS",
|
|
64
|
+
})}
|
|
65
|
+
</button>
|
|
66
|
+
</form>
|
|
76
67
|
);
|
|
77
68
|
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { useLingui } from "@lingui/react/macro";
|
|
6
6
|
import type { ColorTheme } from "../../color-themes.js";
|
|
7
|
-
import { AppearanceNav } from "./AppearanceNav.js";
|
|
8
7
|
|
|
9
8
|
function ThemeCard({
|
|
10
9
|
theme,
|
|
@@ -87,40 +86,36 @@ export function ColorThemeContent({
|
|
|
87
86
|
);
|
|
88
87
|
|
|
89
88
|
return (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
class="
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
comment: "@context: Appearance settings description",
|
|
110
|
-
})}
|
|
111
|
-
</p>
|
|
89
|
+
<div
|
|
90
|
+
data-signals={themeSignals}
|
|
91
|
+
data-on:change="@post('/dash/settings/color-theme')"
|
|
92
|
+
class="max-w-3xl"
|
|
93
|
+
>
|
|
94
|
+
<fieldset>
|
|
95
|
+
<legend class="text-lg font-semibold">
|
|
96
|
+
{t({
|
|
97
|
+
message: "Color theme",
|
|
98
|
+
comment: "@context: Appearance settings heading",
|
|
99
|
+
})}
|
|
100
|
+
</legend>
|
|
101
|
+
<p class="text-sm text-muted-foreground mb-4">
|
|
102
|
+
{t({
|
|
103
|
+
message:
|
|
104
|
+
"This will theme both your site and your dashboard. All color themes support dark mode.",
|
|
105
|
+
comment: "@context: Appearance settings description",
|
|
106
|
+
})}
|
|
107
|
+
</p>
|
|
112
108
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
</>
|
|
109
|
+
<div class="flex flex-col gap-4">
|
|
110
|
+
{themes.map((theme) => (
|
|
111
|
+
<ThemeCard
|
|
112
|
+
key={theme.id}
|
|
113
|
+
theme={theme}
|
|
114
|
+
selected={theme.id === currentThemeId}
|
|
115
|
+
/>
|
|
116
|
+
))}
|
|
117
|
+
</div>
|
|
118
|
+
</fieldset>
|
|
119
|
+
</div>
|
|
125
120
|
);
|
|
126
121
|
}
|