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.
- package/LICENSE +20 -20
- package/README.md +70 -4
- package/README.zh-CN.md +67 -4
- package/nuxt.config.ts +217 -214
- package/package.json +35 -37
- package/{app → src}/app.config.ts +110 -110
- package/{app → src}/app.vue +5 -5
- package/{app → src}/components/blog/BlogAside.vue +25 -25
- package/{app → src}/components/blog/BlogFooter.vue +25 -25
- package/{app → src}/components/blog/BlogHeader.global.vue +48 -48
- package/{app → src}/components/blog/BlogPanel.vue +43 -43
- package/{app → src}/components/blog/BlogSidebar.vue +53 -53
- package/{app → src}/components/blog/BlogWidget.vue +42 -42
- package/{app → src}/components/blog/Mask.vue +25 -25
- package/{app → src}/components/blog/SkipToContent.vue +9 -9
- package/{app → src}/components/blog/ThemeToggle.vue +22 -22
- package/{app → src}/components/content/Badge.vue +45 -45
- package/{app → src}/components/content/Blur.vue +14 -14
- package/{app → src}/components/content/CardList.vue +8 -8
- package/{app → src}/components/content/Chat.vue +41 -41
- package/{app → src}/components/content/Copy.vue +71 -71
- package/{app → src}/components/content/EmojiClock.vue +49 -49
- package/{app → src}/components/content/FeedCard.vue +96 -96
- package/{app → src}/components/content/FeedGroup.vue +61 -61
- package/{app → src}/components/content/Folding.vue +19 -19
- package/{app → src}/components/content/Key.vue +143 -143
- package/{app → src}/components/content/LinkBanner.vue +27 -27
- package/{app → src}/components/content/LinkCard.vue +28 -28
- package/{app → src}/components/content/MdTitle.vue +8 -8
- package/{app → src}/components/content/Mermaid.vue +99 -99
- package/{app → src}/components/content/MusicScore.vue +63 -63
- package/{app → src}/components/content/Pic.vue +49 -49
- package/{app → src}/components/content/Poetry.vue +27 -27
- package/{app → src}/components/content/ProseA.vue +24 -24
- package/{app → src}/components/content/ProseCode.vue +16 -16
- package/{app → src}/components/content/ProsePre.vue +117 -117
- package/{app → src}/components/content/ProseTable.vue +23 -23
- package/{app → src}/components/content/Quote.vue +21 -21
- package/{app → src}/components/content/Tab.vue +32 -32
- package/{app → src}/components/content/Timeline.vue +33 -33
- package/{app → src}/components/content/Tip.vue +40 -40
- package/{app → src}/components/content/VideoEmbed.vue +112 -112
- package/{app → src}/components/partial/Button.vue +36 -36
- package/{app → src}/components/partial/DlGroup.vue +31 -31
- package/{app → src}/components/partial/Dropdown.vue +21 -21
- package/{app → src}/components/partial/Error.vue +39 -39
- package/{app → src}/components/partial/Expand.vue +26 -26
- package/{app → src}/components/partial/IconNavList.vue +24 -24
- package/{app → src}/components/partial/Pagination.vue +62 -62
- package/{app → src}/components/partial/RadioGroup.vue +30 -30
- package/{app → src}/components/partial/Secret.vue +11 -11
- package/{app → src}/components/partial/Slider.vue +48 -48
- package/{app → src}/components/partial/Toggle.vue +17 -17
- package/{app → src}/components/popover/Lightbox.vue +44 -44
- package/{app → src}/components/popover/Search.vue +143 -143
- package/{app → src}/components/popover/SearchItem.vue +28 -28
- package/{app → src}/components/post/Archive.vue +40 -40
- package/{app → src}/components/post/Article.vue +49 -49
- package/{app → src}/components/post/Comment.vue +119 -119
- package/{app → src}/components/post/Excerpt.vue +40 -40
- package/{app → src}/components/post/OrderToggle.vue +70 -70
- package/{app → src}/components/post/PostFooter.vue +52 -52
- package/{app → src}/components/post/PostHeader.vue +66 -66
- package/{app → src}/components/post/PostSurround.vue +51 -51
- package/{app → src}/components/post/Slide.vue +85 -85
- package/{app → src}/components/util/Date.vue +62 -62
- package/{app → src}/components/util/HydrateSafe.vue +10 -10
- package/{app → src}/components/util/Img.vue +38 -38
- package/{app → src}/components/util/Link.vue +11 -11
- package/{app → src}/components/widget/BlogLog.vue +23 -23
- package/{app → src}/components/widget/BlogStats.vue +38 -38
- package/{app → src}/components/widget/BlogTech.vue +57 -57
- package/{app → src}/components/widget/Empty.vue +3 -3
- package/{app → src}/components/widget/Toc.vue +67 -67
- package/{app → src}/composables/useArticle.ts +115 -115
- package/{app → src}/composables/useAvoid.ts +87 -87
- package/{app → src}/composables/useCopy.ts +21 -21
- package/{app → src}/composables/usePagination.ts +70 -70
- package/{app → src}/composables/useShiki.ts +129 -129
- package/{app → src}/composables/useToc.ts +57 -57
- package/{app → src}/composables/useWidgets.ts +56 -56
- package/{config → src/config}/app.ts +62 -62
- package/{config → src/config}/content.ts +75 -75
- package/{config → src/config}/define.ts +3 -3
- package/src/config/feeds.empty.ts +6 -0
- package/{config → src/config}/index.ts +1 -1
- package/{config → src/config}/schema.ts +89 -89
- package/{app → src}/error.vue +31 -31
- package/{img → src/img}/index.ts +2 -2
- package/{app → src}/layouts/default.vue +25 -25
- package/{modules → src/modules}/clarity-config/index.ts +168 -162
- package/src/modules/clarity-source-layout/index.ts +78 -0
- package/{app → src}/pages/[...slug].vue +59 -59
- package/{app → src}/pages/archive.vue +129 -129
- package/{app → src}/pages/index.vue +76 -76
- package/{app → src}/pages/link.vue +62 -62
- package/{app → src}/pages/preview.vue +46 -46
- package/{app → src}/plugins/easter-egg.ts +23 -23
- package/{app → src}/plugins/init.ts +6 -6
- package/{app → src}/plugins/tippy.ts +22 -22
- package/{public → src/public}/assets/atom.css +274 -274
- package/{public → src/public}/assets/atom.xsl +109 -109
- package/{remark-plugins → src/remark-plugins}/rehype-meta-slots.ts +58 -58
- package/{remark-plugins → src/remark-plugins}/remark-code-component.ts +41 -41
- package/{server → src/server}/api/stats.get.ts +84 -83
- package/{server → src/server}/routes/atom.xml.get.ts +85 -85
- package/{server → src/server}/routes/subscriptions.opml.get.ts +64 -64
- package/{shared → src/shared}/utils/clarity.ts +24 -24
- package/{shared → src/shared}/utils/icon.ts +218 -218
- package/{shared → src/shared}/utils/link.ts +52 -52
- package/{shared → src/shared}/utils/str.ts +88 -88
- package/{shared → src/shared}/utils/time.ts +115 -115
- package/{app → src}/shiki.config.ts +8 -8
- package/{app → src}/stores/layout.ts +34 -34
- package/{app → src}/stores/search.ts +37 -37
- package/{app → src}/types/article.ts +16 -16
- package/src/types/feed.ts +1 -0
- package/{app → src}/types/index.ts +14 -14
- package/{app → src}/types/nav.ts +11 -11
- package/{app → src}/utils/anim.ts +37 -37
- package/{app → src}/utils/img.ts +83 -83
- package/app/types/feed.ts +0 -1
- package/config/feeds.empty.ts +0 -4
- 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/content/Alert.vue +0 -0
- package/{config → src/config}/content.d.mts +0 -0
- package/{config → src/config}/content.mjs +0 -0
- package/{config → src/config}/define.mjs +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}/public.ts +1 -1
- package/{config → src/config}/schema.d.mts +0 -0
- package/{config → src/config}/schema.mjs +0 -0
- package/{config → src/config}/server.ts +1 -1
- /package/{img → src/img}/index.d.mts +0 -0
- /package/{img → src/img}/index.mjs +0 -0
- /package/{modules → src/modules}/clarity-config/anti-mirror-client.ts +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}/remark-code-component.d.mts +0 -0
- /package/{remark-plugins → src/remark-plugins}/remark-code-component.mjs +0 -0
- /package/{server → src/server}/utils/clarity.ts +0 -0
- /package/{shared → src/shared}/types/content.ts +0 -0
- /package/{app → src}/types/modal.ts +0 -0
|
@@ -1,101 +1,101 @@
|
|
|
1
1
|
import type { ClarityContentRow } from '../../shared/types/content'
|
|
2
2
|
import { queryCollection } from '@nuxt/content/server'
|
|
3
3
|
import XmlBuilder from 'fast-xml-builder'
|
|
4
|
-
import { toZonedTemporal } from '../../shared/utils/time'
|
|
5
|
-
|
|
6
|
-
const runtimeConfig = useRuntimeConfig()
|
|
7
|
-
|
|
8
|
-
const builder = new XmlBuilder({
|
|
9
|
-
attributeNamePrefix: '$',
|
|
10
|
-
cdataPropName: '$',
|
|
11
|
-
format: true,
|
|
12
|
-
ignoreAttributes: false,
|
|
13
|
-
textNodeName: '_',
|
|
14
|
-
})
|
|
15
|
-
|
|
4
|
+
import { toZonedTemporal } from '../../shared/utils/time'
|
|
5
|
+
|
|
6
|
+
const runtimeConfig = useRuntimeConfig()
|
|
7
|
+
|
|
8
|
+
const builder = new XmlBuilder({
|
|
9
|
+
attributeNamePrefix: '$',
|
|
10
|
+
cdataPropName: '$',
|
|
11
|
+
format: true,
|
|
12
|
+
ignoreAttributes: false,
|
|
13
|
+
textNodeName: '_',
|
|
14
|
+
})
|
|
15
|
+
|
|
16
16
|
export default defineEventHandler(async (event) => {
|
|
17
17
|
const { site, feed, features } = useClarityServerConfig()
|
|
18
18
|
if (!features.atom) {
|
|
19
19
|
throw createError({ statusCode: 404, statusMessage: 'Atom feed is disabled' })
|
|
20
20
|
}
|
|
21
21
|
const themeInfo = runtimeConfig.public.clarity as { theme: string, themeVersion: string, themeHomepage: string }
|
|
22
|
-
|
|
23
|
-
function formatIsoDate(date?: string) {
|
|
24
|
-
if (!date)
|
|
25
|
-
return
|
|
26
|
-
try {
|
|
27
|
-
return toZonedTemporal(date, site.timezone).toInstant().toString()
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
console.error('Invalid date format', date)
|
|
31
|
-
return date
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function getUrl(path: string | undefined) {
|
|
36
|
-
return new URL(path ?? '', site.url).toString()
|
|
37
|
-
}
|
|
38
|
-
|
|
22
|
+
|
|
23
|
+
function formatIsoDate(date?: string) {
|
|
24
|
+
if (!date)
|
|
25
|
+
return
|
|
26
|
+
try {
|
|
27
|
+
return toZonedTemporal(date, site.timezone).toInstant().toString()
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
console.error('Invalid date format', date)
|
|
31
|
+
return date
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getUrl(path: string | undefined) {
|
|
36
|
+
return new URL(path ?? '', site.url).toString()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
39
|
function renderContent(post: ClarityContentRow) {
|
|
40
|
-
return [
|
|
41
|
-
post.image && `<img src="${post.image}" alt="${post.title}" />`,
|
|
42
|
-
post.description && `<p>${post.description}</p>`,
|
|
43
|
-
`<a class="view-full" href="${getUrl(post.path)}" target="_blank">点击查看全文</a>`,
|
|
44
|
-
].filter(Boolean).join(' ')
|
|
45
|
-
}
|
|
46
|
-
|
|
40
|
+
return [
|
|
41
|
+
post.image && `<img src="${post.image}" alt="${post.title}" />`,
|
|
42
|
+
post.description && `<p>${post.description}</p>`,
|
|
43
|
+
`<a class="view-full" href="${getUrl(post.path)}" target="_blank">点击查看全文</a>`,
|
|
44
|
+
].filter(Boolean).join(' ')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
47
|
const posts = await queryCollection(event, 'content' as never)
|
|
48
48
|
.where('stem', 'LIKE', 'posts/%')
|
|
49
49
|
.order('updated', 'DESC')
|
|
50
50
|
.limit(feed.limit)
|
|
51
51
|
.all() as ClarityContentRow[]
|
|
52
|
-
|
|
53
|
-
const entries = posts.map(post => ({
|
|
54
|
-
id: getUrl(post.path),
|
|
55
|
-
title: post.title ?? '',
|
|
56
|
-
updated: formatIsoDate(post.updated),
|
|
52
|
+
|
|
53
|
+
const entries = posts.map(post => ({
|
|
54
|
+
id: getUrl(post.path),
|
|
55
|
+
title: post.title ?? '',
|
|
56
|
+
updated: formatIsoDate(post.updated),
|
|
57
57
|
author: { name: (post as any).author || site.author.name },
|
|
58
|
-
content: {
|
|
59
|
-
$type: 'html',
|
|
60
|
-
$: renderContent(post),
|
|
61
|
-
},
|
|
62
|
-
link: { $href: getUrl(post.path) },
|
|
63
|
-
summary: post.description,
|
|
64
|
-
category: { $term: post.categories?.[0] },
|
|
65
|
-
published: formatIsoDate(post.published ?? post.date),
|
|
66
|
-
}))
|
|
67
|
-
|
|
68
|
-
const feedData = {
|
|
69
|
-
$xmlns: 'http://www.w3.org/2005/Atom',
|
|
70
|
-
id: site.url,
|
|
71
|
-
title: site.title,
|
|
72
|
-
updated: runtimeConfig.public.buildTime,
|
|
73
|
-
description: site.description,
|
|
74
|
-
author: {
|
|
75
|
-
name: site.author.name,
|
|
76
|
-
email: site.author.email,
|
|
77
|
-
uri: site.author.homepage,
|
|
78
|
-
},
|
|
79
|
-
link: [
|
|
80
|
-
{ $href: getUrl('atom.xml'), $rel: 'self' },
|
|
81
|
-
{ $href: site.url, $rel: 'alternate' },
|
|
82
|
-
],
|
|
83
|
-
language: site.language,
|
|
84
|
-
generator: {
|
|
85
|
-
$uri: themeInfo.themeHomepage,
|
|
86
|
-
$version: themeInfo.themeVersion,
|
|
87
|
-
_: themeInfo.theme,
|
|
88
|
-
},
|
|
89
|
-
icon: site.favicon,
|
|
90
|
-
logo: site.author.avatar,
|
|
91
|
-
rights: `© ${new Date().getFullYear()} ${site.author.name}`,
|
|
92
|
-
subtitle: site.subtitle || site.description,
|
|
93
|
-
entry: entries,
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return builder.build({
|
|
97
|
-
'?xml': { $version: '1.0', $encoding: 'UTF-8' },
|
|
98
|
-
'?xml-stylesheet': feed.enableStyle ? { $type: 'text/xsl', $href: '/assets/atom.xsl' } : undefined,
|
|
99
|
-
'feed': feedData,
|
|
100
|
-
})
|
|
101
|
-
})
|
|
58
|
+
content: {
|
|
59
|
+
$type: 'html',
|
|
60
|
+
$: renderContent(post),
|
|
61
|
+
},
|
|
62
|
+
link: { $href: getUrl(post.path) },
|
|
63
|
+
summary: post.description,
|
|
64
|
+
category: { $term: post.categories?.[0] },
|
|
65
|
+
published: formatIsoDate(post.published ?? post.date),
|
|
66
|
+
}))
|
|
67
|
+
|
|
68
|
+
const feedData = {
|
|
69
|
+
$xmlns: 'http://www.w3.org/2005/Atom',
|
|
70
|
+
id: site.url,
|
|
71
|
+
title: site.title,
|
|
72
|
+
updated: runtimeConfig.public.buildTime,
|
|
73
|
+
description: site.description,
|
|
74
|
+
author: {
|
|
75
|
+
name: site.author.name,
|
|
76
|
+
email: site.author.email,
|
|
77
|
+
uri: site.author.homepage,
|
|
78
|
+
},
|
|
79
|
+
link: [
|
|
80
|
+
{ $href: getUrl('atom.xml'), $rel: 'self' },
|
|
81
|
+
{ $href: site.url, $rel: 'alternate' },
|
|
82
|
+
],
|
|
83
|
+
language: site.language,
|
|
84
|
+
generator: {
|
|
85
|
+
$uri: themeInfo.themeHomepage,
|
|
86
|
+
$version: themeInfo.themeVersion,
|
|
87
|
+
_: themeInfo.theme,
|
|
88
|
+
},
|
|
89
|
+
icon: site.favicon,
|
|
90
|
+
logo: site.author.avatar,
|
|
91
|
+
rights: `© ${new Date().getFullYear()} ${site.author.name}`,
|
|
92
|
+
subtitle: site.subtitle || site.description,
|
|
93
|
+
entry: entries,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return builder.build({
|
|
97
|
+
'?xml': { $version: '1.0', $encoding: 'UTF-8' },
|
|
98
|
+
'?xml-stylesheet': feed.enableStyle ? { $type: 'text/xsl', $href: '/assets/atom.xsl' } : undefined,
|
|
99
|
+
'feed': feedData,
|
|
100
|
+
})
|
|
101
|
+
})
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
import type { FeedEntry, FeedGroup } from '../../
|
|
2
|
-
import XmlBuilder from 'fast-xml-builder'
|
|
3
|
-
import { toZonedTemporal } from '../../shared/utils/time'
|
|
4
|
-
|
|
5
|
-
const runtimeConfig = useRuntimeConfig()
|
|
6
|
-
|
|
7
|
-
const builder = new XmlBuilder({
|
|
8
|
-
attributeNamePrefix: '$',
|
|
9
|
-
format: true,
|
|
10
|
-
ignoreAttributes: false,
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
function mapEntry(item: FeedEntry, timeZone: string) {
|
|
14
|
-
return {
|
|
15
|
-
$text: item.title || item.sitenick || item.author,
|
|
16
|
-
$type: 'rss',
|
|
17
|
-
$xmlUrl: item.feed,
|
|
18
|
-
$created: toZonedTemporal(item.date, timeZone).toInstant().toString(),
|
|
19
|
-
$description: item.desc,
|
|
20
|
-
$htmlUrl: item.link || item.feed,
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function flattenGroups(groups: FeedGroup[], timeZone: string) {
|
|
25
|
-
return groups.flatMap(({ entries }) => entries.filter(({ feed }) => feed).map(item => mapEntry(item, timeZone)))
|
|
26
|
-
}
|
|
27
|
-
|
|
1
|
+
import type { FeedEntry, FeedGroup } from '../../types/feed'
|
|
2
|
+
import XmlBuilder from 'fast-xml-builder'
|
|
3
|
+
import { toZonedTemporal } from '../../shared/utils/time'
|
|
4
|
+
|
|
5
|
+
const runtimeConfig = useRuntimeConfig()
|
|
6
|
+
|
|
7
|
+
const builder = new XmlBuilder({
|
|
8
|
+
attributeNamePrefix: '$',
|
|
9
|
+
format: true,
|
|
10
|
+
ignoreAttributes: false,
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
function mapEntry(item: FeedEntry, timeZone: string) {
|
|
14
|
+
return {
|
|
15
|
+
$text: item.title || item.sitenick || item.author,
|
|
16
|
+
$type: 'rss',
|
|
17
|
+
$xmlUrl: item.feed,
|
|
18
|
+
$created: toZonedTemporal(item.date, timeZone).toInstant().toString(),
|
|
19
|
+
$description: item.desc,
|
|
20
|
+
$htmlUrl: item.link || item.feed,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function flattenGroups(groups: FeedGroup[], timeZone: string) {
|
|
25
|
+
return groups.flatMap(({ entries }) => entries.filter(({ feed }) => feed).map(item => mapEntry(item, timeZone)))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
28
|
export default defineEventHandler(async () => {
|
|
29
29
|
const { site, features } = useClarityServerConfig()
|
|
30
30
|
if (!features.opml) {
|
|
31
31
|
throw createError({ statusCode: 404, statusMessage: 'OPML subscription output is disabled' })
|
|
32
32
|
}
|
|
33
33
|
const feeds = (await import('#clarity/feeds')).default as FeedGroup[]
|
|
34
|
-
const myFeed: FeedEntry = {
|
|
35
|
-
author: site.author.name,
|
|
36
|
-
title: site.title,
|
|
37
|
-
desc: site.subtitle || site.description,
|
|
38
|
-
link: site.url,
|
|
39
|
-
feed: new URL('/atom.xml', site.url).toString(),
|
|
40
|
-
icon: site.favicon,
|
|
41
|
-
avatar: site.author.avatar || site.favicon,
|
|
42
|
-
date: site.established || '',
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const outlines = [
|
|
46
|
-
mapEntry(myFeed, site.timezone),
|
|
47
|
-
...flattenGroups(feeds, site.timezone),
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
const opml = {
|
|
51
|
-
$version: '2.0',
|
|
52
|
-
head: {
|
|
53
|
-
title: `${site.title}的友链订阅`,
|
|
54
|
-
dateCreated: site.established
|
|
55
|
-
? toZonedTemporal(site.established, site.timezone).toInstant().toString()
|
|
56
|
-
: undefined,
|
|
57
|
-
dateModified: runtimeConfig.public.buildTime,
|
|
58
|
-
ownerName: site.author.name,
|
|
59
|
-
ownerEmail: site.author.email,
|
|
60
|
-
ownerId: site.author.homepage,
|
|
61
|
-
docs: 'https://opml.org/spec2.opml',
|
|
62
|
-
},
|
|
63
|
-
body: { outline: outlines },
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return builder.build({
|
|
67
|
-
'?xml': { $version: '1.0', $encoding: 'UTF-8' },
|
|
68
|
-
opml,
|
|
69
|
-
})
|
|
70
|
-
})
|
|
34
|
+
const myFeed: FeedEntry = {
|
|
35
|
+
author: site.author.name,
|
|
36
|
+
title: site.title,
|
|
37
|
+
desc: site.subtitle || site.description,
|
|
38
|
+
link: site.url,
|
|
39
|
+
feed: new URL('/atom.xml', site.url).toString(),
|
|
40
|
+
icon: site.favicon,
|
|
41
|
+
avatar: site.author.avatar || site.favicon,
|
|
42
|
+
date: site.established || '',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const outlines = [
|
|
46
|
+
mapEntry(myFeed, site.timezone),
|
|
47
|
+
...flattenGroups(feeds, site.timezone),
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
const opml = {
|
|
51
|
+
$version: '2.0',
|
|
52
|
+
head: {
|
|
53
|
+
title: `${site.title}的友链订阅`,
|
|
54
|
+
dateCreated: site.established
|
|
55
|
+
? toZonedTemporal(site.established, site.timezone).toInstant().toString()
|
|
56
|
+
: undefined,
|
|
57
|
+
dateModified: runtimeConfig.public.buildTime,
|
|
58
|
+
ownerName: site.author.name,
|
|
59
|
+
ownerEmail: site.author.email,
|
|
60
|
+
ownerId: site.author.homepage,
|
|
61
|
+
docs: 'https://opml.org/spec2.opml',
|
|
62
|
+
},
|
|
63
|
+
body: { outline: outlines },
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return builder.build({
|
|
67
|
+
'?xml': { $version: '1.0', $encoding: 'UTF-8' },
|
|
68
|
+
opml,
|
|
69
|
+
})
|
|
70
|
+
})
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import type { ClarityAppConfig } from '../../config/app'
|
|
2
2
|
import type { FeedEntry } from '../../config/feed'
|
|
3
3
|
import type { ClaritySiteConfig } from '../../config/schema'
|
|
4
|
-
|
|
5
|
-
/** 获取完整 Clarity 配置(站点配置 + UI 配置) */
|
|
4
|
+
|
|
5
|
+
/** 获取完整 Clarity 配置(站点配置 + UI 配置) */
|
|
6
6
|
export function useClarityConfig(): ClarityAppConfig {
|
|
7
7
|
return useAppConfig().clarity as unknown as ClarityAppConfig
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
/** 获取站点配置(标题、作者、URL 等) */
|
|
11
|
-
export function useClaritySite(): ClaritySiteConfig {
|
|
12
|
-
return useClarityConfig().site
|
|
13
|
-
}
|
|
14
|
-
|
|
9
|
+
|
|
10
|
+
/** 获取站点配置(标题、作者、URL 等) */
|
|
11
|
+
export function useClaritySite(): ClaritySiteConfig {
|
|
12
|
+
return useClarityConfig().site
|
|
13
|
+
}
|
|
14
|
+
|
|
15
15
|
/** 获取文章配置的客户端子集(分类图标/颜色、排序方式) */
|
|
16
16
|
export function useClarityArticle(): ClarityAppConfig['article'] {
|
|
17
17
|
return useClarityConfig().article
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
/** 由站点配置生成本站订阅源条目(用于友链页与 OPML) */
|
|
21
|
-
export function useClaritySiteFeedEntry(): FeedEntry {
|
|
22
|
-
const site = useClaritySite()
|
|
23
|
-
return {
|
|
24
|
-
author: site.author.name,
|
|
25
|
-
title: site.title,
|
|
26
|
-
desc: site.subtitle || site.description,
|
|
27
|
-
link: site.url,
|
|
28
|
-
feed: new URL('/atom.xml', site.url).toString(),
|
|
29
|
-
icon: site.favicon,
|
|
30
|
-
avatar: site.author.avatar || site.favicon,
|
|
31
|
-
date: site.established || '',
|
|
32
|
-
comment: '这是我自己',
|
|
33
|
-
}
|
|
34
|
-
}
|
|
19
|
+
|
|
20
|
+
/** 由站点配置生成本站订阅源条目(用于友链页与 OPML) */
|
|
21
|
+
export function useClaritySiteFeedEntry(): FeedEntry {
|
|
22
|
+
const site = useClaritySite()
|
|
23
|
+
return {
|
|
24
|
+
author: site.author.name,
|
|
25
|
+
title: site.title,
|
|
26
|
+
desc: site.subtitle || site.description,
|
|
27
|
+
link: site.url,
|
|
28
|
+
feed: new URL('/atom.xml', site.url).toString(),
|
|
29
|
+
icon: site.favicon,
|
|
30
|
+
avatar: site.author.avatar || site.favicon,
|
|
31
|
+
date: site.established || '',
|
|
32
|
+
comment: '这是我自己',
|
|
33
|
+
}
|
|
34
|
+
}
|