@ansidev-oss/vitepress-theme-ansidev 1.0.6

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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/dist/client/Donation-D9Xn0MPt.js +76 -0
  3. package/dist/client/GoogleAnalytics-Dp3EGn1x.js +29 -0
  4. package/dist/client/VPAlgoliaSearchBox-DXE-LCVf.js +126 -0
  5. package/dist/client/VPCarbonAds-Czmm53YE.js +31 -0
  6. package/dist/client/VPLocalSearchBox-ihwA4uH-.js +4086 -0
  7. package/dist/client/composables/date.d.ts +2 -0
  8. package/dist/client/composables/index.d.ts +4 -0
  9. package/dist/client/composables/locale.d.ts +3 -0
  10. package/dist/client/composables/project.d.ts +13 -0
  11. package/dist/client/composables/rank.d.ts +1 -0
  12. package/dist/client/composables/slug.d.ts +2 -0
  13. package/dist/client/index-BtT3qA6T.js +12663 -0
  14. package/dist/client/index-CCR5sUM8.js +10688 -0
  15. package/dist/client/index-CZCdwVUW.js +7566 -0
  16. package/dist/client/index.d.ts +6 -0
  17. package/dist/client/index.js +5 -0
  18. package/dist/client/plugins/donation/index.d.ts +19 -0
  19. package/dist/client/plugins/google-analytics/index.d.ts +8 -0
  20. package/dist/client/plugins/i18n/index.d.ts +53 -0
  21. package/dist/client/styles.css +1 -0
  22. package/dist/client/types/index.d.ts +45 -0
  23. package/dist/node/composables.d.mts +30 -0
  24. package/dist/node/composables.mjs +51 -0
  25. package/dist/node/config.d.mts +46 -0
  26. package/dist/node/config.mjs +47 -0
  27. package/package.json +87 -0
  28. package/src/client/components/EmptyFooter.vue +3 -0
  29. package/src/client/components/Footer.vue +87 -0
  30. package/src/client/components/Link.vue +31 -0
  31. package/src/client/components/LocaleSwitcher.vue +59 -0
  32. package/src/client/components/PostDate.vue +42 -0
  33. package/src/client/components/PostItem.vue +33 -0
  34. package/src/client/components/PostList.vue +23 -0
  35. package/src/client/components/ProjectCard.vue +68 -0
  36. package/src/client/components/ProjectList.vue +23 -0
  37. package/src/client/components/RouterLink.vue +19 -0
  38. package/src/client/components/StatusBadge.vue +56 -0
  39. package/src/client/components/TermBadge.vue +29 -0
  40. package/src/client/components/TermLink.vue +25 -0
  41. package/src/client/composables/date.ts +12 -0
  42. package/src/client/composables/index.ts +4 -0
  43. package/src/client/composables/locale.ts +7 -0
  44. package/src/client/composables/project.ts +30 -0
  45. package/src/client/composables/rank.ts +13 -0
  46. package/src/client/composables/slug.ts +12 -0
  47. package/src/client/index.ts +43 -0
  48. package/src/client/layouts/Layout.vue +25 -0
  49. package/src/client/pages/ArchivesPage.vue +43 -0
  50. package/src/client/pages/CategoriesPage.vue +30 -0
  51. package/src/client/pages/HomePage.vue +18 -0
  52. package/src/client/pages/Page.vue +20 -0
  53. package/src/client/pages/PostsPage.vue +23 -0
  54. package/src/client/pages/ProjectsPage.vue +65 -0
  55. package/src/client/pages/TagsPage.vue +30 -0
  56. package/src/client/plugins/donation/components/Donation.vue +43 -0
  57. package/src/client/plugins/donation/components/DonationButton.vue +22 -0
  58. package/src/client/plugins/donation/index.ts +42 -0
  59. package/src/client/plugins/google-analytics/components/GoogleAnalytics.vue +52 -0
  60. package/src/client/plugins/google-analytics/index.ts +8 -0
  61. package/src/client/plugins/i18n/index.ts +13 -0
  62. package/src/client/plugins/i18n/locales/en.json +25 -0
  63. package/src/client/plugins/i18n/locales/vi.json +25 -0
  64. package/src/client/styles/index.css +30 -0
  65. package/src/client/types/index.ts +50 -0
  66. package/src/node/composables/index.ts +3 -0
  67. package/src/node/composables/markdown.ts +14 -0
  68. package/src/node/composables/route.ts +26 -0
  69. package/src/node/composables/slug.ts +40 -0
  70. package/src/node/composables/types.ts +7 -0
  71. package/src/node/config.ts +79 -0
  72. package/src/vite-env.d.ts +7 -0
