clarity-theme 0.1.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/README.md +276 -0
- package/README.zh-CN.md +297 -0
- package/app/app.config.ts +110 -0
- package/app/app.vue +5 -0
- package/app/assets/css/_variable.scss +8 -0
- package/app/assets/css/animation.scss +50 -0
- package/app/assets/css/article.scss +152 -0
- package/app/assets/css/color.scss +58 -0
- package/app/assets/css/font.scss +35 -0
- package/app/assets/css/main.scss +230 -0
- package/app/assets/css/reusable.scss +186 -0
- package/app/assets/icons/solar-rewind-back-bold-duotone.svg +1 -0
- package/app/assets/icons/solar-rewind-forward-bold-duotone.svg +1 -0
- package/app/components/blog/BlogAside.vue +63 -0
- package/app/components/blog/BlogFooter.vue +61 -0
- package/app/components/blog/BlogHeader.global.vue +146 -0
- package/app/components/blog/BlogPanel.vue +79 -0
- package/app/components/blog/BlogSidebar.vue +160 -0
- package/app/components/blog/BlogWidget.vue +134 -0
- package/app/components/blog/Mask.vue +42 -0
- package/app/components/blog/SkipToContent.vue +22 -0
- package/app/components/blog/ThemeToggle.vue +50 -0
- package/app/components/content/Alert.vue +96 -0
- package/app/components/content/Badge.vue +90 -0
- package/app/components/content/Blur.vue +22 -0
- package/app/components/content/CardList.vue +32 -0
- package/app/components/content/Chat.vue +79 -0
- package/app/components/content/Copy.vue +134 -0
- package/app/components/content/EmojiClock.vue +53 -0
- package/app/components/content/FeedCard.vue +212 -0
- package/app/components/content/FeedGroup.vue +130 -0
- package/app/components/content/Folding.vue +69 -0
- package/app/components/content/Key.vue +164 -0
- package/app/components/content/LinkBanner.vue +59 -0
- package/app/components/content/LinkCard.vue +74 -0
- package/app/components/content/MdTitle.vue +26 -0
- package/app/components/content/Mermaid.vue +133 -0
- package/app/components/content/MusicScore.vue +178 -0
- package/app/components/content/Pic.vue +55 -0
- package/app/components/content/Poetry.vue +41 -0
- package/app/components/content/ProseA.vue +40 -0
- package/app/components/content/ProseCode.vue +95 -0
- package/app/components/content/ProsePre.vue +291 -0
- package/app/components/content/ProseTable.vue +70 -0
- package/app/components/content/Quote.vue +51 -0
- package/app/components/content/Tab.vue +100 -0
- package/app/components/content/Timeline.vue +73 -0
- package/app/components/content/Tip.vue +52 -0
- package/app/components/content/VideoEmbed.vue +127 -0
- package/app/components/partial/Button.vue +98 -0
- package/app/components/partial/DlGroup.vue +69 -0
- package/app/components/partial/Dropdown.vue +54 -0
- package/app/components/partial/Error.vue +70 -0
- package/app/components/partial/Expand.vue +51 -0
- package/app/components/partial/IconNavList.vue +42 -0
- package/app/components/partial/Pagination.vue +113 -0
- package/app/components/partial/RadioGroup.vue +77 -0
- package/app/components/partial/Secret.vue +23 -0
- package/app/components/partial/Slider.vue +96 -0
- package/app/components/partial/Toggle.vue +70 -0
- package/app/components/popover/Lightbox.vue +77 -0
- package/app/components/popover/Search.vue +214 -0
- package/app/components/popover/SearchItem.vue +64 -0
- package/app/components/post/Archive.vue +104 -0
- package/app/components/post/Article.vue +138 -0
- package/app/components/post/Comment.vue +275 -0
- package/app/components/post/Excerpt.vue +66 -0
- package/app/components/post/OrderToggle.vue +101 -0
- package/app/components/post/PostFooter.vue +80 -0
- package/app/components/post/PostHeader.vue +147 -0
- package/app/components/post/PostSurround.vue +111 -0
- package/app/components/post/Slide.vue +215 -0
- package/app/components/util/Date.vue +62 -0
- package/app/components/util/HydrateSafe.vue +10 -0
- package/app/components/util/Img.vue +38 -0
- package/app/components/util/Link.vue +11 -0
- package/app/components/widget/BlogLog.vue +27 -0
- package/app/components/widget/BlogStats.vue +39 -0
- package/app/components/widget/BlogTech.vue +65 -0
- package/app/components/widget/Empty.vue +3 -0
- package/app/components/widget/Toc.vue +129 -0
- package/app/composables/useArticle.ts +118 -0
- package/app/composables/useAvoid.ts +87 -0
- package/app/composables/useCopy.ts +21 -0
- package/app/composables/usePagination.ts +70 -0
- package/app/composables/useShiki.ts +129 -0
- package/app/composables/useToc.ts +57 -0
- package/app/composables/useWidgets.ts +56 -0
- package/app/error.vue +34 -0
- package/app/layouts/default.vue +66 -0
- package/app/pages/[...slug].vue +59 -0
- package/app/pages/archive.vue +207 -0
- package/app/pages/index.vue +83 -0
- package/app/pages/link.vue +65 -0
- package/app/pages/preview.vue +59 -0
- package/app/plugins/easter-egg.ts +23 -0
- package/app/plugins/init.ts +6 -0
- package/app/plugins/tippy.ts +22 -0
- package/app/shiki.config.ts +8 -0
- package/app/stores/layout.ts +34 -0
- package/app/stores/search.ts +37 -0
- package/app/types/article.ts +16 -0
- package/app/types/feed.ts +1 -0
- package/app/types/index.ts +14 -0
- package/app/types/modal.ts +16 -0
- package/app/types/nav.ts +11 -0
- package/app/utils/anim.ts +37 -0
- package/app/utils/img.ts +83 -0
- package/config/app.ts +88 -0
- package/config/content.d.mts +1 -0
- package/config/content.mjs +69 -0
- package/config/content.ts +91 -0
- package/config/define.mjs +21 -0
- package/config/define.ts +23 -0
- package/config/feed.ts +42 -0
- package/config/feeds.empty.ts +4 -0
- package/config/index.d.mts +1 -0
- package/config/index.mjs +6 -0
- package/config/index.ts +6 -0
- package/config/public.ts +71 -0
- package/config/schema.d.mts +1 -0
- package/config/schema.mjs +103 -0
- package/config/schema.ts +129 -0
- package/config/server.ts +35 -0
- package/img/index.d.mts +1 -0
- package/img/index.mjs +78 -0
- package/img/index.ts +8 -0
- package/modules/clarity-config/anti-mirror-client.ts +11 -0
- package/modules/clarity-config/index.ts +324 -0
- package/nuxt.config.ts +225 -0
- package/package.json +148 -0
- package/public/assets/atom.css +274 -0
- package/public/assets/atom.xsl +110 -0
- package/public/fonts/AlimamaFangYuanTi.woff2 +0 -0
- package/remark-plugins/rehype-meta-slots.d.mts +1 -0
- package/remark-plugins/rehype-meta-slots.mjs +49 -0
- package/remark-plugins/rehype-meta-slots.ts +58 -0
- package/remark-plugins/remark-code-component.d.mts +1 -0
- package/remark-plugins/remark-code-component.mjs +25 -0
- package/remark-plugins/remark-code-component.ts +41 -0
- package/server/api/stats.get.ts +109 -0
- package/server/routes/atom.xml.get.ts +101 -0
- package/server/routes/subscriptions.opml.get.ts +70 -0
- package/server/utils/clarity.ts +11 -0
- package/shared/types/content.ts +30 -0
- package/shared/utils/clarity.ts +34 -0
- package/shared/utils/icon.ts +218 -0
- package/shared/utils/link.ts +52 -0
- package/shared/utils/str.ts +88 -0
- package/shared/utils/time.ts +116 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Temporal } from 'temporal-polyfill'
|
|
2
|
+
|
|
3
|
+
export function isSameUnit(date1: string, date2: string, unit: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second', timeZone = 'UTC') {
|
|
4
|
+
try {
|
|
5
|
+
const p1 = toZonedTemporal(date1, timeZone).toPlainDateTime()
|
|
6
|
+
const p2 = toZonedTemporal(date2, timeZone).toPlainDateTime()
|
|
7
|
+
return p1.until(p2, {
|
|
8
|
+
largestUnit: unit,
|
|
9
|
+
smallestUnit: unit,
|
|
10
|
+
roundingMode: 'trunc',
|
|
11
|
+
}).blank
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 检查两个时间相对现在是否相差显著 */
|
|
19
|
+
export function isTimeDiffSignificant(
|
|
20
|
+
date1?: string,
|
|
21
|
+
date2?: string,
|
|
22
|
+
timeZone = 'UTC',
|
|
23
|
+
/** 对于时间差的敏感程度,0~1 之间,1:不同则认为显著,>1:始终认为显著 */
|
|
24
|
+
threshold = 0.6,
|
|
25
|
+
) {
|
|
26
|
+
if (!date1 || !date2 || threshold <= 0)
|
|
27
|
+
return false
|
|
28
|
+
if (threshold > 1)
|
|
29
|
+
return true
|
|
30
|
+
try {
|
|
31
|
+
const now = Temporal.Now.instant().epochMilliseconds
|
|
32
|
+
const diff1 = now - toZonedTemporal(date1, timeZone).epochMilliseconds
|
|
33
|
+
const diff2 = now - toZonedTemporal(date2, timeZone).epochMilliseconds
|
|
34
|
+
return diff1 / diff2 < threshold || diff2 / diff1 < threshold
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const timeIntervals = [
|
|
42
|
+
{ label: '世纪', threshold: 60 * 60 * 24 * 365.2422 * 100 },
|
|
43
|
+
{ label: '年', threshold: 60 * 60 * 24 * 365.2422 },
|
|
44
|
+
{ label: '个月', threshold: 60 * 60 * 24 * 30.44 },
|
|
45
|
+
{ label: '天', threshold: 60 * 60 * 24 },
|
|
46
|
+
{ label: '小时', threshold: 60 * 60 },
|
|
47
|
+
{ label: '分', threshold: 60 },
|
|
48
|
+
{ label: '秒', threshold: 1 },
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
export function timeElapse(date: string | Temporal.PlainDateTime, maxDepth = 2) {
|
|
52
|
+
let timeString = ''
|
|
53
|
+
let secRemained = Temporal.Now.plainDateTimeISO().since(date, { largestUnit: 'second' }).seconds
|
|
54
|
+
for (const interval of timeIntervals) {
|
|
55
|
+
const count = Math.floor(secRemained / interval.threshold)
|
|
56
|
+
if (count <= 0)
|
|
57
|
+
continue
|
|
58
|
+
timeString += `${count}${interval.label}`
|
|
59
|
+
secRemained -= count * interval.threshold
|
|
60
|
+
if (--maxDepth <= 0)
|
|
61
|
+
break
|
|
62
|
+
}
|
|
63
|
+
return timeString || '刚刚'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function toInstantString(date: string | Temporal.ZonedDateTime, timeZone = 'UTC') {
|
|
67
|
+
return (typeof date === 'string' ? toZonedTemporal(date, timeZone) : date).toInstant().toString()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 将日期字符串解析为带时区的 Temporal 对象
|
|
72
|
+
* @param date 日期字符串
|
|
73
|
+
* @param timeZone 无时区信息时使用的默认时区(来自站点配置)
|
|
74
|
+
*/
|
|
75
|
+
export function toZonedTemporal(date: string, timeZone = 'UTC') {
|
|
76
|
+
try {
|
|
77
|
+
return Temporal.ZonedDateTime.from(date)
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
try {
|
|
81
|
+
return Temporal.Instant.from(date).toZonedDateTimeISO(timeZone)
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return Temporal.PlainDateTime.from(date).toZonedDateTime(timeZone)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const dateTimeFormat = {
|
|
90
|
+
date: {
|
|
91
|
+
year: 'numeric',
|
|
92
|
+
month: '2-digit',
|
|
93
|
+
day: '2-digit',
|
|
94
|
+
},
|
|
95
|
+
monthDay: {
|
|
96
|
+
month: '2-digit',
|
|
97
|
+
day: '2-digit',
|
|
98
|
+
},
|
|
99
|
+
full: {
|
|
100
|
+
year: 'numeric',
|
|
101
|
+
month: '2-digit',
|
|
102
|
+
day: '2-digit',
|
|
103
|
+
weekday: 'long',
|
|
104
|
+
hour: '2-digit',
|
|
105
|
+
minute: '2-digit',
|
|
106
|
+
second: '2-digit',
|
|
107
|
+
timeZoneName: 'long',
|
|
108
|
+
},
|
|
109
|
+
} satisfies Record<string, Intl.DateTimeFormatOptions>
|
|
110
|
+
|
|
111
|
+
export type dateTimeFormatOptions = keyof typeof dateTimeFormat | Intl.DateTimeFormatOptions
|
|
112
|
+
|
|
113
|
+
export function toZdtLocaleString(date: string | Temporal.ZonedDateTime, format: dateTimeFormatOptions = 'full', timeZone = 'UTC') {
|
|
114
|
+
return (typeof date === 'string' ? toZonedTemporal(date, timeZone) : date)
|
|
115
|
+
.toLocaleString(undefined, typeof format === 'string' ? dateTimeFormat[format] : format)
|
|
116
|
+
}
|