@hefou/lum 0.0.0-stage → 1.0.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/License +21 -0
- package/components/Aside.vue +130 -0
- package/components/BoxCube.vue +89 -0
- package/components/Card.vue +111 -0
- package/components/CopyText.vue +214 -0
- package/components/Footer.vue +194 -0
- package/components/Links.vue +121 -0
- package/components/Notice.vue +85 -0
- package/components/Pill.vue +108 -0
- package/components/Underline.vue +22 -0
- package/components/common/Icon.vue +67 -0
- package/components/common/Image.vue +94 -0
- package/components/common/Link.vue +33 -0
- package/components/common/Svg.vue +28 -0
- package/components/common/index.ts +4 -0
- package/components/index.ts +9 -0
- package/composables/baiduAnalytics.ts +60 -0
- package/composables/googleAnalytics.ts +26 -0
- package/composables/index.ts +4 -0
- package/composables/umamiAnalytics.ts +49 -0
- package/composables/utils.ts +61 -0
- package/dist/cjs/_virtual/_plugin-vue_export-helper.cjs +1 -0
- package/dist/cjs/components/Aside.cjs +1 -0
- package/dist/cjs/components/Aside.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/BoxCube.cjs +1 -0
- package/dist/cjs/components/BoxCube.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/Card.cjs +1 -0
- package/dist/cjs/components/Card.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/CopyText.cjs +1 -0
- package/dist/cjs/components/CopyText.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/Footer.cjs +1 -0
- package/dist/cjs/components/Footer.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/Links.cjs +1 -0
- package/dist/cjs/components/Links.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/Notice.cjs +1 -0
- package/dist/cjs/components/Notice.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/Pill.cjs +1 -0
- package/dist/cjs/components/Pill.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/Underline.cjs +1 -0
- package/dist/cjs/components/Underline.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/common/Icon.cjs +1 -0
- package/dist/cjs/components/common/Icon.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/common/Image.cjs +1 -0
- package/dist/cjs/components/common/Image.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/common/Link.cjs +1 -0
- package/dist/cjs/components/common/Link.vue_vue_type_script_setup_true_lang.cjs +1 -0
- package/dist/cjs/components/common/Svg.cjs +1 -0
- package/dist/cjs/composables/baiduAnalytics.cjs +1 -0
- package/dist/cjs/composables/googleAnalytics.cjs +1 -0
- package/dist/cjs/composables/umamiAnalytics.cjs +1 -0
- package/dist/cjs/composables/utils.cjs +1 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/lum.css +2 -0
- package/dist/cjs/node_modules/.pnpm/@iconify_vue@5.0.5_vue@3.5.45_typescript@5.9.3_/node_modules/@iconify/vue/dist/iconify.cjs +1 -0
- package/dist/cjs/node_modules/.pnpm/iconify-icon@3.0.5/node_modules/iconify-icon/dist/iconify-icon.cjs +1 -0
- package/dist/esm/_virtual/_plugin-vue_export-helper.js +7 -0
- package/dist/esm/components/Aside.js +6 -0
- package/dist/esm/components/Aside.vue_vue_type_script_setup_true_lang.js +85 -0
- package/dist/esm/components/BoxCube.js +6 -0
- package/dist/esm/components/BoxCube.vue_vue_type_script_setup_true_lang.js +45 -0
- package/dist/esm/components/Card.js +6 -0
- package/dist/esm/components/Card.vue_vue_type_script_setup_true_lang.js +50 -0
- package/dist/esm/components/CopyText.js +6 -0
- package/dist/esm/components/CopyText.vue_vue_type_script_setup_true_lang.js +63 -0
- package/dist/esm/components/Footer.js +6 -0
- package/dist/esm/components/Footer.vue_vue_type_script_setup_true_lang.js +170 -0
- package/dist/esm/components/Links.js +6 -0
- package/dist/esm/components/Links.vue_vue_type_script_setup_true_lang.js +59 -0
- package/dist/esm/components/Notice.js +6 -0
- package/dist/esm/components/Notice.vue_vue_type_script_setup_true_lang.js +61 -0
- package/dist/esm/components/Pill.js +6 -0
- package/dist/esm/components/Pill.vue_vue_type_script_setup_true_lang.js +51 -0
- package/dist/esm/components/Underline.js +6 -0
- package/dist/esm/components/Underline.vue_vue_type_script_setup_true_lang.js +13 -0
- package/dist/esm/components/common/Icon.js +4 -0
- package/dist/esm/components/common/Icon.vue_vue_type_script_setup_true_lang.js +53 -0
- package/dist/esm/components/common/Image.js +6 -0
- package/dist/esm/components/common/Image.vue_vue_type_script_setup_true_lang.js +79 -0
- package/dist/esm/components/common/Link.js +4 -0
- package/dist/esm/components/common/Link.vue_vue_type_script_setup_true_lang.js +36 -0
- package/dist/esm/components/common/Svg.js +19 -0
- package/dist/esm/composables/baiduAnalytics.js +23 -0
- package/dist/esm/composables/googleAnalytics.js +12 -0
- package/dist/esm/composables/umamiAnalytics.js +12 -0
- package/dist/esm/composables/utils.js +24 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/lum.css +2 -0
- package/dist/esm/node_modules/.pnpm/@iconify_vue@5.0.5_vue@3.5.45_typescript@5.9.3_/node_modules/@iconify/vue/dist/iconify.js +988 -0
- package/dist/esm/node_modules/.pnpm/iconify-icon@3.0.5/node_modules/iconify-icon/dist/iconify-icon.js +1209 -0
- package/dist/types/bump.config.d.ts +2 -0
- package/dist/types/changelogithub.config.d.ts +26 -0
- package/dist/types/components/Aside.vue.d.ts +7 -0
- package/dist/types/components/BoxCube.vue.d.ts +8 -0
- package/dist/types/components/Card.vue.d.ts +8 -0
- package/dist/types/components/CopyText.vue.d.ts +15 -0
- package/dist/types/components/Footer.vue.d.ts +7 -0
- package/dist/types/components/Links.vue.d.ts +8 -0
- package/dist/types/components/Notice.vue.d.ts +3 -0
- package/dist/types/components/Pill.vue.d.ts +13 -0
- package/dist/types/components/Underline.vue.d.ts +3 -0
- package/dist/types/components/common/Icon.vue.d.ts +9 -0
- package/dist/types/components/common/Image.vue.d.ts +8 -0
- package/dist/types/components/common/Link.vue.d.ts +23 -0
- package/dist/types/components/common/Svg.vue.d.ts +3 -0
- package/dist/types/components/common/index.d.ts +4 -0
- package/dist/types/components/index.d.ts +9 -0
- package/dist/types/composables/baiduAnalytics.d.ts +17 -0
- package/dist/types/composables/googleAnalytics.d.ts +12 -0
- package/dist/types/composables/index.d.ts +4 -0
- package/dist/types/composables/umamiAnalytics.d.ts +13 -0
- package/dist/types/composables/utils.d.ts +30 -0
- package/dist/types/types/index.d.ts +5 -0
- package/dist/types/types/types.d.ts +313 -0
- package/dist/types/vite.config.d.ts +2 -0
- package/package.json +131 -3
- package/readme.md +39 -0
- package/style/all.css +9 -0
- package/style/badge.css +21 -0
- package/style/button.css +48 -0
- package/style/colors.css +59 -0
- package/style/components-var.css +173 -0
- package/style/doc-blocks.css +136 -0
- package/style/doc.css +17 -0
- package/style/home.css +34 -0
- package/style/icon.css +11 -0
- package/style/picture.css +40 -0
- package/tsconfig.json +17 -0
- package/types/index.d.ts +3 -0
- package/types/index.ts +6 -0
- package/types/shims.d.ts +36 -0
- package/types/style.d.ts +10 -0
- package/types/types.ts +318 -0
- package/README.md +0 -3
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useData } from 'vitepress'
|
|
3
|
+
import { computed, onMounted, ref } from 'vue'
|
|
4
|
+
import { getLocaleKey, isExternal } from '../composables'
|
|
5
|
+
import type { FooterData } from '../types'
|
|
6
|
+
import { Icon, Image, Link } from './common'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{ Footer_Data: FooterData }>()
|
|
9
|
+
|
|
10
|
+
const localeKey = getLocaleKey()
|
|
11
|
+
|
|
12
|
+
const footer = computed<NonNullable<FooterData>>(() => {
|
|
13
|
+
const localized = props.Footer_Data?.i18n?.[localeKey.value]
|
|
14
|
+
return {
|
|
15
|
+
...props.Footer_Data,
|
|
16
|
+
...localized,
|
|
17
|
+
author: localized?.author ?? props.Footer_Data?.author ?? undefined,
|
|
18
|
+
beian: localized?.beian ?? props.Footer_Data?.beian ?? undefined,
|
|
19
|
+
group: localized?.group ?? props.Footer_Data?.group ?? [],
|
|
20
|
+
noIcon: localized?.noIcon ?? props.Footer_Data?.noIcon ?? false,
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const footerAuthor = computed(() => footer.value.author ?? null)
|
|
25
|
+
const beian = computed(() => footer.value.beian ?? {})
|
|
26
|
+
const icp = computed(() => beian.value.icp)
|
|
27
|
+
const police = computed(() => beian.value.police)
|
|
28
|
+
|
|
29
|
+
const currentYear = ref('')
|
|
30
|
+
onMounted(() => (currentYear.value = new Date().getFullYear().toString()))
|
|
31
|
+
|
|
32
|
+
const { frontmatter } = useData()
|
|
33
|
+
const isHome = computed(() => {
|
|
34
|
+
return !!(frontmatter.value.isHome ?? frontmatter.value.layout === 'home')
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<footer v-if="isHome" class="footer">
|
|
40
|
+
<div v-if="footer.group?.length" class="list-container">
|
|
41
|
+
<section v-for="(section, i) in footer.group" :key="section.title + i">
|
|
42
|
+
<h3 class="list-title">
|
|
43
|
+
<Icon v-if="section.icon" class="icon-space" :icon="section.icon" size="12" />
|
|
44
|
+
<Image v-else-if="section.image" class="image-inline" :image="section.image" size="12" />
|
|
45
|
+
{{ section.title }}
|
|
46
|
+
</h3>
|
|
47
|
+
<ul class="list-links">
|
|
48
|
+
<li v-for="(link, i) in section.links" :key="link.name + i">
|
|
49
|
+
<Icon v-if="link.icon" class="icon-space" :icon="link.icon" size="12" />
|
|
50
|
+
<Image v-else-if="link.image" class="image-inline" :image="link.image" size="12" />
|
|
51
|
+
<Link :href="link.link" :rel="link.rel" :target="link.target"
|
|
52
|
+
:no-icon="footer.noIcon || section.noIcon || link.noIcon || !isExternal(link.link ?? '')">
|
|
53
|
+
{{ link.name }}
|
|
54
|
+
</Link>
|
|
55
|
+
</li>
|
|
56
|
+
</ul>
|
|
57
|
+
</section>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div v-if="footer.beian?.icp || footer.beian?.police || footer.author" class="footer-info">
|
|
61
|
+
<template v-if="footer.beian?.icp || footer.beian?.police">
|
|
62
|
+
<span v-if="footer.beian?.icp?.number" class="footer-infotext">
|
|
63
|
+
<template v-if="footer.beian?.showIcon">
|
|
64
|
+
<Icon v-if="footer.beian.icp.icon" class="icon-space" :icon="footer.beian.icp.icon" size="12" />
|
|
65
|
+
<Image v-else-if="footer.beian.icp.image" class="image-inline" :image="footer.beian.icp.image" size="12" />
|
|
66
|
+
<Image v-else class="image-inline" image="https://i.theojs.net/logo/miit.webp" size="12" loading="eager" />
|
|
67
|
+
</template>
|
|
68
|
+
<Link :href="icp?.link || 'https://beian.miit.gov.cn/'" :rel="icp?.rel || 'nofollow'" :target="icp?.target"
|
|
69
|
+
no-icon>
|
|
70
|
+
{{ icp?.number }}
|
|
71
|
+
</Link>
|
|
72
|
+
</span>
|
|
73
|
+
|
|
74
|
+
<span class="info-spacing"></span>
|
|
75
|
+
|
|
76
|
+
<span v-if="police?.number" class="footer-infotext">
|
|
77
|
+
<template v-if="footer.beian?.showIcon">
|
|
78
|
+
<Icon v-if="police?.icon" class="icon-space" :icon="police.icon" size="12" />
|
|
79
|
+
<Image v-else-if="police?.image" class="image-inline" :image="police.image" size="12" />
|
|
80
|
+
<Image v-else class="image-inline" image="https://i.theojs.net/logo/mps.webp" size="12" loading="eager" />
|
|
81
|
+
</template>
|
|
82
|
+
<Link :href="police?.link || 'https://beian.mps.gov.cn/'" :rel="police?.rel" :target="police?.target" no-icon>
|
|
83
|
+
{{ police?.number }}
|
|
84
|
+
</Link>
|
|
85
|
+
</span>
|
|
86
|
+
</template>
|
|
87
|
+
|
|
88
|
+
<span class="info-spacing-copyright"></span>
|
|
89
|
+
|
|
90
|
+
<span v-if="footer.author?.name" class="footer-infotext">
|
|
91
|
+
<Icon v-if="footer.author.icon" class="icon-space" :icon="footer.author.icon" size="12" />
|
|
92
|
+
<Image v-else-if="footer.author.image" class="image-inline" :image="footer.author.image" size="12" />
|
|
93
|
+
<Icon v-else class="icon-space" :icon="'ri:copyright-line'" size="12" />
|
|
94
|
+
<Link :href="footerAuthor?.link || `https://github.com/${footerAuthor?.name}`" :rel="footerAuthor?.rel"
|
|
95
|
+
:target="footerAuthor?.target" no-icon>
|
|
96
|
+
{{ footerAuthor?.startYear ? `${footerAuthor.startYear} - ` : '' }}{{ currentYear }}
|
|
97
|
+
{{ footerAuthor?.name }}
|
|
98
|
+
{{ footerAuthor?.text || 'All Rights Reserved.' }}
|
|
99
|
+
</Link>
|
|
100
|
+
</span>
|
|
101
|
+
</div>
|
|
102
|
+
</footer>
|
|
103
|
+
</template>
|
|
104
|
+
|
|
105
|
+
<style scoped>
|
|
106
|
+
.footer {
|
|
107
|
+
background: var(---Footer-bg);
|
|
108
|
+
width: 100%;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.footer a {
|
|
112
|
+
position: relative;
|
|
113
|
+
transition:
|
|
114
|
+
color 0.25s,
|
|
115
|
+
opacity 0.25s,
|
|
116
|
+
text-decoration-color 0.25s;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.footer a:hover {
|
|
120
|
+
color: var(---Footer-link-hover);
|
|
121
|
+
-webkit-text-decoration: underline solid;
|
|
122
|
+
text-decoration: underline solid;
|
|
123
|
+
text-underline-offset: 4px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.list-container {
|
|
127
|
+
display: grid;
|
|
128
|
+
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
129
|
+
row-gap: 1.25em;
|
|
130
|
+
justify-items: center;
|
|
131
|
+
margin: 1.25em auto;
|
|
132
|
+
max-width: 65%;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.list-title {
|
|
136
|
+
margin-bottom: 0.5em;
|
|
137
|
+
font-weight: 600;
|
|
138
|
+
font-size: 0.75em;
|
|
139
|
+
line-height: 1.5;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.list-links {
|
|
143
|
+
font-weight: 500;
|
|
144
|
+
font-size: 0.75em;
|
|
145
|
+
line-height: 2.4;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.list-links a {
|
|
149
|
+
opacity: 0.75;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.list-links a:hover {
|
|
153
|
+
opacity: 1;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.iconify {
|
|
157
|
+
display: inline-block;
|
|
158
|
+
flex-shrink: 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.icon-space {
|
|
162
|
+
margin-right: 0.3em;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.footer-info {
|
|
166
|
+
margin: 0.875em 0;
|
|
167
|
+
text-align: center;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.footer-infotext {
|
|
171
|
+
display: inline-block;
|
|
172
|
+
margin: 0;
|
|
173
|
+
font-weight: 500;
|
|
174
|
+
font-size: 0.75em;
|
|
175
|
+
line-height: 1.6;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.info-spacing,
|
|
179
|
+
.info-spacing-copyright {
|
|
180
|
+
margin-left: 1em;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.image-inline {
|
|
184
|
+
display: inline-block;
|
|
185
|
+
vertical-align: -0.125em;
|
|
186
|
+
margin-right: 0.3em;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@media (max-width: 768px) {
|
|
190
|
+
.info-spacing-copyright {
|
|
191
|
+
margin-left: -1em;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
</style>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { LinkItem } from '../types'
|
|
3
|
+
import { Icon, Image, Link } from './common'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
items: LinkItem[]
|
|
7
|
+
grid?: number
|
|
8
|
+
}>()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="grid"
|
|
13
|
+
:style="typeof props.grid === 'number' ? { gridTemplateColumns: `repeat(${props.grid}, 1fr)` } : undefined">
|
|
14
|
+
<Link v-for="(link, i) in props.items" :key="link.name + i" class="link" :href="link.link" :rel="link.rel"
|
|
15
|
+
:target="link.target" no-icon>
|
|
16
|
+
<span class="row">
|
|
17
|
+
<Icon v-if="link.icon" :icon="link.icon" :size="link.size || '32'" />
|
|
18
|
+
<Image v-else-if="link.image" :image="link.image" :size="link.size || '32'" />
|
|
19
|
+
<span class="name" v-html="link.name"></span>
|
|
20
|
+
</span>
|
|
21
|
+
<p v-if="link.desc" class="desc" v-html="link.desc"></p>
|
|
22
|
+
<p v-if="link.linkText" class="link-text">
|
|
23
|
+
{{ link.linkText }} <span class="vpi-arrow-right" style="margin-left: 6px" />
|
|
24
|
+
</p>
|
|
25
|
+
</Link>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<style scoped>
|
|
30
|
+
.grid {
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: repeat(1, 1fr);
|
|
33
|
+
gap: 0.5em;
|
|
34
|
+
margin: 0.5em 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.row {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: 0.75em;
|
|
41
|
+
width: 100%;
|
|
42
|
+
min-width: 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.link {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
align-items: flex-start;
|
|
49
|
+
transition:
|
|
50
|
+
color 0.25s,
|
|
51
|
+
transform 0.25s,
|
|
52
|
+
box-shadow 0.25s,
|
|
53
|
+
border-color 0.25s,
|
|
54
|
+
background-color 0.25s;
|
|
55
|
+
margin: 0;
|
|
56
|
+
border: 1px solid var(---Links-border);
|
|
57
|
+
border-radius: 0.75em;
|
|
58
|
+
background-color: var(---Links-bg);
|
|
59
|
+
padding: 1em;
|
|
60
|
+
min-width: 0;
|
|
61
|
+
text-decoration: none !important;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.link.-link {
|
|
65
|
+
color: var(---Links-name);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.link.-link:hover {
|
|
69
|
+
transform: var(---Links-transform-hover);
|
|
70
|
+
box-shadow: var(---Links-boxshadow-hover);
|
|
71
|
+
border-color: var(---Links-border-hover);
|
|
72
|
+
background-color: var(---Links-bg-hover);
|
|
73
|
+
color: var(---Links-name-hover);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.link.-link:active {
|
|
77
|
+
transform: var(---Links-transform-active);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.iconify {
|
|
81
|
+
flex-shrink: 0;
|
|
82
|
+
color: var(---iconify-defColor);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.name {
|
|
86
|
+
flex: 1 1 0%;
|
|
87
|
+
width: 100%;
|
|
88
|
+
min-width: 0;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
font-size: 0.875rem;
|
|
92
|
+
line-height: 1.5;
|
|
93
|
+
text-overflow: ellipsis;
|
|
94
|
+
white-space: nowrap;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.desc {
|
|
98
|
+
margin: 0.875em 0 0 0;
|
|
99
|
+
color: var(---Links-desc);
|
|
100
|
+
font-weight: 500;
|
|
101
|
+
font-size: 0.75em;
|
|
102
|
+
line-height: 1.5;
|
|
103
|
+
word-break: break-all;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.link-text {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
margin: 0;
|
|
110
|
+
padding-top: 8px;
|
|
111
|
+
font-weight: 500;
|
|
112
|
+
font-size: 0.75em;
|
|
113
|
+
line-height: 1.5;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@media (max-width: 600px) {
|
|
117
|
+
.grid {
|
|
118
|
+
grid-template-columns: repeat(auto-fit, minmax(45%, 1fr)) !important;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useNotice } from '../composables'
|
|
3
|
+
import { Icon, Image, Link } from './common'
|
|
4
|
+
|
|
5
|
+
const notice = useNotice()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<Link v-if="notice" :key="(notice.link ?? '') + (notice.rel ?? '') + (notice.target ?? '') || notice.title || notice.desc || notice.date
|
|
10
|
+
" class="notice" :tag="notice.link ? 'a' : 'div'" :href="notice.link" :rel="notice.rel" :target="notice.target"
|
|
11
|
+
no-icon>
|
|
12
|
+
<div class="content">
|
|
13
|
+
<span class="title" v-html="notice.title"></span>
|
|
14
|
+
<p v-if="notice.desc" class="desc" v-html="notice.desc"></p>
|
|
15
|
+
<div v-if="notice.date" class="time-info">
|
|
16
|
+
<Icon v-if="notice.dateIcon" :icon="notice.dateIcon" size="14" />
|
|
17
|
+
<Image v-else-if="notice.dateImage" :image="notice.dateImage" size="14" />
|
|
18
|
+
<Icon v-else icon="heroicons:calendar-days" size="14" style="transform: translateY(-0.5px)" />
|
|
19
|
+
<time v-html="notice.dateText || '活动时间: 即日至'"></time>
|
|
20
|
+
<time class="date">{{ notice.date }}</time>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</Link>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<style scoped>
|
|
27
|
+
.notice {
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
transition:
|
|
31
|
+
transform 0.25s,
|
|
32
|
+
border-color 0.25s,
|
|
33
|
+
background-color 0.25s;
|
|
34
|
+
margin-bottom: 1em;
|
|
35
|
+
border: 1px solid var(---Notice-border);
|
|
36
|
+
border-radius: 0.5em;
|
|
37
|
+
background-color: var(---Notice-bg);
|
|
38
|
+
padding: 0.15em 1em;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.notice.-link:hover {
|
|
42
|
+
transform: var(---Notice-transform-hover);
|
|
43
|
+
border-color: var(---Notice-border-hover);
|
|
44
|
+
background-color: var(---Notice-bg-hover);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.notice.-link:active {
|
|
48
|
+
transform: var(---Notice-transform-active);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.content {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.title {
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
font-size: 0.75em;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.desc {
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
font-size: 0.75em;
|
|
64
|
+
white-space: pre-wrap;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.time-info {
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
gap: 0.25em;
|
|
71
|
+
font-weight: 500;
|
|
72
|
+
font-size: 0.75em;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.date {
|
|
76
|
+
color: var(---Notice-data);
|
|
77
|
+
font-weight: bold;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@media (max-width: 768px) {
|
|
81
|
+
.time-info {
|
|
82
|
+
justify-content: center;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
</style>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { IconType, ImageType, LinkType, RelType, SizeType, TargetType } from '../types'
|
|
3
|
+
import { Icon, Image, Link } from './common'
|
|
4
|
+
|
|
5
|
+
const pill = defineProps<{
|
|
6
|
+
name: string
|
|
7
|
+
link?: LinkType
|
|
8
|
+
rel?: RelType
|
|
9
|
+
target?: TargetType
|
|
10
|
+
icon?: IconType
|
|
11
|
+
image?: ImageType
|
|
12
|
+
size?: SizeType
|
|
13
|
+
}>()
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<Link :class="['link', 'ignore-header', { 'no-icon-img': !pill.icon && !pill.image }]" :href="pill.link"
|
|
18
|
+
:rel="pill.rel" :target="pill.target" no-icon>
|
|
19
|
+
<Icon v-if="pill.icon" :icon="pill.icon" :size="pill.size || '14'" />
|
|
20
|
+
<Image v-else-if="pill.image" :image="pill.image" :size="pill.size || '14'" />
|
|
21
|
+
<span class="name" v-html="pill.name"></span>
|
|
22
|
+
</Link>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<style scoped>
|
|
26
|
+
.link {
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
vertical-align: -1px;
|
|
30
|
+
gap: 0.25em;
|
|
31
|
+
transition:
|
|
32
|
+
color 0.25s,
|
|
33
|
+
transform 0.25s,
|
|
34
|
+
box-shadow 0.25s,
|
|
35
|
+
border-color 0.25s,
|
|
36
|
+
background-color 0.25s;
|
|
37
|
+
margin: 0 0.125em;
|
|
38
|
+
border: 1px solid var(---Pill-border);
|
|
39
|
+
border-radius: 0.5em;
|
|
40
|
+
background-color: var(---Pill-bg);
|
|
41
|
+
padding: 0 0.25em;
|
|
42
|
+
height: 1.375em;
|
|
43
|
+
font-size: 1rem;
|
|
44
|
+
text-decoration: none !important;
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.link.no-icon-img {
|
|
49
|
+
vertical-align: 1.5px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.link.-link {
|
|
53
|
+
color: var(---Pill-name);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.link.-link:hover {
|
|
57
|
+
transform: var(---Pill-transform-hover);
|
|
58
|
+
box-shadow: var(---Pill-boxshadow-hover);
|
|
59
|
+
border-color: var(---Pill-border-hover);
|
|
60
|
+
background-color: var(---Pill-bg-hover);
|
|
61
|
+
color: var(---Pill-name-hover);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.link.-link:active {
|
|
65
|
+
transform: var(---Pill-transform-active);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.vp-doc h1>.link {
|
|
69
|
+
vertical-align: top;
|
|
70
|
+
margin-top: 2px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.vp-doc h2>.link {
|
|
74
|
+
vertical-align: top;
|
|
75
|
+
margin-top: 1px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.vp-doc h3>.link {
|
|
79
|
+
vertical-align: top;
|
|
80
|
+
margin-top: 1px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.vp-doc h4>.link,
|
|
84
|
+
.vp-doc h5>.link,
|
|
85
|
+
.vp-doc h6>.link {
|
|
86
|
+
vertical-align: top;
|
|
87
|
+
line-height: 18px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.vp-doc td>.link {
|
|
91
|
+
vertical-align: -1px;
|
|
92
|
+
font-size: 1em;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.vp-doc td>.link.no-icon-img {
|
|
96
|
+
vertical-align: 1.5px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.iconify {
|
|
100
|
+
flex-shrink: 0;
|
|
101
|
+
color: var(---iconify-defColor);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.name {
|
|
105
|
+
font-weight: 500;
|
|
106
|
+
font-size: 0.875em;
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useData } from 'vitepress'
|
|
3
|
+
import { moveDomElements } from '../composables'
|
|
4
|
+
import { Svg } from './common'
|
|
5
|
+
|
|
6
|
+
const { frontmatter: fm } = useData()
|
|
7
|
+
moveDomElements('heroText')
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<span ref="heroText">
|
|
12
|
+
<span class="hero-text">{{ fm.hero?.text }}<Svg /></span>
|
|
13
|
+
{{ fm.hero?.textsuffix }}
|
|
14
|
+
</span>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<style scoped>
|
|
18
|
+
.hero-text {
|
|
19
|
+
display: inline-block;
|
|
20
|
+
position: relative;
|
|
21
|
+
}
|
|
22
|
+
</style>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Icon } from '@iconify/vue'
|
|
3
|
+
import { useData } from 'vitepress'
|
|
4
|
+
import { computed, onMounted, ref, watchEffect } from 'vue'
|
|
5
|
+
import type { IconMode, IconType, SizeType } from '../../types'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
icon: IconType
|
|
9
|
+
color?: IconMode
|
|
10
|
+
size?: SizeType
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
const { isDark } = useData()
|
|
14
|
+
|
|
15
|
+
const resolvedIcon = computed(() => {
|
|
16
|
+
if (typeof props.icon === 'string') return props.icon
|
|
17
|
+
if ('icon' in props.icon) return props.icon.icon
|
|
18
|
+
if ('light' in props.icon && 'dark' in props.icon) return isDark.value ? props.icon.dark : props.icon.light
|
|
19
|
+
if ('svg' in props.icon) {
|
|
20
|
+
if (typeof props.icon.svg === 'object') return isDark.value ? props.icon.svg.dark : props.icon.svg.light
|
|
21
|
+
return props.icon.svg
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const resolvedColor = computed(() => {
|
|
26
|
+
if (!props.icon || typeof props.icon === 'string') return undefined
|
|
27
|
+
if ('color' in props.icon) {
|
|
28
|
+
if (typeof props.icon.color === 'object') return isDark.value ? props.icon.color.dark : props.icon.color.light
|
|
29
|
+
return props.icon.color
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const resizeSvg = (svgString: string, size: string) => {
|
|
34
|
+
if (typeof window !== 'undefined') {
|
|
35
|
+
const svgElement = new DOMParser().parseFromString(svgString, 'image/svg+xml').querySelector('svg')
|
|
36
|
+
svgElement?.setAttribute('width', size)
|
|
37
|
+
svgElement?.setAttribute('height', size)
|
|
38
|
+
return svgElement?.outerHTML ?? svgString
|
|
39
|
+
}
|
|
40
|
+
return svgString
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const resolvedSvg = computed(() =>
|
|
44
|
+
resolvedIcon.value?.includes('<svg') && props.size ? resizeSvg(resolvedIcon.value, String(props.size)) : null
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const svgRef = ref<HTMLElement | null>(null)
|
|
48
|
+
|
|
49
|
+
onMounted(() => {
|
|
50
|
+
watchEffect(() => {
|
|
51
|
+
if (svgRef.value && resolvedSvg.value) svgRef.value.innerHTML = resolvedSvg.value
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<span v-if="resolvedSvg" ref="svgRef" class="iconify" aria-hidden="true" />
|
|
58
|
+
<Icon
|
|
59
|
+
v-else
|
|
60
|
+
:icon="resolvedIcon ?? ''"
|
|
61
|
+
:color="resolvedColor"
|
|
62
|
+
:inline="true"
|
|
63
|
+
:ssr="true"
|
|
64
|
+
:width="size"
|
|
65
|
+
:height="size"
|
|
66
|
+
/>
|
|
67
|
+
</template>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { withBase } from 'vitepress'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import type { ImageType, SizeType } from '../../types'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
image: ImageType
|
|
8
|
+
size?: SizeType
|
|
9
|
+
}>()
|
|
10
|
+
|
|
11
|
+
defineOptions({ inheritAttrs: false })
|
|
12
|
+
|
|
13
|
+
const isThemedImage = (image: ImageType): image is { light: string; dark: string } =>
|
|
14
|
+
typeof image === 'object' && 'light' in image && 'dark' in image
|
|
15
|
+
|
|
16
|
+
const shouldCrop = computed(() => Boolean(typeof props.image === 'object' && 'crop' in props.image && props.image.crop))
|
|
17
|
+
|
|
18
|
+
const imageAttrs = computed(() => {
|
|
19
|
+
if (typeof props.image === 'string') return {}
|
|
20
|
+
const { light, dark, crop, ...restAttrs } = props.image
|
|
21
|
+
return restAttrs
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const IMAGE_ERROR_FALLBACK =
|
|
25
|
+
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill='%238cbcd6' d='M40 41H8c-2.2 0-4-1.8-4-4V11c0-2.2 1.8-4 4-4h32c2.2 0 4 1.8 4 4v26c0 2.2-1.8 4-4 4'/%3E%3Ccircle cx='35' cy='16' r='3' fill='%23b3ddf5'/%3E%3Cpath fill='%239ac9e3' d='M20 16L9 32h22z'/%3E%3Cpath fill='%23b3ddf5' d='m31 22l-8 10h16z'/%3E%3Ccircle cx='38' cy='38' r='10' fill='%23f44336'/%3E%3Cg fill='%23fff'%3E%3Cpath d='m43.31 41.181l-2.12 2.122l-8.485-8.484l2.121-2.122z'/%3E%3Cpath d='m34.819 43.31l-2.122-2.12l8.484-8.485l2.122 2.121z'/%3E%3C/g%3E%3C/svg%3E"
|
|
26
|
+
|
|
27
|
+
const handleImageError = (event: Event): void => {
|
|
28
|
+
if (event.target instanceof HTMLImageElement) {
|
|
29
|
+
event.target.onerror = null
|
|
30
|
+
event.target.src = IMAGE_ERROR_FALLBACK
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<template v-if="isThemedImage(props.image)">
|
|
37
|
+
<img
|
|
38
|
+
:class="['lm-img', 'dark-img', shouldCrop && 'crop']"
|
|
39
|
+
:src="withBase(props.image.dark)"
|
|
40
|
+
:width="size ?? undefined"
|
|
41
|
+
:height="size ?? undefined"
|
|
42
|
+
loading="lazy"
|
|
43
|
+
aria-hidden="true"
|
|
44
|
+
alt=""
|
|
45
|
+
data-no-viewer
|
|
46
|
+
v-bind="{ ...imageAttrs, ...$attrs }"
|
|
47
|
+
@error="handleImageError"
|
|
48
|
+
/>
|
|
49
|
+
<img
|
|
50
|
+
:class="['lm-img', 'light-img', shouldCrop && 'crop']"
|
|
51
|
+
:src="withBase(props.image.light)"
|
|
52
|
+
:width="size ?? undefined"
|
|
53
|
+
:height="size ?? undefined"
|
|
54
|
+
loading="lazy"
|
|
55
|
+
aria-hidden="true"
|
|
56
|
+
alt=""
|
|
57
|
+
data-no-viewer
|
|
58
|
+
v-bind="{ ...imageAttrs, ...$attrs }"
|
|
59
|
+
@error="handleImageError"
|
|
60
|
+
/>
|
|
61
|
+
</template>
|
|
62
|
+
<template v-else>
|
|
63
|
+
<img
|
|
64
|
+
:class="['lm-img', shouldCrop && 'crop']"
|
|
65
|
+
:src="typeof props.image === 'string' ? withBase(props.image) : withBase(props.image.src)"
|
|
66
|
+
:width="size ?? undefined"
|
|
67
|
+
:height="size ?? undefined"
|
|
68
|
+
loading="lazy"
|
|
69
|
+
aria-hidden="true"
|
|
70
|
+
alt=""
|
|
71
|
+
data-no-viewer
|
|
72
|
+
v-bind="typeof props.image === 'string' ? $attrs : { ...imageAttrs, ...$attrs }"
|
|
73
|
+
@error="handleImageError"
|
|
74
|
+
/>
|
|
75
|
+
</template>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<style scoped>
|
|
79
|
+
:root:not(.dark) .dark-img,
|
|
80
|
+
:root:is(.dark) .light-img {
|
|
81
|
+
display: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.lm-img {
|
|
85
|
+
margin: 0;
|
|
86
|
+
border-radius: 0.25em;
|
|
87
|
+
pointer-events: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.lm-img.crop {
|
|
91
|
+
aspect-ratio: 1 / 1;
|
|
92
|
+
object-fit: cover;
|
|
93
|
+
}
|
|
94
|
+
</style>
|