@ansidev-oss/vitepress-theme-ansidev 1.0.10 → 1.0.11

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.
Files changed (45) hide show
  1. package/dist/client/Sharing-ZrU7YF-x.js +190 -0
  2. package/dist/client/Swetrix-CM1mbD6X.js +450 -0
  3. package/dist/client/{VPAlgoliaSearchBox-DXE-LCVf.js → VPAlgoliaSearchBox-BAhNuo7n.js} +1 -1
  4. package/dist/client/{VPCarbonAds-Czmm53YE.js → VPCarbonAds-CSK7KnIu.js} +1 -1
  5. package/dist/client/{VPLocalSearchBox-ihwA4uH-.js → VPLocalSearchBox-TYbANUkJ.js} +1 -1
  6. package/dist/client/composables/index.d.ts +1 -1
  7. package/dist/client/{index-CZCdwVUW.js → index-C43AnX3f.js} +1623 -1573
  8. package/dist/client/index-DuYWs0vj.js +265 -0
  9. package/dist/client/index.d.ts +2 -1
  10. package/dist/client/index.js +7 -2
  11. package/dist/client/plugins/medium-zoom/index.d.ts +14 -0
  12. package/dist/client/plugins/sharing/index.d.ts +59 -0
  13. package/dist/client/plugins/swetrix/index.d.ts +10 -0
  14. package/dist/client/styles.css +1 -1
  15. package/dist/client/types/index.d.ts +14 -1
  16. package/dist/node/composables/index.d.ts +3 -0
  17. package/dist/node/composables/markdown.d.ts +2 -0
  18. package/dist/node/composables/route.d.ts +15 -0
  19. package/dist/node/composables/slug.d.ts +7 -0
  20. package/dist/node/composables/types.d.ts +7 -0
  21. package/dist/node/composables.d.mts +4 -2
  22. package/dist/node/composables.mjs +4 -1
  23. package/dist/node/config.d.mts +90 -8
  24. package/dist/node/config.d.ts +45 -0
  25. package/dist/node/config.mjs +19 -10
  26. package/dist/shared/composables/index.d.ts +1 -0
  27. package/package.json +11 -3
  28. package/src/client/components/DonationWidget.vue +22 -0
  29. package/src/client/components/Footer.vue +12 -12
  30. package/src/client/components/SharingWidget.vue +19 -0
  31. package/src/client/composables/index.ts +1 -1
  32. package/src/client/index.ts +2 -8
  33. package/src/client/layouts/Layout.vue +48 -2
  34. package/src/client/plugins/medium-zoom/index.ts +30 -0
  35. package/src/client/plugins/sharing/components/Sharing.vue +81 -0
  36. package/src/client/plugins/sharing/components/SharingButton.vue +115 -0
  37. package/src/client/plugins/sharing/index.ts +76 -0
  38. package/src/client/plugins/swetrix/components/Swetrix.vue +43 -0
  39. package/src/client/plugins/swetrix/index.ts +11 -0
  40. package/src/client/types/index.ts +14 -1
  41. package/src/node/composables/slug.ts +3 -13
  42. package/src/node/config.ts +22 -13
  43. package/src/shared/composables/index.ts +1 -0
  44. /package/dist/{client/composables/slug.d.ts → shared/composables/useSlug.d.ts} +0 -0
  45. /package/src/{client/composables/slug.ts → shared/composables/useSlug.ts} +0 -0
@@ -1,6 +1,9 @@
1
1
  import type { DefaultTheme } from 'vitepress/theme';
2
2
  import type { DonationPluginConfig } from '../plugins/donation';
3
3
  import type { GoogleAnalyticsOptions } from '../plugins/google-analytics';
