@ansidev-oss/vitepress-theme-ansidev 1.1.0 → 1.2.0
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/client/{Swetrix-k7SUudua.js → Swetrix-GKEyGNrV.js} +29 -6
- package/dist/client/index.js +54 -54
- package/dist/client/styles.css +1 -1
- package/dist/client/types/index.d.ts +8 -0
- package/dist/node/composables.d.mts +9 -0
- package/dist/node/composables.mjs +33 -1
- package/package.json +20 -22
- package/src/client/components/DonationWidget.vue +9 -3
- package/src/client/components/Footer.vue +11 -4
- package/src/client/components/Link.vue +11 -5
- package/src/client/components/LocaleSwitcher.vue +5 -5
- package/src/client/components/PostDate.test.ts +16 -7
- package/src/client/components/PostDate.vue +16 -7
- package/src/client/components/PostItem.vue +17 -7
- package/src/client/components/PostList.vue +7 -4
- package/src/client/components/ProjectCard.vue +42 -14
- package/src/client/components/ProjectList.vue +12 -5
- package/src/client/components/RouterLink.vue +3 -3
- package/src/client/components/SharingWidget.vue +3 -1
- package/src/client/components/StatusBadge.vue +10 -10
- package/src/client/components/TermBadge.vue +11 -7
- package/src/client/components/TermLink.vue +4 -4
- package/src/client/composables/date.ts +1 -1
- package/src/client/composables/lang.test.ts +6 -2
- package/src/client/composables/lang.ts +12 -5
- package/src/client/composables/locale.ts +4 -1
- package/src/client/composables/project.ts +3 -3
- package/src/client/composables/rank.ts +5 -2
- package/src/client/index.ts +1 -1
- package/src/client/layouts/Layout.vue +2 -2
- package/src/client/pages/ArchivesPage.vue +10 -5
- package/src/client/pages/CategoriesPage.vue +13 -5
- package/src/client/pages/HomePage.vue +3 -3
- package/src/client/pages/Page.vue +13 -11
- package/src/client/pages/PostsPage.vue +4 -4
- package/src/client/pages/ProjectsPage.vue +10 -7
- package/src/client/pages/TagsPage.vue +10 -4
- package/src/client/plugins/donation/components/Donation.vue +5 -3
- package/src/client/plugins/donation/components/DonationButton.vue +3 -1
- package/src/client/plugins/donation/index.ts +11 -8
- package/src/client/plugins/i18n/index.ts +2 -2
- package/src/client/plugins/sharing/components/Sharing.vue +39 -15
- package/src/client/plugins/sharing/components/SharingButton.vue +34 -14
- package/src/client/plugins/sharing/index.ts +3 -1
- package/src/client/styles/base.css +1 -1
- package/src/client/styles/blog.css +38 -14
- package/src/client/styles/index.css +2 -3
- package/src/client/types/index.ts +8 -0
- package/src/node/composables/excerpt.test.ts +88 -0
- package/src/node/composables/excerpt.ts +57 -0
- package/src/node/composables/index.ts +1 -0
- package/src/node/composables/markdown.ts +8 -2
- package/src/node/composables/route.ts +15 -7
- package/src/node/composables/slug.ts +12 -4
- package/src/node/config.ts +20 -14
- package/src/shared/composables/useSlug.ts +2 -1
- package/dist/node/composables/index.d.ts +0 -3
- package/dist/node/composables/markdown.d.ts +0 -2
- package/dist/node/composables/route.d.ts +0 -15
- package/dist/node/composables/slug.d.ts +0 -7
- package/dist/node/composables/types.d.ts +0 -7
- package/dist/node/config.d.ts +0 -45
|
@@ -4,25 +4,29 @@ import Link from './Link.vue'
|
|
|
4
4
|
defineProps({
|
|
5
5
|
title: {
|
|
6
6
|
type: String,
|
|
7
|
-
required: true
|
|
7
|
+
required: true
|
|
8
8
|
},
|
|
9
9
|
count: {
|
|
10
10
|
type: Number,
|
|
11
|
-
required: true
|
|
11
|
+
required: true
|
|
12
12
|
},
|
|
13
13
|
href: {
|
|
14
14
|
type: String,
|
|
15
|
-
required: true
|
|
16
|
-
}
|
|
15
|
+
required: true
|
|
16
|
+
}
|
|
17
17
|
})
|
|
18
18
|
</script>
|
|
19
19
|
|
|
20
20
|
<template>
|
|
21
|
-
<Link
|
|
22
|
-
|
|
21
|
+
<Link
|
|
22
|
+
:key="title"
|
|
23
|
+
:href="href"
|
|
24
|
+
class="inline-flex items-center mt-2 mb-2 mr-2 px-5 py-2.5 text-sm font-medium text-center text-white component-border"
|
|
25
|
+
>
|
|
23
26
|
{{ title }}
|
|
24
27
|
<span
|
|
25
|
-
class="inline-flex items-center justify-center w-4 h-4 ms-2 text-xs font-semibold text-gray-900 dark:text-white bg-gray-300 dark:bg-gray-700 p-2.5 rounded"
|
|
28
|
+
class="inline-flex items-center justify-center w-4 h-4 ms-2 text-xs font-semibold text-gray-900 dark:text-white bg-gray-300 dark:bg-gray-700 p-2.5 rounded"
|
|
29
|
+
>
|
|
26
30
|
{{ count }}
|
|
27
31
|
</span>
|
|
28
32
|
</Link>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup lang=
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useSlug } from '../composables'
|
|
4
4
|
import RouterLink from './RouterLink.vue'
|
|
@@ -6,12 +6,12 @@ import RouterLink from './RouterLink.vue'
|
|
|
6
6
|
const props = defineProps({
|
|
7
7
|
text: {
|
|
8
8
|
type: String,
|
|
9
|
-
required: true
|
|
9
|
+
required: true
|
|
10
10
|
},
|
|
11
11
|
basePath: {
|
|
12
12
|
type: String,
|
|
13
|
-
required: true
|
|
14
|
-
}
|
|
13
|
+
required: true
|
|
14
|
+
}
|
|
15
15
|
})
|
|
16
16
|
|
|
17
17
|
const slug = computed(() => useSlug(props.text))
|
|
@@ -7,6 +7,6 @@ export const usePostDate: (raw: Date) => PostDate = (raw: Date) => {
|
|
|
7
7
|
time: +date,
|
|
8
8
|
day: date.toLocaleDateString('en-US', { day: 'numeric' }),
|
|
9
9
|
month: date.toLocaleDateString('en-US', { month: 'short' }),
|
|
10
|
-
year: date.toLocaleDateString('en-US', { year: 'numeric' })
|
|
10
|
+
year: date.toLocaleDateString('en-US', { year: 'numeric' })
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from '
|
|
1
|
+
import { describe, expect, it, vi } from 'vite-plus/test'
|
|
2
2
|
import { nextTick, ref } from 'vue'
|
|
3
3
|
import { createI18n } from 'vue-i18n'
|
|
4
4
|
import { matchLocale, usePageLocale } from './lang'
|
|
@@ -25,7 +25,11 @@ describe('matchLocale', () => {
|
|
|
25
25
|
|
|
26
26
|
describe('usePageLocale', () => {
|
|
27
27
|
const setup = () => {
|
|
28
|
-
const i18n = createI18n({
|
|
28
|
+
const i18n = createI18n({
|
|
29
|
+
legacy: false,
|
|
30
|
+
locale: 'en',
|
|
31
|
+
messages: { en: {}, vi: {} }
|
|
32
|
+
})
|
|
29
33
|
usePageLocale(i18n)
|
|
30
34
|
return i18n
|
|
31
35
|
}
|
|
@@ -9,7 +9,9 @@ export const usePageLang = (): ComputedRef<string> => {
|
|
|
9
9
|
const { frontmatter, lang } = useData()
|
|
10
10
|
return computed(() => {
|
|
11
11
|
const pageLang = frontmatter.value.lang
|
|
12
|
-
return typeof pageLang === 'string' && pageLang.trim()
|
|
12
|
+
return typeof pageLang === 'string' && pageLang.trim()
|
|
13
|
+
? pageLang.trim()
|
|
14
|
+
: lang.value
|
|
13
15
|
})
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -25,7 +27,7 @@ export const useHtmlLang = (): void => {
|
|
|
25
27
|
() => {
|
|
26
28
|
document.documentElement.lang = pageLang.value
|
|
27
29
|
},
|
|
28
|
-
{ flush: 'post' }
|
|
30
|
+
{ flush: 'post' }
|
|
29
31
|
)
|
|
30
32
|
})
|
|
31
33
|
}
|
|
@@ -33,7 +35,10 @@ export const useHtmlLang = (): void => {
|
|
|
33
35
|
/**
|
|
34
36
|
* Picks the available locale matching `lang` exactly or by base language (`vi-VN` -> `vi`).
|
|
35
37
|
*/
|
|
36
|
-
export const matchLocale = (
|
|
38
|
+
export const matchLocale = (
|
|
39
|
+
lang: string,
|
|
40
|
+
availableLocales: readonly Locale[]
|
|
41
|
+
): Locale | undefined => {
|
|
37
42
|
const normalized = lang.toLowerCase()
|
|
38
43
|
return (
|
|
39
44
|
availableLocales.find((l) => l.toLowerCase() === normalized) ??
|
|
@@ -45,7 +50,9 @@ export const matchLocale = (lang: string, availableLocales: readonly Locale[]):
|
|
|
45
50
|
* Syncs the vue-i18n locale with the resolved page lang, synchronously so SSR renders the right strings.
|
|
46
51
|
* A manual `LocaleSwitcher` choice lasts until the page lang changes.
|
|
47
52
|
*/
|
|
48
|
-
export const usePageLocale = (i18n: {
|
|
53
|
+
export const usePageLocale = (i18n: {
|
|
54
|
+
global: { locale: { value: Locale }; availableLocales: Locale[] }
|
|
55
|
+
}): void => {
|
|
49
56
|
const pageLang = usePageLang()
|
|
50
57
|
watch(
|
|
51
58
|
pageLang,
|
|
@@ -53,6 +60,6 @@ export const usePageLocale = (i18n: { global: { locale: { value: Locale }; avail
|
|
|
53
60
|
const matched = matchLocale(lang, i18n.global.availableLocales)
|
|
54
61
|
if (matched) i18n.global.locale.value = matched
|
|
55
62
|
},
|
|
56
|
-
{ immediate: true }
|
|
63
|
+
{ immediate: true }
|
|
57
64
|
)
|
|
58
65
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { WritableComputedRef } from 'vue'
|
|
2
2
|
import type { Locale } from 'vue-i18n'
|
|
3
3
|
|
|
4
|
-
export const switchLocale = (
|
|
4
|
+
export const switchLocale = (
|
|
5
|
+
availableLocales: string[],
|
|
6
|
+
locale: WritableComputedRef<Locale>
|
|
7
|
+
) => {
|
|
5
8
|
const locales = availableLocales
|
|
6
9
|
locale.value = locales[(locales.indexOf(locale.value) + 1) % locales.length]
|
|
7
10
|
}
|
|
@@ -6,7 +6,7 @@ export const useProjectStatusStyle = (developmentStatus: string) => {
|
|
|
6
6
|
backgroundColor: 'bg-green-100',
|
|
7
7
|
darkBackgroundColor: 'dark:bg-green-800',
|
|
8
8
|
textColor: 'text-green-800',
|
|
9
|
-
darkTextColor: 'dark:text-green-100'
|
|
9
|
+
darkTextColor: 'dark:text-green-100'
|
|
10
10
|
}
|
|
11
11
|
case 'inactive':
|
|
12
12
|
return {
|
|
@@ -14,7 +14,7 @@ export const useProjectStatusStyle = (developmentStatus: string) => {
|
|
|
14
14
|
backgroundColor: 'bg-yellow-100',
|
|
15
15
|
darkBackgroundColor: 'dark:bg-yellow-800',
|
|
16
16
|
textColor: 'text-yellow-800',
|
|
17
|
-
darkTextColor: 'dark:text-yellow-100'
|
|
17
|
+
darkTextColor: 'dark:text-yellow-100'
|
|
18
18
|
}
|
|
19
19
|
case 'unmaintained':
|
|
20
20
|
return {
|
|
@@ -22,7 +22,7 @@ export const useProjectStatusStyle = (developmentStatus: string) => {
|
|
|
22
22
|
backgroundColor: 'bg-red-100',
|
|
23
23
|
darkBackgroundColor: 'dark:bg-red-800',
|
|
24
24
|
textColor: 'text-red-800',
|
|
25
|
-
darkTextColor: 'dark:text-red-100'
|
|
25
|
+
darkTextColor: 'dark:text-red-100'
|
|
26
26
|
}
|
|
27
27
|
default:
|
|
28
28
|
return {}
|
|
@@ -4,10 +4,13 @@ export const useRank = <T extends string>(arr: T[]): Record<T, number> => {
|
|
|
4
4
|
acc[item] = (acc[item] || 0) + 1 // Increment the count if the key exists, otherwise initialize to 1
|
|
5
5
|
return acc
|
|
6
6
|
},
|
|
7
|
-
{} as Record<T, number
|
|
7
|
+
{} as Record<T, number>
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
const entries = Object.entries(rank) as [T, number][]
|
|
11
11
|
|
|
12
|
-
return Object.fromEntries(entries.sort(([, a], [, b]) => b - a)) as Record<
|
|
12
|
+
return Object.fromEntries(entries.sort(([, a], [, b]) => b - a)) as Record<
|
|
13
|
+
T,
|
|
14
|
+
number
|
|
15
|
+
>
|
|
13
16
|
}
|
package/src/client/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup lang=
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { useData, useRoute } from 'vitepress'
|
|
3
3
|
import DefaultTheme from 'vitepress/theme'
|
|
4
4
|
import { onMounted, watch } from 'vue'
|
|
@@ -30,7 +30,7 @@ watch(
|
|
|
30
30
|
if (newPath !== oldPath) {
|
|
31
31
|
initMediumZoom()
|
|
32
32
|
}
|
|
33
|
-
}
|
|
33
|
+
}
|
|
34
34
|
)
|
|
35
35
|
</script>
|
|
36
36
|
|
|
@@ -9,26 +9,31 @@ const props = defineProps({
|
|
|
9
9
|
posts: {
|
|
10
10
|
type: Object as PropType<Post[]>,
|
|
11
11
|
required: true,
|
|
12
|
-
default: []
|
|
13
|
-
}
|
|
12
|
+
default: []
|
|
13
|
+
}
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
const { t } = useI18n()
|
|
17
17
|
|
|
18
18
|
const totalPostsByYears = computed(() =>
|
|
19
|
-
useRank(
|
|
19
|
+
useRank(
|
|
20
|
+
props.posts.flatMap((post) => new Date(post.date).getFullYear().toString())
|
|
21
|
+
)
|
|
20
22
|
)
|
|
21
23
|
const sortedYearDesc = computed(() =>
|
|
22
24
|
Object.keys(totalPostsByYears.value)
|
|
23
25
|
.map((str) => Number(str))
|
|
24
|
-
.reverse()
|
|
26
|
+
.reverse()
|
|
25
27
|
)
|
|
26
28
|
</script>
|
|
27
29
|
|
|
28
30
|
<template>
|
|
29
31
|
<Page :title="t('archives')">
|
|
30
32
|
<div class="flex flex-wrap pt-4">
|
|
31
|
-
<div
|
|
33
|
+
<div
|
|
34
|
+
v-if="Object.keys(sortedYearDesc).length === 0"
|
|
35
|
+
class="mt-2 mb-2 mr-5"
|
|
36
|
+
>
|
|
32
37
|
{{ t('no_archive') }}
|
|
33
38
|
</div>
|
|
34
39
|
<TermBadge
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup lang=
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { computed, type PropType } from 'vue'
|
|
3
3
|
import { useI18n } from 'vue-i18n'
|
|
4
4
|
import TermBadge from '../components/TermBadge.vue'
|
|
@@ -9,13 +9,15 @@ const props = defineProps({
|
|
|
9
9
|
posts: {
|
|
10
10
|
type: Object as PropType<Post[]>,
|
|
11
11
|
required: true,
|
|
12
|
-
default: []
|
|
13
|
-
}
|
|
12
|
+
default: []
|
|
13
|
+
}
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
const { t } = useI18n()
|
|
17
17
|
|
|
18
|
-
const categories = computed(() =>
|
|
18
|
+
const categories = computed(() =>
|
|
19
|
+
useRank(props.posts.flatMap((post) => post.categories))
|
|
20
|
+
)
|
|
19
21
|
</script>
|
|
20
22
|
|
|
21
23
|
<template>
|
|
@@ -24,7 +26,13 @@ const categories = computed(() => useRank(props.posts.flatMap((post) => post.cat
|
|
|
24
26
|
<div v-if="Object.keys(categories).length === 0" class="mt-2 mb-2 mr-5">
|
|
25
27
|
{{ t('no_category') }}
|
|
26
28
|
</div>
|
|
27
|
-
<TermBadge
|
|
29
|
+
<TermBadge
|
|
30
|
+
v-for="(count, category) in categories"
|
|
31
|
+
:key="category"
|
|
32
|
+
:title="category"
|
|
33
|
+
:count="count"
|
|
34
|
+
:href="`/categories/${useSlug(category)}`"
|
|
35
|
+
/>
|
|
28
36
|
</div>
|
|
29
37
|
</Page>
|
|
30
38
|
</template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup lang=
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import type { PropType } from 'vue'
|
|
3
3
|
import { useI18n } from 'vue-i18n'
|
|
4
4
|
import type { Post } from '../types'
|
|
@@ -7,8 +7,8 @@ defineProps({
|
|
|
7
7
|
posts: {
|
|
8
8
|
type: Object as PropType<Post[]>,
|
|
9
9
|
required: true,
|
|
10
|
-
default: []
|
|
11
|
-
}
|
|
10
|
+
default: []
|
|
11
|
+
}
|
|
12
12
|
})
|
|
13
13
|
const { t } = useI18n()
|
|
14
14
|
</script>
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
<script setup lang=
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
defineProps({
|
|
3
3
|
title: {
|
|
4
4
|
type: String,
|
|
5
5
|
required: true,
|
|
6
|
-
default: ''
|
|
7
|
-
}
|
|
6
|
+
default: ''
|
|
7
|
+
}
|
|
8
8
|
})
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
|
-
<
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
<main class="main">
|
|
13
|
+
<div class="pt-6 pb-8 space-y-2 md:space-y-5">
|
|
14
|
+
<h1
|
|
15
|
+
class="mb-6 text-3xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl sm:leading-10 md:text-6xl md:leading-14"
|
|
16
|
+
>
|
|
17
|
+
{{ title }}
|
|
18
|
+
</h1>
|
|
19
|
+
</div>
|
|
20
|
+
<slot />
|
|
21
|
+
</main>
|
|
20
22
|
</template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup lang=
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import type { PropType } from 'vue'
|
|
3
3
|
import PostList from '../components/PostList.vue'
|
|
4
4
|
import type { Post } from '../types'
|
|
@@ -6,13 +6,13 @@ import type { Post } from '../types'
|
|
|
6
6
|
defineProps({
|
|
7
7
|
title: {
|
|
8
8
|
type: String,
|
|
9
|
-
required: true
|
|
9
|
+
required: true
|
|
10
10
|
},
|
|
11
11
|
posts: {
|
|
12
12
|
type: Object as PropType<Post[]>,
|
|
13
13
|
required: true,
|
|
14
|
-
default: []
|
|
15
|
-
}
|
|
14
|
+
default: []
|
|
15
|
+
}
|
|
16
16
|
})
|
|
17
17
|
</script>
|
|
18
18
|
|
|
@@ -10,31 +10,34 @@ const props = defineProps({
|
|
|
10
10
|
projectPage: {
|
|
11
11
|
type: String,
|
|
12
12
|
required: false,
|
|
13
|
-
default: '/projects.html'
|
|
13
|
+
default: '/projects.html'
|
|
14
14
|
},
|
|
15
15
|
projects: {
|
|
16
16
|
type: Object as PropType<Project[]>,
|
|
17
17
|
required: true,
|
|
18
|
-
default: []
|
|
18
|
+
default: []
|
|
19
19
|
},
|
|
20
20
|
technology: {
|
|
21
21
|
type: String,
|
|
22
|
-
required: false
|
|
23
|
-
}
|
|
22
|
+
required: false
|
|
23
|
+
}
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
const { t } = useI18n()
|
|
27
27
|
const tech = props.technology
|
|
28
28
|
const hasTechParam = typeof tech === 'string' && tech.length > 0
|
|
29
|
-
const byTech: (project: Project) => boolean = (project) =>
|
|
29
|
+
const byTech: (project: Project) => boolean = (project) =>
|
|
30
|
+
!hasTechParam || project.techs.some(useSlugFilter(tech))
|
|
30
31
|
const projectsByTech = computed(() => props.projects.filter(byTech))
|
|
31
32
|
const technologies = computed(() => {
|
|
32
|
-
const uniqueTechnologies = [
|
|
33
|
+
const uniqueTechnologies = [
|
|
34
|
+
...new Set(props.projects.flatMap((project) => project.techs))
|
|
35
|
+
]
|
|
33
36
|
return uniqueTechnologies
|
|
34
37
|
.map((name) => ({
|
|
35
38
|
name,
|
|
36
39
|
slug: useSlug(name),
|
|
37
|
-
selected: hasTechParam && useSlug(name) === tech
|
|
40
|
+
selected: hasTechParam && useSlug(name) === tech
|
|
38
41
|
}))
|
|
39
42
|
.sort((a, b) => (b.selected === a.selected ? 0 : b.selected ? 1 : -1))
|
|
40
43
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup lang=
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { computed, type PropType } from 'vue'
|
|
3
3
|
import { useI18n } from 'vue-i18n'
|
|
4
4
|
import TermBadge from '../components/TermBadge.vue'
|
|
@@ -9,8 +9,8 @@ const props = defineProps({
|
|
|
9
9
|
posts: {
|
|
10
10
|
type: Object as PropType<Post[]>,
|
|
11
11
|
required: true,
|
|
12
|
-
default: []
|
|
13
|
-
}
|
|
12
|
+
default: []
|
|
13
|
+
}
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
const { t } = useI18n()
|
|
@@ -24,7 +24,13 @@ const tags = computed(() => useRank(props.posts.flatMap((post) => post.tags)))
|
|
|
24
24
|
<div v-if="Object.keys(tags).length === 0" class="mt-2 mb-2 mr-5">
|
|
25
25
|
{{ t('no_tag') }}
|
|
26
26
|
</div>
|
|
27
|
-
<TermBadge
|
|
27
|
+
<TermBadge
|
|
28
|
+
v-for="(count, tag) in tags"
|
|
29
|
+
:key="tag"
|
|
30
|
+
:title="tag"
|
|
31
|
+
:count="count"
|
|
32
|
+
:href="`/tags/${useSlug(tag)}`"
|
|
33
|
+
/>
|
|
28
34
|
</div>
|
|
29
35
|
</Page>
|
|
30
36
|
</template>
|
|
@@ -17,15 +17,17 @@ const computedDonationConfig = computed(() => {
|
|
|
17
17
|
if (donationPlatform === 'custom') {
|
|
18
18
|
continue
|
|
19
19
|
}
|
|
20
|
-
const donationId: string = donationConfigs[
|
|
20
|
+
const donationId: string = donationConfigs[
|
|
21
|
+
donationPlatform as keyof typeof donationConfigs
|
|
22
|
+
] as string
|
|
21
23
|
donationConfig[donationPlatform] = {
|
|
22
24
|
...supportedDonationPlatforms[donationPlatform],
|
|
23
|
-
donationId
|
|
25
|
+
donationId
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
return {
|
|
27
29
|
...donationConfig,
|
|
28
|
-
...donationConfigs.custom
|
|
30
|
+
...donationConfigs.custom
|
|
29
31
|
}
|
|
30
32
|
})
|
|
31
33
|
</script>
|
|
@@ -8,7 +8,9 @@ interface DonationButtonProps extends CustomDonationConfig {
|
|
|
8
8
|
|
|
9
9
|
const props = defineProps<DonationButtonProps>()
|
|
10
10
|
|
|
11
|
-
const donationUrl = computed(() =>
|
|
11
|
+
const donationUrl = computed(() =>
|
|
12
|
+
new URL(props.donationId, props.donationBaseUrl).toString()
|
|
13
|
+
)
|
|
12
14
|
</script>
|
|
13
15
|
|
|
14
16
|
<template>
|
|
@@ -22,21 +22,24 @@ export const supportedDonationPlatforms: {
|
|
|
22
22
|
} = {
|
|
23
23
|
buymeacoffee: {
|
|
24
24
|
donationBaseUrl: 'https://buymeacoffee.com',
|
|
25
|
-
donationButtonImage:
|
|
25
|
+
donationButtonImage:
|
|
26
|
+
'https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png',
|
|
26
27
|
donationButtonStyle: {
|
|
27
28
|
height: '60px !important',
|
|
28
|
-
width: '217px !important'
|
|
29
|
-
}
|
|
29
|
+
width: '217px !important'
|
|
30
|
+
}
|
|
30
31
|
},
|
|
31
32
|
kofi: {
|
|
32
33
|
donationBaseUrl: 'https://ko-fi.com',
|
|
33
|
-
donationButtonImage:
|
|
34
|
+
donationButtonImage:
|
|
35
|
+
'https://storage.ko-fi.com/cdn/brandasset/kofi_bg_tag_white.png',
|
|
34
36
|
donationButtonStyle: {
|
|
35
|
-
height: '60px !important'
|
|
36
|
-
}
|
|
37
|
+
height: '60px !important'
|
|
38
|
+
}
|
|
37
39
|
},
|
|
38
40
|
paypal: {
|
|
39
41
|
donationBaseUrl: 'https://paypal.me',
|
|
40
|
-
donationButtonImage:
|
|
41
|
-
|
|
42
|
+
donationButtonImage:
|
|
43
|
+
'https://paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif'
|
|
44
|
+
}
|
|
42
45
|
}
|
|
@@ -9,11 +9,22 @@ const defaultConfigs = {
|
|
|
9
9
|
titleCssClass: 'text-sm/[32px] font-semibold mb-2',
|
|
10
10
|
buttonCssClass: 'flex flex-wrap space-x-1',
|
|
11
11
|
title: 'Share',
|
|
12
|
-
networks: [
|
|
12
|
+
networks: [
|
|
13
|
+
'email',
|
|
14
|
+
'facebook',
|
|
15
|
+
'twitter',
|
|
16
|
+
'telegram',
|
|
17
|
+
'reddit',
|
|
18
|
+
'linkedin',
|
|
19
|
+
'whatsapp',
|
|
20
|
+
'pinterest',
|
|
21
|
+
'tumblr',
|
|
22
|
+
'vk'
|
|
23
|
+
],
|
|
13
24
|
buttonSize: 18,
|
|
14
25
|
iconSize: 20,
|
|
15
26
|
iconStyle: 'solid',
|
|
16
|
-
displayMode: 'both'
|
|
27
|
+
displayMode: 'both'
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
const props = defineProps<SharingComponentProps>()
|
|
@@ -24,45 +35,51 @@ const pluginConfig = computed(() => theme.value.sharing || false)
|
|
|
24
35
|
const wrapperCssClass = computed(() =>
|
|
25
36
|
pluginConfig.value && typeof pluginConfig.value.wrapperCssClass === 'string'
|
|
26
37
|
? pluginConfig.value.wrapperCssClass
|
|
27
|
-
: defaultConfigs.wrapperCssClass
|
|
38
|
+
: defaultConfigs.wrapperCssClass
|
|
28
39
|
)
|
|
29
40
|
const title = computed(() =>
|
|
30
|
-
pluginConfig.value && typeof pluginConfig.value.title === 'string'
|
|
41
|
+
pluginConfig.value && typeof pluginConfig.value.title === 'string'
|
|
42
|
+
? pluginConfig.value.title
|
|
43
|
+
: defaultConfigs.title
|
|
31
44
|
)
|
|
32
45
|
const titleCssClass = computed(() =>
|
|
33
46
|
pluginConfig.value && typeof pluginConfig.value.titleCssClass === 'string'
|
|
34
47
|
? pluginConfig.value.titleCssClass
|
|
35
|
-
: defaultConfigs.titleCssClass
|
|
48
|
+
: defaultConfigs.titleCssClass
|
|
36
49
|
)
|
|
37
50
|
const buttonCssClass = computed(() =>
|
|
38
51
|
pluginConfig.value && typeof pluginConfig.value.buttonCssClass === 'string'
|
|
39
52
|
? pluginConfig.value.buttonCssClass
|
|
40
|
-
: defaultConfigs.buttonCssClass
|
|
53
|
+
: defaultConfigs.buttonCssClass
|
|
41
54
|
)
|
|
42
55
|
const networks = computed(() =>
|
|
43
56
|
pluginConfig.value && Array.isArray(pluginConfig.value.networks)
|
|
44
57
|
? pluginConfig.value.networks
|
|
45
|
-
: defaultConfigs.networks
|
|
58
|
+
: defaultConfigs.networks
|
|
46
59
|
)
|
|
47
60
|
const buttonSize = computed(() =>
|
|
48
|
-
pluginConfig.value &&
|
|
61
|
+
pluginConfig.value &&
|
|
62
|
+
Number.isInteger(pluginConfig.value.buttonSize) &&
|
|
63
|
+
pluginConfig.value.buttonSize > 0
|
|
49
64
|
? pluginConfig.value.buttonSize
|
|
50
|
-
: defaultConfigs.buttonSize
|
|
65
|
+
: defaultConfigs.buttonSize
|
|
51
66
|
)
|
|
52
67
|
const iconSize = computed(() =>
|
|
53
|
-
pluginConfig.value &&
|
|
68
|
+
pluginConfig.value &&
|
|
69
|
+
Number.isInteger(pluginConfig.value.iconSize) &&
|
|
70
|
+
pluginConfig.value.iconSize > 0
|
|
54
71
|
? pluginConfig.value.iconSize
|
|
55
|
-
: defaultConfigs.iconSize
|
|
72
|
+
: defaultConfigs.iconSize
|
|
56
73
|
)
|
|
57
74
|
const iconStyle = computed(() =>
|
|
58
75
|
pluginConfig.value && typeof pluginConfig.value.iconStyle === 'string'
|
|
59
76
|
? pluginConfig.value.iconStyle
|
|
60
|
-
: defaultConfigs.iconStyle
|
|
77
|
+
: defaultConfigs.iconStyle
|
|
61
78
|
)
|
|
62
79
|
const displayMode = computed(() =>
|
|
63
80
|
pluginConfig.value && typeof pluginConfig.value.displayMode === 'string'
|
|
64
81
|
? pluginConfig.value.displayMode
|
|
65
|
-
: defaultConfigs.displayMode
|
|
82
|
+
: defaultConfigs.displayMode
|
|
66
83
|
)
|
|
67
84
|
</script>
|
|
68
85
|
|
|
@@ -73,8 +90,15 @@ const displayMode = computed(() =>
|
|
|
73
90
|
</p>
|
|
74
91
|
<div :class="buttonCssClass">
|
|
75
92
|
<template v-for="network in networks" :key="network">
|
|
76
|
-
<SharingButton
|
|
77
|
-
:
|
|
93
|
+
<SharingButton
|
|
94
|
+
:url="props.url"
|
|
95
|
+
:text="props.text"
|
|
96
|
+
:network="network"
|
|
97
|
+
:button-size="buttonSize"
|
|
98
|
+
:icon-size="iconSize"
|
|
99
|
+
:icon-style="iconStyle"
|
|
100
|
+
:display-mode="displayMode"
|
|
101
|
+
/>
|
|
78
102
|
</template>
|
|
79
103
|
</div>
|
|
80
104
|
</div>
|