clarity-theme 0.1.0 → 0.1.2

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 (154) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +70 -4
  3. package/README.zh-CN.md +67 -4
  4. package/nuxt.config.ts +217 -214
  5. package/package.json +35 -37
  6. package/{app → src}/app.config.ts +110 -110
  7. package/{app → src}/app.vue +5 -5
  8. package/{app → src}/components/blog/BlogAside.vue +25 -25
  9. package/{app → src}/components/blog/BlogFooter.vue +25 -25
  10. package/{app → src}/components/blog/BlogHeader.global.vue +48 -48
  11. package/{app → src}/components/blog/BlogPanel.vue +43 -43
  12. package/{app → src}/components/blog/BlogSidebar.vue +53 -53
  13. package/{app → src}/components/blog/BlogWidget.vue +42 -42
  14. package/{app → src}/components/blog/Mask.vue +25 -25
  15. package/{app → src}/components/blog/SkipToContent.vue +9 -9
  16. package/{app → src}/components/blog/ThemeToggle.vue +22 -22
  17. package/{app → src}/components/content/Badge.vue +45 -45
  18. package/{app → src}/components/content/Blur.vue +14 -14
  19. package/{app → src}/components/content/CardList.vue +8 -8
  20. package/{app → src}/components/content/Chat.vue +41 -41
  21. package/{app → src}/components/content/Copy.vue +71 -71
  22. package/{app → src}/components/content/EmojiClock.vue +49 -49
  23. package/{app → src}/components/content/FeedCard.vue +96 -96
  24. package/{app → src}/components/content/FeedGroup.vue +61 -61
  25. package/{app → src}/components/content/Folding.vue +19 -19
  26. package/{app → src}/components/content/Key.vue +143 -143
  27. package/{app → src}/components/content/LinkBanner.vue +27 -27
  28. package/{app → src}/components/content/LinkCard.vue +28 -28
  29. package/{app → src}/components/content/MdTitle.vue +8 -8
  30. package/{app → src}/components/content/Mermaid.vue +99 -99
  31. package/{app → src}/components/content/MusicScore.vue +63 -63
  32. package/{app → src}/components/content/Pic.vue +49 -49
  33. package/{app → src}/components/content/Poetry.vue +27 -27
  34. package/{app → src}/components/content/ProseA.vue +24 -24
  35. package/{app → src}/components/content/ProseCode.vue +16 -16
  36. package/{app → src}/components/content/ProsePre.vue +117 -117
  37. package/{app → src}/components/content/ProseTable.vue +23 -23
  38. package/{app → src}/components/content/Quote.vue +21 -21
  39. package/{app → src}/components/content/Tab.vue +32 -32
  40. package/{app → src}/components/content/Timeline.vue +33 -33
  41. package/{app → src}/components/content/Tip.vue +40 -40
  42. package/{app → src}/components/content/VideoEmbed.vue +112 -112
  43. package/{app → src}/components/partial/Button.vue +36 -36
  44. package/{app → src}/components/partial/DlGroup.vue +31 -31
  45. package/{app → src}/components/partial/Dropdown.vue +21 -21
  46. package/{app → src}/components/partial/Error.vue +39 -39
  47. package/{app → src}/components/partial/Expand.vue +26 -26
  48. package/{app → src}/components/partial/IconNavList.vue +24 -24
  49. package/{app → src}/components/partial/Pagination.vue +62 -62
  50. package/{app → src}/components/partial/RadioGroup.vue +30 -30
  51. package/{app → src}/components/partial/Secret.vue +11 -11
  52. package/{app → src}/components/partial/Slider.vue +48 -48
  53. package/{app → src}/components/partial/Toggle.vue +17 -17
  54. package/{app → src}/components/popover/Lightbox.vue +44 -44
  55. package/{app → src}/components/popover/Search.vue +143 -143
  56. package/{app → src}/components/popover/SearchItem.vue +28 -28
  57. package/{app → src}/components/post/Archive.vue +40 -40
  58. package/{app → src}/components/post/Article.vue +49 -49
  59. package/{app → src}/components/post/Comment.vue +119 -119
  60. package/{app → src}/components/post/Excerpt.vue +40 -40
  61. package/{app → src}/components/post/OrderToggle.vue +70 -70
  62. package/{app → src}/components/post/PostFooter.vue +52 -52
  63. package/{app → src}/components/post/PostHeader.vue +66 -66
  64. package/{app → src}/components/post/PostSurround.vue +51 -51
  65. package/{app → src}/components/post/Slide.vue +85 -85
  66. package/{app → src}/components/util/Date.vue +62 -62
  67. package/{app → src}/components/util/HydrateSafe.vue +10 -10
  68. package/{app → src}/components/util/Img.vue +38 -38
  69. package/{app → src}/components/util/Link.vue +11 -11
  70. package/{app → src}/components/widget/BlogLog.vue +23 -23
  71. package/{app → src}/components/widget/BlogStats.vue +38 -38
  72. package/{app → src}/components/widget/BlogTech.vue +57 -57
  73. package/{app → src}/components/widget/Empty.vue +3 -3
  74. package/{app → src}/components/widget/Toc.vue +67 -67
  75. package/{app → src}/composables/useArticle.ts +115 -115
  76. package/{app → src}/composables/useAvoid.ts +87 -87
  77. package/{app → src}/composables/useCopy.ts +21 -21
  78. package/{app → src}/composables/usePagination.ts +70 -70
  79. package/{app → src}/composables/useShiki.ts +129 -129
  80. package/{app → src}/composables/useToc.ts +57 -57
  81. package/{app → src}/composables/useWidgets.ts +56 -56
  82. package/{config → src/config}/app.ts +62 -62
  83. package/{config → src/config}/content.ts +75 -75
  84. package/{config → src/config}/define.ts +3 -3
  85. package/src/config/feeds.empty.ts +6 -0
  86. package/{config → src/config}/index.ts +1 -1
  87. package/{config → src/config}/schema.ts +89 -89
  88. package/{app → src}/error.vue +31 -31
  89. package/{img → src/img}/index.ts +2 -2
  90. package/{app → src}/layouts/default.vue +25 -25
  91. package/{modules → src/modules}/clarity-config/index.ts +168 -162
  92. package/src/modules/clarity-source-layout/index.ts +78 -0
  93. package/{app → src}/pages/[...slug].vue +59 -59
  94. package/{app → src}/pages/archive.vue +129 -129
  95. package/{app → src}/pages/index.vue +76 -76
  96. package/{app → src}/pages/link.vue +62 -62
  97. package/{app → src}/pages/preview.vue +46 -46
  98. package/{app → src}/plugins/easter-egg.ts +23 -23
  99. package/{app → src}/plugins/init.ts +6 -6
  100. package/{app → src}/plugins/tippy.ts +22 -22
  101. package/{public → src/public}/assets/atom.css +274 -274
  102. package/{public → src/public}/assets/atom.xsl +109 -109
  103. package/{remark-plugins → src/remark-plugins}/rehype-meta-slots.ts +58 -58
  104. package/{remark-plugins → src/remark-plugins}/remark-code-component.ts +41 -41
  105. package/{server → src/server}/api/stats.get.ts +84 -83
  106. package/{server → src/server}/routes/atom.xml.get.ts +85 -85
  107. package/{server → src/server}/routes/subscriptions.opml.get.ts +64 -64
  108. package/{shared → src/shared}/utils/clarity.ts +24 -24
  109. package/{shared → src/shared}/utils/icon.ts +218 -218
  110. package/{shared → src/shared}/utils/link.ts +52 -52
  111. package/{shared → src/shared}/utils/str.ts +88 -88
  112. package/{shared → src/shared}/utils/time.ts +115 -115
  113. package/{app → src}/shiki.config.ts +8 -8
  114. package/{app → src}/stores/layout.ts +34 -34
  115. package/{app → src}/stores/search.ts +37 -37
  116. package/{app → src}/types/article.ts +16 -16
  117. package/src/types/feed.ts +1 -0
  118. package/{app → src}/types/index.ts +14 -14
  119. package/{app → src}/types/nav.ts +11 -11
  120. package/{app → src}/utils/anim.ts +37 -37
  121. package/{app → src}/utils/img.ts +83 -83
  122. package/app/types/feed.ts +0 -1
  123. package/config/feeds.empty.ts +0 -4
  124. package/{app → src}/assets/css/_variable.scss +0 -0
  125. package/{app → src}/assets/css/animation.scss +0 -0
  126. package/{app → src}/assets/css/article.scss +0 -0
  127. package/{app → src}/assets/css/color.scss +0 -0
  128. package/{app → src}/assets/css/font.scss +0 -0
  129. package/{app → src}/assets/css/main.scss +0 -0
  130. package/{app → src}/assets/css/reusable.scss +0 -0
  131. package/{app → src}/assets/icons/solar-rewind-back-bold-duotone.svg +0 -0
  132. package/{app → src}/assets/icons/solar-rewind-forward-bold-duotone.svg +0 -0
  133. package/{app → src}/components/content/Alert.vue +0 -0
  134. package/{config → src/config}/content.d.mts +0 -0
  135. package/{config → src/config}/content.mjs +0 -0
  136. package/{config → src/config}/define.mjs +0 -0
  137. package/{config → src/config}/feed.ts +0 -0
  138. package/{config → src/config}/index.d.mts +0 -0
  139. package/{config → src/config}/index.mjs +0 -0
  140. package/{config → src/config}/public.ts +1 -1
  141. package/{config → src/config}/schema.d.mts +0 -0
  142. package/{config → src/config}/schema.mjs +0 -0
  143. package/{config → src/config}/server.ts +1 -1
  144. /package/{img → src/img}/index.d.mts +0 -0
  145. /package/{img → src/img}/index.mjs +0 -0
  146. /package/{modules → src/modules}/clarity-config/anti-mirror-client.ts +0 -0
  147. /package/{public → src/public}/fonts/AlimamaFangYuanTi.woff2 +0 -0
  148. /package/{remark-plugins → src/remark-plugins}/rehype-meta-slots.d.mts +0 -0
  149. /package/{remark-plugins → src/remark-plugins}/rehype-meta-slots.mjs +0 -0
  150. /package/{remark-plugins → src/remark-plugins}/remark-code-component.d.mts +0 -0
  151. /package/{remark-plugins → src/remark-plugins}/remark-code-component.mjs +0 -0
  152. /package/{server → src/server}/utils/clarity.ts +0 -0
  153. /package/{shared → src/shared}/types/content.ts +0 -0
  154. /package/{app → src}/types/modal.ts +0 -0
