@kirchdev/duxt 0.3.4 → 0.3.5-dev-main.44-5337cc1
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/README.md +24 -9
- package/app/app.vue +17 -11
- package/app/assets/css/duxt.css +47 -6
- package/app/components/DuxtAnnouncements.vue +117 -0
- package/app/components/DuxtBrunoEntries.vue +62 -0
- package/app/components/DuxtCodeBlock.vue +18 -34
- package/app/components/DuxtCodeToolbar.vue +14 -0
- package/app/components/DuxtCopyButton.vue +33 -0
- package/app/components/DuxtCopyPage.vue +32 -30
- package/app/components/DuxtFooter.vue +39 -8
- package/app/components/DuxtHeader.vue +107 -48
- package/app/components/DuxtLandingProse.vue +1 -1
- package/app/components/DuxtLinkLabel.vue +36 -0
- package/app/components/DuxtLiveWindow.vue +8 -8
- package/app/components/DuxtLocale.vue +10 -1
- package/app/components/DuxtNavigation.vue +2 -2
- package/app/components/DuxtOpenApiClient.vue +285 -90
- package/app/components/DuxtOpenApiMedia.vue +30 -18
- package/app/components/DuxtOpenApiSchema.vue +10 -7
- package/app/components/DuxtPageFeedback.vue +7 -0
- package/app/components/DuxtPageInfo.vue +15 -12
- package/app/components/DuxtPageNav.vue +41 -27
- package/app/components/DuxtPreviewSkeleton.vue +4 -4
- package/app/components/DuxtProgress.vue +2 -14
- package/app/components/DuxtSearch.vue +230 -90
- package/app/components/DuxtSearchInput.vue +70 -0
- package/app/components/DuxtSections.vue +11 -1
- package/app/components/DuxtSegmented.vue +64 -0
- package/app/components/DuxtShortcuts.vue +16 -11
- package/app/components/DuxtShortcutsTrigger.vue +49 -0
- package/app/components/DuxtSkipLink.vue +1 -1
- package/app/components/DuxtToc.vue +16 -10
- package/app/components/DuxtTranslationBanner.vue +1 -1
- package/app/components/DuxtVersion.vue +53 -12
- package/app/components/DuxtVersionBanner.vue +5 -5
- package/app/components/content/AccordionItem.vue +2 -2
- package/app/components/content/BrunoOverview.vue +260 -0
- package/app/components/content/BrunoRequest.vue +141 -0
- package/app/components/content/BrunoRequests.vue +104 -0
- package/app/components/content/Callout.vue +5 -5
- package/app/components/content/ChangelogReleases.vue +161 -40
- package/app/components/content/CodeGroup.vue +41 -37
- package/app/components/content/Field.vue +1 -1
- package/app/components/content/FileTree.vue +1 -1
- package/app/components/content/OpenApiOperation.vue +4 -4
- package/app/components/content/OpenApiOperations.vue +1 -1
- package/app/components/content/OpenApiOverview.vue +1 -1
- package/app/components/content/PackageManagers.vue +42 -58
- package/app/components/content/PageCards.vue +7 -4
- package/app/components/content/Preview.vue +15 -39
- package/app/components/content/ProseImg.vue +596 -49
- package/app/components/content/Since.vue +1 -1
- package/app/components/content/Steps.vue +6 -4
- package/app/components/content/TabGroup.vue +13 -12
- package/app/components/ui/breadcrumb/BreadcrumbSeparator.vue +1 -1
- package/app/components/ui/command/CommandShortcut.vue +1 -1
- package/app/components/ui/dialog/DialogContent.vue +2 -2
- package/app/components/ui/dialog/DialogHeader.vue +1 -1
- package/app/components/ui/dialog/DialogScrollContent.vue +1 -1
- package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +2 -2
- package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +1 -1
- package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +1 -1
- package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +2 -2
- package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +1 -1
- package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +2 -2
- package/app/components/ui/navigation-menu/NavigationMenuContent.vue +1 -1
- package/app/components/ui/navigation-menu/NavigationMenuTrigger.vue +1 -1
- package/app/components/ui/navigation-menu/NavigationMenuViewport.vue +1 -1
- package/app/components/ui/scroll-area/ScrollBar.vue +1 -1
- package/app/components/ui/select/SelectItem.vue +2 -2
- package/app/components/ui/sheet/SheetContent.vue +29 -3
- package/app/components/ui/sidebar/Sidebar.vue +28 -4
- package/app/components/ui/sidebar/SidebarGroupAction.vue +1 -1
- package/app/components/ui/sidebar/SidebarInset.vue +1 -1
- package/app/components/ui/sidebar/SidebarMenuAction.vue +1 -1
- package/app/components/ui/sidebar/SidebarMenuBadge.vue +1 -1
- package/app/components/ui/sidebar/SidebarMenuSub.vue +1 -1
- package/app/components/ui/sidebar/SidebarMenuSubButton.vue +1 -1
- package/app/components/ui/sidebar/SidebarProvider.vue +7 -16
- package/app/components/ui/sidebar/index.ts +10 -2
- package/app/components/ui/sidebar/utils.ts +0 -1
- package/app/components/ui/sonner/Sonner.vue +18 -0
- package/app/components/ui/tabs/TabsList.vue +13 -3
- package/app/components/ui/tabs/TabsTrigger.vue +24 -3
- package/app/components/ui/tooltip/TooltipContent.vue +2 -2
- package/app/composables/useActiveHeading.ts +3 -25
- package/app/composables/useDuxtAnalytics.ts +50 -0
- package/app/composables/useDuxtAnimatedHeight.ts +8 -38
- package/app/composables/useDuxtAnnouncements.ts +153 -0
- package/app/composables/useDuxtCopy.ts +51 -0
- package/app/composables/useDuxtDirection.ts +23 -0
- package/app/composables/useDuxtNavigation.ts +28 -8
- package/app/composables/useDuxtPath.ts +3 -5
- package/app/composables/useDuxtSearch.ts +87 -35
- package/app/composables/useDuxtSection.ts +15 -1
- package/app/composables/useDuxtSectionRow.ts +6 -5
- package/app/composables/useDuxtShortcuts.ts +319 -20
- package/app/composables/useDuxtVersion.ts +57 -6
- package/app/composables/useDuxtViewportMeasure.ts +37 -0
- package/app/composables/useFuzzySearch.ts +9 -4
- package/app/composables/useRecentPages.ts +14 -17
- package/app/error.vue +112 -74
- package/app/layouts/changelog.vue +9 -1
- package/app/layouts/default.vue +9 -0
- package/app/layouts/docs.vue +9 -1
- package/app/layouts/reference.vue +9 -1
- package/app/middleware/duxt-section-layout.global.ts +1 -3
- package/app/pages/[...slug].vue +146 -35
- package/app/pages/index.vue +15 -23
- package/app/types/duxt.d.ts +312 -4
- package/app/utils/analytics.ts +91 -0
- package/app/utils/announcements.ts +205 -0
- package/app/utils/changelog.ts +0 -28
- package/app/utils/code-highlight.ts +3 -1
- package/app/utils/contributor-avatar.ts +27 -0
- package/app/utils/direction.ts +43 -0
- package/app/utils/duxt-config.ts +43 -0
- package/app/utils/duxt-text.ts +10 -0
- package/app/utils/format-date.ts +28 -0
- package/app/utils/generated-sections.ts +68 -12
- package/app/utils/generated-toc.ts +14 -7
- package/app/utils/locale-path.ts +43 -0
- package/app/utils/navigation-tree.ts +51 -1
- package/app/utils/nearest-page.ts +8 -0
- package/app/utils/openapi.ts +16 -11
- package/app/utils/page-controls.ts +215 -0
- package/app/utils/pill.ts +61 -0
- package/app/utils/prose-image.ts +128 -0
- package/app/utils/search-context.ts +110 -0
- package/app/utils/search-display.ts +248 -0
- package/app/utils/section-scope.ts +65 -4
- package/app/utils/stored-json.ts +31 -0
- package/app/utils/version-choices.ts +6 -13
- package/app/utils/version-paths.ts +21 -0
- package/bin/duxt-cache-key.mjs +61 -0
- package/bin/duxt-og-cache.mjs +58 -0
- package/bin/{duxt-report.mjs → duxt.mjs} +13 -7
- package/bruno-model.ts +169 -0
- package/bruno-parse.ts +656 -0
- package/bruno-zip.ts +195 -0
- package/cli.ts +240 -0
- package/duxt-app-config.ts +18 -1
- package/frontmatter.ts +49 -0
- package/git-contributors.ts +322 -0
- package/i18n/locales/de/duxt/announcement.json +7 -0
- package/i18n/locales/de/duxt/bruno.json +25 -0
- package/i18n/locales/de/duxt/changelog.json +1 -1
- package/i18n/locales/de/duxt/code.json +2 -1
- package/i18n/locales/de/duxt/page.json +9 -0
- package/i18n/locales/de/duxt/shortcuts.json +1 -0
- package/i18n/locales/de/duxt/theme.json +2 -1
- package/i18n/locales/en/duxt/announcement.json +7 -0
- package/i18n/locales/en/duxt/bruno.json +25 -0
- package/i18n/locales/en/duxt/changelog.json +1 -1
- package/i18n/locales/en/duxt/code.json +2 -1
- package/i18n/locales/en/duxt/page.json +9 -0
- package/i18n/locales/en/duxt/shortcuts.json +1 -0
- package/i18n/locales/en/duxt/theme.json +2 -1
- package/i18n/locales/es/duxt/announcement.json +7 -0
- package/i18n/locales/es/duxt/bruno.json +25 -0
- package/i18n/locales/es/duxt/changelog.json +1 -1
- package/i18n/locales/es/duxt/code.json +2 -1
- package/i18n/locales/es/duxt/page.json +9 -0
- package/i18n/locales/es/duxt/shortcuts.json +1 -0
- package/i18n/locales/es/duxt/theme.json +2 -1
- package/i18n/locales/fr/duxt/announcement.json +7 -0
- package/i18n/locales/fr/duxt/bruno.json +25 -0
- package/i18n/locales/fr/duxt/changelog.json +1 -1
- package/i18n/locales/fr/duxt/code.json +2 -1
- package/i18n/locales/fr/duxt/page.json +9 -0
- package/i18n/locales/fr/duxt/shortcuts.json +1 -0
- package/i18n/locales/fr/duxt/theme.json +2 -1
- package/i18n/locales/pt/duxt/announcement.json +7 -0
- package/i18n/locales/pt/duxt/bruno.json +25 -0
- package/i18n/locales/pt/duxt/changelog.json +1 -1
- package/i18n/locales/pt/duxt/code.json +2 -1
- package/i18n/locales/pt/duxt/page.json +9 -0
- package/i18n/locales/pt/duxt/shortcuts.json +1 -0
- package/i18n/locales/pt/duxt/theme.json +2 -1
- package/modules/bruno.ts +118 -0
- package/modules/config.ts +26 -0
- package/modules/devtools.ts +2 -3
- package/modules/git-meta.ts +16 -47
- package/modules/search-records.ts +132 -0
- package/nuxt.config.ts +81 -7
- package/og-image-cache.ts +742 -0
- package/package.json +42 -10
- package/public/devtools/checks.html +2 -2
- package/public/devtools/config.html +59 -4
- package/public/devtools/pages.html +8 -1
- package/public/devtools/paths.html +1 -1
- package/public/devtools/sources.html +2 -2
- package/public/devtools/versions.html +3 -0
- package/report.ts +28 -19
- package/search-records.ts +380 -0
- package/section-input.ts +142 -0
- package/section-markdown.ts +67 -0
- package/section-reports.ts +10 -4
- package/sections-bruno.ts +571 -0
- package/sections-changelog.ts +76 -43
- package/sections-openapi.ts +12 -83
- package/sections-resolve.ts +174 -8
- package/sections.ts +33 -10
- package/server/devtools/shell.ts +1 -1
- package/server/mcp/tools/list-pages.ts +77 -36
- package/server/mcp/tools/list-versions.ts +84 -0
- package/server/mcp/tools/read-page.ts +80 -26
- package/server/mcp/tools/search-docs.ts +87 -53
- package/server/middleware/raw-markdown.ts +1 -1
- package/server/routes/llms-full.txt.get.ts +6 -8
- package/server/routes/llms.txt.get.ts +1 -1
- package/server/utils/duxt-server-text.ts +0 -13
- package/server/utils/llms-pages.ts +24 -9
- package/server/utils/mcp-docs.ts +577 -0
- package/sources-cache.ts +376 -0
- package/sources-git.ts +186 -31
- package/sources-resolve.ts +59 -1
- package/sources.ts +122 -13
- package/tfplugindocs.ts +158 -0
|
@@ -35,9 +35,12 @@ const props = withDefaults(
|
|
|
35
35
|
);
|
|
36
36
|
|
|
37
37
|
const DEPTH = 8;
|
|
38
|
+
const duxt = useDuxtConfig();
|
|
38
39
|
|
|
39
40
|
const schema = computed(() => props.schema);
|
|
40
|
-
const deep = computed(
|
|
41
|
+
const deep = computed(
|
|
42
|
+
() => props.depth >= (duxt.openapi?.schemaDepth ?? DEPTH)
|
|
43
|
+
);
|
|
41
44
|
|
|
42
45
|
const type = computed(() => openApiTypeLabel(schema.value));
|
|
43
46
|
const constraints = computed(() => openApiConstraints(schema.value));
|
|
@@ -224,7 +227,7 @@ const open = computed(() => size.value < MANY);
|
|
|
224
227
|
said. -->
|
|
225
228
|
<span
|
|
226
229
|
v-if="collapsible && size >= MANY"
|
|
227
|
-
class="
|
|
230
|
+
class="ms-auto rounded-md bg-muted px-1.5 font-mono text-[0.6875rem] text-muted-foreground tabular-nums"
|
|
228
231
|
:aria-label="$t('duxt.openapi.fields', { count: size })"
|
|
229
232
|
>
|
|
230
233
|
{{ size }}
|
|
@@ -268,7 +271,7 @@ const open = computed(() => size.value < MANY);
|
|
|
268
271
|
<template v-else-if="!schema?.circular">
|
|
269
272
|
<ul
|
|
270
273
|
v-if="schema?.properties?.length"
|
|
271
|
-
class="mt-3 space-y-3 border-
|
|
274
|
+
class="mt-3 space-y-3 border-s ps-4"
|
|
272
275
|
>
|
|
273
276
|
<li v-for="property in schema.properties" :key="property.name">
|
|
274
277
|
<DuxtOpenApiSchema
|
|
@@ -281,7 +284,7 @@ const open = computed(() => size.value < MANY);
|
|
|
281
284
|
</li>
|
|
282
285
|
</ul>
|
|
283
286
|
|
|
284
|
-
<div v-if="items" class="mt-3 border-
|
|
287
|
+
<div v-if="items" class="mt-3 border-s ps-4">
|
|
285
288
|
<p class="mb-1 text-xs font-medium text-muted-foreground">
|
|
286
289
|
{{ $t('duxt.openapi.items') }}
|
|
287
290
|
</p>
|
|
@@ -292,7 +295,7 @@ const open = computed(() => size.value < MANY);
|
|
|
292
295
|
/>
|
|
293
296
|
</div>
|
|
294
297
|
|
|
295
|
-
<div v-if="additional" class="mt-3 border-
|
|
298
|
+
<div v-if="additional" class="mt-3 border-s ps-4">
|
|
296
299
|
<p class="mb-1 text-xs font-medium text-muted-foreground">
|
|
297
300
|
{{ $t('duxt.openapi.additionalProperties') }}
|
|
298
301
|
</p>
|
|
@@ -313,7 +316,7 @@ const open = computed(() => size.value < MANY);
|
|
|
313
316
|
<div
|
|
314
317
|
v-for="[kind, list] in branches"
|
|
315
318
|
:key="kind"
|
|
316
|
-
class="mt-3 border-
|
|
319
|
+
class="mt-3 border-s ps-4"
|
|
317
320
|
>
|
|
318
321
|
<p class="mb-1 text-xs font-medium text-muted-foreground">
|
|
319
322
|
{{ $t(`duxt.openapi.composition.${kind}`) }}
|
|
@@ -329,7 +332,7 @@ const open = computed(() => size.value < MANY);
|
|
|
329
332
|
</ul>
|
|
330
333
|
</div>
|
|
331
334
|
|
|
332
|
-
<div v-if="schema?.not" class="mt-3 border-
|
|
335
|
+
<div v-if="schema?.not" class="mt-3 border-s ps-4">
|
|
333
336
|
<p class="mb-1 text-xs font-medium text-muted-foreground">
|
|
334
337
|
{{ $t('duxt.openapi.composition.not') }}
|
|
335
338
|
</p>
|
|
@@ -11,9 +11,15 @@
|
|
|
11
11
|
* A consumer that wants the answer kept listens for it:
|
|
12
12
|
*
|
|
13
13
|
* <DuxtPageFeedback @feedback="(helpful) => track(helpful)" />
|
|
14
|
+
*
|
|
15
|
+
* A site that has wired `duxt.analytics.track` gets the same answer as a
|
|
16
|
+
* `feedback` event without wrapping anything — and the event above stays, so
|
|
17
|
+
* this component is usable either way and neither route needs the other.
|
|
14
18
|
*/
|
|
15
19
|
const emit = defineEmits<{ feedback: [helpful: boolean] }>();
|
|
16
20
|
|
|
21
|
+
const analytics = useDuxtAnalytics();
|
|
22
|
+
|
|
17
23
|
const answered = ref<boolean | undefined>();
|
|
18
24
|
|
|
19
25
|
// A new page is a new question. Without this the answer given on one page
|
|
@@ -26,6 +32,7 @@ watch(
|
|
|
26
32
|
|
|
27
33
|
function answer(helpful: boolean) {
|
|
28
34
|
answered.value = helpful;
|
|
35
|
+
analytics.track({ name: 'feedback', helpful });
|
|
29
36
|
emit('feedback', helpful);
|
|
30
37
|
}
|
|
31
38
|
</script>
|
|
@@ -44,6 +44,7 @@ const page = computed(() => props.page);
|
|
|
44
44
|
|
|
45
45
|
const { source } = useDuxtCollection();
|
|
46
46
|
const { locale, t } = useI18n();
|
|
47
|
+
const duxt = useDuxtConfig();
|
|
47
48
|
|
|
48
49
|
const file = computed(() => {
|
|
49
50
|
// A GENERATED SECTION has no file per page: every page in it was split out of
|
|
@@ -80,7 +81,9 @@ const link = computed(() =>
|
|
|
80
81
|
* the browser, which is a hydration mismatch as well as a wrong date. The
|
|
81
82
|
* commit date IS a moment and is left alone.
|
|
82
83
|
*/
|
|
83
|
-
const released = computed(() =>
|
|
84
|
+
const released = computed(() =>
|
|
85
|
+
formatDate(page.value?.date, locale.value, { calendarDay: true })
|
|
86
|
+
);
|
|
84
87
|
|
|
85
88
|
const updated = computed(() => {
|
|
86
89
|
// The page's own date wins. Both lines would be true and only one is useful:
|
|
@@ -89,18 +92,18 @@ const updated = computed(() => {
|
|
|
89
92
|
// one's and at worst years off.
|
|
90
93
|
if (page.value?.date) return undefined;
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
if (!value) return undefined;
|
|
94
|
-
|
|
95
|
-
const date = new Date(value);
|
|
96
|
-
if (Number.isNaN(date.getTime())) return undefined;
|
|
97
|
-
|
|
98
|
-
return new Intl.DateTimeFormat(locale.value, { dateStyle: 'medium' }).format(
|
|
99
|
-
date
|
|
100
|
-
);
|
|
95
|
+
return formatDate(page.value?.lastUpdated, locale.value);
|
|
101
96
|
});
|
|
102
97
|
|
|
103
98
|
const contributors = computed(() => page.value?.contributors ?? []);
|
|
99
|
+
// `DuxtText` also permits a record of strings, so the resolved-config mapped
|
|
100
|
+
// type narrows this all-optional object too far. It remains an object at
|
|
101
|
+
// runtime; only its template is configurable.
|
|
102
|
+
const contributorConfig = duxt.contributors as unknown as
|
|
103
|
+
| { avatarUrl?: string }
|
|
104
|
+
| undefined;
|
|
105
|
+
const avatar = (username: string) =>
|
|
106
|
+
contributorAvatar(contributorConfig?.avatarUrl, username);
|
|
104
107
|
|
|
105
108
|
/**
|
|
106
109
|
* What this page lets a reader DO with where it came from.
|
|
@@ -171,8 +174,8 @@ const notes = computed(() => {
|
|
|
171
174
|
class="flex items-center gap-1.5"
|
|
172
175
|
>
|
|
173
176
|
<img
|
|
174
|
-
v-if="person.username"
|
|
175
|
-
:src="
|
|
177
|
+
v-if="person.username && avatar(person.username)"
|
|
178
|
+
:src="avatar(person.username)"
|
|
176
179
|
alt=""
|
|
177
180
|
width="18"
|
|
178
181
|
height="18"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { flattenedNavigationPages } from '../utils/navigation-tree';
|
|
3
3
|
// Previous and next within the current section only. Content's own
|
|
4
4
|
// surroundings query walks the whole collection in one flat order, so the last
|
|
5
5
|
// page of one section would offer a "next" that lands in another — crossing a
|
|
@@ -12,19 +12,7 @@ const { items } = useDuxtSection(navigation);
|
|
|
12
12
|
const localeLink = useDuxtLink();
|
|
13
13
|
|
|
14
14
|
/** The section's pages in reading order, groups flattened into their children. */
|
|
15
|
-
const pages = computed(() =>
|
|
16
|
-
const flat: ContentNavigationItem[] = [];
|
|
17
|
-
|
|
18
|
-
const walk = (entries: ContentNavigationItem[]) => {
|
|
19
|
-
for (const entry of entries) {
|
|
20
|
-
if (entry.page !== false) flat.push(entry);
|
|
21
|
-
if (entry.children?.length) walk(entry.children);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
walk(items.value);
|
|
26
|
-
return flat;
|
|
27
|
-
});
|
|
15
|
+
const pages = computed(() => flattenedNavigationPages(items.value));
|
|
28
16
|
|
|
29
17
|
const index = computed(() =>
|
|
30
18
|
pages.value.findIndex((page) => page.path === props.path)
|
|
@@ -44,17 +32,29 @@ const next = computed(() =>
|
|
|
44
32
|
* chance to disagree with what the links say.
|
|
45
33
|
*/
|
|
46
34
|
const router = useRouter();
|
|
35
|
+
const { hint, on } = useDuxtShortcuts();
|
|
47
36
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
37
|
+
/**
|
|
38
|
+
* And they say so, on the two links they move between.
|
|
39
|
+
*
|
|
40
|
+
* These were the least findable keys in the theme: the search button at least
|
|
41
|
+
* carried `⌘K`, while `[` and `]` appeared nowhere a reader would look — only
|
|
42
|
+
* in a sheet they had to already know `?` to open. The cap goes on the link that
|
|
43
|
+
* does the same thing, which is where a reader is already looking when they
|
|
44
|
+
* want it.
|
|
45
|
+
*
|
|
46
|
+
* Nothing is drawn where the policy unbound the keys, and nothing is read out:
|
|
47
|
+
* `aria-hidden` keeps the link's accessible name the page it leads to, since
|
|
48
|
+
* "Next page ] Collections" is a worse thing to hear than the title, and the
|
|
49
|
+
* sheet announces the binding properly.
|
|
50
|
+
*/
|
|
51
|
+
const previousHint = computed(() => hint('previous'));
|
|
52
|
+
const nextHint = computed(() => hint('next'));
|
|
53
|
+
|
|
54
|
+
on(['previous', 'next'], (action) => {
|
|
55
|
+
const target = action === 'previous' ? previous.value : next.value;
|
|
56
|
+
if (target?.path) void router.push(localeLink(target.path)!);
|
|
57
|
+
});
|
|
58
58
|
</script>
|
|
59
59
|
|
|
60
60
|
<template>
|
|
@@ -69,8 +69,15 @@ onDuxtShortcut(
|
|
|
69
69
|
class="flex flex-col gap-1 rounded-lg border p-4 transition-colors hover:bg-accent"
|
|
70
70
|
>
|
|
71
71
|
<span class="flex items-center gap-1 text-xs text-muted-foreground">
|
|
72
|
-
<Icon name="lucide:arrow-left" class="size-3.5" />
|
|
72
|
+
<Icon name="lucide:arrow-left" class="size-3.5 rtl:-scale-x-100" />
|
|
73
73
|
{{ $t('duxt.nav.previous') }}
|
|
74
|
+
<kbd
|
|
75
|
+
v-if="previousHint"
|
|
76
|
+
aria-hidden="true"
|
|
77
|
+
class="ms-auto rounded border bg-muted px-1.5 font-mono text-[10px]"
|
|
78
|
+
>
|
|
79
|
+
{{ previousHint }}
|
|
80
|
+
</kbd>
|
|
74
81
|
</span>
|
|
75
82
|
<span class="font-medium">{{ previous.title }}</span>
|
|
76
83
|
</NuxtLink>
|
|
@@ -79,13 +86,20 @@ onDuxtShortcut(
|
|
|
79
86
|
<NuxtLink
|
|
80
87
|
v-if="next"
|
|
81
88
|
:to="localeLink(next.path)"
|
|
82
|
-
class="flex flex-col gap-1 rounded-lg border p-4 text-
|
|
89
|
+
class="flex flex-col gap-1 rounded-lg border p-4 text-end transition-colors hover:bg-accent"
|
|
83
90
|
>
|
|
84
91
|
<span
|
|
85
92
|
class="flex items-center justify-end gap-1 text-xs text-muted-foreground"
|
|
86
93
|
>
|
|
94
|
+
<kbd
|
|
95
|
+
v-if="nextHint"
|
|
96
|
+
aria-hidden="true"
|
|
97
|
+
class="me-auto rounded border bg-muted px-1.5 font-mono text-[10px]"
|
|
98
|
+
>
|
|
99
|
+
{{ nextHint }}
|
|
100
|
+
</kbd>
|
|
87
101
|
{{ $t('duxt.nav.next') }}
|
|
88
|
-
<Icon name="lucide:arrow-right" class="size-3.5" />
|
|
102
|
+
<Icon name="lucide:arrow-right" class="size-3.5 rtl:-scale-x-100" />
|
|
89
103
|
</span>
|
|
90
104
|
<span class="font-medium">{{ next.title }}</span>
|
|
91
105
|
</NuxtLink>
|
|
@@ -42,7 +42,7 @@ withDefaults(
|
|
|
42
42
|
/**
|
|
43
43
|
* `docs` — a Markdown page: two sidebars, prose, a code card.
|
|
44
44
|
* `api` — an operation list: a run of method-and-path rows.
|
|
45
|
-
* `text` — a plain-text artefact such as `llms.txt`: no
|
|
45
|
+
* `text` — a plain-text artefact such as `llms.txt`: no layout at all,
|
|
46
46
|
* because the browser renders one in a bare monospace document.
|
|
47
47
|
*/
|
|
48
48
|
variant?: DuxtSkeletonVariant;
|
|
@@ -81,7 +81,7 @@ withDefaults(
|
|
|
81
81
|
<!-- The navbar row, then a clear gap, then the version pill, the search
|
|
82
82
|
box at its real `w-56` and the three icons. Measured off the page
|
|
83
83
|
this stands in for, not sketched. -->
|
|
84
|
-
<div class="
|
|
84
|
+
<div class="ms-auto hidden items-center gap-6 @2xl:flex">
|
|
85
85
|
<div
|
|
86
86
|
v-for="width in [32, 62, 50, 42]"
|
|
87
87
|
:key="width"
|
|
@@ -90,7 +90,7 @@ withDefaults(
|
|
|
90
90
|
/>
|
|
91
91
|
</div>
|
|
92
92
|
|
|
93
|
-
<div class="
|
|
93
|
+
<div class="ms-6 flex items-center gap-6">
|
|
94
94
|
<div class="h-5 w-12 rounded-full bg-muted/60" />
|
|
95
95
|
<div class="h-8 w-56 rounded-md border bg-muted/30 @max-2xl:w-24" />
|
|
96
96
|
<div class="hidden gap-6 @2xl:flex">
|
|
@@ -181,7 +181,7 @@ withDefaults(
|
|
|
181
181
|
:style="{ width: `${row.path}px` }"
|
|
182
182
|
/>
|
|
183
183
|
<div
|
|
184
|
-
class="
|
|
184
|
+
class="ms-auto h-2.5 rounded bg-muted/40"
|
|
185
185
|
:style="{ width: `${row.summary}px` }"
|
|
186
186
|
/>
|
|
187
187
|
</div>
|
|
@@ -8,27 +8,15 @@
|
|
|
8
8
|
* reader cannot already ask the document.
|
|
9
9
|
*
|
|
10
10
|
* Measured against the document, not against a scroll container, so it is
|
|
11
|
-
* correct on the docs layout and on the landing page alike.
|
|
12
|
-
* this must never be the thing that makes scrolling stutter.
|
|
11
|
+
* correct on the docs layout and on the landing page alike.
|
|
13
12
|
*/
|
|
14
13
|
const progress = ref(0);
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
useDuxtViewportMeasure(() => {
|
|
17
16
|
const doc = document.documentElement;
|
|
18
17
|
const scrollable = doc.scrollHeight - doc.clientHeight;
|
|
19
18
|
|
|
20
19
|
progress.value = scrollable > 0 ? (doc.scrollTop / scrollable) * 100 : 0;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
onMounted(() => {
|
|
24
|
-
measure();
|
|
25
|
-
window.addEventListener('scroll', measure, { passive: true });
|
|
26
|
-
window.addEventListener('resize', measure, { passive: true });
|
|
27
|
-
|
|
28
|
-
onBeforeUnmount(() => {
|
|
29
|
-
window.removeEventListener('scroll', measure);
|
|
30
|
-
window.removeEventListener('resize', measure);
|
|
31
|
-
});
|
|
32
20
|
});
|
|
33
21
|
</script>
|
|
34
22
|
|