chore(config): 添加项目配置文件和隐私协议

- 添加 .editorconfig 文件统一代码风格
- 添加 .env.development 和 .env.example 环境配置文件
- 添加 .eslintignore 和 .eslintrc.js 代码检查配置
- 添加 .gitignore 版本控制忽略文件配置
- 添加 .prettierignore 格式化忽略配置
- 添加隐私协议HTML文件
- 添加API密钥管理组件基础结构
This commit is contained in:
2026-01-26 14:05:01 +08:00
commit 482e2a2718
1192 changed files with 238401 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
<!-- markdown 解析 -->
<template>
<!-- eslint-disable vue/no-v-html -->
<div
ref="rootRef"
v-html="content"
class="markdown-body"
@click="handleClick"
>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
import type { BytemdPlugin } from 'bytemd';
import { getProcessor } from 'bytemd';
const props = defineProps<{
value: string;
plugins?: BytemdPlugin[];
sanitize?: (schema: any) => any;
}>();
const rootRef = ref<HTMLElement | null>(null);
const content = ref<any | null>(null);
const cbs = ref<(void | (() => void))[]>([]);
const on = () => {
if (props.plugins && rootRef.value && content.value) {
cbs.value = props.plugins.map(({ viewerEffect }) => {
return (
viewerEffect &&
viewerEffect({
markdownBody: rootRef.value as HTMLElement,
file: content.value
})
);
});
}
};
const off = () => {
if (cbs.value) {
cbs.value.forEach((cb) => cb && cb());
}
};
const handleClick = (e: MouseEvent) => {
const $ = e.target as HTMLElement;
if ($.tagName !== 'A') {
return;
}
const href = $.getAttribute('href');
if (!href || !href.startsWith('#')) {
return;
}
const dest = rootRef.value?.querySelector('#user-content-' + href.slice(1));
if (dest) {
dest.scrollIntoView();
}
};
watch(
[() => props.value, () => props.plugins, () => props.sanitize],
() => {
try {
content.value = getProcessor({
plugins: props.plugins,
sanitize: props.sanitize
}).processSync(props.value);
} catch (e) {
console.error(e);
}
off();
nextTick(() => {
on();
});
},
{
immediate: true
}
);
onMounted(() => {
on();
});
onBeforeUnmount(() => {
off();
});
</script>