@@ -0,0 +1,52 @@
1
+ <script setup lang="ts">
2
+ import { onMounted } from 'vue'
3
+ import { GoogleAnalyticsOptions } from '..'
4
+
5
+ // biome-ignore lint/suspicious/noExplicitAny: ignore check for this line
6
+ declare const dataLayer: any[]
7
+ // biome-ignore lint/suspicious/noExplicitAny: ignore check for this line
8
+ declare const gtag: (...args: any[]) => void
9
+ declare global {
10
+ interface Window {
11
+ dataLayer?: typeof dataLayer
12
+ gtag?: typeof gtag
13
+ }
14
+ }
15
+
16
+ const props = defineProps<{
17
+ googleAnalytics: GoogleAnalyticsOptions
18
+ }>()
19
+
20
+ const googleAnalyticsOptions = props.googleAnalytics
21
+
22
+ let isInitialized = false
23
+
24
+ function init() {
25
+ if (window.dataLayer && window.gtag) {
26
+ return
27
+ }
28
+
29
+ if (!isInitialized) {
30
+ isInitialized = true
31
+ const externalScript = document.createElement('script')
32
+ externalScript.src = `https://www.googletagmanager.com/gtag/js?id=${googleAnalyticsOptions.id}`
33
+ externalScript.async = true
34
+ document.head.appendChild(externalScript)
35
+
36
+ const inlineScript = document.createElement('script')
37
+ inlineScript.textContent = `
38
+ window.dataLayer = window.dataLayer || [];
39
+ function gtag(){dataLayer.push(arguments);}
40
+ gtag('js', new Date());
41
+ gtag('config', '${googleAnalyticsOptions.id}');
42
+ `
43
+ document.head.appendChild(inlineScript)
44
+ }
45
+ }
46
+
47
+ if (googleAnalyticsOptions) {
48
+ onMounted(init)
49
+ }
50
+ </script>
51
+
52
+ <template />
@@ -0,0 +1,8 @@
1
+ export interface GoogleAnalyticsOptions {
2
+ /**
3
+ * The Google Analytics ID.
4
+ *
5
+ * @default process.env.VITE_GA_ID
6
+ */
7
+ id: string
8
+ }
@@ -0,0 +1,13 @@
1
+ import { createI18n } from 'vue-i18n'
2
+
3
+ import en from './locales/en.json' with { type: 'json' }
4
+ import vi from './locales/vi.json' with { type: 'json' }
5
+
6
+ export default createI18n({
7
+ legacy: false,
8
+ locale: 'en',
9
+ messages: {
10
+ en,
11
+ vi,
12
+ },
13
+ })
@@ -0,0 +1,25 @@
1
+ {
2
+ "button": {
3
+ "toggle_locale": "Change language",
4
+ "read_more": "Read more"
5
+ },
6
+ "all_posts": "All posts",
7
+ "posted_on": "Posted on",
8
+ "my_projects": "My projects",
9
+ "categories": "Categories",
10
+ "tags": "Tags",
11
+ "archives": "Archives",
12
+ "no_post": "No post.",
13
+ "no_category": "No category.",
14
+ "no_tag": "No tag.",
15
+ "no_archive": "No archive.",
16
+ "license": "License",
17
+ "source_code": "Source Code",
18
+ "technologies": "Technologies",
19
+ "development_status": {
20
+ "title": "Development status",
21
+ "active": "Active",
22
+ "inactive": "Inactive",
23
+ "unmaintained": "Unmaintained"
24
+ }
25
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "button": {
3
+ "toggle_locale": "Đổi ngôn ngữ",
4
+ "read_more": "Đọc thêm"
5
+ },
6
+ "all_posts": "Tất cả bài viết",
7
+ "posted_on": "Đăng vào",
8
+ "my_projects": "Các dự án của tôi",
9
+ "categories": "Chủ đề",
10
+ "tags": "Thẻ",
11
+ "archives": "Lưu trữ",
12
+ "no_post": "Không có bài viết nào.",
13
+ "no_category": "Không có chủ đề nào.",
14
+ "no_archive": "Không có bản lưu trữ nào.",
15
+ "no_tag": "Không có thẻ nào.",
16
+ "license": "Giấy phép",
17
+ "source_code": "Mã nguồn",
18
+ "technologies": "Công nghệ",
19
+ "development_status": {
20
+ "title": "Trạng thái dự án",
21
+ "active": "Đang phát triển",
22
+ "inactive": "Không hoạt động",
23
+ "unmaintained": "Ngừng phát triển"
24
+ }
25
+ }
@@ -0,0 +1,30 @@
1
+ @import "tailwindcss";
2
+ @variant dark (&:where(.dark, .dark *));
3
+
4
+ @theme {
5
+ --color-primary: rgb(59, 130, 246);
6
+ --color-primary-alt: rgb(29, 78, 216);
7
+ --color-primary-alt-dark: rgb(147, 197, 253);
8
+ --color-secondary: rgb(239, 68, 68);
9
+ --color-secondary-dark: rgb(234, 179, 8);
10
+ }
11
+
12
+ @utility component-border {
13
+ @apply border rounded-md border-gray-500 hover:border-secondary dark:hover:border-secondary-dark;
14
+ }
15
+
16
+ @utility link {
17
+ @apply no-underline hover:text-secondary dark:hover:text-secondary-dark;
18
+ }
19
+
20
+ @utility link-alt {
21
+ @apply text-primary-alt! dark:text-primary-alt-dark! link!;
22
+ }
23
+
24
+ :root {
25
+ --vp-c-brand-1: var(--color-primary);
26
+ }
27
+
28
+ .vp-doc a {
29
+ @apply link;
30
+ }
@@ -0,0 +1,50 @@
1
+ import type { DefaultTheme } from 'vitepress/theme'
2
+ import type { DonationPluginConfig } from '../plugins/donation'
3
+ import type { GoogleAnalyticsOptions } from '../plugins/google-analytics'
4
+
5
+ export interface ThemeConfig extends DefaultTheme.Config {
6
+ /**
7
+ * The site URL.
8
+ *
9
+ * @default process.env.VITE_BASE_URL
10
+ */
11
+ siteURL?: string
12
+ googleAnalytics?: GoogleAnalyticsOptions
13
+ donation?: DonationPluginConfig
14
+ }
15
+
16
+ export type { DonationPluginConfig } from '../plugins/donation'
17
+ export type { GoogleAnalyticsOptions } from '../plugins/google-analytics'
18
+
19
+ export interface Post {
20
+ type: string
21
+ title: string
22
+ author: string
23
+ gravatar: string
24
+ twitter: string
25
+ url?: string
26
+ date: Date
27
+ excerpt: string | undefined
28
+ categories: string[]
29
+ tags: string[]
30
+ }
31
+
32
+ export interface PostDate {
33
+ time: number
34
+ day: string
35
+ month: string
36
+ year: string
37
+ }
38
+
39
+ export interface Project {
40
+ title: string
41
+ url: string
42
+ showcaseUrl: string
43
+ repositoryUrl: string
44
+ excerpt: string | undefined
45
+ license: string
46
+ licenseUrl: string
47
+ developmentStatus: string
48
+ techs: string[]
49
+ date: Date
50
+ }
@@ -0,0 +1,3 @@
1
+ export * from './markdown'
2
+ export * from './route'
3
+ export * from './slug'
@@ -0,0 +1,14 @@
1
+ import fs from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+ import { globSync } from 'glob'
4
+ import matter from 'gray-matter'
5
+ import type { Frontmatter, Pattern } from './types'
6
+
7
+ export const useMarkdownFrontmatter = (pattern: Pattern, excerptSeparator: string = '---'): Array<Frontmatter> => {
8
+ const files = globSync(pattern, { ignore: ['node_modules/**', '.git/**'] })
9
+ return files.map((file) => {
10
+ const src = fs.readFileSync(resolve(file), 'utf-8')
11
+ const { data, excerpt } = matter(src, { excerpt: true, excerpt_separator: excerptSeparator })
12
+ return { ...data, excerpt }
13
+ })
14
+ }
@@ -0,0 +1,26 @@
1
+ import { useSlugFromMarkdownFrontMatter } from './slug'
2
+ import type { Frontmatter, Pattern } from './types'
3
+
4
+ export const useMarkdownFrontmatterRoute = (
5
+ pattern: Pattern,
6
+ frontmatterKey: string,
7
+ excerptSeparator: string = '---',
8
+ ) => {
9
+ return {
10
+ paths() {
11
+ return useSlugFromMarkdownFrontMatter(pattern, frontmatterKey, excerptSeparator)
12
+ },
13
+ }
14
+ }
15
+
16
+ export const useArchiveRoute = (pattern: Pattern, excerptSeparator: string = '---') => {
17
+ return {
18
+ paths() {
19
+ return useSlugFromMarkdownFrontMatter(
20
+ pattern,
21
+ (frontmatter: Frontmatter) => new Date(frontmatter.date as string).getFullYear().toString(),
22
+ excerptSeparator,
23
+ )
24
+ },
25
+ }
26
+ }
@@ -0,0 +1,40 @@
1
+ import { useMarkdownFrontmatter } from './markdown'
2
+ import type { Frontmatter, FrontmatterToString, Pattern, StringOrFrontmatterToString } from './types'
3
+
4
+ export const useSlug = (str: string) => {
5
+ const s = str.replace(/#/, '-sharp-').replace(/\./, '-dot-').replace(/-$/, '')
6
+ return s
7
+ .toLowerCase()
8
+ .normalize('NFD') // Decompose Unicode characters
9
+ .replace(/[\u0300-\u036f]/g, '') // Remove diacritical marks
10
+ .replace(/đ/g, 'd') // Handle Vietnamese "đ"
11
+ .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric characters with dashes
12
+ .replace(/^-+|-+$/g, '') // Remove leading or trailing dashes
13
+ }
14
+
15
+ export const useSlugFilter = (slug: string) => (str: string) => useSlug(str) === slug
16
+
17
+ export const useSlugFromMarkdownFrontMatter = (
18
+ pattern: Pattern,
19
+ frontmatterKeyOrMappingFn: StringOrFrontmatterToString,
20
+ excerptSeparator: string = '---',
21
+ ) => {
22
+ const frontMatters = useMarkdownFrontmatter(pattern, excerptSeparator)
23
+ const _frontmatterMappingFn: FrontmatterToString =
24
+ typeof frontmatterKeyOrMappingFn === 'string'
25
+ ? (frontMatter: Frontmatter) => frontMatter[frontmatterKeyOrMappingFn] as string
26
+ : frontmatterKeyOrMappingFn
27
+
28
+ const arr: string[] = frontMatters.flatMap(_frontmatterMappingFn)
29
+
30
+ const set = [...new Set(arr)]
31
+ const slugs = set.map((str: string) => {
32
+ const slug = useSlug(str)
33
+ if ('index' === slug) {
34
+ console.warn("[WARN] Generated routes contain the reserved route 'index'.")
35
+ }
36
+ return { params: { slug } }
37
+ })
38
+ // console.log(slugs)
39
+ return slugs
40
+ }
@@ -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
@@ -0,0 +1,79 @@
1
+ // @ts-nocheck
2
+ import { fileURLToPath, URL } from 'node:url'
3
+ import { loadEnv } from 'vitepress'
4
+
5
+ process.env.VITE_EXTRA_EXTENSIONS = 'rss'
6
+ globalThis.__VUE_PROD_DEVTOOLS__ = process.env.NODE_ENV === 'development'
7
+
8
+ const env = loadEnv(process.env.NODE_ENV || 'development', process.cwd(), 'VITE_')
9
+
10
+ const siteURL = env.VITE_BASE_URL
11
+
12
+ /**
13
+ * This file is intended to be required from VitePress
14
+ * consuming project's config file.
15
+ *
16
+ * It runs in Node.js.
17
+ */
18
+
19
+ // for local-linked development
20
+ const deps = ['vitepress-theme-ansidev']
21
+
22
+ /**
23
+ * @type {import('vitepress').UserConfig}
24
+ */
25
+ const config = {
26
+ themeConfig: {
27
+ siteURL,
28
+ googleAnalytics: {
29
+ id: env.VITE_GA_ID,
30
+ },
31
+ search: {
32
+ provider: 'local',
33
+ options: {
34
+ /**
35
+ * @param {string} src
36
+ * @param {import('vitepress').MarkdownEnv} env
37
+ * @param {import('markdown-it')} md
38
+ */
39
+ async _render(src, env, md) {
40
+ const html = await md.renderAsync(src, env)
41
+ if (env.frontmatter?.search === false) return ''
42
+ let renderedHtml = ''
43
+ if (env.frontmatter?.title) {
44
+ renderedHtml += `<h1>${env.frontmatter.title} <a href="#">&#8203;</a></h1>`
45
+ }
46
+ if (html.length > 0) {
47
+ renderedHtml += html
48
+ }
49
+ return renderedHtml
50
+ },
51
+ },
52
+ },
53
+ },
54
+ vite: {
55
+ ssr: {
56
+ noExternal: deps,
57
+ },
58
+ optimizeDeps: {
59
+ exclude: deps,
60
+ },
61
+ css: {
62
+ preprocessorOptions: {
63
+ scss: {
64
+ api: 'modern-compiler',
65
+ },
66
+ },
67
+ },
68
+ resolve: {
69
+ alias: [
70
+ {
71
+ find: /^.*\/VPFooter\.vue$/,
72
+ replacement: fileURLToPath(new URL('./components/EmptyFooter.vue', import.meta.url)),
73
+ },
74
+ ],
75
+ },
76
+ },
77
+ }
78
+
79
+ export default config
@@ -0,0 +1,7 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module '*.vue' {
4
+ import type { Component } from 'vue'
5
+ const component: Component
6
+ export default component
7
+ }