@ampernic/vitepress-theme-alt-docs 0.1.15 → 0.1.18
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/components/ADExportButton.vue +228 -0
- package/dist/config/shared.d.ts +7 -1
- package/dist/config/shared.js +8 -2
- package/dist/config/shared.mjs +9 -1
- package/dist/index.mjs +3 -1
- package/dist/styles/print.css +20 -2
- package/package.json +4 -3
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="exports.length > 0" class="ad-export" ref="rootRef">
|
|
3
|
+
<p class="ad-export-label">Скачать документацию</p>
|
|
4
|
+
<div class="ad-export-dropdown">
|
|
5
|
+
<button
|
|
6
|
+
class="ad-export-trigger"
|
|
7
|
+
:class="{ 'is-open': isOpen }"
|
|
8
|
+
@click="isOpen = !isOpen"
|
|
9
|
+
:aria-expanded="isOpen"
|
|
10
|
+
>
|
|
11
|
+
<svg class="ad-export-dl-icon" xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
12
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
|
13
|
+
<polyline points="7 10 12 15 17 10"/>
|
|
14
|
+
<line x1="12" y1="15" x2="12" y2="3"/>
|
|
15
|
+
</svg>
|
|
16
|
+
Скачать
|
|
17
|
+
<svg class="ad-export-chevron" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
18
|
+
<polyline points="6 9 12 15 18 9"/>
|
|
19
|
+
</svg>
|
|
20
|
+
</button>
|
|
21
|
+
|
|
22
|
+
<Transition name="ad-dropdown">
|
|
23
|
+
<div v-show="isOpen" class="ad-export-menu">
|
|
24
|
+
<a
|
|
25
|
+
v-for="item in exports"
|
|
26
|
+
:key="item.format"
|
|
27
|
+
:href="item.url"
|
|
28
|
+
:download="item.filename"
|
|
29
|
+
:title="item.title"
|
|
30
|
+
class="ad-export-option"
|
|
31
|
+
@click="isOpen = false"
|
|
32
|
+
>
|
|
33
|
+
<span class="ad-export-option-icon" v-html="item.icon" />
|
|
34
|
+
<span>{{ item.label }}</span>
|
|
35
|
+
</a>
|
|
36
|
+
</div>
|
|
37
|
+
</Transition>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script setup lang="ts">
|
|
43
|
+
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
|
44
|
+
import { useData, useRoute } from 'vitepress'
|
|
45
|
+
|
|
46
|
+
const { site } = useData()
|
|
47
|
+
const route = useRoute()
|
|
48
|
+
|
|
49
|
+
interface ExportItem { format: string; url: string; filename: string; label: string; title: string; icon: string }
|
|
50
|
+
|
|
51
|
+
const manifest = ref<Record<string, { pdf?: string; epub?: string; html?: string }> | null>(null)
|
|
52
|
+
// Base prefix that actually served the manifest — may differ from site.base in vitepress preview
|
|
53
|
+
const resolvedBase = ref('')
|
|
54
|
+
const isOpen = ref(false)
|
|
55
|
+
const rootRef = ref<HTMLElement | null>(null)
|
|
56
|
+
|
|
57
|
+
onMounted(async () => {
|
|
58
|
+
try {
|
|
59
|
+
const base = site.value.base.replace(/\/$/, '')
|
|
60
|
+
let res = await fetch(`${base}/export-manifest.json`)
|
|
61
|
+
if (res.ok) {
|
|
62
|
+
resolvedBase.value = base
|
|
63
|
+
} else if (base) {
|
|
64
|
+
// vitepress preview strips base from file paths — try without prefix
|
|
65
|
+
res = await fetch('/export-manifest.json')
|
|
66
|
+
if (res.ok) resolvedBase.value = ''
|
|
67
|
+
}
|
|
68
|
+
if (res.ok) {
|
|
69
|
+
const data = await res.json()
|
|
70
|
+
manifest.value = data.versions ?? null
|
|
71
|
+
}
|
|
72
|
+
} catch { /* manifest absent — silent */ }
|
|
73
|
+
|
|
74
|
+
document.addEventListener('click', onClickOutside)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
onBeforeUnmount(() => {
|
|
78
|
+
document.removeEventListener('click', onClickOutside)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
function onClickOutside(e: MouseEvent) {
|
|
82
|
+
if (rootRef.value && !rootRef.value.contains(e.target as Node)) {
|
|
83
|
+
isOpen.value = false
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const currentVersion = computed(() => {
|
|
88
|
+
const base = site.value.base
|
|
89
|
+
const p = route.path
|
|
90
|
+
const contentPath = base.length > 1 && p.startsWith(base) ? p.slice(base.length - 1) : p
|
|
91
|
+
const parts = contentPath.split('/').filter(Boolean)
|
|
92
|
+
return parts[0] && /^\d+\.\d+/.test(parts[0]) ? parts[0] : null
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const exports = computed((): ExportItem[] => {
|
|
96
|
+
if (!currentVersion.value || !manifest.value) return []
|
|
97
|
+
const vEntry = manifest.value[currentVersion.value]
|
|
98
|
+
if (!vEntry) return []
|
|
99
|
+
|
|
100
|
+
const items: ExportItem[] = []
|
|
101
|
+
|
|
102
|
+
if (vEntry.pdf) {
|
|
103
|
+
items.push({
|
|
104
|
+
format: 'pdf',
|
|
105
|
+
url: `${resolvedBase.value}/${vEntry.pdf}`,
|
|
106
|
+
filename: vEntry.pdf,
|
|
107
|
+
label: 'PDF',
|
|
108
|
+
title: `Скачать версию ${currentVersion.value} в формате PDF`,
|
|
109
|
+
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><line x1="9" y1="15" x2="15" y2="15"/></svg>',
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return items
|
|
114
|
+
})
|
|
115
|
+
</script>
|
|
116
|
+
|
|
117
|
+
<style scoped>
|
|
118
|
+
.ad-export {
|
|
119
|
+
padding: 16px 0 8px;
|
|
120
|
+
border-top: 1px solid var(--vp-c-divider);
|
|
121
|
+
margin-top: 8px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.ad-export-label {
|
|
125
|
+
font-size: 12px;
|
|
126
|
+
font-weight: 600;
|
|
127
|
+
color: var(--vp-c-text-2);
|
|
128
|
+
text-transform: uppercase;
|
|
129
|
+
letter-spacing: 0.04em;
|
|
130
|
+
margin-bottom: 8px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.ad-export-dropdown {
|
|
134
|
+
position: relative;
|
|
135
|
+
display: block;
|
|
136
|
+
width: 100%;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.ad-export-trigger {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
gap: 5px;
|
|
144
|
+
padding: 0 12px;
|
|
145
|
+
width: 100%;
|
|
146
|
+
height: 34px;
|
|
147
|
+
font-size: 13px;
|
|
148
|
+
font-weight: 500;
|
|
149
|
+
color: var(--vp-c-text-1);
|
|
150
|
+
background: var(--vp-c-default-soft);
|
|
151
|
+
border: 1px solid var(--vp-c-divider);
|
|
152
|
+
border-radius: 4px;
|
|
153
|
+
cursor: pointer;
|
|
154
|
+
transition: border-color 0.25s, background-color 0.25s, color 0.25s;
|
|
155
|
+
white-space: nowrap;
|
|
156
|
+
user-select: none;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.ad-export-trigger:hover,
|
|
160
|
+
.ad-export-trigger.is-open {
|
|
161
|
+
background: var(--vp-c-default-soft);
|
|
162
|
+
border-color: var(--vp-c-brand-1);
|
|
163
|
+
color: var(--vp-c-brand-1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.ad-export-dl-icon {
|
|
167
|
+
flex-shrink: 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.ad-export-chevron {
|
|
171
|
+
flex-shrink: 0;
|
|
172
|
+
transition: transform 0.2s;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.ad-export-trigger.is-open .ad-export-chevron {
|
|
176
|
+
transform: rotate(180deg);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.ad-export-menu {
|
|
180
|
+
position: absolute;
|
|
181
|
+
top: calc(100% + 6px);
|
|
182
|
+
left: 0;
|
|
183
|
+
right: 0;
|
|
184
|
+
z-index: 100;
|
|
185
|
+
min-width: 130px;
|
|
186
|
+
background: var(--vp-c-bg-elv);
|
|
187
|
+
border: 1px solid var(--vp-c-divider);
|
|
188
|
+
border-radius: 8px;
|
|
189
|
+
box-shadow: var(--vp-shadow-3);
|
|
190
|
+
overflow: hidden;
|
|
191
|
+
padding: 4px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.ad-export-option {
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
gap: 8px;
|
|
198
|
+
padding: 6px 10px;
|
|
199
|
+
font-size: 13px;
|
|
200
|
+
font-weight: 500;
|
|
201
|
+
color: var(--vp-c-text-1);
|
|
202
|
+
border-radius: 5px;
|
|
203
|
+
text-decoration: none;
|
|
204
|
+
transition: background-color 0.15s, color 0.15s;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.ad-export-option:hover {
|
|
208
|
+
background: var(--vp-c-default-soft);
|
|
209
|
+
color: var(--vp-c-brand-1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.ad-export-option-icon {
|
|
213
|
+
display: flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
flex-shrink: 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.ad-dropdown-enter-active,
|
|
219
|
+
.ad-dropdown-leave-active {
|
|
220
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.ad-dropdown-enter-from,
|
|
224
|
+
.ad-dropdown-leave-to {
|
|
225
|
+
opacity: 0;
|
|
226
|
+
transform: translateY(-4px);
|
|
227
|
+
}
|
|
228
|
+
</style>
|
package/dist/config/shared.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DefaultTheme } from 'vitepress';
|
|
2
2
|
import type { SectionInfo } from '@ampernic/vitepress-plugin-alt-docs-versioning';
|
|
3
|
-
|
|
3
|
+
import type { ExportPluginOptions } from '@ampernic/vitepress-plugin-export';
|
|
4
|
+
export type { SectionInfo, ExportPluginOptions };
|
|
4
5
|
export interface SharedConfigOptions {
|
|
5
6
|
/** Distro slug for this VitePress instance, e.g. `'alt-domain'`. */
|
|
6
7
|
distroName: string;
|
|
@@ -27,6 +28,11 @@ export interface SharedConfigOptions {
|
|
|
27
28
|
* @default 'https://altlinux.space/alt-docs/docs-vitepress'
|
|
28
29
|
*/
|
|
29
30
|
editLinkRepo?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Export plugin options. When provided, generates per-version export bundles
|
|
33
|
+
* (PDF, etc.) after the build and writes `export-manifest.json` to the dist dir.
|
|
34
|
+
*/
|
|
35
|
+
export?: ExportPluginOptions;
|
|
30
36
|
}
|
|
31
37
|
/**
|
|
32
38
|
* Creates the shared VitePress config for a single-distro instance.
|
package/dist/config/shared.js
CHANGED
|
@@ -11,6 +11,7 @@ var _markdownItKbd = _interopRequireDefault(require("markdown-it-kbd"));
|
|
|
11
11
|
var _vitepressPluginAltDocsVersioning = require("@ampernic/vitepress-plugin-alt-docs-versioning");
|
|
12
12
|
var _vitepressPluginHtmlImage = require("@ampernic/vitepress-plugin-html-image");
|
|
13
13
|
var _vitepressPluginPagefind = require("@ampernic/vitepress-plugin-pagefind");
|
|
14
|
+
var _vitepressPluginExport = require("@ampernic/vitepress-plugin-export");
|
|
14
15
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
16
|
function createSharedConfig(options) {
|
|
16
17
|
const base = process.env.VITE_BASE ?? "/";
|
|
@@ -23,8 +24,13 @@ function createSharedConfig(options) {
|
|
|
23
24
|
} : null;
|
|
24
25
|
}
|
|
25
26
|
});
|
|
27
|
+
const exportInst = options.export ? (0, _vitepressPluginExport.ExportPlugin)(options.export) : null;
|
|
26
28
|
return (0, _vitepress.defineConfigWithTheme)({
|
|
27
29
|
...pagefind,
|
|
30
|
+
buildEnd: async () => {
|
|
31
|
+
await pagefind.buildEnd();
|
|
32
|
+
await exportInst?.buildEnd();
|
|
33
|
+
},
|
|
28
34
|
vue: {
|
|
29
35
|
template: {
|
|
30
36
|
transformAssetUrls: {
|
|
@@ -45,9 +51,9 @@ function createSharedConfig(options) {
|
|
|
45
51
|
exclude: ["@nolebase/vitepress-plugin-enhanced-readabilities/client", "vitepress", "@nolebase/ui", "@ampernic/vitepress-theme-alt-docs"]
|
|
46
52
|
},
|
|
47
53
|
ssr: {
|
|
48
|
-
noExternal: ["@nolebase/vitepress-plugin-enhanced-readabilities", "@nolebase/ui", "@ampernic/vitepress-plugin-alt-docs-versioning", "@ampernic/vitepress-theme-alt-docs"]
|
|
54
|
+
noExternal: ["@nolebase/vitepress-plugin-enhanced-readabilities", "@nolebase/ui", "@ampernic/vitepress-plugin-alt-docs-versioning", "@ampernic/vitepress-theme-alt-docs", "@ampernic/vitepress-plugin-export"]
|
|
49
55
|
},
|
|
50
|
-
plugins: [...pagefind.vite.plugins, (0, _vitepressPluginAltDocsVersioning.VersioningPlugin)({
|
|
56
|
+
plugins: [...pagefind.vite.plugins, ...(exportInst?.vite.plugins ?? []), (0, _vitepressPluginAltDocsVersioning.VersioningPlugin)({
|
|
51
57
|
distroName: options.distroName,
|
|
52
58
|
allDistros: options.allDistros,
|
|
53
59
|
sections: options.sections
|
package/dist/config/shared.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import markdownItKbd from "markdown-it-kbd";
|
|
|
5
5
|
import { VersioningPlugin } from "@ampernic/vitepress-plugin-alt-docs-versioning";
|
|
6
6
|
import { htmlImagePlugin } from "@ampernic/vitepress-plugin-html-image";
|
|
7
7
|
import { PagefindPlugin } from "@ampernic/vitepress-plugin-pagefind";
|
|
8
|
+
import { ExportPlugin } from "@ampernic/vitepress-plugin-export";
|
|
8
9
|
export function createSharedConfig(options) {
|
|
9
10
|
const base = process.env.VITE_BASE ?? "/";
|
|
10
11
|
const pagefind = PagefindPlugin({
|
|
@@ -14,8 +15,13 @@ export function createSharedConfig(options) {
|
|
|
14
15
|
return m ? { version: m[1] } : null;
|
|
15
16
|
}
|
|
16
17
|
});
|
|
18
|
+
const exportInst = options.export ? ExportPlugin(options.export) : null;
|
|
17
19
|
return defineConfigWithTheme({
|
|
18
20
|
...pagefind,
|
|
21
|
+
buildEnd: async () => {
|
|
22
|
+
await pagefind.buildEnd();
|
|
23
|
+
await exportInst?.buildEnd();
|
|
24
|
+
},
|
|
19
25
|
vue: {
|
|
20
26
|
template: {
|
|
21
27
|
transformAssetUrls: {
|
|
@@ -45,11 +51,13 @@ export function createSharedConfig(options) {
|
|
|
45
51
|
"@nolebase/vitepress-plugin-enhanced-readabilities",
|
|
46
52
|
"@nolebase/ui",
|
|
47
53
|
"@ampernic/vitepress-plugin-alt-docs-versioning",
|
|
48
|
-
"@ampernic/vitepress-theme-alt-docs"
|
|
54
|
+
"@ampernic/vitepress-theme-alt-docs",
|
|
55
|
+
"@ampernic/vitepress-plugin-export"
|
|
49
56
|
]
|
|
50
57
|
},
|
|
51
58
|
plugins: [
|
|
52
59
|
...pagefind.vite.plugins,
|
|
60
|
+
...exportInst?.vite.plugins ?? [],
|
|
53
61
|
VersioningPlugin({
|
|
54
62
|
distroName: options.distroName,
|
|
55
63
|
allDistros: options.allDistros,
|
package/dist/index.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import ADProductsSidebar from "./components/ADProductsSidebar.vue";
|
|
|
18
18
|
import ADInlineImage from "./components/ADInlineImage.vue";
|
|
19
19
|
import ADAssetLink from "./components/ADAssetLink.vue";
|
|
20
20
|
import ADNavBarSearch from "./components/ADNavBarSearch.vue";
|
|
21
|
+
import ExportButton from "@ampernic/vitepress-plugin-export/components/ExportButton.vue";
|
|
21
22
|
import "./styles/theme.css";
|
|
22
23
|
import "./styles/custom.css";
|
|
23
24
|
import "./styles/icons.css";
|
|
@@ -27,7 +28,8 @@ export const Theme = {
|
|
|
27
28
|
"nav-bar-content-before": () => h(ADNavBarSearch),
|
|
28
29
|
"nav-bar-content-after": () => h(NolebaseEnhancedReadabilitiesMenu),
|
|
29
30
|
"nav-screen-content-after": () => h(NolebaseEnhancedReadabilitiesScreenMenu),
|
|
30
|
-
"sidebar-nav-before": () => h(ADProductsSidebar)
|
|
31
|
+
"sidebar-nav-before": () => h(ADProductsSidebar),
|
|
32
|
+
"aside-outline-after": () => h(ExportButton)
|
|
31
33
|
}),
|
|
32
34
|
enhanceApp({ app, router, siteData }) {
|
|
33
35
|
installCrossSiteRouter(router, siteData);
|
package/dist/styles/print.css
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
.VPSidebar,
|
|
11
11
|
.VPSocialLink,
|
|
12
12
|
.vp-sponsor,
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
.products-menu,
|
|
15
15
|
.versioning-menu,
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
.VPDoc .aside,
|
|
18
18
|
.VPDoc .aside-container {
|
|
19
19
|
display: none !important;
|
|
@@ -33,4 +33,22 @@
|
|
|
33
33
|
display: block !important;
|
|
34
34
|
visibility: visible !important;
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
/* Keep blocks and elements from splitting across pages */
|
|
38
|
+
.custom-block,
|
|
39
|
+
.custom-block-title + p,
|
|
40
|
+
pre,
|
|
41
|
+
blockquote,
|
|
42
|
+
figure,
|
|
43
|
+
table,
|
|
44
|
+
img {
|
|
45
|
+
break-inside: avoid;
|
|
46
|
+
page-break-inside: avoid;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Keep heading with its following content */
|
|
50
|
+
h1, h2, h3, h4, h5, h6 {
|
|
51
|
+
break-after: avoid;
|
|
52
|
+
page-break-after: avoid;
|
|
53
|
+
}
|
|
36
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ampernic/vitepress-theme-alt-docs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "Shared VitePress theme for ALT Linux documentation",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"author": "Ampernic",
|
|
@@ -34,9 +34,10 @@
|
|
|
34
34
|
"markdown-it-kbd": "^1.0.0",
|
|
35
35
|
"vitepress-plugin-tabs": "^0.6.0",
|
|
36
36
|
"@ampernic/vitepress-plugin-alt-docs-versioning": "0.1.5",
|
|
37
|
+
"@ampernic/vitepress-plugin-export": "0.1.17",
|
|
38
|
+
"@ampernic/vitepress-plugin-pagefind": "0.1.8",
|
|
37
39
|
"@ampernic/vitepress-plugin-cross-site-router": "0.1.2",
|
|
38
|
-
"@ampernic/vitepress-plugin-html-image": "0.1.2"
|
|
39
|
-
"@ampernic/vitepress-plugin-pagefind": "0.1.8"
|
|
40
|
+
"@ampernic/vitepress-plugin-html-image": "0.1.2"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"builtin-modules": "^3.3.0",
|