@kirchdev/duxt 0.3.4-dev-main.40-7fa9937 → 0.3.4
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.
|
@@ -24,7 +24,7 @@ const props = withDefaults(defineProps<{ variant?: 'badge' | 'block' }>(), {
|
|
|
24
24
|
const duxt = useDuxtConfig();
|
|
25
25
|
const path = useDuxtPath();
|
|
26
26
|
const localeLink = useDuxtLink();
|
|
27
|
-
const {
|
|
27
|
+
const { source } = useDuxtCollection();
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Versions come from the resolved source manifest, so the control can only
|
|
@@ -35,31 +35,13 @@ const { collection, source } = useDuxtCollection();
|
|
|
35
35
|
*/
|
|
36
36
|
const { choices: versions } = useDuxtVersion();
|
|
37
37
|
|
|
38
|
-
/**
|
|
39
|
-
* A changelog is one global history, so it deliberately has no version
|
|
40
|
-
* selector. Its current release is still useful context, though: read the
|
|
41
|
-
* latest one from the overview's generated frontmatter instead of falling
|
|
42
|
-
* back to the site's package version. The parser writes that value while
|
|
43
|
-
* turning the changelog into the overview and release pages.
|
|
44
|
-
*/
|
|
38
|
+
/** A global changelog switches between its source's documentation editions. */
|
|
45
39
|
const changelog = computed(
|
|
46
40
|
() =>
|
|
47
41
|
source.value?.generated?.type === 'changelog' &&
|
|
48
42
|
source.value.generated.versioning === 'global'
|
|
49
43
|
);
|
|
50
44
|
|
|
51
|
-
const { data: changelogPage } = await useAsyncData(
|
|
52
|
-
() => `duxt-changelog-version-${collection.value}-${path.value}`,
|
|
53
|
-
async () => {
|
|
54
|
-
if (!changelog.value) return undefined;
|
|
55
|
-
|
|
56
|
-
return (await queryCollection(collection.value as DuxtCollectionArg)
|
|
57
|
-
.path(path.value)
|
|
58
|
-
.first()) as { release?: string } | null;
|
|
59
|
-
},
|
|
60
|
-
{ watch: [collection, path, changelog] }
|
|
61
|
-
);
|
|
62
|
-
|
|
63
45
|
const current = computed(() =>
|
|
64
46
|
sourceForPath(
|
|
65
47
|
path.value,
|
|
@@ -67,9 +49,7 @@ const current = computed(() =>
|
|
|
67
49
|
)
|
|
68
50
|
);
|
|
69
51
|
|
|
70
|
-
const label = computed(
|
|
71
|
-
() => changelogPage.value?.release ?? current.value?.label ?? duxt.version
|
|
72
|
-
);
|
|
52
|
+
const label = computed(() => current.value?.label ?? duxt.version);
|
|
73
53
|
|
|
74
54
|
const { t, te } = useI18n();
|
|
75
55
|
|
|
@@ -92,7 +72,12 @@ function caption(version: DuxtLink) {
|
|
|
92
72
|
/** Same page, other version: swap the prefix rather than jumping to its root. */
|
|
93
73
|
function pathIn(version: { to?: string }) {
|
|
94
74
|
return localeLink(
|
|
95
|
-
versionPath(
|
|
75
|
+
versionPath(
|
|
76
|
+
path.value,
|
|
77
|
+
current.value?.to,
|
|
78
|
+
version.to ?? '/',
|
|
79
|
+
changelog.value
|
|
80
|
+
)
|
|
96
81
|
);
|
|
97
82
|
}
|
|
98
83
|
</script>
|
|
@@ -15,14 +15,60 @@
|
|
|
15
15
|
* that lives there: prefix work done inline in a component can only be checked
|
|
16
16
|
* by clicking.
|
|
17
17
|
*/
|
|
18
|
-
import { isInside, sourceForPath } from './version-paths';
|
|
18
|
+
import { isInside, sourceForPath, versionPath } from './version-paths';
|
|
19
19
|
|
|
20
20
|
/** The minimum a source has to carry to place a path or an entry. */
|
|
21
21
|
interface Area {
|
|
22
22
|
prefix: string;
|
|
23
|
+
repo?: string;
|
|
24
|
+
version?: string;
|
|
23
25
|
generated?: unknown;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
/** The documentation source that owns an area, without a generated section. */
|
|
29
|
+
function documentationFor(source: Area | undefined, sources: Area[]) {
|
|
30
|
+
if (!source?.generated) return source;
|
|
31
|
+
|
|
32
|
+
const candidates = source.repo
|
|
33
|
+
? sources.filter(
|
|
34
|
+
(other) =>
|
|
35
|
+
!other.generated &&
|
|
36
|
+
other.repo === source.repo &&
|
|
37
|
+
(!source.version || other.version === source.version)
|
|
38
|
+
)
|
|
39
|
+
: sources.filter(
|
|
40
|
+
(other) => !other.generated && isInside(source.prefix, other.prefix)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// A generated section belongs to the deepest documentation source it hangs
|
|
44
|
+
// under. A global section has no version of its own, so its area is the
|
|
45
|
+
// shallowest edition of that source instead.
|
|
46
|
+
return candidates.sort((a, b) =>
|
|
47
|
+
source.version || !source.repo
|
|
48
|
+
? b.prefix.length - a.prefix.length
|
|
49
|
+
: a.prefix.length - b.prefix.length
|
|
50
|
+
)[0];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The version-neutral root of a documentation area. */
|
|
54
|
+
function areaRoot(source: Area | undefined, sources: Area[]): string {
|
|
55
|
+
const documentation = documentationFor(source, sources);
|
|
56
|
+
if (!documentation) return '';
|
|
57
|
+
|
|
58
|
+
// A slug is the source identity and survives the version segment. All
|
|
59
|
+
// versions of `/demo` are therefore one area, whose shallowest prefix is
|
|
60
|
+
// the default edition. Sources without an identity retain their own prefix.
|
|
61
|
+
if (!documentation.repo) return documentation.prefix;
|
|
62
|
+
|
|
63
|
+
return sources
|
|
64
|
+
.filter((other) => !other.generated && other.repo === documentation.repo)
|
|
65
|
+
.reduce(
|
|
66
|
+
(root, other) =>
|
|
67
|
+
other.prefix.length < root.prefix.length ? other : root,
|
|
68
|
+
documentation
|
|
69
|
+
).prefix;
|
|
70
|
+
}
|
|
71
|
+
|
|
26
72
|
/**
|
|
27
73
|
* The AREAS a site has — one per documentation tree, never per generated
|
|
28
74
|
* section.
|
|
@@ -33,7 +79,11 @@ interface Area {
|
|
|
33
79
|
* of the site and the row would empty out on it.
|
|
34
80
|
*/
|
|
35
81
|
const areas = (sources: Area[]): string[] => [
|
|
36
|
-
...new Set(
|
|
82
|
+
...new Set(
|
|
83
|
+
sources
|
|
84
|
+
.filter((source) => !source.generated)
|
|
85
|
+
.map((source) => areaRoot(source, sources))
|
|
86
|
+
)
|
|
37
87
|
];
|
|
38
88
|
|
|
39
89
|
/**
|
|
@@ -43,12 +93,7 @@ const areas = (sources: Area[]): string[] => [
|
|
|
43
93
|
* never asked for any of this.
|
|
44
94
|
*/
|
|
45
95
|
export function areaForPath(path: string, sources: Area[]): string {
|
|
46
|
-
return (
|
|
47
|
-
sourceForPath(
|
|
48
|
-
path,
|
|
49
|
-
areas(sources).map((prefix) => ({ prefix }))
|
|
50
|
-
)?.prefix ?? ''
|
|
51
|
-
);
|
|
96
|
+
return areaRoot(sourceForPath(path, sources), sources);
|
|
52
97
|
}
|
|
53
98
|
|
|
54
99
|
/**
|
|
@@ -66,13 +111,40 @@ export function sectionsForPath<T extends { to?: string }>(
|
|
|
66
111
|
const area = areaForPath(path, sources);
|
|
67
112
|
const all = areas(sources);
|
|
68
113
|
|
|
69
|
-
// Only when the site HAS two areas
|
|
70
|
-
//
|
|
71
|
-
|
|
114
|
+
// Only when the site HAS two areas does the filter change the membership.
|
|
115
|
+
// Even one area's hand-written entries may need their URL moved to the
|
|
116
|
+
// reader's version, so do not return before that mapping below.
|
|
117
|
+
const scoped =
|
|
118
|
+
all.length < 2
|
|
119
|
+
? sections
|
|
120
|
+
: sections.filter(
|
|
121
|
+
(section) => !section.to || areaForPath(section.to, sources) === area
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const reader = documentationFor(sourceForPath(path, sources), sources);
|
|
125
|
+
if (!reader?.version) return scoped;
|
|
126
|
+
|
|
127
|
+
return scoped.map((section) => {
|
|
128
|
+
const target = section.to ? sourceForPath(section.to, sources) : undefined;
|
|
129
|
+
|
|
130
|
+
// A consumer declares the overview once, at the default edition. It is a
|
|
131
|
+
// part of every version of the same documentation source, so move it to
|
|
132
|
+
// the reader's edition. Generated sections already resolve their own
|
|
133
|
+
// per-version destination, and global generated sections must stay global.
|
|
134
|
+
if (
|
|
135
|
+
target &&
|
|
136
|
+
!target.generated &&
|
|
137
|
+
target.repo === reader.repo &&
|
|
138
|
+
target.version !== reader.version
|
|
139
|
+
) {
|
|
140
|
+
return {
|
|
141
|
+
...section,
|
|
142
|
+
to: versionPath(section.to!, target.prefix, reader.prefix)
|
|
143
|
+
} as T;
|
|
144
|
+
}
|
|
72
145
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
146
|
+
return section;
|
|
147
|
+
});
|
|
76
148
|
}
|
|
77
149
|
|
|
78
150
|
/**
|
|
@@ -65,11 +65,22 @@ export function versionChoices(
|
|
|
65
65
|
current: DuxtResolvedSource | undefined,
|
|
66
66
|
configured: DuxtLink[] | undefined
|
|
67
67
|
): DuxtLink[] {
|
|
68
|
-
// A
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
|
|
68
|
+
// A global generated section has no version of its own, but its reader still
|
|
69
|
+
// needs the documentation context of the source that owns it. Start from
|
|
70
|
+
// that source's default edition: its choices lead to the version overviews,
|
|
71
|
+
// never to non-existent versioned copies of the generated section.
|
|
72
|
+
const global = current?.generated?.versioning === 'global';
|
|
73
|
+
|
|
74
|
+
if (global && current?.generated?.type !== 'changelog') return [];
|
|
75
|
+
|
|
76
|
+
const context = global
|
|
77
|
+
? sources.find(
|
|
78
|
+
(source) =>
|
|
79
|
+
source.repo === current.repo && source.isDefault && !source.generated
|
|
80
|
+
)
|
|
81
|
+
: current;
|
|
82
|
+
|
|
83
|
+
if (!context) return [];
|
|
73
84
|
|
|
74
85
|
// `versions` in the config still wins where a label needs to read differently
|
|
75
86
|
// from the URL segment.
|
|
@@ -81,8 +92,8 @@ export function versionChoices(
|
|
|
81
92
|
.filter(
|
|
82
93
|
(source) =>
|
|
83
94
|
source.version &&
|
|
84
|
-
source.repo ===
|
|
85
|
-
sameArtefact(source,
|
|
95
|
+
source.repo === context.repo &&
|
|
96
|
+
sameArtefact(source, context)
|
|
86
97
|
)
|
|
87
98
|
.filter((source) => {
|
|
88
99
|
// Repository and artefact are scoped above; translations share the
|
|
@@ -43,8 +43,11 @@ export function isInside(path: string, prefix: string): boolean {
|
|
|
43
43
|
export function versionPath(
|
|
44
44
|
path: string,
|
|
45
45
|
from: string | undefined,
|
|
46
|
-
to: string
|
|
46
|
+
to: string,
|
|
47
|
+
overview = false
|
|
47
48
|
): string {
|
|
49
|
+
if (overview) return to || '/';
|
|
50
|
+
|
|
48
51
|
const rest =
|
|
49
52
|
from && from !== '/' && isInside(path, from)
|
|
50
53
|
? path.slice(from.length)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "@kirchdev/duxt",
|
|
4
|
-
"version": "0.3.4
|
|
4
|
+
"version": "0.3.4",
|
|
5
5
|
"description": "Nuxt documentation layer on Content v3 — multi-repo, versioned docs from one compact source list.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"content-v3",
|