@@ -1,51 +1,51 @@
1
- <script setup lang="ts">
2
- import type { ArticleProps } from '../../types/article'
3
-
4
- const props = defineProps<{ useUpdated?: boolean } & ArticleProps>()
5
- const showAllDate = isTimeDiffSignificant(props.date, props.updated)
6
- </script>
7
-
8
- <template>
9
- <UtilLink class="article-card card upraise">
10
- <NuxtImg v-if="image" class="article-cover" :src="image" :alt="title" />
11
- <article>
12
- <h2 class="article-title text-creative">
13
- {{ title }}
14
- </h2>
15
-
16
- <p v-if="description" class="article-description">
17
- {{ description }}
18
- </p>
19
-
20
- <div class="article-info">
21
- <UtilDate
22
- v-if="date && (showAllDate || !useUpdated)"
23
- :date
24
- icon="tabler:pencil-minus"
25
- />
26
-
27
- <UtilDate
28
- v-if="updated && (showAllDate || useUpdated)"
29
- :class="{ 'use-updated': useUpdated }"
30
- :date="updated"
31
- icon="tabler:clock-edit"
32
- />
33
-
34
- <span v-if="categories" :style="{ color: getCategoryColor(categories[0]) }">
35
- <Icon :name="getCategoryIcon(categories[0])" />
36
- {{ categories[0] }}
37
- </span>
38
-
39
- <span v-if="readingTime?.words" class="article-words">
40
- <Icon name="tabler:pilcrow" />
41
- {{ formatNumber(readingTime?.words) }}字
42
- </span>
43
- </div>
44
- </article>
45
- </UtilLink>
46
- </template>
47
-
48
- <style lang="scss" scoped>
1
+ <script setup lang="ts">
2
+ import type { ArticleProps } from '../../types/article'
3
+
4
+ const props = defineProps<{ useUpdated?: boolean } & ArticleProps>()
5
+ const showAllDate = isTimeDiffSignificant(props.date, props.updated)
6
+ </script>
7
+
8
+ <template>
9
+ <UtilLink class="article-card card upraise">
10
+ <NuxtImg v-if="image" class="article-cover" :src="image" :alt="title" />
11
+ <article>
12
+ <h2 class="article-title text-creative">
13
+ {{ title }}
14
+ </h2>
15
+
16
+ <p v-if="description" class="article-description">
17
+ {{ description }}
18
+ </p>
19
+
20
+ <div class="article-info">
21
+ <UtilDate
22
+ v-if="date && (showAllDate || !useUpdated)"
23
+ :date
24
+ icon="tabler:pencil-minus"
25
+ />
26
+
27
+ <UtilDate
28
+ v-if="updated && (showAllDate || useUpdated)"
29
+ :class="{ 'use-updated': useUpdated }"
30
+ :date="updated"
31
+ icon="tabler:clock-edit"
32
+ />
33
+
34
+ <span v-if="categories" :style="{ color: getCategoryColor(categories[0]) }">
35
+ <Icon :name="getCategoryIcon(categories[0])" />
36
+ {{ categories[0] }}
37
+ </span>
38
+
39
+ <span v-if="readingTime?.words" class="article-words">
40
+ <Icon name="tabler:pilcrow" />
41
+ {{ formatNumber(readingTime?.words) }}字
42
+ </span>
43
+ </div>
44
+ </article>
45
+ </UtilLink>
46
+ </template>
47
+
48
+ <style lang="scss" scoped>
49
49
  .article-card {
50
50
  container-type: inline-size;
51
51
  position: relative;
@@ -135,4 +135,4 @@ const showAllDate = isTimeDiffSignificant(props.date, props.updated)
135
135
  @include cover-narrow;
136
136
  }
