@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.
Files changed (133) hide show
  1. package/License +21 -0
  2. package/components/Aside.vue +130 -0
  3. package/components/BoxCube.vue +89 -0
  4. package/components/Card.vue +111 -0
  5. package/components/CopyText.vue +214 -0
  6. package/components/Footer.vue +194 -0
  7. package/components/Links.vue +121 -0
  8. package/components/Notice.vue +85 -0
  9. package/components/Pill.vue +108 -0
  10. package/components/Underline.vue +22 -0
  11. package/components/common/Icon.vue +67 -0
  12. package/components/common/Image.vue +94 -0
  13. package/components/common/Link.vue +33 -0
  14. package/components/common/Svg.vue +28 -0
  15. package/components/common/index.ts +4 -0
  16. package/components/index.ts +9 -0
  17. package/composables/baiduAnalytics.ts +60 -0
  18. package/composables/googleAnalytics.ts +26 -0
  19. package/composables/index.ts +4 -0
  20. package/composables/umamiAnalytics.ts +49 -0
  21. package/composables/utils.ts +61 -0
  22. package/dist/cjs/_virtual/_plugin-vue_export-helper.cjs +1 -0
  23. package/dist/cjs/components/Aside.cjs +1 -0
  24. package/dist/cjs/components/Aside.vue_vue_type_script_setup_true_lang.cjs +1 -0
  25. package/dist/cjs/components/BoxCube.cjs +1 -0
  26. package/dist/cjs/components/BoxCube.vue_vue_type_script_setup_true_lang.cjs +1 -0
  27. package/dist/cjs/components/Card.cjs +1 -0
  28. package/dist/cjs/components/Card.vue_vue_type_script_setup_true_lang.cjs +1 -0
  29. package/dist/cjs/components/CopyText.cjs +1 -0
  30. package/dist/cjs/components/CopyText.vue_vue_type_script_setup_true_lang.cjs +1 -0
  31. package/dist/cjs/components/Footer.cjs +1 -0
  32. package/dist/cjs/components/Footer.vue_vue_type_script_setup_true_lang.cjs +1 -0
  33. package/dist/cjs/components/Links.cjs +1 -0
  34. package/dist/cjs/components/Links.vue_vue_type_script_setup_true_lang.cjs +1 -0
  35. package/dist/cjs/components/Notice.cjs +1 -0
  36. package/dist/cjs/components/Notice.vue_vue_type_script_setup_true_lang.cjs +1 -0
  37. package/dist/cjs/components/Pill.cjs +1 -0
  38. package/dist/cjs/components/Pill.vue_vue_type_script_setup_true_lang.cjs +1 -0
  39. package/dist/cjs/components/Underline.cjs +1 -0
  40. package/dist/cjs/components/Underline.vue_vue_type_script_setup_true_lang.cjs +1 -0
  41. package/dist/cjs/components/common/Icon.cjs +1 -0
  42. package/dist/cjs/components/common/Icon.vue_vue_type_script_setup_true_lang.cjs +1 -0
  43. package/dist/cjs/components/common/Image.cjs +1 -0
  44. package/dist/cjs/components/common/Image.vue_vue_type_script_setup_true_lang.cjs +1 -0
  45. package/dist/cjs/components/common/Link.cjs +1 -0
  46. package/dist/cjs/components/common/Link.vue_vue_type_script_setup_true_lang.cjs +1 -0
  47. package/dist/cjs/components/common/Svg.cjs +1 -0
  48. package/dist/cjs/composables/baiduAnalytics.cjs +1 -0
  49. package/dist/cjs/composables/googleAnalytics.cjs +1 -0
  50. package/dist/cjs/composables/umamiAnalytics.cjs +1 -0
  51. package/dist/cjs/composables/utils.cjs +1 -0
  52. package/dist/cjs/index.cjs +1 -0
  53. package/dist/cjs/lum.css +2 -0
  54. 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
  55. package/dist/cjs/node_modules/.pnpm/iconify-icon@3.0.5/node_modules/iconify-icon/dist/iconify-icon.cjs +1 -0
  56. package/dist/esm/_virtual/_plugin-vue_export-helper.js +7 -0
  57. package/dist/esm/components/Aside.js +6 -0
  58. package/dist/esm/components/Aside.vue_vue_type_script_setup_true_lang.js +85 -0
  59. package/dist/esm/components/BoxCube.js +6 -0
  60. package/dist/esm/components/BoxCube.vue_vue_type_script_setup_true_lang.js +45 -0
  61. package/dist/esm/components/Card.js +6 -0
  62. package/dist/esm/components/Card.vue_vue_type_script_setup_true_lang.js +50 -0
  63. package/dist/esm/components/CopyText.js +6 -0
  64. package/dist/esm/components/CopyText.vue_vue_type_script_setup_true_lang.js +63 -0
  65. package/dist/esm/components/Footer.js +6 -0
  66. package/dist/esm/components/Footer.vue_vue_type_script_setup_true_lang.js +170 -0
  67. package/dist/esm/components/Links.js +6 -0
  68. package/dist/esm/components/Links.vue_vue_type_script_setup_true_lang.js +59 -0
  69. package/dist/esm/components/Notice.js +6 -0
  70. package/dist/esm/components/Notice.vue_vue_type_script_setup_true_lang.js +61 -0
  71. package/dist/esm/components/Pill.js +6 -0
  72. package/dist/esm/components/Pill.vue_vue_type_script_setup_true_lang.js +51 -0
  73. package/dist/esm/components/Underline.js +6 -0
  74. package/dist/esm/components/Underline.vue_vue_type_script_setup_true_lang.js +13 -0
  75. package/dist/esm/components/common/Icon.js +4 -0
  76. package/dist/esm/components/common/Icon.vue_vue_type_script_setup_true_lang.js +53 -0
  77. package/dist/esm/components/common/Image.js +6 -0
  78. package/dist/esm/components/common/Image.vue_vue_type_script_setup_true_lang.js +79 -0
  79. package/dist/esm/components/common/Link.js +4 -0
  80. package/dist/esm/components/common/Link.vue_vue_type_script_setup_true_lang.js +36 -0
  81. package/dist/esm/components/common/Svg.js +19 -0
  82. package/dist/esm/composables/baiduAnalytics.js +23 -0
  83. package/dist/esm/composables/googleAnalytics.js +12 -0
  84. package/dist/esm/composables/umamiAnalytics.js +12 -0
  85. package/dist/esm/composables/utils.js +24 -0
  86. package/dist/esm/index.js +16 -0
  87. package/dist/esm/lum.css +2 -0
  88. 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
  89. package/dist/esm/node_modules/.pnpm/iconify-icon@3.0.5/node_modules/iconify-icon/dist/iconify-icon.js +1209 -0
  90. package/dist/types/bump.config.d.ts +2 -0
  91. package/dist/types/changelogithub.config.d.ts +26 -0
  92. package/dist/types/components/Aside.vue.d.ts +7 -0
  93. package/dist/types/components/BoxCube.vue.d.ts +8 -0
  94. package/dist/types/components/Card.vue.d.ts +8 -0
  95. package/dist/types/components/CopyText.vue.d.ts +15 -0
  96. package/dist/types/components/Footer.vue.d.ts +7 -0
  97. package/dist/types/components/Links.vue.d.ts +8 -0
  98. package/dist/types/components/Notice.vue.d.ts +3 -0
  99. package/dist/types/components/Pill.vue.d.ts +13 -0
  100. package/dist/types/components/Underline.vue.d.ts +3 -0
  101. package/dist/types/components/common/Icon.vue.d.ts +9 -0
  102. package/dist/types/components/common/Image.vue.d.ts +8 -0
  103. package/dist/types/components/common/Link.vue.d.ts +23 -0
  104. package/dist/types/components/common/Svg.vue.d.ts +3 -0
  105. package/dist/types/components/common/index.d.ts +4 -0
  106. package/dist/types/components/index.d.ts +9 -0
  107. package/dist/types/composables/baiduAnalytics.d.ts +17 -0
  108. package/dist/types/composables/googleAnalytics.d.ts +12 -0
  109. package/dist/types/composables/index.d.ts +4 -0
  110. package/dist/types/composables/umamiAnalytics.d.ts +13 -0
  111. package/dist/types/composables/utils.d.ts +30 -0
  112. package/dist/types/types/index.d.ts +5 -0
  113. package/dist/types/types/types.d.ts +313 -0
  114. package/dist/types/vite.config.d.ts +2 -0
  115. package/package.json +131 -3
  116. package/readme.md +39 -0
  117. package/style/all.css +9 -0
  118. package/style/badge.css +21 -0
  119. package/style/button.css +48 -0
  120. package/style/colors.css +59 -0
  121. package/style/components-var.css +173 -0
  122. package/style/doc-blocks.css +136 -0
  123. package/style/doc.css +17 -0
  124. package/style/home.css +34 -0
  125. package/style/icon.css +11 -0
  126. package/style/picture.css +40 -0
  127. package/tsconfig.json +17 -0
  128. package/types/index.d.ts +3 -0
  129. package/types/index.ts +6 -0
  130. package/types/shims.d.ts +36 -0
  131. package/types/style.d.ts +10 -0
  132. package/types/types.ts +318 -0
  133. 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>