feat: show copyright in header (#297)
Signed-off-by: 北雁 Cryolitia <Cryolitia@gmail.com> Co-authored-by: BeiyanYunyi <14120445+BeiyanYunyi@users.noreply.github.com> Co-authored-by: Neko Ayaka <neko@ayaka.moe>pull/288/head^2
parent
8cea374cb1
commit
fe31b9ef6b
|
@ -35,4 +35,6 @@ coverage/
|
|||
.vscode/settings.json
|
||||
|
||||
# Wrangler temp files
|
||||
.wrangler
|
||||
.wrangler
|
||||
|
||||
.idea
|
|
@ -10,6 +10,7 @@ declare module 'vue' {
|
|||
AppearanceToggle: typeof import('./theme/components/AppearanceToggle.vue')['default']
|
||||
AppSBox: typeof import('./theme/components/AppSBox.vue')['default']
|
||||
ArticlesMenu: typeof import('./theme/components/ArticlesMenu.vue')['default']
|
||||
CopyrightInfo: typeof import('./theme/components/CopyrightInfo.vue')['default']
|
||||
HomeContent: typeof import('./theme/components/HomeContent.vue')['default']
|
||||
PageInfo: typeof import('./theme/components/PageInfo.vue')['default']
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import { ContentData, createContentLoader, defineLoader } from "vitepress";
|
||||
|
||||
let contentLoader = createContentLoader('/**/*.md')
|
||||
|
||||
export interface Node<T> {
|
||||
value: T | null;
|
||||
children: { [key: string]: Node<T> };
|
||||
}
|
||||
|
||||
export interface Trie<T> {
|
||||
root: Node<T>;
|
||||
insert(path: string[], value: T, node: Node<T>): void;
|
||||
insert(path: string[], value: T): void;
|
||||
}
|
||||
|
||||
declare const data: Trie<Record<string, any>>
|
||||
export { data };
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default defineLoader({
|
||||
watch: contentLoader.watch,
|
||||
async load(): Promise<Trie<Record<string, any>>> {
|
||||
let raw: ContentData[] = await contentLoader.load()
|
||||
let trie: Trie<Record<string, any>> = {
|
||||
root: { value: null, children: {} },
|
||||
|
||||
insert(this: Trie<Record<string, any>>, path, value, node: Node<Record<string, any>> = this.root) {
|
||||
if (path.length === 0) {
|
||||
node.value = value
|
||||
} else if (path.length === 1) {
|
||||
if (!(path[0] in node.children)) {
|
||||
node.children[path[0]] = { value: value, children: {} }
|
||||
} else {
|
||||
node.children[path[0]].value = value
|
||||
}
|
||||
} else {
|
||||
if (!(path[0] in node.children)) {
|
||||
let new_node = { value: null, children: {} }
|
||||
this.insert(path.slice(1), value, new_node)
|
||||
node.children[path[0]] = new_node
|
||||
} else {
|
||||
this.insert(path.slice(1), value, node.children[path[0]])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let v of raw) {
|
||||
let frontmatter = v.frontmatter ?? null
|
||||
let copyright = frontmatter?.copyright ?? null
|
||||
if (copyright !== null) {
|
||||
trie.insert(v.url.split('/').filter((item, _index, _array) => item !== ''), {
|
||||
author: frontmatter.author ?? null,
|
||||
title: frontmatter.title ?? null,
|
||||
copyright: copyright
|
||||
})
|
||||
}
|
||||
}
|
||||
return trie;
|
||||
}
|
||||
})
|
|
@ -63,7 +63,7 @@ interface Context {
|
|||
}
|
||||
}
|
||||
|
||||
export interface AppendMarkdownSectionOptions {
|
||||
export interface MarkdownSectionWrapperOptions {
|
||||
/**
|
||||
* The list of file names to exclude from the transformation
|
||||
* @default ['index.md']
|
||||
|
@ -79,7 +79,7 @@ export interface AppendMarkdownSectionOptions {
|
|||
exclude?: (id: string, context: Context) => boolean
|
||||
}
|
||||
|
||||
export function AppendMarkdownSection(options?: AppendMarkdownSectionOptions): Plugin {
|
||||
export function MarkdownSectionWrapper(headerTransformers: ((origin: string) => string)[], footerTransformers: ((origin: string) => string)[], options?: MarkdownSectionWrapperOptions): Plugin {
|
||||
const {
|
||||
excludes = ['index.md'],
|
||||
exclude = () => false,
|
||||
|
@ -88,7 +88,7 @@ export function AppendMarkdownSection(options?: AppendMarkdownSectionOptions): P
|
|||
let root = ''
|
||||
|
||||
return {
|
||||
name: '@pjts/append-markdown-section',
|
||||
name: '@pjts/markdown-section-wrapper',
|
||||
// May set to 'pre' since end user may use vitepress wrapped vite plugin to
|
||||
// specify the plugins, which may cause this plugin to be executed after
|
||||
// vitepress or the other markdown processing plugins.
|
||||
|
@ -116,18 +116,28 @@ export function AppendMarkdownSection(options?: AppendMarkdownSectionOptions): P
|
|||
if (exclude(id, { helpers: { idEndsWith, idEquals, idStartsWith, pathEndsWith, pathEquals, pathStartsWith } }))
|
||||
return null
|
||||
|
||||
code = TemplateAppSBox(code)
|
||||
let headers: string[] = headerTransformers.map(f => f(code))
|
||||
let footers: string[] = footerTransformers.map(f => f(code))
|
||||
|
||||
return code
|
||||
return [...headers, code, ...footers].join("")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function TemplateAppSBox(code: string) {
|
||||
return `${code}
|
||||
export function TemplateAppSBox(_code: string): string {
|
||||
return `
|
||||
|
||||
## 意见反馈
|
||||
|
||||
<AppSBox />
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
export function TemplateCopyrightInfo(_code: string): string {
|
||||
return `
|
||||
|
||||
<CopyrightInfo />
|
||||
|
||||
`
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<script setup lang="ts">
|
||||
import { useData } from "vitepress";
|
||||
import { Node, Trie, data } from "../../plugins/CopyrightLoader.data";
|
||||
|
||||
function searchClosestInTrie(
|
||||
that: Trie<Record<string, any>>,
|
||||
path: string[],
|
||||
node: Node<Record<string, any>> = that.root
|
||||
): Record<string, any> | null {
|
||||
if (path.length === 0) {
|
||||
return node.value;
|
||||
}
|
||||
if (path[0] in node.children) {
|
||||
let value = searchClosestInTrie(
|
||||
that,
|
||||
path.slice(1),
|
||||
node.children[path[0]]
|
||||
);
|
||||
if (value === null) {
|
||||
value = node.value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return node.value;
|
||||
}
|
||||
|
||||
const paths = useData()
|
||||
.page.value.relativePath.split('/')
|
||||
.filter((item: string) => item !== '');
|
||||
const attrs = searchClosestInTrie(data, paths);
|
||||
const frontmatter = useData().frontmatter.value;
|
||||
|
||||
const originUrlExists = (attrs?.copyright?.url ?? null) != null;
|
||||
const originUrl = attrs?.copyright?.url ?? 'javascript:void(0)';
|
||||
|
||||
const license = attrs?.copyright?.license ?? null;
|
||||
const licenseExists = license != null;
|
||||
const licenseUrlExists = (attrs?.copyright?.licenseUrl ?? null) != null;
|
||||
const licenseUrl = attrs?.copyright?.licenseUrl ?? 'javascript:void(0)'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="attrs?.copyright?.enable ?? false">
|
||||
<br />
|
||||
<hr />
|
||||
<div class="tip custom-block">
|
||||
<p class="custom-block-title">Copyright</p>
|
||||
<p>
|
||||
<span>这篇文章 </span>
|
||||
<a v-if="originUrlExists" :href="originUrl">{{ frontmatter.title }}</a>
|
||||
<span v-else>{{ frontmatter.title }}</span>
|
||||
<span> 由 </span>
|
||||
<span v-for="author in attrs?.author" :key="author">{{ author }}</span>
|
||||
<span> 创作</span>
|
||||
<span v-if="licenseExists">
|
||||
<span>,Project Trans 在 </span>
|
||||
<a v-if="licenseUrlExists" :href="licenseUrl">{{ license }}</a>
|
||||
<span v-else>{{ license }}</span>
|
||||
<span> 许可下使用</span>
|
||||
</span>
|
||||
<span>。</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,6 +1,11 @@
|
|||
---
|
||||
title: be a girl 系列
|
||||
author: yuzu trans
|
||||
copyright:
|
||||
enable: true
|
||||
url: https://yuzu-trans.notion.site/efaf2995998b475b95e47aa5efce3edc
|
||||
license: CC BY 4.0
|
||||
licenseUrl: https://creativecommons.org/licenses/by/4.0/
|
||||
---
|
||||
|
||||
'sayo 跨性别公益' 致力于帮助跨性别女性, 和宣传跨性别信息.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { resolve } from 'node:path'
|
||||
import { defineConfig } from 'vite'
|
||||
import { MarkdownTransform } from './.vitepress/plugins/markdownTransform'
|
||||
import { AppendMarkdownSection } from './.vitepress/plugins/appendMarkdownSection'
|
||||
import { MarkdownTransform } from './.vitepress/plugins/MarkdownTransform'
|
||||
import { MarkdownSectionWrapper, TemplateAppSBox, TemplateCopyrightInfo } from './.vitepress/plugins/MarkdownSectionWrapper'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import { GitChangelog, GitChangelogMarkdownSection } from '@nolebase/vitepress-plugin-git-changelog/vite'
|
||||
|
@ -43,15 +43,18 @@ export default defineConfig({
|
|||
return false
|
||||
},
|
||||
}),
|
||||
AppendMarkdownSection({
|
||||
excludes: [],
|
||||
exclude: (_, { helpers }): boolean => {
|
||||
if (helpers.idEquals('index.md'))
|
||||
return true
|
||||
MarkdownSectionWrapper(
|
||||
[TemplateCopyrightInfo],
|
||||
[TemplateAppSBox],
|
||||
{
|
||||
excludes: [],
|
||||
exclude: (_, { helpers }): boolean => {
|
||||
if (helpers.idEquals('index.md'))
|
||||
return true
|
||||
|
||||
return false
|
||||
},
|
||||
}),
|
||||
return false
|
||||
},
|
||||
}),
|
||||
Components({
|
||||
dirs: resolve(__dirname, '.vitepress/theme/components'),
|
||||
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
|
||||
|
|
Loading…
Reference in New Issue