clarity-theme 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -5
- package/README.zh-CN.md +15 -5
- package/nuxt.config.ts +19 -1
- package/package.json +14 -2
- package/src/app.config.ts +8 -104
- package/src/assets/icons/zhilu.svg +8 -0
- package/src/blog.config.ts +71 -0
- package/src/components/blog/BlogFooter.vue +3 -3
- package/src/components/blog/BlogHeader.global.vue +9 -9
- package/src/components/blog/BlogSidebar.vue +3 -3
- package/src/components/blog/ThemeToggle.vue +2 -2
- package/src/components/content/Alert.vue +2 -2
- package/src/components/content/FeedCard.vue +2 -2
- package/src/components/content/Mermaid.vue +1 -1
- package/src/components/content/ProseCode.vue +4 -32
- package/src/components/content/ProsePre.vue +2 -2
- package/src/components/content/ProseTable.vue +1 -1
- package/src/components/popover/Search.vue +3 -3
- package/src/components/post/Comment.vue +3 -15
- package/src/components/post/Excerpt.vue +3 -3
- package/src/components/post/OrderToggle.vue +3 -3
- package/src/components/post/PostFooter.vue +3 -4
- package/src/components/post/PostHeader.vue +4 -4
- package/src/components/post/PostSurround.vue +2 -2
- package/src/components/post/Slide.vue +2 -2
- package/src/components/util/Img.vue +1 -1
- package/src/components/widget/BlogLog.vue +9 -19
- package/src/components/widget/BlogStats.vue +4 -4
- package/src/components/widget/BlogTech.vue +16 -17
- package/src/components/widget/CommGroup.vue +43 -0
- package/src/composables/useArticle.ts +9 -9
- package/src/composables/usePagination.ts +2 -2
- package/src/composables/useWidgets.ts +2 -0
- package/src/config/app.ts +40 -11
- package/src/config/content.ts +6 -0
- package/src/config/feed.ts +2 -42
- package/src/config/index.ts +2 -2
- package/src/config/pnpm-workspace.ts +19 -0
- package/src/config/public.ts +3 -61
- package/src/config/ui.ts +111 -0
- package/src/modules/anti-mirror/index.ts +38 -0
- package/src/modules/{clarity-config/anti-mirror-client.ts → anti-mirror/runtime/client.ts} +3 -3
- package/src/modules/clarity-config/index.ts +354 -93
- package/src/modules/clarity-source-layout/index.ts +13 -0
- package/src/pages/archive.vue +4 -4
- package/src/pages/index.vue +4 -3
- package/src/pages/link.vue +5 -5
- package/src/pages/preview.vue +2 -2
- package/src/server/api/stats.get.ts +9 -19
- package/src/server/routes/atom.xml.get.ts +48 -50
- package/src/server/routes/subscriptions.opml.get.ts +14 -31
- package/src/server/utils/clarity.ts +1 -1
- package/src/shared/utils/time.ts +13 -18
- package/src/types/article.ts +2 -2
- package/src/types/feed.ts +35 -1
- package/src/types/upstream-compat.d.ts +17 -0
- package/src/types/yaml-modules.d.ts +26 -0
- package/src/shared/types/content.ts +0 -30
- package/src/shared/utils/clarity.ts +0 -34
- package/src/types/modal.ts +0 -16
- /package/src/assets/icons/{solar-rewind-back-bold-duotone.svg → SolarRewindBackBoldDuotone.svg} +0 -0
- /package/src/assets/icons/{solar-rewind-forward-bold-duotone.svg → SolarRewindForwardBoldDuotone.svg} +0 -0
package/src/config/public.ts
CHANGED
|
@@ -1,71 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ClarityArticleConfig,
|
|
3
|
-
ClarityAuthor,
|
|
4
|
-
ClarityChangelogEntry,
|
|
5
|
-
ClarityConfig,
|
|
6
|
-
ClarityIntegrationsConfig,
|
|
7
|
-
ClaritySiteConfig,
|
|
8
|
-
} from './schema'
|
|
1
|
+
import type { ClarityIntegrationsConfig } from './schema'
|
|
9
2
|
|
|
10
3
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 可见性约定(详见 docs/guides/configuration.md):
|
|
14
|
-
* - 只有客户端渲染确实需要的字段进入 appConfig;
|
|
4
|
+
* 客户端可见性约定(详见 docs/guides/configuration.md):
|
|
15
5
|
* - feed、完整 stats、features 与 site.author.email 等服务端/构建期字段
|
|
16
6
|
* 改由 Nitro 私有 runtimeConfig 提供(config/server.ts),不进入客户端 bundle;
|
|
17
7
|
* - 仅构建期使用的字段(integrations.scripts、article.hidePostPrefix、
|
|
18
8
|
* article.robotsNotIndex)由模块直接消费,同样不进入 appConfig。
|
|
19
|
-
*
|
|
9
|
+
* 允许进入客户端 bundle 的配置不包含任何密钥(secret 只允许 runtimeConfig)。
|
|
20
10
|
*/
|
|
21
11
|
|
|
22
12
|
/** appConfig 中暴露的 integrations 子集:scripts 仅构建期注入 <head> */
|
|
23
13
|
export type ClarityPublicIntegrationsConfig = Omit<ClarityIntegrationsConfig, 'scripts'>
|
|
24
|
-
|
|
25
|
-
/** appConfig 中暴露的 site 子集:author.email 仅用于服务端 feed/meta 输出 */
|
|
26
|
-
export type ClarityPublicSiteConfig = Omit<ClaritySiteConfig, 'author'> & {
|
|
27
|
-
author: Omit<ClarityAuthor, 'email'>
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** appConfig 中暴露的 article 子集:其余字段仅构建期使用 */
|
|
31
|
-
export type ClarityPublicArticleConfig = Pick<ClarityArticleConfig, 'categories' | 'order'>
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* appConfig 中暴露的 stats 子集:由 includePaths 派生的展示事实,
|
|
35
|
-
* 决定 BlogStats 标签使用「文章字数」还是「总字数」,不透出完整匹配规则。
|
|
36
|
-
*/
|
|
37
|
-
export interface ClarityPublicStatsConfig {
|
|
38
|
-
postsOnly: boolean
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface ClarityPublicConfig {
|
|
42
|
-
site: ClarityPublicSiteConfig
|
|
43
|
-
article: ClarityPublicArticleConfig
|
|
44
|
-
stats: ClarityPublicStatsConfig
|
|
45
|
-
integrations: ClarityPublicIntegrationsConfig
|
|
46
|
-
changelog: ClarityChangelogEntry[]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function toPublicClarityConfig(config: ClarityConfig): ClarityPublicConfig {
|
|
50
|
-
return {
|
|
51
|
-
site: {
|
|
52
|
-
...config.site,
|
|
53
|
-
author: {
|
|
54
|
-
name: config.site.author.name,
|
|
55
|
-
avatar: config.site.author.avatar,
|
|
56
|
-
homepage: config.site.author.homepage,
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
article: {
|
|
60
|
-
categories: config.article.categories,
|
|
61
|
-
order: config.article.order,
|
|
62
|
-
},
|
|
63
|
-
stats: {
|
|
64
|
-
postsOnly: config.stats.includePaths.length > 0,
|
|
65
|
-
},
|
|
66
|
-
integrations: config.integrations.twikoo
|
|
67
|
-
? { twikoo: config.integrations.twikoo }
|
|
68
|
-
: {},
|
|
69
|
-
changelog: config.changelog,
|
|
70
|
-
}
|
|
71
|
-
}
|
package/src/config/ui.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clarity Theme UI 默认值(上游 blog-v3 `app/app.config.ts` 的可分发子集)。
|
|
3
|
+
*
|
|
4
|
+
* 上游的 app/app.config.ts 属于消费项目文件(其 init-project 会重置),
|
|
5
|
+
* Layer 无法引用消费项目的 blog.config 来派生 logo / subtitle / copyright,
|
|
6
|
+
* 因此这些站点派生值由 src/modules/clarity-config 注入;
|
|
7
|
+
* 本文件只保留不携带个人数据的结构性默认值(footer.iconNav / footer.nav
|
|
8
|
+
* 的个人链接不能随 npm 包分发,默认置空,由消费项目自行填写)。
|
|
9
|
+
*/
|
|
10
|
+
import type { Nav, NavItem } from '../types/nav'
|
|
11
|
+
|
|
12
|
+
// @keep-sorted
|
|
13
|
+
export default {
|
|
14
|
+
component: {
|
|
15
|
+
alert: {
|
|
16
|
+
/** 默认使用卡片风格还是扁平风格 */
|
|
17
|
+
defaultStyle: 'card' as 'card' | 'flat',
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
codeblock: {
|
|
21
|
+
/** 代码块触发折叠的行数 */
|
|
22
|
+
triggerRows: 32,
|
|
23
|
+
/** 代码块折叠后的行数 */
|
|
24
|
+
collapsedRows: 16,
|
|
25
|
+
/** 启用代码块缩进导航会关闭空格渲染 */
|
|
26
|
+
enableIndentGuide: true,
|
|
27
|
+
/** 代码块缩进导航(Indent Guide)竖线匹配空格数 */
|
|
28
|
+
indent: 4,
|
|
29
|
+
/** tab渲染宽度 */
|
|
30
|
+
tabSize: 3,
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/** 文章开头摘要 */
|
|
34
|
+
excerpt: {
|
|
35
|
+
animation: true,
|
|
36
|
+
caret: '_',
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/** 精选文章 Slide */
|
|
40
|
+
slide: {
|
|
41
|
+
/** 适合封面图无字时启用 */
|
|
42
|
+
showTitle: true,
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
stats: {
|
|
46
|
+
/** 归档页面每年标题对应的年龄,无需展示时可设为 0 */
|
|
47
|
+
birthYear: 0,
|
|
48
|
+
/** blog-stats widget 的预置文本 */
|
|
49
|
+
wordCount: '',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// @keep-sorted
|
|
54
|
+
footer: {
|
|
55
|
+
/** 侧边栏底部图标导航(个人链接不随 Theme 分发,由消费项目配置) */
|
|
56
|
+
iconNav: [] as NavItem[],
|
|
57
|
+
/** 页脚站点地图(同上,默认为空) */
|
|
58
|
+
nav: [] as Nav,
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/** 左侧栏顶部 Logo */
|
|
62
|
+
header: {
|
|
63
|
+
/** 展示标题文本,否则展示纯 Logo */
|
|
64
|
+
showTitle: true,
|
|
65
|
+
/** 标题后的随机表情 */
|
|
66
|
+
emojiTail: ['📝', '✨', '🌱'] as string[],
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
/** 友链页面 */
|
|
70
|
+
link: {
|
|
71
|
+
/** 无订阅源展示静音图标 */
|
|
72
|
+
remindNoFeed: true,
|
|
73
|
+
/** 友链分组内随机排序 */
|
|
74
|
+
randomInGroup: true,
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/** 左侧栏导航 */
|
|
78
|
+
nav: [
|
|
79
|
+
{
|
|
80
|
+
title: '',
|
|
81
|
+
items: [
|
|
82
|
+
{ icon: 'tabler:files', text: '文章', url: '/' },
|
|
83
|
+
{ icon: 'tabler:link', text: '友链', url: '/link' },
|
|
84
|
+
{ icon: 'tabler:archive', text: '归档', url: '/archive' },
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
] as Nav,
|
|
88
|
+
|
|
89
|
+
pagination: {
|
|
90
|
+
perPage: 10,
|
|
91
|
+
/** 默认排序方式,需要是 article.order 中的键名 */
|
|
92
|
+
sortOrder: 'date',
|
|
93
|
+
/** 允许(普通/预览/归档)文章列表正序,开启后排序方式左侧图标可切换顺序 */
|
|
94
|
+
allowAscending: false,
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
themes: {
|
|
98
|
+
light: {
|
|
99
|
+
icon: 'tabler:sun',
|
|
100
|
+
tip: '浅色模式',
|
|
101
|
+
},
|
|
102
|
+
system: {
|
|
103
|
+
icon: 'tabler:device-desktop',
|
|
104
|
+
tip: '跟随系统',
|
|
105
|
+
},
|
|
106
|
+
dark: {
|
|
107
|
+
icon: 'tabler:moon',
|
|
108
|
+
tip: '深色模式',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { pathToFileURL } from 'node:url'
|
|
3
|
+
import { defineNuxtModule } from 'nuxt/kit'
|
|
4
|
+
import { minifySync } from 'oxc-minify'
|
|
5
|
+
import handleMirror from './runtime/client'
|
|
6
|
+
|
|
7
|
+
const blacklist = [
|
|
8
|
+
'dgjlx.com', // blog.revincx.icu
|
|
9
|
+
'dgvhqt.com', // blog.zhilu.cyou
|
|
10
|
+
'hcmsla.com', // thyuu.com
|
|
11
|
+
'wmlop.com', // xaoxuu.com
|
|
12
|
+
'yswjxs.com', // blog.zhilu.cyou
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
export default defineNuxtModule({
|
|
16
|
+
meta: {
|
|
17
|
+
name: 'anti-mirror',
|
|
18
|
+
},
|
|
19
|
+
async setup(_options, nuxt) {
|
|
20
|
+
// 生成的数据模块由 clarity-config(先于本模块注册)在 setup 阶段写入
|
|
21
|
+
// <buildDir>/clarity/;静态相对路径会命中安装包内部位置(穿透 pnpm
|
|
22
|
+
// 硬链接污染 store),改用基于 buildDir 的 file URL 动态导入,jiti 与
|
|
23
|
+
// Node 原生加载均可解析。
|
|
24
|
+
const buildInfoUrl = pathToFileURL(join(nuxt.options.buildDir, 'clarity', 'blog.config.mjs')).href
|
|
25
|
+
const { default: blogConfig } = await import(buildInfoUrl)
|
|
26
|
+
nuxt.options.app.head.script ??= []
|
|
27
|
+
nuxt.options.app.head.script.push({
|
|
28
|
+
innerHTML: toIifeString(handleMirror, blacklist.map(btoa), btoa(blogConfig.url)),
|
|
29
|
+
})
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
function toIifeString<T extends unknown[]>(fn: (...args: T) => void, ...args: T) {
|
|
34
|
+
const fnString = fn.toString()
|
|
35
|
+
const argsString = JSON.stringify(args).slice(1, -1)
|
|
36
|
+
const minified = minifySync('', `(${fnString})(${argsString})`)
|
|
37
|
+
return minified.code
|
|
38
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export default (sourcesEncoded: string[], targetEncoded: string) => {
|
|
2
2
|
const sources = sourcesEncoded.map(atob)
|
|
3
|
-
const
|
|
3
|
+
const target = atob(targetEncoded)
|
|
4
4
|
const canonical = document.querySelector<HTMLLinkElement>('link[rel="canonical"]')
|
|
5
5
|
const isBadMirror = sources.some(domain => location.hostname.endsWith(domain))
|
|
6
6
|
if (isBadMirror) {
|
|
7
7
|
if (canonical)
|
|
8
|
-
canonical.href = canonical.href.replace(location.host,
|
|
9
|
-
location.host =
|
|
8
|
+
canonical.href = canonical.href.replace(location.host, target)
|
|
9
|
+
location.host = target
|
|
10
10
|
}
|
|
11
11
|
}
|