clarity-theme 0.1.1 → 0.1.3
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 +48 -222
- package/README.zh-CN.md +50 -245
- package/nuxt.config.ts +18 -15
- package/package.json +17 -19
- package/{app → src}/app.config.ts +1 -1
- package/{app → src}/components/widget/BlogTech.vue +2 -0
- package/{app → src}/composables/useArticle.ts +2 -2
- package/{config → src/config}/app.ts +1 -1
- package/{config → src/config}/define.mjs +1 -1
- package/{config → src/config}/define.ts +1 -1
- package/{config → src/config}/feeds.empty.ts +1 -1
- package/{config → src/config}/index.ts +1 -1
- package/{config → src/config}/public.ts +1 -1
- package/{img → src/img}/index.ts +2 -2
- package/{modules → src/modules}/clarity-config/index.ts +12 -9
- package/src/modules/clarity-source-layout/index.ts +78 -0
- package/{server → src/server}/routes/subscriptions.opml.get.ts +1 -1
- package/{app → src}/types/article.ts +3 -3
- package/src/types/feed.ts +1 -0
- package/app/types/feed.ts +0 -1
- /package/{app → src}/app.vue +0 -0
- /package/{app → src}/assets/css/_variable.scss +0 -0
- /package/{app → src}/assets/css/animation.scss +0 -0
- /package/{app → src}/assets/css/article.scss +0 -0
- /package/{app → src}/assets/css/color.scss +0 -0
- /package/{app → src}/assets/css/font.scss +0 -0
- /package/{app → src}/assets/css/main.scss +0 -0
- /package/{app → src}/assets/css/reusable.scss +0 -0
- /package/{app → src}/assets/icons/solar-rewind-back-bold-duotone.svg +0 -0
- /package/{app → src}/assets/icons/solar-rewind-forward-bold-duotone.svg +0 -0
- /package/{app → src}/components/blog/BlogAside.vue +0 -0
- /package/{app → src}/components/blog/BlogFooter.vue +0 -0
- /package/{app → src}/components/blog/BlogHeader.global.vue +0 -0
- /package/{app → src}/components/blog/BlogPanel.vue +0 -0
- /package/{app → src}/components/blog/BlogSidebar.vue +0 -0
- /package/{app → src}/components/blog/BlogWidget.vue +0 -0
- /package/{app → src}/components/blog/Mask.vue +0 -0
- /package/{app → src}/components/blog/SkipToContent.vue +0 -0
- /package/{app → src}/components/blog/ThemeToggle.vue +0 -0
- /package/{app → src}/components/content/Alert.vue +0 -0
- /package/{app → src}/components/content/Badge.vue +0 -0
- /package/{app → src}/components/content/Blur.vue +0 -0
- /package/{app → src}/components/content/CardList.vue +0 -0
- /package/{app → src}/components/content/Chat.vue +0 -0
- /package/{app → src}/components/content/Copy.vue +0 -0
- /package/{app → src}/components/content/EmojiClock.vue +0 -0
- /package/{app → src}/components/content/FeedCard.vue +0 -0
- /package/{app → src}/components/content/FeedGroup.vue +0 -0
- /package/{app → src}/components/content/Folding.vue +0 -0
- /package/{app → src}/components/content/Key.vue +0 -0
- /package/{app → src}/components/content/LinkBanner.vue +0 -0
- /package/{app → src}/components/content/LinkCard.vue +0 -0
- /package/{app → src}/components/content/MdTitle.vue +0 -0
- /package/{app → src}/components/content/Mermaid.vue +0 -0
- /package/{app → src}/components/content/MusicScore.vue +0 -0
- /package/{app → src}/components/content/Pic.vue +0 -0
- /package/{app → src}/components/content/Poetry.vue +0 -0
- /package/{app → src}/components/content/ProseA.vue +0 -0
- /package/{app → src}/components/content/ProseCode.vue +0 -0
- /package/{app → src}/components/content/ProsePre.vue +0 -0
- /package/{app → src}/components/content/ProseTable.vue +0 -0
- /package/{app → src}/components/content/Quote.vue +0 -0
- /package/{app → src}/components/content/Tab.vue +0 -0
- /package/{app → src}/components/content/Timeline.vue +0 -0
- /package/{app → src}/components/content/Tip.vue +0 -0
- /package/{app → src}/components/content/VideoEmbed.vue +0 -0
- /package/{app → src}/components/partial/Button.vue +0 -0
- /package/{app → src}/components/partial/DlGroup.vue +0 -0
- /package/{app → src}/components/partial/Dropdown.vue +0 -0
- /package/{app → src}/components/partial/Error.vue +0 -0
- /package/{app → src}/components/partial/Expand.vue +0 -0
- /package/{app → src}/components/partial/IconNavList.vue +0 -0
- /package/{app → src}/components/partial/Pagination.vue +0 -0
- /package/{app → src}/components/partial/RadioGroup.vue +0 -0
- /package/{app → src}/components/partial/Secret.vue +0 -0
- /package/{app → src}/components/partial/Slider.vue +0 -0
- /package/{app → src}/components/partial/Toggle.vue +0 -0
- /package/{app → src}/components/popover/Lightbox.vue +0 -0
- /package/{app → src}/components/popover/Search.vue +0 -0
- /package/{app → src}/components/popover/SearchItem.vue +0 -0
- /package/{app → src}/components/post/Archive.vue +0 -0
- /package/{app → src}/components/post/Article.vue +0 -0
- /package/{app → src}/components/post/Comment.vue +0 -0
- /package/{app → src}/components/post/Excerpt.vue +0 -0
- /package/{app → src}/components/post/OrderToggle.vue +0 -0
- /package/{app → src}/components/post/PostFooter.vue +0 -0
- /package/{app → src}/components/post/PostHeader.vue +0 -0
- /package/{app → src}/components/post/PostSurround.vue +0 -0
- /package/{app → src}/components/post/Slide.vue +0 -0
- /package/{app → src}/components/util/Date.vue +0 -0
- /package/{app → src}/components/util/HydrateSafe.vue +0 -0
- /package/{app → src}/components/util/Img.vue +0 -0
- /package/{app → src}/components/util/Link.vue +0 -0
- /package/{app → src}/components/widget/BlogLog.vue +0 -0
- /package/{app → src}/components/widget/BlogStats.vue +0 -0
- /package/{app → src}/components/widget/Empty.vue +0 -0
- /package/{app → src}/components/widget/Toc.vue +0 -0
- /package/{app → src}/composables/useAvoid.ts +0 -0
- /package/{app → src}/composables/useCopy.ts +0 -0
- /package/{app → src}/composables/usePagination.ts +0 -0
- /package/{app → src}/composables/useShiki.ts +0 -0
- /package/{app → src}/composables/useToc.ts +0 -0
- /package/{app → src}/composables/useWidgets.ts +0 -0
- /package/{config → src/config}/content.d.mts +0 -0
- /package/{config → src/config}/content.mjs +0 -0
- /package/{config → src/config}/content.ts +0 -0
- /package/{config → src/config}/feed.ts +0 -0
- /package/{config → src/config}/index.d.mts +0 -0
- /package/{config → src/config}/index.mjs +0 -0
- /package/{config → src/config}/schema.d.mts +0 -0
- /package/{config → src/config}/schema.mjs +0 -0
- /package/{config → src/config}/schema.ts +0 -0
- /package/{config → src/config}/server.ts +0 -0
- /package/{app → src}/error.vue +0 -0
- /package/{img → src/img}/index.d.mts +0 -0
- /package/{img → src/img}/index.mjs +0 -0
- /package/{app → src}/layouts/default.vue +0 -0
- /package/{modules → src/modules}/clarity-config/anti-mirror-client.ts +0 -0
- /package/{app → src}/pages/[...slug].vue +0 -0
- /package/{app → src}/pages/archive.vue +0 -0
- /package/{app → src}/pages/index.vue +0 -0
- /package/{app → src}/pages/link.vue +0 -0
- /package/{app → src}/pages/preview.vue +0 -0
- /package/{app → src}/plugins/easter-egg.ts +0 -0
- /package/{app → src}/plugins/init.ts +0 -0
- /package/{app → src}/plugins/tippy.ts +0 -0
- /package/{public → src/public}/assets/atom.css +0 -0
- /package/{public → src/public}/assets/atom.xsl +0 -0
- /package/{public → src/public}/fonts/AlimamaFangYuanTi.woff2 +0 -0
- /package/{remark-plugins → src/remark-plugins}/rehype-meta-slots.d.mts +0 -0
- /package/{remark-plugins → src/remark-plugins}/rehype-meta-slots.mjs +0 -0
- /package/{remark-plugins → src/remark-plugins}/rehype-meta-slots.ts +0 -0
- /package/{remark-plugins → src/remark-plugins}/remark-code-component.d.mts +0 -0
- /package/{remark-plugins → src/remark-plugins}/remark-code-component.mjs +0 -0
- /package/{remark-plugins → src/remark-plugins}/remark-code-component.ts +0 -0
- /package/{server → src/server}/api/stats.get.ts +0 -0
- /package/{server → src/server}/routes/atom.xml.get.ts +0 -0
- /package/{server → src/server}/utils/clarity.ts +0 -0
- /package/{shared → src/shared}/types/content.ts +0 -0
- /package/{shared → src/shared}/utils/clarity.ts +0 -0
- /package/{shared → src/shared}/utils/icon.ts +0 -0
- /package/{shared → src/shared}/utils/link.ts +0 -0
- /package/{shared → src/shared}/utils/str.ts +0 -0
- /package/{shared → src/shared}/utils/time.ts +0 -0
- /package/{app → src}/shiki.config.ts +0 -0
- /package/{app → src}/stores/layout.ts +0 -0
- /package/{app → src}/stores/search.ts +0 -0
- /package/{app → src}/types/index.ts +0 -0
- /package/{app → src}/types/modal.ts +0 -0
- /package/{app → src}/types/nav.ts +0 -0
- /package/{app → src}/utils/anim.ts +0 -0
- /package/{app → src}/utils/img.ts +0 -0
|
@@ -21,7 +21,10 @@ import { toServerClarityConfig } from '../../config/server'
|
|
|
21
21
|
import handleMirror from './anti-mirror-client'
|
|
22
22
|
|
|
23
23
|
const moduleDir = dirname(fileURLToPath(import.meta.url))
|
|
24
|
-
|
|
24
|
+
/** Theme 运行时源码根(src/):模块位于 src/modules/clarity-config */
|
|
25
|
+
const themeSrcDir = resolve(moduleDir, '../..')
|
|
26
|
+
/** Theme npm 包根(nuxt.config.ts / package.json 所在层) */
|
|
27
|
+
const themePkgDir = resolve(moduleDir, '../../..')
|
|
25
28
|
|
|
26
29
|
/** app/app.config.ts 的 clarity 键只允许 UI 覆盖(站点级字段属于 clarity.config.ts) */
|
|
27
30
|
const uiConfigKeys = new Set(['component', 'footer', 'header', 'link', 'nav', 'pagination', 'themes'])
|
|
@@ -42,7 +45,7 @@ export default defineNuxtModule<ModuleOptions>({
|
|
|
42
45
|
const rootDir = nuxt.options.rootDir
|
|
43
46
|
|
|
44
47
|
const configPath = resolve(rootDir, options.configFile ?? findConfigFile(rootDir))
|
|
45
|
-
const feedsPath = findFeedsFile(rootDir,
|
|
48
|
+
const feedsPath = findFeedsFile(rootDir, themeSrcDir)
|
|
46
49
|
|
|
47
50
|
// ---- 依赖注入层:Theme 内部不感知消费项目的文件布局 ----
|
|
48
51
|
Object.assign(nuxt.options.alias, {
|
|
@@ -51,14 +54,14 @@ export default defineNuxtModule<ModuleOptions>({
|
|
|
51
54
|
})
|
|
52
55
|
|
|
53
56
|
// @pinia/nuxt 不会自动扫描 Layer 的 stores 目录,需显式注册
|
|
54
|
-
addImportsDir(resolve(
|
|
57
|
+
addImportsDir(resolve(themeSrcDir, 'stores'))
|
|
55
58
|
|
|
56
59
|
// ---- AppConfig 类型化:消费者 defineAppConfig({ clarity: ... }) 获得完整类型提示 ----
|
|
57
60
|
// 注意:类型文件生成于 buildDir/types/ 下,相对路径必须以其为基准计算,
|
|
58
61
|
// 否则导入解析失败会因 skipLibCheck 静默退化为 any(审计发现 #9)。
|
|
59
62
|
const appConfigTypeDir = resolve(nuxt.options.buildDir, 'types')
|
|
60
|
-
const appConfigTypePath = relative(appConfigTypeDir, resolve(
|
|
61
|
-
const globalsTypePath = relative(appConfigTypeDir, resolve(
|
|
63
|
+
const appConfigTypePath = relative(appConfigTypeDir, resolve(themeSrcDir, 'config/app.ts')).replaceAll('\\', '/')
|
|
64
|
+
const globalsTypePath = relative(appConfigTypeDir, resolve(themeSrcDir, 'types/index.ts')).replaceAll('\\', '/')
|
|
62
65
|
addTypeTemplate({
|
|
63
66
|
filename: 'types/clarity-app-config.d.ts',
|
|
64
67
|
getContents: () => [
|
|
@@ -86,7 +89,7 @@ export default defineNuxtModule<ModuleOptions>({
|
|
|
86
89
|
// 需置于 '~' 之前以保证 Vite 别名前缀优先匹配
|
|
87
90
|
if (!existsSync(resolve(nuxt.options.srcDir, 'shiki.config.ts'))) {
|
|
88
91
|
nuxt.options.alias = {
|
|
89
|
-
'~/shiki.config': resolve(
|
|
92
|
+
'~/shiki.config': resolve(themeSrcDir, 'shiki.config.ts'),
|
|
90
93
|
...nuxt.options.alias,
|
|
91
94
|
}
|
|
92
95
|
}
|
|
@@ -176,7 +179,7 @@ export default defineNuxtModule<ModuleOptions>({
|
|
|
176
179
|
|
|
177
180
|
// ---- 构建信息(供 BlogTech 等 Widget 使用) ----
|
|
178
181
|
const consumerPkg = await loadJson(resolve(rootDir, 'package.json'), jiti)
|
|
179
|
-
const themePkg = await loadJson(resolve(
|
|
182
|
+
const themePkg = await loadJson(resolve(themePkgDir, 'package.json'), jiti)
|
|
180
183
|
nuxt.options.runtimeConfig.public.clarity = {
|
|
181
184
|
theme: 'Clarity',
|
|
182
185
|
themeVersion: String(themePkg?.version ?? ''),
|
|
@@ -308,13 +311,13 @@ function findConfigFile(rootDir: string) {
|
|
|
308
311
|
return 'clarity.config.ts'
|
|
309
312
|
}
|
|
310
313
|
|
|
311
|
-
function findFeedsFile(rootDir: string,
|
|
314
|
+
function findFeedsFile(rootDir: string, themeSrcDir: string) {
|
|
312
315
|
for (const name of ['feeds.ts', 'feeds.mjs', 'feeds.js']) {
|
|
313
316
|
if (existsSync(resolve(rootDir, name))) {
|
|
314
317
|
return { found: true, resolved: resolve(rootDir, name) }
|
|
315
318
|
}
|
|
316
319
|
}
|
|
317
|
-
return { found: false, resolved: resolve(
|
|
320
|
+
return { found: false, resolved: resolve(themeSrcDir, 'config/feeds.empty.ts') }
|
|
318
321
|
}
|
|
319
322
|
|
|
320
323
|
async function loadJson(path: string, jiti: ReturnType<typeof createJiti>) {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Nuxt } from '@nuxt/schema'
|
|
2
|
+
import { dirname, relative, resolve } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { defineNuxtModule, getLayerDirectories } from 'nuxt/kit'
|
|
5
|
+
|
|
6
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
const themeSrcDir = resolve(moduleDir, '../..')
|
|
8
|
+
const themePkgDir = resolve(moduleDir, '../../..')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Clarity keeps all runtime source under `src/`. These values must only apply
|
|
12
|
+
* to the theme layer; declaring them statically in `nuxt.config.ts` would let
|
|
13
|
+
* c12 merge them into consumers which do not explicitly override them.
|
|
14
|
+
*/
|
|
15
|
+
export default defineNuxtModule({
|
|
16
|
+
meta: {
|
|
17
|
+
name: 'clarity-source-layout',
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
setup(_options, nuxt) {
|
|
21
|
+
const layer = findThemeLayer(nuxt)
|
|
22
|
+
if (!layer) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const sourceDir = withTrailingSlash(themeSrcDir)
|
|
27
|
+
const directories = {
|
|
28
|
+
layouts: withTrailingSlash(resolve(themeSrcDir, 'layouts')),
|
|
29
|
+
middleware: withTrailingSlash(resolve(themeSrcDir, 'middleware')),
|
|
30
|
+
modules: withTrailingSlash(resolve(themeSrcDir, 'modules')),
|
|
31
|
+
pages: withTrailingSlash(resolve(themeSrcDir, 'pages')),
|
|
32
|
+
plugins: withTrailingSlash(resolve(themeSrcDir, 'plugins')),
|
|
33
|
+
public: withTrailingSlash(resolve(themeSrcDir, 'public')),
|
|
34
|
+
server: withTrailingSlash(resolve(themeSrcDir, 'server')),
|
|
35
|
+
shared: withTrailingSlash(resolve(themeSrcDir, 'shared')),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
layer.config.srcDir = sourceDir
|
|
39
|
+
layer.config.serverDir = directories.server
|
|
40
|
+
layer.config.dir = {
|
|
41
|
+
...layer.config.dir,
|
|
42
|
+
app: sourceDir,
|
|
43
|
+
modules: directories.modules,
|
|
44
|
+
public: directories.public,
|
|
45
|
+
shared: directories.shared,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// `getLayerDirectories()` caches a plain metadata object per layer before
|
|
49
|
+
// modules are installed. Nuxt exposes no invalidation API, so update the
|
|
50
|
+
// cached paths in place as well as `layer.config`.
|
|
51
|
+
const cached = getLayerDirectories(nuxt).find(directory => isSamePath(directory.root, themePkgDir))
|
|
52
|
+
if (cached) {
|
|
53
|
+
Object.assign(cached, {
|
|
54
|
+
app: sourceDir,
|
|
55
|
+
appLayouts: directories.layouts,
|
|
56
|
+
appMiddleware: directories.middleware,
|
|
57
|
+
appPages: directories.pages,
|
|
58
|
+
appPlugins: directories.plugins,
|
|
59
|
+
modules: directories.modules,
|
|
60
|
+
public: directories.public,
|
|
61
|
+
server: directories.server,
|
|
62
|
+
shared: directories.shared,
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
function findThemeLayer(nuxt: Nuxt) {
|
|
69
|
+
return nuxt.options._layers.find(layer => isSamePath(layer.config.rootDir ?? layer.cwd, themePkgDir))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isSamePath(left: string, right: string) {
|
|
73
|
+
return left === right || relative(resolve(left), resolve(right)) === ''
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function withTrailingSlash(path: string) {
|
|
77
|
+
return `${path.replace(/[\\/]$/, '').replaceAll('\\', '/')}/`
|
|
78
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ClarityAppConfig } from '
|
|
2
|
-
import type { ArticleSchema } from '
|
|
3
|
-
import type { MetaSlotsTree } from '
|
|
1
|
+
import type { ClarityAppConfig } from '../config/app'
|
|
2
|
+
import type { ArticleSchema } from '../config/content'
|
|
3
|
+
import type { MetaSlotsTree } from '../remark-plugins/rehype-meta-slots'
|
|
4
4
|
|
|
5
5
|
export type ArticleOrderType = keyof ClarityAppConfig['article']['order']
|
|
6
6
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { FeedEntry, FeedGroup } from '../config/feed'
|
package/app/types/feed.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type { FeedEntry, FeedGroup } from '../../config/feed'
|
/package/{app → src}/app.vue
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{app → src}/error.vue
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|