@jant/core 0.6.12 → 0.6.13
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/bin/commands/import-site.js +2 -10
- package/bin/commands/migrate-text-attachments.js +1 -3
- package/bin/commands/site/export.js +1 -3
- package/bin/commands/telegram/register-webhooks.js +9 -3
- package/bin/lib/site-snapshot.js +1 -5
- package/dist/app-CWJFPjuR.js +6 -0
- package/dist/{app-D-zAhayc.js → app-HnzmsaqU.js} +416 -444
- package/dist/client/.vite/manifest.json +3 -3
- package/dist/client/_assets/{client-S1cdvulk.js → client-3_OaxhTs.js} +1 -1
- package/dist/client/_assets/{client-BUxR-E8O.css → client-DCrcHVJl.css} +1 -1
- package/dist/client/_assets/{client-auth-YW92ZH7u.js → client-auth-TsYq90xm.js} +570 -567
- package/dist/{export-Ckwh4BiE.js → export-Dfbq9aot.js} +10 -13
- package/dist/{github-sync-Dl9wQMar.js → github-sync--PSoE-Ne.js} +1 -1
- package/dist/{github-sync-BMmK3JZ0.js → github-sync-BGTLx8Mf.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/node.js +4 -4
- package/package.json +1 -1
- package/src/__tests__/export-service.test.ts +1 -2
- package/src/__tests__/helpers/app.ts +3 -0
- package/src/__tests__/helpers/export-fixtures.ts +0 -1
- package/src/__tests__/import-site-command.test.ts +1 -2
- package/src/client/__tests__/site-header-nav.test.ts +36 -2
- package/src/client/components/__tests__/compose-title-from-heading.test.ts +57 -0
- package/src/client/components/__tests__/jant-compose-editor.test.ts +94 -2
- package/src/client/components/__tests__/jant-nav-manager.test.ts +107 -22
- package/src/client/components/__tests__/jant-settings-general.test.ts +1 -0
- package/src/client/components/compose-title-from-heading.ts +66 -0
- package/src/client/components/compose-types.ts +8 -0
- package/src/client/components/inline-image-issues.ts +17 -0
- package/src/client/components/jant-compose-dialog.ts +2 -0
- package/src/client/components/jant-compose-editor.ts +78 -1
- package/src/client/components/jant-compose-fullscreen.ts +2 -0
- package/src/client/components/jant-nav-manager.ts +245 -155
- package/src/client/components/nav-manager-types.ts +0 -10
- package/src/client/site-header-nav.d.ts +1 -0
- package/src/client/site-header-nav.js +105 -47
- package/src/client/tiptap/__tests__/block-insertion.test.ts +35 -0
- package/src/client/tiptap/__tests__/image-input-rules.test.ts +117 -0
- package/src/client/tiptap/create-editor.ts +7 -0
- package/src/client/tiptap/extensions.ts +7 -2
- package/src/client/tiptap/image-input-rules.ts +48 -0
- package/src/client/tiptap/image-node.ts +189 -7
- package/src/client-auth.ts +0 -1
- package/src/i18n/locales/public/en.po +20 -4
- package/src/i18n/locales/public/en.ts +1 -1
- package/src/i18n/locales/public/zh-Hans.po +20 -4
- package/src/i18n/locales/public/zh-Hans.ts +1 -1
- package/src/i18n/locales/public/zh-Hant.po +20 -4
- package/src/i18n/locales/public/zh-Hant.ts +1 -1
- package/src/i18n/locales/settings/en.po +23 -20
- package/src/i18n/locales/settings/en.ts +1 -1
- package/src/i18n/locales/settings/zh-Hans.po +23 -20
- package/src/i18n/locales/settings/zh-Hans.ts +1 -1
- package/src/i18n/locales/settings/zh-Hant.po +23 -20
- package/src/i18n/locales/settings/zh-Hant.ts +1 -1
- package/src/lib/__tests__/navigation.test.ts +4 -37
- package/src/lib/__tests__/resolve-config.test.ts +6 -1
- package/src/lib/__tests__/view.test.ts +6 -30
- package/src/lib/github-sync-site-config.ts +0 -2
- package/src/lib/hugo-markdown.ts +1 -1
- package/src/lib/navigation.ts +5 -22
- package/src/lib/resolve-config.ts +9 -2
- package/src/lib/site-header-fragment.tsx +37 -0
- package/src/lib/view.ts +2 -7
- package/src/node/__tests__/cli-site-snapshot.test.ts +45 -45
- package/src/routes/api/__tests__/nav-items.test.ts +26 -0
- package/src/routes/api/export.ts +0 -2
- package/src/routes/api/internal/__tests__/uploads.test.ts +9 -13
- package/src/routes/api/internal/sites.ts +5 -5
- package/src/routes/api/nav-items.ts +25 -4
- package/src/routes/dash/settings.tsx +8 -2
- package/src/routes/feed/__tests__/feed.test.ts +42 -0
- package/src/routes/feed/__tests__/sitemap.test.ts +2 -13
- package/src/routes/feed/feed.ts +1 -0
- package/src/routes/feed/sitemap.ts +2 -6
- package/src/routes/pages/archive.tsx +1 -0
- package/src/routes/pages/collection.tsx +1 -0
- package/src/routes/pages/featured.tsx +0 -4
- package/src/routes/pages/home.tsx +4 -51
- package/src/routes/pages/latest.tsx +2 -51
- package/src/services/__tests__/github-app-installations.test.ts +10 -10
- package/src/services/__tests__/navigation.test.ts +41 -0
- package/src/services/__tests__/post-timeline.test.ts +56 -0
- package/src/services/__tests__/post.test.ts +33 -0
- package/src/services/__tests__/settings.test.ts +5 -20
- package/src/services/export-theme/assets/client-site.js +10 -10
- package/src/services/export-theme/layouts/_default/rss.xml +5 -15
- package/src/services/export-theme/layouts/index.html +26 -39
- package/src/services/export.ts +5 -10
- package/src/services/github-app-installations.ts +1 -3
- package/src/services/navigation.ts +44 -13
- package/src/services/post.ts +80 -57
- package/src/services/settings.ts +0 -10
- package/src/services/site-admin.ts +0 -2
- package/src/services/upload-session.ts +4 -18
- package/src/styles/tokens.css +2 -2
- package/src/styles/ui.css +200 -6
- package/src/types/bindings.ts +0 -1
- package/src/types/config.ts +3 -7
- package/src/ui/compose/ComposeDialog.tsx +28 -0
- package/src/ui/dash/appearance/NavigationContent.tsx +1 -1
- package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
- package/src/ui/dash/settings/SettingsRootContent.tsx +3 -3
- package/src/ui/layouts/SiteLayout.tsx +249 -216
- package/dist/app-B5P1b4TF.js +0 -6
- package/src/client/nav-manager-bridge.ts +0 -54
|
@@ -66,7 +66,7 @@ export function AccountMenuContent({
|
|
|
66
66
|
: i18n._(
|
|
67
67
|
msg({
|
|
68
68
|
message:
|
|
69
|
-
"Manage sign-in security, exports, and irreversible actions.",
|
|
69
|
+
"Manage sign-in security, site exports, and irreversible actions.",
|
|
70
70
|
comment:
|
|
71
71
|
"@context: Intro text on the account settings menu page below the title",
|
|
72
72
|
}),
|
|
@@ -105,7 +105,7 @@ export function AccountMenuContent({
|
|
|
105
105
|
<h1 class="page-intro-title page-intro-title-compact">
|
|
106
106
|
{i18n._(
|
|
107
107
|
msg({
|
|
108
|
-
message: "Account",
|
|
108
|
+
message: "Account & Data",
|
|
109
109
|
comment: "@context: Page title for the account settings menu",
|
|
110
110
|
}),
|
|
111
111
|
)}
|
|
@@ -51,7 +51,7 @@ export function SettingsRootContent({
|
|
|
51
51
|
)
|
|
52
52
|
: i18n._(
|
|
53
53
|
msg({
|
|
54
|
-
message: "
|
|
54
|
+
message: "Sign-in, export, and deletion",
|
|
55
55
|
comment:
|
|
56
56
|
"@context: Settings item description for account settings on the settings home page",
|
|
57
57
|
}),
|
|
@@ -171,7 +171,7 @@ export function SettingsRootContent({
|
|
|
171
171
|
)}
|
|
172
172
|
description={i18n._(
|
|
173
173
|
msg({
|
|
174
|
-
message: "Header links,
|
|
174
|
+
message: "Header links, built-in destinations, and overflow menu",
|
|
175
175
|
comment: "@context: Settings item description for navigation",
|
|
176
176
|
}),
|
|
177
177
|
)}
|
|
@@ -333,7 +333,7 @@ export function SettingsRootContent({
|
|
|
333
333
|
tone="subtle"
|
|
334
334
|
name={i18n._(
|
|
335
335
|
msg({
|
|
336
|
-
message: "Account",
|
|
336
|
+
message: "Account & Data",
|
|
337
337
|
comment: "@context: Settings item — account settings",
|
|
338
338
|
}),
|
|
339
339
|
)}
|
|
@@ -112,26 +112,35 @@ function HeaderLink({
|
|
|
112
112
|
);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
export
|
|
115
|
+
export interface SiteHeaderProps {
|
|
116
|
+
siteName: string;
|
|
117
|
+
links: NavItemView[];
|
|
118
|
+
currentPath: string;
|
|
119
|
+
sitePathPrefix?: string;
|
|
120
|
+
siteAvatarUrl?: string;
|
|
121
|
+
showHeaderAvatar?: boolean;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function linkCollapseTier(idx: number): string {
|
|
125
|
+
if (idx < 2) return "";
|
|
126
|
+
if (idx === 2) return "site-header-link-collapse-sm";
|
|
127
|
+
if (idx === 3) return "site-header-link-collapse-md";
|
|
128
|
+
return "site-header-link-collapse-lg";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function moreLinkRevealTier(idx: number): string {
|
|
132
|
+
if (idx === 2) return "site-header-more-link-show-sm";
|
|
133
|
+
if (idx === 3) return "site-header-more-link-show-md";
|
|
134
|
+
return "site-header-more-link-show-lg";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const SiteHeader: FC<SiteHeaderProps> = ({
|
|
116
138
|
siteName,
|
|
117
139
|
links,
|
|
118
140
|
currentPath,
|
|
119
141
|
sitePathPrefix = "",
|
|
120
|
-
isAuthenticated,
|
|
121
|
-
collections,
|
|
122
142
|
siteAvatarUrl,
|
|
123
143
|
showHeaderAvatar,
|
|
124
|
-
siteDescriptionHtml,
|
|
125
|
-
siteFooterHtml,
|
|
126
|
-
showHomeBranding = false,
|
|
127
|
-
sidebar,
|
|
128
|
-
uploadMaxFileSize,
|
|
129
|
-
showComposeDialog = true,
|
|
130
|
-
showHeader = true,
|
|
131
|
-
composeOpenShortcutDiscovered = false,
|
|
132
|
-
slashCommandDiscovered = false,
|
|
133
|
-
composeCollectionId,
|
|
134
|
-
children,
|
|
135
144
|
}) => {
|
|
136
145
|
const { i18n } = useLingui();
|
|
137
146
|
const linksWithLabels = links.map((link) => ({
|
|
@@ -154,46 +163,25 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
154
163
|
comment: "@context: Hamburger menu button label",
|
|
155
164
|
}),
|
|
156
165
|
);
|
|
157
|
-
const
|
|
158
|
-
const newPostLabel = i18n._(
|
|
166
|
+
const closeMenuLabel = i18n._(
|
|
159
167
|
msg({
|
|
160
|
-
message: "
|
|
161
|
-
comment:
|
|
162
|
-
"@context: Mobile floating action button label to open the compose dialog",
|
|
168
|
+
message: "Close menu",
|
|
169
|
+
comment: "@context: Close drawer button label",
|
|
163
170
|
}),
|
|
164
171
|
);
|
|
172
|
+
const moreLabel = i18n._(NAV_MORE_LABEL);
|
|
165
173
|
|
|
166
|
-
// Split custom links by placement
|
|
174
|
+
// Split custom links by placement.
|
|
167
175
|
const headerLinks = linksWithLabels.filter(
|
|
168
176
|
(l) => l.placement === "header" || !l.placement,
|
|
169
177
|
);
|
|
170
178
|
const moreLinks = linksWithLabels.filter((l) => l.placement === "more");
|
|
171
|
-
// Responsive collapse tiers — first two links always stay inline; the
|
|
172
|
-
// remaining links collapse into the "More" popover in stages so wider
|
|
173
|
-
// windows (tablets, narrow laptops) can show 3 or 4 links before falling
|
|
174
|
-
// back to the minimum of 2.
|
|
175
|
-
//
|
|
176
|
-
// idx 2 → collapse-sm (hidden ≤580px, shown in popover)
|
|
177
|
-
// idx 3 → collapse-md (hidden ≤780px)
|
|
178
|
-
// idx ≥ 4 → collapse-lg (hidden ≤960px)
|
|
179
|
-
function linkCollapseTier(idx: number): string {
|
|
180
|
-
if (idx < 2) return "";
|
|
181
|
-
if (idx === 2) return "site-header-link-collapse-sm";
|
|
182
|
-
if (idx === 3) return "site-header-link-collapse-md";
|
|
183
|
-
return "site-header-link-collapse-lg";
|
|
184
|
-
}
|
|
185
|
-
function moreLinkRevealTier(idx: number): string {
|
|
186
|
-
if (idx === 2) return "site-header-more-link-show-sm";
|
|
187
|
-
if (idx === 3) return "site-header-more-link-show-md";
|
|
188
|
-
return "site-header-more-link-show-lg";
|
|
189
|
-
}
|
|
190
179
|
const hasResponsiveOverflow = headerLinks.length > 2;
|
|
191
180
|
const hasSupplementalMoreLinks = moreLinks.length > 0;
|
|
192
181
|
const showMoreMenu = hasResponsiveOverflow || hasSupplementalMoreLinks;
|
|
182
|
+
|
|
193
183
|
// Decide the widest breakpoint at which the "More" button must appear
|
|
194
|
-
// when there are no supplemental links.
|
|
195
|
-
// collapses (≤780); with 4 links idx 3 starts collapsing at ≤920; with 5+
|
|
196
|
-
// idx 4 starts collapsing at ≤1100.
|
|
184
|
+
// when there are no supplemental links.
|
|
197
185
|
let responsiveTierClass = "";
|
|
198
186
|
if (hasResponsiveOverflow && !hasSupplementalMoreLinks) {
|
|
199
187
|
if (headerLinks.length >= 5) {
|
|
@@ -213,127 +201,87 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
213
201
|
]
|
|
214
202
|
.filter(Boolean)
|
|
215
203
|
.join(" ");
|
|
216
|
-
|
|
217
204
|
const isHomePage =
|
|
218
205
|
currentPath === toPublicPath("/", sitePathPrefix) ||
|
|
219
206
|
currentPath === toPublicPath("/featured", sitePathPrefix) ||
|
|
220
207
|
currentPath === toPublicPath("/latest", sitePathPrefix);
|
|
221
|
-
const showMobileComposeFab = Boolean(
|
|
222
|
-
(isHomePage || composeCollectionId) && isAuthenticated && showComposeDialog,
|
|
223
|
-
);
|
|
224
|
-
const mobileComposeFabClick = composeCollectionId
|
|
225
|
-
? `document.getElementById('compose-dialog')?.querySelector('jant-compose-dialog')?.openNew(${JSON.stringify(
|
|
226
|
-
{ collectionId: composeCollectionId },
|
|
227
|
-
)})`
|
|
228
|
-
: "document.getElementById('compose-dialog')?.querySelector('jant-compose-dialog')?.openNew()";
|
|
229
|
-
const contentClass = [
|
|
230
|
-
"site-content",
|
|
231
|
-
isHomePage ? "site-content-home" : "",
|
|
232
|
-
showMobileComposeFab ? "site-content-mobile-compose-enabled" : "",
|
|
233
|
-
]
|
|
234
|
-
.filter(Boolean)
|
|
235
|
-
.join(" ");
|
|
236
208
|
|
|
237
209
|
return (
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
<
|
|
241
|
-
<div
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
>
|
|
245
|
-
|
|
246
|
-
{
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
{
|
|
268
|
-
<
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
stroke-linejoin="round"
|
|
287
|
-
aria-hidden="true"
|
|
288
|
-
>
|
|
289
|
-
<path d="m6 9 6 6 6-6" />
|
|
290
|
-
</svg>
|
|
291
|
-
</button>
|
|
292
|
-
<div
|
|
293
|
-
id="site-nav-more-popover"
|
|
294
|
-
class="site-header-more-popover"
|
|
295
|
-
data-popover
|
|
296
|
-
data-align="start"
|
|
210
|
+
<>
|
|
211
|
+
<header class="site-header" data-site-header-fragment="header">
|
|
212
|
+
<div class="site-header-inner">
|
|
213
|
+
<div
|
|
214
|
+
class={`site-header-top site-header-top-bordered${isHomePage ? " site-header-top-home" : ""}`}
|
|
215
|
+
>
|
|
216
|
+
<a href={toPublicPath("/", sitePathPrefix)} class="site-logo">
|
|
217
|
+
{showHeaderAvatar && siteAvatarUrl && (
|
|
218
|
+
<img src={siteAvatarUrl} class="site-logo-avatar" alt="" />
|
|
219
|
+
)}
|
|
220
|
+
{siteName}
|
|
221
|
+
</a>
|
|
222
|
+
<nav class="site-header-nav" aria-label="Primary">
|
|
223
|
+
{headerLinks.map((link, idx) => (
|
|
224
|
+
<HeaderLink
|
|
225
|
+
key={link.id}
|
|
226
|
+
link={link}
|
|
227
|
+
label={link.displayLabel}
|
|
228
|
+
className={[
|
|
229
|
+
idx < 2
|
|
230
|
+
? "site-header-link-primary"
|
|
231
|
+
: "site-header-link-overflow",
|
|
232
|
+
linkCollapseTier(idx),
|
|
233
|
+
]
|
|
234
|
+
.filter(Boolean)
|
|
235
|
+
.join(" ")}
|
|
236
|
+
/>
|
|
237
|
+
))}
|
|
238
|
+
{showMoreMenu && (
|
|
239
|
+
<div class={moreMenuClass}>
|
|
240
|
+
<button
|
|
241
|
+
type="button"
|
|
242
|
+
class="site-header-more-btn"
|
|
243
|
+
id="site-nav-more-trigger"
|
|
244
|
+
aria-haspopup="menu"
|
|
245
|
+
aria-expanded="false"
|
|
246
|
+
>
|
|
247
|
+
{moreLabel}
|
|
248
|
+
<svg
|
|
249
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
250
|
+
width="12"
|
|
251
|
+
height="12"
|
|
252
|
+
viewBox="0 0 24 24"
|
|
253
|
+
fill="none"
|
|
254
|
+
stroke="currentColor"
|
|
255
|
+
stroke-width="2.5"
|
|
256
|
+
stroke-linecap="round"
|
|
257
|
+
stroke-linejoin="round"
|
|
297
258
|
aria-hidden="true"
|
|
298
259
|
>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
{...(link.freshAt
|
|
321
|
-
? { "data-fresh-at": link.freshAt }
|
|
322
|
-
: {})}
|
|
323
|
-
>
|
|
324
|
-
{link.displayLabel}
|
|
325
|
-
{link.isExternal && <ExternalLinkIcon />}
|
|
326
|
-
</a>
|
|
327
|
-
);
|
|
328
|
-
})}
|
|
329
|
-
{hasResponsiveOverflow && hasSupplementalMoreLinks && (
|
|
330
|
-
<div class="site-header-more-divider site-header-more-divider-responsive" />
|
|
331
|
-
)}
|
|
332
|
-
{moreLinks.map((link) => (
|
|
260
|
+
<path d="m6 9 6 6 6-6" />
|
|
261
|
+
</svg>
|
|
262
|
+
</button>
|
|
263
|
+
<div
|
|
264
|
+
id="site-nav-more-popover"
|
|
265
|
+
class="site-header-more-popover"
|
|
266
|
+
data-popover
|
|
267
|
+
data-align="start"
|
|
268
|
+
aria-hidden="true"
|
|
269
|
+
>
|
|
270
|
+
{headerLinks.slice(2).map((link, i) => {
|
|
271
|
+
const idx = i + 2;
|
|
272
|
+
const classes = [
|
|
273
|
+
"site-header-more-link",
|
|
274
|
+
"site-header-more-link-responsive",
|
|
275
|
+
moreLinkRevealTier(idx),
|
|
276
|
+
link.isActive ? "site-header-more-link-active" : "",
|
|
277
|
+
]
|
|
278
|
+
.filter(Boolean)
|
|
279
|
+
.join(" ");
|
|
280
|
+
return (
|
|
333
281
|
<a
|
|
334
282
|
key={link.id}
|
|
335
283
|
href={link.url}
|
|
336
|
-
class={
|
|
284
|
+
class={classes}
|
|
337
285
|
{...(link.isExternal
|
|
338
286
|
? {
|
|
339
287
|
target: "_blank",
|
|
@@ -347,75 +295,99 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
347
295
|
{link.displayLabel}
|
|
348
296
|
{link.isExternal && <ExternalLinkIcon />}
|
|
349
297
|
</a>
|
|
350
|
-
)
|
|
351
|
-
|
|
298
|
+
);
|
|
299
|
+
})}
|
|
300
|
+
{hasResponsiveOverflow && hasSupplementalMoreLinks && (
|
|
301
|
+
<div class="site-header-more-divider site-header-more-divider-responsive" />
|
|
302
|
+
)}
|
|
303
|
+
{moreLinks.map((link) => (
|
|
304
|
+
<a
|
|
305
|
+
key={link.id}
|
|
306
|
+
href={link.url}
|
|
307
|
+
class={`site-header-more-link site-header-more-link-supplemental ${link.isActive ? "site-header-more-link-active" : ""}`}
|
|
308
|
+
{...(link.isExternal
|
|
309
|
+
? {
|
|
310
|
+
target: "_blank",
|
|
311
|
+
rel: "noopener noreferrer",
|
|
312
|
+
}
|
|
313
|
+
: {})}
|
|
314
|
+
{...(link.freshAt
|
|
315
|
+
? { "data-fresh-at": link.freshAt }
|
|
316
|
+
: {})}
|
|
317
|
+
>
|
|
318
|
+
{link.displayLabel}
|
|
319
|
+
{link.isExternal && <ExternalLinkIcon />}
|
|
320
|
+
</a>
|
|
321
|
+
))}
|
|
352
322
|
</div>
|
|
353
|
-
|
|
354
|
-
|
|
323
|
+
</div>
|
|
324
|
+
)}
|
|
325
|
+
</nav>
|
|
355
326
|
|
|
356
|
-
|
|
357
|
-
<
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
placeholder={searchLabel}
|
|
369
|
-
aria-label={searchLabel}
|
|
370
|
-
enterkeyhint="search"
|
|
371
|
-
/>
|
|
372
|
-
</form>
|
|
373
|
-
<a
|
|
374
|
-
href={searchHref}
|
|
375
|
-
class="site-header-search-link"
|
|
327
|
+
<div class="site-header-search-slot">
|
|
328
|
+
<form
|
|
329
|
+
class="site-header-search-form"
|
|
330
|
+
action={searchHref}
|
|
331
|
+
method="get"
|
|
332
|
+
>
|
|
333
|
+
<SearchIcon class="site-header-search-icon" />
|
|
334
|
+
<input
|
|
335
|
+
type="search"
|
|
336
|
+
name="q"
|
|
337
|
+
class="site-header-search-input"
|
|
338
|
+
placeholder={searchLabel}
|
|
376
339
|
aria-label={searchLabel}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
340
|
+
enterkeyhint="search"
|
|
341
|
+
/>
|
|
342
|
+
</form>
|
|
343
|
+
<a
|
|
344
|
+
href={searchHref}
|
|
345
|
+
class="site-header-search-link"
|
|
346
|
+
aria-label={searchLabel}
|
|
347
|
+
title={searchLabel}
|
|
348
|
+
>
|
|
349
|
+
<SearchIcon class="site-header-search-link-icon" />
|
|
350
|
+
</a>
|
|
351
|
+
</div>
|
|
382
352
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
353
|
+
<div class="site-header-right">
|
|
354
|
+
<button
|
|
355
|
+
type="button"
|
|
356
|
+
class="site-header-hamburger"
|
|
357
|
+
aria-controls="site-nav-drawer"
|
|
358
|
+
aria-expanded="false"
|
|
359
|
+
aria-label={menuLabel}
|
|
360
|
+
>
|
|
361
|
+
<svg
|
|
362
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
363
|
+
width="20"
|
|
364
|
+
height="20"
|
|
365
|
+
viewBox="0 0 24 24"
|
|
366
|
+
fill="none"
|
|
367
|
+
stroke="currentColor"
|
|
368
|
+
stroke-width="2"
|
|
369
|
+
stroke-linecap="round"
|
|
370
|
+
stroke-linejoin="round"
|
|
391
371
|
>
|
|
392
|
-
<
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
fill="none"
|
|
398
|
-
stroke="currentColor"
|
|
399
|
-
stroke-width="2"
|
|
400
|
-
stroke-linecap="round"
|
|
401
|
-
stroke-linejoin="round"
|
|
402
|
-
>
|
|
403
|
-
<line x1="4" x2="20" y1="12" y2="12" />
|
|
404
|
-
<line x1="4" x2="20" y1="6" y2="6" />
|
|
405
|
-
<line x1="4" x2="20" y1="18" y2="18" />
|
|
406
|
-
</svg>
|
|
407
|
-
</button>
|
|
408
|
-
</div>
|
|
372
|
+
<line x1="4" x2="20" y1="12" y2="12" />
|
|
373
|
+
<line x1="4" x2="20" y1="6" y2="6" />
|
|
374
|
+
<line x1="4" x2="20" y1="18" y2="18" />
|
|
375
|
+
</svg>
|
|
376
|
+
</button>
|
|
409
377
|
</div>
|
|
410
378
|
</div>
|
|
411
|
-
</
|
|
412
|
-
|
|
379
|
+
</div>
|
|
380
|
+
</header>
|
|
413
381
|
|
|
414
|
-
|
|
415
|
-
|
|
382
|
+
<div
|
|
383
|
+
class="site-nav-drawer-backdrop"
|
|
384
|
+
data-site-header-fragment="drawer-backdrop"
|
|
385
|
+
aria-hidden="true"
|
|
386
|
+
/>
|
|
416
387
|
<div
|
|
417
388
|
id="site-nav-drawer"
|
|
418
389
|
class="site-nav-drawer"
|
|
390
|
+
data-site-header-fragment="drawer"
|
|
419
391
|
role="dialog"
|
|
420
392
|
aria-modal="true"
|
|
421
393
|
aria-label={menuLabel}
|
|
@@ -439,12 +411,7 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
439
411
|
<button
|
|
440
412
|
type="button"
|
|
441
413
|
class="site-nav-drawer-close"
|
|
442
|
-
aria-label={
|
|
443
|
-
msg({
|
|
444
|
-
message: "Close menu",
|
|
445
|
-
comment: "@context: Close drawer button label",
|
|
446
|
-
}),
|
|
447
|
-
)}
|
|
414
|
+
aria-label={closeMenuLabel}
|
|
448
415
|
>
|
|
449
416
|
<svg
|
|
450
417
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -499,6 +466,72 @@ export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
|
499
466
|
)}
|
|
500
467
|
</nav>
|
|
501
468
|
</div>
|
|
469
|
+
</>
|
|
470
|
+
);
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
export const SiteLayout: FC<PropsWithChildren<SiteLayoutProps>> = ({
|
|
474
|
+
siteName,
|
|
475
|
+
links,
|
|
476
|
+
currentPath,
|
|
477
|
+
sitePathPrefix = "",
|
|
478
|
+
isAuthenticated,
|
|
479
|
+
collections,
|
|
480
|
+
siteAvatarUrl,
|
|
481
|
+
showHeaderAvatar,
|
|
482
|
+
siteDescriptionHtml,
|
|
483
|
+
siteFooterHtml,
|
|
484
|
+
showHomeBranding = false,
|
|
485
|
+
sidebar,
|
|
486
|
+
uploadMaxFileSize,
|
|
487
|
+
showComposeDialog = true,
|
|
488
|
+
showHeader = true,
|
|
489
|
+
composeOpenShortcutDiscovered = false,
|
|
490
|
+
slashCommandDiscovered = false,
|
|
491
|
+
composeCollectionId,
|
|
492
|
+
children,
|
|
493
|
+
}) => {
|
|
494
|
+
const { i18n } = useLingui();
|
|
495
|
+
const newPostLabel = i18n._(
|
|
496
|
+
msg({
|
|
497
|
+
message: "New post",
|
|
498
|
+
comment:
|
|
499
|
+
"@context: Mobile floating action button label to open the compose dialog",
|
|
500
|
+
}),
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
const isHomePage =
|
|
504
|
+
currentPath === toPublicPath("/", sitePathPrefix) ||
|
|
505
|
+
currentPath === toPublicPath("/featured", sitePathPrefix) ||
|
|
506
|
+
currentPath === toPublicPath("/latest", sitePathPrefix);
|
|
507
|
+
const showMobileComposeFab = Boolean(
|
|
508
|
+
(isHomePage || composeCollectionId) && isAuthenticated && showComposeDialog,
|
|
509
|
+
);
|
|
510
|
+
const mobileComposeFabClick = composeCollectionId
|
|
511
|
+
? `document.getElementById('compose-dialog')?.querySelector('jant-compose-dialog')?.openNew(${JSON.stringify(
|
|
512
|
+
{ collectionId: composeCollectionId },
|
|
513
|
+
)})`
|
|
514
|
+
: "document.getElementById('compose-dialog')?.querySelector('jant-compose-dialog')?.openNew()";
|
|
515
|
+
const contentClass = [
|
|
516
|
+
"site-content",
|
|
517
|
+
isHomePage ? "site-content-home" : "",
|
|
518
|
+
showMobileComposeFab ? "site-content-mobile-compose-enabled" : "",
|
|
519
|
+
]
|
|
520
|
+
.filter(Boolean)
|
|
521
|
+
.join(" ");
|
|
522
|
+
|
|
523
|
+
return (
|
|
524
|
+
<div class="site-page">
|
|
525
|
+
{showHeader && (
|
|
526
|
+
<SiteHeader
|
|
527
|
+
siteName={siteName}
|
|
528
|
+
links={links}
|
|
529
|
+
currentPath={currentPath}
|
|
530
|
+
sitePathPrefix={sitePathPrefix}
|
|
531
|
+
siteAvatarUrl={siteAvatarUrl}
|
|
532
|
+
showHeaderAvatar={showHeaderAvatar}
|
|
533
|
+
/>
|
|
534
|
+
)}
|
|
502
535
|
|
|
503
536
|
<main class="site-main">
|
|
504
537
|
{sidebar ? (
|
package/dist/app-B5P1b4TF.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Nav Manager Bridge
|
|
3
|
-
*
|
|
4
|
-
* Handles communication between <jant-nav-manager> and the server.
|
|
5
|
-
* Listens for `jant:nav-update` and `jant:nav-delete`, calls API endpoints,
|
|
6
|
-
* and reloads the page on success.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type {
|
|
10
|
-
NavManagerUpdateDetail,
|
|
11
|
-
NavManagerDeleteDetail,
|
|
12
|
-
} from "./components/nav-manager-types.js";
|
|
13
|
-
import { showToast } from "./toast.js";
|
|
14
|
-
|
|
15
|
-
document.addEventListener("jant:nav-update", async (event: Event) => {
|
|
16
|
-
const { detail } = event as CustomEvent<NavManagerUpdateDetail>;
|
|
17
|
-
if (!detail?.id) return;
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
const res = await fetch(`/api/nav-items/${detail.id}`, {
|
|
21
|
-
method: "PUT",
|
|
22
|
-
headers: {
|
|
23
|
-
"Content-Type": "application/json",
|
|
24
|
-
Accept: "application/json",
|
|
25
|
-
},
|
|
26
|
-
body: JSON.stringify({
|
|
27
|
-
label: detail.label,
|
|
28
|
-
...(detail.url !== undefined && { url: detail.url }),
|
|
29
|
-
}),
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
33
|
-
window.location.reload();
|
|
34
|
-
} catch {
|
|
35
|
-
showToast("Failed to save. Please try again.", "error");
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
document.addEventListener("jant:nav-delete", async (event: Event) => {
|
|
40
|
-
const { detail } = event as CustomEvent<NavManagerDeleteDetail>;
|
|
41
|
-
if (!detail?.id) return;
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const res = await fetch(`/api/nav-items/${detail.id}`, {
|
|
45
|
-
method: "DELETE",
|
|
46
|
-
headers: { Accept: "application/json" },
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
50
|
-
window.location.reload();
|
|
51
|
-
} catch {
|
|
52
|
-
showToast("Failed to delete. Please try again.", "error");
|
|
53
|
-
}
|
|
54
|
-
});
|