137
137
  }
138
- </style>
138
+ </style>
@@ -1,123 +1,123 @@
1
- <script setup lang="tsx">
2
- import type { TippyComponent } from 'vue-tippy'
3
-
4
- const clarity = useClarityConfig()
5
- const enabled = computed(() => !!clarity.integrations.twikoo?.envId)
6
-
7
- const commentEl = useTemplateRef('comment')
8
- const popoverEl = useTemplateRef<TippyComponent>('popover')
9
- const popoverJumpTo = ref('')
10
- const popoverInputEl = useTemplateRef('popover-input')
11
- const showUndo = ref(false)
12
-
13
- const popoverBind = ref<TippyComponent['$props']>({})
14
-
15
- /** 评论区链接守卫 */
16
- useEventListener(commentEl, 'click', (e) => {
17
- if (!(e.target instanceof Element))
18
- return
19
-
20
- if (e.target.matches('.tk-avatar-img'))
21
- e.stopPropagation()
22
-
23
- const popoverTarget = e.target.closest('a[target="_blank"]')
24
- if (!(popoverTarget instanceof HTMLAnchorElement))
25
- return
26
-
27
- e.preventDefault()
28
- popoverEl.value?.hide()
29
-
30
- popoverJumpTo.value = safelyDecodeUriComponent(popoverTarget.href)
31
- popoverBind.value = {
32
- getReferenceClientRect: () => popoverTarget.getBoundingClientRect(),
33
- triggerTarget: popoverTarget,
34
- }
35
-
36
- nextTick(checkUndoable)
37
- popoverEl.value?.show()
38
- }, { capture: true })
39
-
40
- function checkUndoable() {
41
- showUndo.value = popoverInputEl.value?.textContent !== popoverJumpTo.value
42
- }
43
-
44
- function undo() {
45
- if (!popoverInputEl.value)
46
- return
47
- popoverInputEl.value.textContent = popoverJumpTo.value
48
- checkUndoable()
49
- }
50
-
51
- function confirmOpen() {
52
- window.open(popoverInputEl.value?.textContent, '_blank')
53
- }
54
-
55
- onMounted(() => {
56
- if (!enabled.value)
57
- return
58
-
1
+ <script setup lang="tsx">
2
+ import type { TippyComponent } from 'vue-tippy'
3
+
4
+ const clarity = useClarityConfig()
5
+ const enabled = computed(() => !!clarity.integrations.twikoo?.envId)
6
+
7
+ const commentEl = useTemplateRef('comment')
8
+ const popoverEl = useTemplateRef<TippyComponent>('popover')
9
+ const popoverJumpTo = ref('')
10
+ const popoverInputEl = useTemplateRef('popover-input')
11
+ const showUndo = ref(false)
12
+
13
+ const popoverBind = ref<TippyComponent['$props']>({})
14
+
15
+ /** 评论区链接守卫 */
16
+ useEventListener(commentEl, 'click', (e) => {
17
+ if (!(e.target instanceof Element))
18
+ return
19
+
20
+ if (e.target.matches('.tk-avatar-img'))
21
+ e.stopPropagation()
22
+
23
+ const popoverTarget = e.target.closest('a[target="_blank"]')
24
+ if (!(popoverTarget instanceof HTMLAnchorElement))
25
+ return
26
+
27
+ e.preventDefault()
28
+ popoverEl.value?.hide()
29
+
30
+ popoverJumpTo.value = safelyDecodeUriComponent(popoverTarget.href)
31
+ popoverBind.value = {
32
+ getReferenceClientRect: () => popoverTarget.getBoundingClientRect(),
33
+ triggerTarget: popoverTarget,
34
+ }
35
+
36
+ nextTick(checkUndoable)
37
+ popoverEl.value?.show()
38
+ }, { capture: true })
39
+
40
+ function checkUndoable() {
41
+ showUndo.value = popoverInputEl.value?.textContent !== popoverJumpTo.value
42
+ }
43
+
44
+ function undo() {
45
+ if (!popoverInputEl.value)
46
+ return
47
+ popoverInputEl.value.textContent = popoverJumpTo.value
48
+ checkUndoable()
49
+ }
50
+
51
+ function confirmOpen() {
52
+ window.open(popoverInputEl.value?.textContent, '_blank')
53
+ }
54
+
55
+ onMounted(() => {
56
+ if (!enabled.value)
57
+ return
58
+
59
59
  window.twikoo?.init?.({
60
60
  envId: clarity.integrations.twikoo?.envId ?? '',
61
- // twikoo 会把挂载后的元素变为 #twikoo
62
- el: '#twikoo',
63
- })
64
- })
65
- </script>
66
-
67
- <template>
68
- <section ref="comment" class="z-comment">
69
- <h3 class="text-creative">
70
- 评论区
71
- </h3>
72
-
73
- <!-- interactive 默认会把气泡移动到 triggerTarget 的父元素上 -->
74
- <Tooltip
75
- ref="popover"
76
- v-bind="popoverBind"
77
- :append-to="() => commentEl!"
78
- interactive
79
- :aria="{ expanded: false }"
80
- trigger="focusin"
81
- >
82
- <template #content>
83
- <div class="popover-confirm">
84
- <span
85
- ref="popover-input"
86
- class="input"
87
- contenteditable="plaintext-only"
88
- spellcheck="false"
89
- @input="checkUndoable"
90
- @keydown.enter.prevent="confirmOpen"
91
- v-text="popoverJumpTo"
92
- />
93
-
94
- <button
95
- v-if="showUndo"
96
- aria-label="恢复原始内容"
97
- @click="undo()"
98
- >
99
- <Icon name="tabler:arrow-back-up" />
100
- </button>
101
-
102
- <ZButton
103
- primary
104
- text="访问"
105
- @click="confirmOpen"
106
- />
107
- </div>
108
- </template>
109
- </Tooltip>
110
-
111
- <div v-if="enabled" id="twikoo">
112
- <p>评论加载中...</p>
113
- </div>
114
- <p v-else class="no-comment">
115
- 本文暂未开启评论
116
- </p>
117
- </section>
118
- </template>
119
-
120
- <style lang="scss" scoped>
61
+ // twikoo 会把挂载后的元素变为 #twikoo
62
+ el: '#twikoo',
63
+ })
64
+ })
65
+ </script>
66
+
67
+ <template>
68
+ <section ref="comment" class="z-comment">
69
+ <h3 class="text-creative">
70
+ 评论区
71
+ </h3>
72
+
73
+ <!-- interactive 默认会把气泡移动到 triggerTarget 的父元素上 -->
74
+ <Tooltip
75
+ ref="popover"
76
+ v-bind="popoverBind"
77
+ :append-to="() => commentEl!"
78
+ interactive
79
+ :aria="{ expanded: false }"
80
+ trigger="focusin"
81
+ >
82
+ <template #content>
83
+ <div class="popover-confirm">
84
+ <span
85
+ ref="popover-input"
86
+ class="input"
87
+ contenteditable="plaintext-only"
88
+ spellcheck="false"
89
+ @input="checkUndoable"
90
+ @keydown.enter.prevent="confirmOpen"
91
+ v-text="popoverJumpTo"
92
+ />
93
+
94
+ <button
95
+ v-if="showUndo"
96
+ aria-label="恢复原始内容"
97
+ @click="undo()"
98
+ >
99
+ <Icon name="tabler:arrow-back-up" />
100
+ </button>
101
+
102
+ <ZButton
103
+ primary
104
+ text="访问"
105
+ @click="confirmOpen"
106
+ />
107
+ </div>
108
+ </template>
109
+ </Tooltip>
110
+
111
+ <div v-if="enabled" id="twikoo">
112
+ <p>评论加载中...</p>
113
+ </div>
114
+ <p v-else class="no-comment">
115
+ 本文暂未开启评论
116
+ </p>
117
+ </section>
118
+ </template>
119
+
120
+ <style lang="scss" scoped>
121
121
  .z-comment {
122
122
  margin: 3rem 1rem;
123
123
 
@@ -272,4 +272,4 @@ onMounted(() => {
272
272
  font-size: 0.9em;
273
273
  }
274
274
  }
275
- </style>
275
+ </style>
@@ -1,42 +1,42 @@
1
- <script setup lang="ts">
2
- import { delay } from 'es-toolkit/promise'
3
-
4
- const props = defineProps<{
5
- excerpt: string
6
- }>()
7
-
8
- const clarity = useClarityConfig()
9
-
10
- const excerpt = ref(props.excerpt)
11
- const caret = ref('')
12
-
13
- if (clarity.component.excerpt?.animation !== false) {
14
- excerpt.value = ''
15
- onMounted(async () => {
16
- caret.value = clarity.component.excerpt?.caret ?? '_'
17
- for (const char of props.excerpt) {
18
- excerpt.value += char
19
- await delay(50)
20
- }
21
- caret.value = ''
22
- })
23
- }
24
-
25
- if (import.meta.dev) {
26
- watch(() => props.excerpt, (newExcerpt) => {
27
- excerpt.value = newExcerpt
28
- })
29
- }
30
- </script>
31
-
32
- <template>
33
- <div class="md-excerpt gradient-card">
34
- <span class="dynamic"><Icon name="tabler:sparkles-2" />{{ excerpt }}{{ caret }}</span>
35
- <span class="static"><Icon name="tabler:sparkles-2" />{{ props.excerpt }}</span>
36
- </div>
37
- </template>
38
-
39
- <style lang="scss" scoped>
1
+ <script setup lang="ts">
2
+ import { delay } from 'es-toolkit/promise'
3
+
4
+ const props = defineProps<{
5
+ excerpt: string
6
+ }>()
7
+
8
+ const clarity = useClarityConfig()
9
+
10
+ const excerpt = ref(props.excerpt)
11
+ const caret = ref('')
12
+
13
+ if (clarity.component.excerpt?.animation !== false) {
14
+ excerpt.value = ''
15
+ onMounted(async () => {
16
+ caret.value = clarity.component.excerpt?.caret ?? '_'
17
+ for (const char of props.excerpt) {
18
+ excerpt.value += char
19
+ await delay(50)
20
+ }
21
+ caret.value = ''
22
+ })
23
+ }
24
+
25
+ if (import.meta.dev) {
26
+ watch(() => props.excerpt, (newExcerpt) => {
27
+ excerpt.value = newExcerpt
28
+ })
29
+ }
30
+ </script>
31
+
32
+ <template>
33
+ <div class="md-excerpt gradient-card">
34
+ <span class="dynamic"><Icon name="tabler:sparkles-2" />{{ excerpt }}{{ caret }}</span>
35
+ <span class="static"><Icon name="tabler:sparkles-2" />{{ props.excerpt }}</span>
36
+ </div>
37
+ </template>
38
+
39
+ <style lang="scss" scoped>
40
40
  .md-excerpt {
41
41
  opacity: 0.6;
42
42
  margin: 1rem 0.5rem;
@@ -63,4 +63,4 @@ if (import.meta.dev) {
63
63
  opacity: 1;
64
64
  }
65
65
  }
66
- </style>
66
+ </style>
@@ -1,72 +1,72 @@
1
- <script setup lang="ts">
2
- import type { ArticleOrderType } from '../../types/article'
3
-
4
- const props = defineProps<{
5
- // 强制允许或禁止升序
6
- enableAscending?: boolean
7
- disableAscending?: boolean
8
- categories?: (string | undefined)[]
9
- secretDelay?: string
10
- }>()
11
-
12
- const clarity = useClarityConfig()
13
- const orderMap = computed(() => clarity.article.order)
14
- // 配置文件中允许升序时,且未明确禁用升序时,允许升序
15
- const allowAscending = computed(() => clarity.pagination.allowAscending ? !props.disableAscending : props.enableAscending)
16
-
17
- const category = defineModel<string>('category')
18
- const sortOrder = defineModel<ArticleOrderType>('sortOrder', { default: 'date' })
19
- const isAscending = defineModel<boolean>('isAscending')
20
-
21
- function toggleOrder() {
22
- const orderKeys = Object.keys(orderMap.value) as (ArticleOrderType)[]
23
- sortOrder.value = orderKeys[(orderKeys.indexOf(sortOrder.value) + 1) % orderKeys.length] || 'date'
24
- }
25
-
26
- function toggleDirection() {
27
- if (!allowAscending.value)
28
- return
29
- isAscending.value = !isAscending.value
30
- }
31
- </script>
32
-
33
- <template>
34
- <div class="order-toggle" :style="{ '--secret-delay': secretDelay }">
35
- <slot />
36
-
37
- <ZDropdown trigger="focusin" tabindex="0">
38
- <button :disabled="!categories">
39
- <Icon :name="getCategoryIcon(category)" />
40
- <span class="order-text">{{ category ?? '全部分类' }}</span>
41
- </button>
42
-
43
- <template #content="{ hide }">
44
- <button :class="{ active: !category }" @click="hide(), category = undefined">
45
- <Icon :name="getCategoryIcon()" />
46
- <span>全部分类</span>
47
- </button>
48
-
49
- <button v-for="item in categories" :key="item" :class="{ active: item === category }" @click="hide(), category = item">
50
- <Icon :name="getCategoryIcon(item)" />
51
- <span>{{ item }}</span>
52
- </button>
53
- </template>
54
- </ZDropdown>
55
-
56
- <span>
57
- <button v-if="allowAscending" aria-label="切换排序方向" @click="toggleDirection">
58
- <Icon name="tabler:sort-descending" class="toggle-direction" :class="{ ascending: isAscending }" />
59
- </button>
60
-
61
- <button @click="toggleOrder">
62
- <Icon v-if="!allowAscending" name="tabler:sort-descending" />
63
- <span class="order-text">{{ orderMap[sortOrder] || sortOrder }}</span>
64
- </button>
65
- </span>
66
- </div>
67
- </template>
68
-
69
- <style lang="scss" scoped>
1
+ <script setup lang="ts">
2
+ import type { ArticleOrderType } from '../../types/article'
3
+
4
+ const props = defineProps<{
5
+ // 强制允许或禁止升序
6
+ enableAscending?: boolean
7
+ disableAscending?: boolean
8
+ categories?: (string | undefined)[]
9
+ secretDelay?: string
10
+ }>()
11
+
12
+ const clarity = useClarityConfig()
13
+ const orderMap = computed(() => clarity.article.order)
14
+ // 配置文件中允许升序时,且未明确禁用升序时,允许升序
15
+ const allowAscending = computed(() => clarity.pagination.allowAscending ? !props.disableAscending : props.enableAscending)
16
+
17
+ const category = defineModel<string>('category')
18
+ const sortOrder = defineModel<ArticleOrderType>('sortOrder', { default: 'date' })
19
+ const isAscending = defineModel<boolean>('isAscending')
20
+
21
+ function toggleOrder() {
22
+ const orderKeys = Object.keys(orderMap.value) as (ArticleOrderType)[]
23
+ sortOrder.value = orderKeys[(orderKeys.indexOf(sortOrder.value) + 1) % orderKeys.length] || 'date'
24
+ }
25
+
26
+ function toggleDirection() {
27
+ if (!allowAscending.value)
28
+ return
29
+ isAscending.value = !isAscending.value
30
+ }
31
+ </script>
32
+
33
+ <template>
34
+ <div class="order-toggle" :style="{ '--secret-delay': secretDelay }">
35
+ <slot />
36
+
37
+ <ZDropdown trigger="focusin" tabindex="0">
38
+ <button :disabled="!categories">
39
+ <Icon :name="getCategoryIcon(category)" />
40
+ <span class="order-text">{{ category ?? '全部分类' }}</span>
41
+ </button>
42
+
43
+ <template #content="{ hide }">
44
+ <button :class="{ active: !category }" @click="hide(), category = undefined">
45
+ <Icon :name="getCategoryIcon()" />
46
+ <span>全部分类</span>
47
+ </button>
48
+
49
+ <button v-for="item in categories" :key="item" :class="{ active: item === category }" @click="hide(), category = item">
50
+ <Icon :name="getCategoryIcon(item)" />
51
+ <span>{{ item }}</span>
52
+ </button>
53
+ </template>
54
+ </ZDropdown>
55
+
56
+ <span>
57
+ <button v-if="allowAscending" aria-label="切换排序方向" @click="toggleDirection">
58
+ <Icon name="tabler:sort-descending" class="toggle-direction" :class="{ ascending: isAscending }" />
59
+ </button>
60
+
61
+ <button @click="toggleOrder">
62
+ <Icon v-if="!allowAscending" name="tabler:sort-descending" />
63
+ <span class="order-text">{{ orderMap[sortOrder] || sortOrder }}</span>
64
+ </button>
65
+ </span>
66
+ </div>
67
+ </template>
68
+
69
+ <style lang="scss" scoped>
70
70
  .order-toggle {
71
71
  display: flex;
72
72
  gap: 1rem;
@@ -98,4 +98,4 @@ function toggleDirection() {
98
98
  .iconify + span {
99
99
  margin-inline-start: 0.2em;
100
100
  }
101
- </style>
101
+ </style>