4
+ import type { MediumZoomPluginConfig } from '../plugins/medium-zoom';
5
+ import type { SharingPluginConfig } from '../plugins/sharing';
6
+ import type { SwetrixOptions } from '../plugins/swetrix';
4
7
  export interface ThemeConfig extends DefaultTheme.Config {
5
8
  /**
6
9
  * The site URL.
@@ -8,11 +11,21 @@ export interface ThemeConfig extends DefaultTheme.Config {
8
11
  * @default process.env.VITE_BASE_URL
9
12
  */
10
13
  siteURL?: string;
11
- googleAnalytics?: GoogleAnalyticsOptions;
12
14
  donation?: DonationPluginConfig;
15
+ googleAnalytics?: GoogleAnalyticsOptions;
16
+ mediumZoom?: MediumZoomPluginConfig;
17
+ sharing?: SharingPluginConfig;
18
+ swetrix?: SwetrixOptions;
19
+ /**
20
+ * The footer configuration.
21
+ */
22
+ themeFooter?: DefaultTheme.Footer;
13
23
  }
14
24
  export type { DonationPluginConfig } from '../plugins/donation';
15
25
  export type { GoogleAnalyticsOptions } from '../plugins/google-analytics';
26
+ export type { MediumZoomPluginConfig } from '../plugins/medium-zoom';
27
+ export type { SharingPluginConfig } from '../plugins/sharing';
28
+ export type { SwetrixOptions } from '../plugins/swetrix';
16
29
  export interface Post {
17
30
  type: string;
18
31
  title: string;
@@ -0,0 +1,3 @@
1
+ export * from './markdown';
2
+ export * from './route';
3
+ export * from './slug';
@@ -0,0 +1,2 @@
1
+ import type { Frontmatter, Pattern } from './types';
2
+ export declare const useMarkdownFrontmatter: (pattern: Pattern, excerptSeparator?: string) => Array<Frontmatter>;
@@ -0,0 +1,15 @@
1
+ import type { Pattern } from './types';
2
+ export declare const useMarkdownFrontmatterRoute: (pattern: Pattern, frontmatterKey: string, excerptSeparator?: string) => {
3
+ paths(): {
4
+ params: {
5
+ slug: string;
6
+ };
7
+ }[];
8
+ };
9
+ export declare const useArchiveRoute: (pattern: Pattern, excerptSeparator?: string) => {
10
+ paths(): {
11
+ params: {
12
+ slug: string;
13
+ };
14
+ }[];
15
+ };
@@ -0,0 +1,7 @@
1
+ import type { Pattern, StringOrFrontmatterToString } from './types';
2
+ export declare const useSlugFromMarkdownFrontMatter: (pattern: Pattern, frontmatterKeyOrMappingFn: StringOrFrontmatterToString, excerptSeparator?: string) => {
3
+ params: {
4
+ slug: string;
5
+ };
6
+ }[];
7
+ export { useSlug, useSlugFilter } from '../../shared/composables';
@@ -0,0 +1,7 @@
1
+ export type Pattern = string | string[];
2
+ export type Frontmatter = Record<string, unknown> & {
3
+ date?: string;
4
+ excerpt?: string;
5
+ };
6
+ export type FrontmatterToString = (frontmatter: Frontmatter) => string;
7
+ export type StringOrFrontmatterToString = string | FrontmatterToString;
@@ -18,12 +18,14 @@ declare const useArchiveRoute: (pattern: Pattern, excerptSeparator?: string) =>
18
18
  paths(): any;
19
19
  };
20
20
  //#endregion
21
- //#region src/node/composables/slug.d.ts
21
+ //#region src/shared/composables/useSlug.d.ts
22
22
  declare const useSlug: (str: string) => string;
23
23
  declare const useSlugFilter: (slug: string) => (str: string) => boolean;
24
+ //#endregion
25
+ //#region src/node/composables/slug.d.ts
24
26
  declare const useSlugFromMarkdownFrontMatter: (pattern: Pattern, frontmatterKeyOrMappingFn: StringOrFrontmatterToString, excerptSeparator?: string) => {
25
27
  params: {
26
- slug: string;
28
+ slug: any;
27
29
  };
28
30
  }[];
29
31
  //#endregion
@@ -18,11 +18,14 @@ const useMarkdownFrontmatter = (pattern, excerptSeparator = "---") => {
18
18
  };
