@ampernic/vitepress-theme-alt-docs 0.1.14 → 0.1.16

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.
@@ -0,0 +1,112 @@
1
+ <template>
2
+ <div v-if="exports.length > 0" class="ad-export">
3
+ <p class="ad-export-label">Скачать документацию</p>
4
+ <a
5
+ v-for="item in exports"
6
+ :key="item.format"
7
+ :href="item.url"
8
+ class="ad-export-link"
9
+ :title="item.title"
10
+ >
11
+ <span class="ad-export-icon" v-html="item.icon" />
12
+ {{ item.label }}
13
+ </a>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { computed, ref, onMounted } from 'vue'
19
+ import { useData, useRoute } from 'vitepress'
20
+
21
+ const { site } = useData()
22
+ const route = useRoute()
23
+
24
+ interface ExportItem { format: string; url: string; label: string; title: string; icon: string }
25
+
26
+ const manifest = ref<Record<string, { pdf?: string; epub?: string; html?: string }> | null>(null)
27
+
28
+ onMounted(async () => {
29
+ try {
30
+ const base = site.value.base.replace(/\/$/, '')
31
+ const res = await fetch(`${base}/export-manifest.json`)
32
+ if (res.ok) {
33
+ const data = await res.json()
34
+ manifest.value = data.versions ?? null
35
+ }
36
+ } catch { /* manifest absent — silent */ }
37
+ })
38
+
39
+ const currentVersion = computed(() => {
40
+ const base = site.value.base
41
+ const p = route.path
42
+ const contentPath = base.length > 1 && p.startsWith(base) ? p.slice(base.length - 1) : p
43
+ const parts = contentPath.split('/').filter(Boolean)
44
+ return parts[0] && /^\d+\.\d+/.test(parts[0]) ? parts[0] : null
45
+ })
46
+
47
+ const exports = computed((): ExportItem[] => {
48
+ if (!currentVersion.value || !manifest.value) return []
49
+ const vEntry = manifest.value[currentVersion.value]
50
+ if (!vEntry) return []
51
+
52
+ const base = site.value.base.replace(/\/$/, '')
53
+ const items: ExportItem[] = []
54
+
55
+ if (vEntry.pdf) {
56
+ items.push({
57
+ format: 'pdf',
58
+ url: `${base}/${vEntry.pdf}`,
59
+ label: 'PDF',
60
+ title: `Скачать версию ${currentVersion.value} в формате PDF`,
61
+ 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>',
62
+ })
63
+ }
64
+
65
+ return items
66
+ })
67
+ </script>
68
+
69
+ <style scoped>
70
+ .ad-export {
71
+ padding: 16px 0 8px;
72
+ border-top: 1px solid var(--vp-c-divider);
73
+ margin-top: 8px;
74
+ }
75
+
76
+ .ad-export-label {
77
+ font-size: 12px;
78
+ font-weight: 600;
79
+ color: var(--vp-c-text-2);
80
+ text-transform: uppercase;
81
+ letter-spacing: 0.04em;
82
+ margin-bottom: 8px;
83
+ }
84
+
85
+ .ad-export-link {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: 6px;
89
+ padding: 6px 10px;
90
+ font-size: 13px;
91
+ font-weight: 500;
92
+ color: var(--vp-c-text-1);
93
+ background: var(--vp-c-default-soft);
94
+ border: 1px solid var(--vp-c-divider);
95
+ border-radius: 6px;
96
+ text-decoration: none;
97
+ transition: background 0.2s, border-color 0.2s, color 0.2s;
98
+ width: fit-content;
99
+ }
100
+
101
+ .ad-export-link:hover {
102
+ background: var(--vp-c-brand-soft);
103
+ border-color: var(--vp-c-brand-2);
104
+ color: var(--vp-c-brand-1);
105
+ }
106
+
107
+ .ad-export-icon {
108
+ display: flex;
109
+ align-items: center;
110
+ flex-shrink: 0;
111
+ }
112
+ </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div v-if="isLandingPage && origin" class="products-sidebar">
2
+ <div v-if="isLandingPage && origin && currentDistro" class="products-sidebar">
3
3
  <template v-for="group in groups" :key="group.title">
4
4
  <div class="group">
5
5
  <p v-if="group.title" class="group-title">{{ group.title }}</p>
@@ -1,6 +1,7 @@
1
1
  import { DefaultTheme } from 'vitepress';
2
2
  import type { SectionInfo } from '@ampernic/vitepress-plugin-alt-docs-versioning';
3
- export type { SectionInfo };
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.
@@ -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: {
@@ -47,7 +53,7 @@ function createSharedConfig(options) {
47
53
  ssr: {
48
54
  noExternal: ["@nolebase/vitepress-plugin-enhanced-readabilities", "@nolebase/ui", "@ampernic/vitepress-plugin-alt-docs-versioning", "@ampernic/vitepress-theme-alt-docs"]
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
@@ -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: {
@@ -50,6 +56,7 @@ export function createSharedConfig(options) {
50
56
  },
51
57
  plugins: [
52
58
  ...pagefind.vite.plugins,
59
+ ...exportInst?.vite.plugins ?? [],
53
60
  VersioningPlugin({
54
61
  distroName: options.distroName,
55
62
  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 ADExportButton from "./components/ADExportButton.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
+ "sidebar-nav-after": () => h(ADExportButton)
31
33
  }),
32
34
  enhanceApp({ app, router, siteData }) {
33
35
  installCrossSiteRouter(router, siteData);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ampernic/vitepress-theme-alt-docs",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Shared VitePress theme for ALT Linux documentation",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Ampernic",
@@ -34,8 +34,9 @@
34
34
  "markdown-it-kbd": "^1.0.0",
35
35
  "vitepress-plugin-tabs": "^0.6.0",
36
36
  "@ampernic/vitepress-plugin-cross-site-router": "0.1.2",
37
+ "@ampernic/vitepress-plugin-export": "0.1.0",
37
38
  "@ampernic/vitepress-plugin-html-image": "0.1.2",
38
- "@ampernic/vitepress-plugin-alt-docs-versioning": "0.1.4",
39
+ "@ampernic/vitepress-plugin-alt-docs-versioning": "0.1.5",
39
40
  "@ampernic/vitepress-plugin-pagefind": "0.1.8"
40
41
  },
41
42
  "devDependencies": {