kecare 1.0.0-beta.54

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 ADDED
@@ -0,0 +1,15 @@
1
+ # kecare-tools
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.2.22. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
package/__VERSION__.ts ADDED
@@ -0,0 +1 @@
1
+ export const __VERSION__ = '1.0.0-beta.54'
@@ -0,0 +1,104 @@
1
+ export type Article = {
2
+ id: string;
3
+ title: string;
4
+ sticky?: number;
5
+ desc?: string;
6
+ coverSrc?: string;
7
+ contentHtml: string;
8
+ date: string;
9
+ author?: string;
10
+ to: string;
11
+ menu?: string | null;
12
+ menudata?: NavItem[] | null;
13
+ headings: Heading[];
14
+ hidden?: boolean;
15
+ filename?: string;
16
+ translate?: boolean;
17
+ targetLanguage?: string;
18
+ Variant: ArticleVariant;
19
+ };
20
+
21
+ type ArticleVariant = {
22
+ title: string | undefined;
23
+ contentHtml: string | undefined;
24
+ language: string | undefined;
25
+ headings: Heading[];
26
+ };
27
+
28
+ export type HeadingH1 = {
29
+ depth: 1;
30
+ text: string;
31
+ id: string;
32
+ children: HeadingH2[];
33
+ };
34
+ export type HeadingH2 = {
35
+ depth: 2;
36
+ text: string;
37
+ id: string;
38
+ };
39
+ export type Heading = HeadingH1 | HeadingH2;
40
+
41
+ /**
42
+ * Translation configuration (user-configurable settings)
43
+ */
44
+ export type TranslationConfigOptions = {
45
+ /**
46
+ * Model name (e.g., 'deepseek-chat', 'gpt-4', etc.)
47
+ */
48
+ model?: string;
49
+ /**
50
+ * API base URL
51
+ */
52
+ baseUrl?: string;
53
+ /**
54
+ * API key
55
+ */
56
+ apiKey?: string;
57
+ /**
58
+ * Additional system prompts
59
+ */
60
+ additionalPrompts?: string[];
61
+ };
62
+
63
+ export type TranslateCallOptions = {
64
+ /**
65
+ * Text to translate
66
+ */
67
+ text: string;
68
+ /**
69
+ * Target language (optional, defaults to TranslationConfig.targetLanguage)
70
+ */
71
+ targetLanguage?: string;
72
+ /**
73
+ * Model name (optional, defaults to TranslationConfig.model)
74
+ */
75
+ model?: string;
76
+ /**
77
+ * Additional system prompts (optional, defaults to TranslationConfig.additionalPrompts)
78
+ */
79
+ additionalPrompts?: string[];
80
+ /*
81
+ *
82
+ */
83
+ title: string;
84
+ };
85
+
86
+ export type ArticleListGenerator = (params: { projectPath: string; article: Article; articles: Article[]; NavItems: NavItem[] }) => Promise<{
87
+ path: string;
88
+ template: string;
89
+ }>;
90
+
91
+ export type PagesListGenerator = (params: { projectPath: string; page: number; cards: []; isIndex: number; pageSize: number; totalPages: number; totalArticles: number; listTitle: number }) => Promise<{
92
+ path: string;
93
+ template: string;
94
+ }>;
95
+
96
+ export type NavItem = { text: string; link: string; level: number; desc?: string; icon?: string } | { text: string; items: NavItem[]; level: number };
97
+
98
+ export function defineArticleListGenerator<Generator extends ArticleListGenerator>(yourGenerator: Generator) {
99
+ return yourGenerator;
100
+ }
101
+
102
+ export function PagesListGenerator<Generator extends PagesListGenerator>(yourGenerator: Generator) {
103
+ return yourGenerator;
104
+ }
package/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./generator-helpers/__ROOT__.ts";
2
+ export * from "./sdk/__ROOT__.ts";
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "kecare",
3
+ "version": "1.0.0-beta.54",
4
+ "module": "index.ts",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/pamperkyumi/kecare"
9
+ },
10
+ "devDependencies": {
11
+ "@types/bun": "latest"
12
+ },
13
+ "peerDependencies": {
14
+ "typescript": "^5"
15
+ }
16
+ }
@@ -0,0 +1,36 @@
1
+ import { onMountedSidebar } from './sidebar';
2
+ import { style } from './style';
3
+ import { onMountedSyntaxHighlight } from './syntax-highlight';
4
+
5
+ let instancePromise: ReturnType<typeof createKecareSDK> | null = null; // 缓存 Promise
6
+
7
+ async function createKecareSDK() {
8
+ if (typeof window === 'undefined' || typeof document === 'undefined') return; // 确保在浏览器环境下运行,在服务端渲染或其他情况下不执行
9
+
10
+ await style();
11
+
12
+ // 等待页面完全加载
13
+ const loaded = new Promise((resolve) => {
14
+ if (document.readyState === 'complete') resolve(undefined);
15
+ else window.addEventListener('load', resolve, { once: true });
16
+ });
17
+
18
+ const kecareSDK = {
19
+ mounted: async () => {
20
+ await loaded;
21
+ const articleElement = document.querySelector('.kecare')! as HTMLDivElement;
22
+ await onMountedSidebar(articleElement);
23
+ await onMountedSyntaxHighlight(articleElement);
24
+ },
25
+ }
26
+
27
+
28
+ return kecareSDK;
29
+ }
30
+
31
+ export function useKecareSDK() {
32
+ if (!instancePromise) {
33
+ instancePromise = createKecareSDK();
34
+ }
35
+ return instancePromise;
36
+ }
package/sdk/sidebar.ts ADDED
@@ -0,0 +1,65 @@
1
+ export async function onMountedSidebar(articleElement: HTMLDivElement) {
2
+ const articleSidebarElement = document.querySelector('.kecare-sidebar');
3
+ if (!articleSidebarElement) return; // 主题开发者如果没有在主题里添加侧边栏元素,则不执行侧边栏相关逻辑
4
+
5
+ const headings = articleElement.querySelectorAll('h1, h2, h3, h4, h5, h6');
6
+ const headingHierarchy: Array<{ level: number; element: HTMLElement; children: typeof headingHierarchy }> = [];
7
+
8
+ const stack: typeof headingHierarchy = [];
9
+ for (let i = 0; i < headings.length; i++) {
10
+ const heading = headings[i]!;
11
+ const level = parseInt(heading.tagName[1]!);
12
+ const node = { level, element: heading as HTMLElement, children: [] };
13
+
14
+ // 找到正确的父节点
15
+ while (stack.length > 0 && stack[stack.length - 1]!.level >= level) {
16
+ stack.pop();
17
+ }
18
+
19
+ if (stack.length > 0) stack[stack.length - 1]!.children.push(node);
20
+ else headingHierarchy.push(node);
21
+
22
+ stack.push(node);
23
+ }
24
+
25
+ function buildTOC(nodes: typeof headingHierarchy, isSub = false): string {
26
+ let result = '';
27
+ for (const node of nodes) {
28
+ const element = node.element;
29
+ const id = element.id || '';
30
+ const text = element.textContent || '';
31
+ const linkClass = isSub ? 'toc-sublink' : 'toc-link';
32
+
33
+ result += `<li class="${isSub ? 'toc-subitem' : 'toc-item'}">`;
34
+ result += `<a class="${linkClass}" data-target="${id}" title="${text}">${text}</a>`;
35
+
36
+ if (node.children.length > 0) {
37
+ result += `<ul class="toc-sublist">`;
38
+ result += buildTOC(node.children, true);
39
+ result += `</ul>`;
40
+ }
41
+
42
+ result += `</li>`;
43
+ }
44
+ return result;
45
+ }
46
+
47
+ const tocHtml = `<ul class="toc-list">${buildTOC(headingHierarchy)}</ul>`;
48
+ articleSidebarElement.innerHTML = tocHtml;
49
+
50
+ // 注册点击事件
51
+ const links = articleSidebarElement.querySelectorAll('a.toc-link, a.toc-sublink');
52
+ for (let i = 0; i < links.length; i++) {
53
+ const link = links[i] as HTMLAnchorElement;
54
+ link.addEventListener('click', (e) => {
55
+ e.preventDefault();
56
+ const targetId = link.dataset.target;
57
+ if (!targetId) return;
58
+ const targetElement = document.getElementById(targetId);
59
+ if (targetElement) {
60
+ targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
61
+ }
62
+ });
63
+ }
64
+
65
+ }
package/sdk/style.ts ADDED
@@ -0,0 +1,12 @@
1
+ export const __STYLE__ = `
2
+ .kecare h1 {
3
+ font-size: 24px;
4
+ }
5
+ `; // 这里放你需要在用户那边加载的编辑器区域的样式
6
+
7
+ export async function style() {
8
+ // 创建 style 标签并添加到 head
9
+ const styleElement = document.createElement('style');
10
+ styleElement.textContent = __STYLE__;
11
+ document.head.appendChild(styleElement);
12
+ }
@@ -0,0 +1,30 @@
1
+ export async function onMountedSyntaxHighlight(articleElement: HTMLDivElement) {
2
+ const codeElements = articleElement.querySelectorAll('code');
3
+ const { codeToHtml } = await import('shiki');
4
+
5
+ for (const codeElement of codeElements) {
6
+ const classList = codeElement.className.split(' ')
7
+ const langClass = classList.find(cls => cls.startsWith('language-'))
8
+ const lang = langClass ? langClass.replace('language-', '') : 'text'
9
+
10
+ const code = codeElement.textContent || '';
11
+
12
+ const highlightedHtml = await codeToHtml(code, {
13
+ lang,
14
+ theme: 'one-dark-pro' // or 亮色主题 one-light
15
+ })
16
+
17
+ const tempDiv = document.createElement('div')
18
+ tempDiv.innerHTML = highlightedHtml
19
+ const preElement = tempDiv.firstElementChild
20
+
21
+ if (!preElement) continue
22
+
23
+ const parentElement = codeElement.parentElement
24
+ if (parentElement && parentElement.tagName === 'PRE') {
25
+ parentElement.replaceWith(preElement)
26
+ } else {
27
+ codeElement.replaceWith(preElement)
28
+ }
29
+ }
30
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext", "DOM"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+
24
+ // Some stricter flags (disabled by default)
25
+ "noUnusedLocals": false,
26
+ "noUnusedParameters": false,
27
+ "noPropertyAccessFromIndexSignature": false
28
+ }
29
+ }