19
19
 
20
20
  //#endregion
21
- //#region src/node/composables/slug.ts
21
+ //#region src/shared/composables/useSlug.ts
22
22
  const useSlug = (str) => {
23
23
  return str.replace(/#/, "-sharp-").replace(/\./, "-dot-").replace(/-$/, "").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/đ/g, "d").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
24
24
  };
25
25
  const useSlugFilter = (slug) => (str) => useSlug(str) === slug;
26
+
27
+ //#endregion
28
+ //#region src/node/composables/slug.ts
26
29
  const useSlugFromMarkdownFrontMatter = (pattern, frontmatterKeyOrMappingFn, excerptSeparator = "---") => {
27
30
  const frontMatters = useMarkdownFrontmatter(pattern, excerptSeparator);
28
31
  const _frontmatterMappingFn = typeof frontmatterKeyOrMappingFn === "string" ? (frontMatter) => frontMatter[frontmatterKeyOrMappingFn] : frontmatterKeyOrMappingFn;
@@ -1,8 +1,91 @@
1
+ import { UserConfig } from "vitepress";
2
+ import { DefaultTheme } from "vitepress/theme";
3
+ import * as Swetrix from "swetrix";
4
+
5
+ //#region src/client/plugins/donation/index.d.ts
6
+ declare interface DonationPluginConfig {
7
+ buymeacoffee?: string;
8
+ kofi?: string;
9
+ paypal?: string;
10
+ custom?: {
11
+ [key: string]: CustomDonationConfig;
12
+ };
13
+ }
14
+ declare interface CustomDonationBaseConfig {
15
+ donationBaseUrl: string;
16
+ donationButtonImage: string;
17
+ donationButtonStyle?: Record<string, string>;
18
+ }
19
+ declare interface CustomDonationConfig extends CustomDonationBaseConfig {
20
+ donationId: string;
21
+ }
22
+ //#endregion
23
+ //#region src/client/plugins/google-analytics/index.d.ts
24
+ interface GoogleAnalyticsOptions {
25
+ /**
26
+ * The Google Analytics ID.
27
+ *
28
+ * @default process.env.VITE_GA_ID
29
+ */
30
+ id: string;
31
+ }
32
+ //#endregion
33
+ //#region src/client/plugins/medium-zoom/index.d.ts
34
+ declare module 'medium-zoom' {
35
+ interface Zoom {
36
+ refresh: (selector?: string) => void;
37
+ }
38
+ }
39
+ type MediumZoomPluginConfig = {
40
+ selector: string;
41
+ zoomOptions?: string;
42
+ delay?: number;
43
+ };
44
+ //#endregion
45
+ //#region src/client/plugins/sharing/index.d.ts
46
+ declare interface SharingPluginConfig {
47
+ networks?: string[];
48
+ displayMode?: string;
49
+ buttonSize?: number;
50
+ iconSize?: number;
51
+ iconStyle?: string;
52
+ }
53
+ //#endregion
54
+ //#region src/client/plugins/swetrix/index.d.ts
55
+ interface SwetrixOptions {
56
+ /**
57
+ * The Swetrix ID.
58
+ *
59
+ * @default process.env.VITE_SWETRIX_ID
60
+ */
61
+ id: string;
62
+ options?: Swetrix.LibOptions;
63
+ }
64
+ //#endregion
65
+ //#region src/client/types/index.d.ts
66
+ interface ThemeConfig extends DefaultTheme.Config {
67
+ /**
68
+ * The site URL.
69
+ *
70
+ * @default process.env.VITE_BASE_URL
71
+ */
72
+ siteURL?: string;
73
+ donation?: DonationPluginConfig;
74
+ googleAnalytics?: GoogleAnalyticsOptions;
75
+ mediumZoom?: MediumZoomPluginConfig;
76
+ sharing?: SharingPluginConfig;
77
+ swetrix?: SwetrixOptions;
78
+ /**
79
+ * The footer configuration.
80
+ */
81
+ themeFooter?: DefaultTheme.Footer;
82
+ }
83
+ //#endregion
1
84
  //#region src/node/config.d.ts
2
85
  /**
3
86
  * @type {import('vitepress').UserConfig}
4
87
  */
5
- declare const config: {
88
+ declare const baseConfig: {
6
89
  themeConfig: {
7
90
  siteURL: string;
8
91
  googleAnalytics: {
@@ -34,13 +117,12 @@ declare const config: {
34
117
  };
35
118
  };
36
119
  };
37
- resolve: {
38
- alias: {
39
- find: RegExp;
40
- replacement: string;
41
- }[];
42
- };
43
120
  };
44
121
  };
122
+ /**
123
+ * Helper function to define theme configuration with proper typing
124
+ * Note: TailwindCSS plugin should be added in vite.config.ts, not here
125
+ */
126
+ declare function defineWithDefaultThemeConfig(config?: UserConfig<ThemeConfig>): UserConfig<ThemeConfig>;
45
127
  //#endregion
46
- export { config as default };
128
+ export { baseConfig as default, defineWithDefaultThemeConfig };
@@ -0,0 +1,45 @@
1
+ import type { UserConfig } from 'vitepress';
2
+ import type { ThemeConfig } from '../client/types';
3
+ /**
4
+ * @type {import('vitepress').UserConfig}
5
+ */
6
+ declare const baseConfig: {
7
+ themeConfig: {
8
+ siteURL: string;
9
+ googleAnalytics: {
10
+ id: string;
11
+ };
12
+ search: {
13
+ provider: string;
14
+ options: {
15
+ /**
16
+ * @param {string} src
17
+ * @param {import('vitepress').MarkdownEnv} env
18
+ * @param {import('markdown-it')} md
19
+ */
20
+ _render(src: any, env: any, md: any): Promise<string>;
21
+ };
22
+ };
23
+ };
24
+ vite: {
25
+ ssr: {
26
+ noExternal: string[];
27
+ };
28
+ optimizeDeps: {
29
+ exclude: string[];
30
+ };
31
+ css: {
32
+ preprocessorOptions: {
33
+ scss: {
34
+ api: string;
35
+ };
36
+ };
37
+ };
38
+ };
39
+ };
40
+ /**
41
+ * Helper function to define theme configuration with proper typing
42
+ * Note: TailwindCSS plugin should be added in vite.config.ts, not here
43
+ */
44
+ export declare function defineWithDefaultThemeConfig(config?: UserConfig<ThemeConfig>): UserConfig<ThemeConfig>;
45
+ export default baseConfig;
@@ -1,5 +1,4 @@
1
- import { URL, fileURLToPath } from "node:url";
2
- import { loadEnv } from "vitepress";
1
+ import { loadEnv, mergeConfig } from "vitepress";
3
2
 
4
3
  //#region src/node/config.ts
5
4
  process.env.VITE_EXTRA_EXTENSIONS = "rss";
@@ -12,11 +11,11 @@ const siteURL = env.VITE_BASE_URL;
12
11
  *
13
12
  * It runs in Node.js.
14
13
  */
15
- const deps = ["vitepress-theme-ansidev"];
14
+ const deps = ["@ansidev-oss/vitepress-theme-ansidev"];
16
15
  /**
17
16
  * @type {import('vitepress').UserConfig}
18
17
  */
19
- const config = {
18
+ const baseConfig = {
20
19
  themeConfig: {
21
20
  siteURL,
22
21
  googleAnalytics: { id: env.VITE_GA_ID },
@@ -35,13 +34,23 @@ const config = {
35
34
  vite: {
36
35
  ssr: { noExternal: deps },
37
36
  optimizeDeps: { exclude: deps },
38
- css: { preprocessorOptions: { scss: { api: "modern-compiler" } } },
39
- resolve: { alias: [{
40
- find: /^.*\/VPFooter\.vue$/,
41
- replacement: fileURLToPath(new URL("./components/EmptyFooter.vue", import.meta.url))
42
- }] }
37
+ css: { preprocessorOptions: { scss: { api: "modern-compiler" } } }
43
38
  }
44
39
  };
40
+ /**
41
+ * Helper function to define theme configuration with proper typing
42
+ * Note: TailwindCSS plugin should be added in vite.config.ts, not here
43
+ */
44
+ function defineWithDefaultThemeConfig(config = {}) {
45
+ if (config.themeConfig?.footer) {
46
+ config.themeConfig = {
47
+ ...config.themeConfig,
48
+ themeFooter: config.themeConfig.footer
49
+ };
50
+ delete config.themeConfig.footer;
51
+ }
52
+ return mergeConfig(baseConfig, config);
53
+ }
45
54
 
46
55
  //#endregion
47
- export { config as default };
56
+ export { baseConfig as default, defineWithDefaultThemeConfig };
@@ -0,0 +1 @@
1
+ export * from './useSlug';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ansidev-oss/vitepress-theme-ansidev",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "The VitePress theme for ansidev's blog",
5
5
  "type": "module",
6
6
  "main": "dist/node/index.js",
@@ -55,12 +55,15 @@
55
55
  "@types/node": "^25.2.3",
56
56
  "@vitejs/plugin-vue": "^6.0.4",
57
57
  "autoprefixer": "^10.4.24",
58
+ "concurrently": "^9.2.1",
58
59
  "glob": "^13.0.5",
59
60
  "gray-matter": "^4.0.3",
61
+ "medium-zoom": "^1.1.0",
60
62
  "postcss": "^8.5.6",
61
63
  "prettier": "^3.8.1",
62
64
  "rimraf": "^6.1.3",
63
65
  "rollup-plugin-copy": "^3.5.0",
66
+ "swetrix": "^4.1.0",
64
67
  "tailwindcss": "^4.1.18",
65
68
  "ts-node": "^10.9.2",
66
69
  "tsdown": "^0.20.3",
@@ -71,6 +74,9 @@
71
74
  "vue-tsc": "^3.2.4"
72
75
  },
73
76
  "peerDependencies": {
77
+ "@iconify/vue": "^5.0.0",
78
+ "medium-zoom": "^1.1.0",
79
+ "swetrix": "^4.1.0",
74
80
  "vitepress": "^2.0.0-alpha.16",
75
81
  "vue": "^3.5.28"
76
82
  },
@@ -78,10 +84,12 @@
78
84
  "typecheck": "tsc --noEmit",
79
85
  "lint:check": "biome check",
80
86
  "lint": "biome check --write",
81
- "dev": "vite build --watch",
87
+ "dev:client": "vite build --watch",
88
+ "dev:node": "tsdown --watch",
89
+ "dev": "concurrently --kill-others \"pnpm dev:client\" \"pnpm dev:node\"",
82
90
  "clean": "rimraf dist",
83
91
  "build:client": "vite build && tsc --emitDeclarationOnly",
84
92
  "build:node": "tsdown",
85
- "build": "pnpm clean && pnpm build:client && pnpm build:node"
93
+ "build": "pnpm clean && concurrently \"pnpm build:client\" \"pnpm build:node\""
86
94
  }
87
95
  }
@@ -0,0 +1,22 @@
1
+ <script setup lang="ts">
2
+ import { useData } from 'vitepress'
3
+ import { defineAsyncComponent } from 'vue'
4
+
5
+ const { theme } = useData()
6
+
7
+ const props = defineProps<{
8
+ direction?: 'horizontal' | 'vertical'
9
+ }>()
10
+
11
+ const directionCssClass = props.direction === 'vertical' ? 'space-y-4' : 'space-x-4'
12
+
13
+ const Donation = theme.value.donation
14
+ ? defineAsyncComponent(() => import('../plugins/donation/components/Donation.vue'))
15
+ : () => null
16
+ </script>
17
+
18
+ <template>
19
+ <div class="flex flex-wrap py-4 items-center justify-center" :class="directionCssClass">
20
+ <Donation :donation="theme.donation" />
21
+ </div>
22
+ </template>
@@ -2,44 +2,44 @@
2
2
  import { useData } from 'vitepress'
3
3
  import { useLayout } from 'vitepress/theme'
4
4
  import { computed, defineAsyncComponent } from 'vue'
5
+ import DonationWidget from './DonationWidget.vue'
5
6
 
6
7
  const { theme, frontmatter } = useData()
7
- const { hasSidebar } = useLayout()
8
+ const { hasSidebar, hasAside } = useLayout()
8
9
 
9
10
  const copyright = computed(() => {
10
- return typeof theme.value.footer.copyright === 'string'
11
- ? theme.value.footer.copyright.replace(/#\{present\}/g, new Date().getFullYear().toString())
12
- : theme.value.footer.copyright
11
+ return typeof theme.value.themeFooter.copyright === 'string'
12
+ ? theme.value.themeFooter.copyright.replace(/#\{present\}/g, new Date().getFullYear().toString())
13
+ : theme.value.themeFooter.copyright
13
14
  })
14
15
 
15
16
  const GoogleAnalytics = theme.value.googleAnalytics
16
17
  ? defineAsyncComponent(() => import('../plugins/google-analytics/components/GoogleAnalytics.vue'))
17
18
  : () => null
18
19
 
19
- const Donation = theme.value.donation
20
- ? defineAsyncComponent(() => import('../plugins/donation/components/Donation.vue'))
20
+ const Swetrix = theme.value.swetrix
21
+ ? defineAsyncComponent(() => import('../plugins/swetrix/components/Swetrix.vue'))
21
22
  : () => null
22
23
  </script>
23
24
 
24
25
  <template>
25
- <div class="flex flex-wrap space-x-4 py-4 items-center justify-center">
26
- <Donation :donation="theme.donation" />
27
- </div>
26
+ <DonationWidget v-if="!hasAside" direction="horizontal" />
28
27
  <footer
29
- v-if="theme.footer && frontmatter.footer !== false"
28
+ v-if="theme.themeFooter && frontmatter.themeFooter !== false"
30
29
  class="VPFooter"
31
30
  :class="{ 'has-sidebar': hasSidebar }"
32
31
  >
33
32
  <div class="container">
34
33
  <p
35
- v-if="theme.footer.message"
34
+ v-if="theme.themeFooter.message"
36
35
  class="message"
37
- v-html="theme.footer.message"
36
+ v-html="theme.themeFooter.message"
38
37
  ></p>
39
38
  <p v-if="copyright" class="copyright" v-html="copyright"></p>
40
39
  </div>
41
40
  </footer>
42
41
  <GoogleAnalytics :google-analytics="theme.googleAnalytics" />
42
+ <Swetrix :swetrix="theme.swetrix" />
43
43
  </template>
44
44
 
45
45
  <style scoped>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import { useData, useRoute } from 'vitepress'
3
+ import { defineAsyncComponent } from 'vue'
4
+
5
+ const route = useRoute()
6
+
7
+ const { theme, frontmatter, page } = useData()
8
+
9
+ const Sharing = theme.value.sharing
10
+ ? defineAsyncComponent(() => import('../plugins/sharing/components/Sharing.vue'))
11
+ : () => null
12
+
13
+ const postURL = new URL(route.path, theme.value.siteURL).href
14
+ const postTitle = frontmatter.value.title || page.value.title
15
+ </script>
16
+
17
+ <template>
18
+ <Sharing :url="postURL" :text="postTitle" />
19
+ </template>
@@ -1,4 +1,4 @@
1
+ export * from '../../shared/composables'
1
2
  export * from './date'
2
3
  export * from './project'
3
4
  export * from './rank'
4
- export * from './slug'
@@ -31,13 +31,7 @@ const theme: Theme = {
31
31
  },
32
32
  } satisfies Theme
33
33
 
34
- export type {
35
- DonationPluginConfig,
36
- GoogleAnalyticsOptions,
37
- Post,
38
- PostDate,
39
- Project,
40
- ThemeConfig,
41
- } from './types'
34
+ export * from './composables'
35
+ export type * from './types'
42
36
 
43
37
  export default theme
@@ -1,11 +1,37 @@
1
1
  <script setup lang='ts'>
2
- import { useData } from 'vitepress'
2
+ import { useData, useRoute } from 'vitepress'
3
3
  import DefaultTheme from 'vitepress/theme'
4
+ import { onMounted, watch } from 'vue'
5
+ import DonationWidget from '../components/DonationWidget.vue'
4
6
  import Footer from '../components/Footer.vue'
5
7
  import LocaleSwitcher from '../components/LocaleSwitcher.vue'
8
+ import SharingWidget from '../components/SharingWidget.vue'
9
+ import type { MediumZoomPluginConfig } from '../plugins/medium-zoom'
6
10
 
7
11
  const { Layout: DefaultLayout } = DefaultTheme
8
- const { frontmatter } = useData()
12
+ const { frontmatter, theme } = useData()
13
+ const route = useRoute()
14
+ let mediumZoomModule = null
15
+ if (theme.value.mediumZoom) {
16
+ mediumZoomModule = import('../plugins/medium-zoom')
17
+ }
18
+
19
+ const initMediumZoom = async () => {
20
+ if (mediumZoomModule) {
21
+ const { useMediumZoom } = await mediumZoomModule
22
+ useMediumZoom(theme.value.mediumZoom as MediumZoomPluginConfig)
23
+ }
24
+ }
25
+
26
+ onMounted(initMediumZoom)
27
+ watch(
28
+ () => route.path,
29
+ (newPath, oldPath) => {
30
+ if (newPath !== oldPath) {
31
+ initMediumZoom()
32
+ }
33
+ },
34
+ )
9
35
  </script>
10
36
 
11
37
  <template>
@@ -18,8 +44,28 @@ const { frontmatter } = useData()
18
44
  <template #nav-bar-content-after>
19
45
  <LocaleSwitcher />
20
46
  </template>
47
+ <template #aside-outline-after>
48
+ <SharingWidget />
49
+ </template>
50
+ <template #aside-ads-before>
51
+ <DonationWidget direction="vertical" />
52
+ </template>
21
53
  <template #layout-bottom>
22
54
  <Footer />
23
55
  </template>
24
56
  </DefaultLayout>
25
57
  </template>
58
+ <style lang="css">
59
+ :root {
60
+ --vp-z-index-aside: 25;
61
+ }
62
+ .VPDoc.has-aside .aside-container {
63
+ z-index: var(--vp-z-index-aside);
64
+ }
65
+ .medium-zoom--opened .medium-zoom-overlay {
66
+ z-index: calc(var(--vp-z-index-aside) + 1);
67
+ }
68
+ .medium-zoom-image--opened {
69
+ z-index: calc(var(--vp-z-index-aside) + 2);
70
+ }
71
+ </style>
@@ -0,0 +1,30 @@
1
+ import mediumZoom from 'medium-zoom'
2
+
3
+ declare module 'medium-zoom' {
4
+ interface Zoom {
5
+ refresh: (selector?: string) => void
6
+ }
7
+ }
8
+
9
+ export type MediumZoomPluginConfig = {
10
+ selector: string
11
+ zoomOptions?: string
12
+ delay?: number
13
+ }
14
+
15
+ /**
16
+ * Inject medium zoom instance
17
+ */
18
+ export const useMediumZoom = (config: MediumZoomPluginConfig): void => {
19
+ if (!config.selector) {
20
+ return
21
+ }
22
+
23
+ const zoom = mediumZoom(config.zoomOptions)
24
+ zoom.refresh = (sel = config.selector) => {
25
+ zoom.detach()
26
+ zoom.attach(sel)
27
+ }
28
+
29
+ setTimeout(() => zoom.refresh(config.selector), config.delay || 1000)
30
+ }