diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9d08a1a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore index ab234eb..c1c1f15 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ **/dist **/out **/tests.failed.json +packages/playground/public/assets/locale/* diff --git a/.localerc.json b/.localerc.json new file mode 100644 index 0000000..0781c8e --- /dev/null +++ b/.localerc.json @@ -0,0 +1,14 @@ +{ + "basic": { + "source": "packages/playground/node_modules/@fuyeor/locale/src/common.json", + "outDir": "packages/playground/public/assets/locale" + }, + "main": { + "source": "packages/playground/src/locale/locale.json", + "outDir": "packages/playground/public/assets/locale" + }, + "prod": { + "source": "packages/playground/src/locale/locale.json", + "outDir": "packages/playground/public/assets/locale" + } +} diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..424942b --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@fuyeor:registry=https://fpm.fuyeor.com/v1/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 1223cd0..af9c146 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "editor.formatOnSave": true, // assign default formatting tool "[html]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "vscode.html-language-features" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" diff --git a/Dockerfile b/Dockerfile index d9352d3..a0be6bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,8 +26,11 @@ COPY . . # build parser package before workspace consumers resolve its package exports RUN pnpm --filter @fuyeor/markdown-parser build +# generate production locale assets before the playground build copies public files +RUN pnpm locale make playground prod + # build playground -RUN pnpm --filter @fuyeor/markdown-parser-playground build +RUN pnpm --filter @fuyeor/markdown-playground build # ========================================== # release diff --git a/package.json b/package.json index c188742..6786f01 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,11 @@ "scripts": { "format": "prettier --write \"**/*.ts\"", "test": "pnpm -F @fuyeor/markdown-parser test", - "playground": "pnpm -F @fuyeor/markdown-playground dev" + "playground": "pnpm -F @fuyeor/markdown-playground dev", + "locale": "locale-cli" }, "devDependencies": { + "@fuyeor/locale-cli": "^0.1.1", "@types/node": "^25.6.0", "jsdom": "^29.0.1", "prettier": "^3.8.3", diff --git a/packages/markdown-parser-vue/src/index.ts b/packages/markdown-parser-vue/src/index.ts new file mode 100644 index 0000000..d54cf72 --- /dev/null +++ b/packages/markdown-parser-vue/src/index.ts @@ -0,0 +1,2 @@ +// @fuyeor/markdown-parser-vue/src/index.ts +export { renderToVue } from './render'; diff --git a/packages/playground/index.html b/packages/playground/index.html index 157bee3..64e5d83 100644 --- a/packages/playground/index.html +++ b/packages/playground/index.html @@ -1,20 +1,114 @@ - - - - - - @fuyeor/markdown-parser - - + + + + + + + + + + + + + + + + + + + + + + Fuyeor Flavored Markdown Playground + + + + + + + + + + + + - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/packages/playground/package.json b/packages/playground/package.json index fa5166f..6dd0db8 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -3,25 +3,32 @@ "license": "MIT", "author": "Fuyeor ", "type": "module", - "sideEffects": false, "scripts": { "dev": "vite dev", - "build": "vite build" - }, - "imports": { - "#/*": "./src/*" + "build": "vite build", + "typecheck": "vue-tsc --noEmit" }, "exports": { ".": "./src/main.ts" }, "dependencies": { - "@fuyeor/markdown-parser-lit": "workspace:*", - "@fuyeor/locale": "https://github.com/Fuyeor/webroamer.git#path:packages/locale", - "lit": "^3.3.2" + "@fuyeor/commons": "^0.1.2", + "@fuyeor/config": "^0.1.1", + "@fuyeor/interactify": "^0.1.1", + "@fuyeor/locale": "^0.1.0", + "@fuyeor/markdown-formatter": "workspace:*", + "@fuyeor/markdown-parser": "workspace:*", + "@fuyeor/markdown-parser-vue": "workspace:*", + "@fuyeor/vue-router": "^0.0.9", + "vue": "^3.5.41" }, "devDependencies": { - "@types/node": "^25.6.0", - "typescript": "^6.0.3", - "vite": "^8.0.1" + "@fuyeor/tsconfig": "0.1.0", + "@types/node": "^26.2.0", + "@vitejs/plugin-vue": "^6.0.8", + "html-minifier-terser": "^7.2.0", + "lightningcss": "^1.33.0", + "typescript": "^7.0.2", + "vite": "8.0.1" } } diff --git a/packages/playground/public/assets/css/style.css b/packages/playground/public/assets/css/style.css new file mode 100644 index 0000000..fbd8821 --- /dev/null +++ b/packages/playground/public/assets/css/style.css @@ -0,0 +1,99 @@ +:root { + --width-body: 100%; + --width-main: 1000px; + --width-left-sidebar: 350px; + --width-right-sidebar: 0; + + --playground-border: #e2e8f0; + --playground-bg-section: #ffffff; + --playground-bg-header: #f8fafc; + --playground-font-mono: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; +} + +@media (width >= 1000px) { + main { + width: 100%; + } + + .header { + border: none; + } +} + +h3::after { + display: none; +} + +.markdown-rendered { + ol, + ul { + margin: 0 0 20px 20px; + padding: 0; + } + + li { + margin: 10px 0 10px 0; + } + + code, + pre, + pre * { + font-size: 0.9rem; + } +} + +html { + /* remove scroll bar */ + scrollbar-gutter: unset; +} + +body { + overflow: hidden; +} + +.playground-layout { + display: grid; + grid-template-columns: minmax(280px, 1fr) minmax(360px, 1.2fr); + height: calc(-110px + 100vh); +} + +.section { + display: flex; + flex-direction: column; + min-width: 0; + min-height: 0; + overflow: hidden; +} + +.editor { + border-right: var(--border-subtle); + + textarea { + flex: 1; + resize: none; + background: transparent; + font: 400 13px / 1.6 var(--playground-font-mono); + tab-size: 2; + overflow-y: auto; + } + + textarea:hover, + textarea:focus { + box-shadow: none; + } +} + +@media (width <= 900px) { + .playground-layout { + height: auto; + grid-template-columns: 1fr; + grid-template-rows: 400px 520px; + position: absolute; + top: var(--height-header); + } + + .preview { + border-top: var(--border-subtle); + } +} diff --git a/packages/playground/public/assets/examples/en.ffm b/packages/playground/public/assets/examples/en.ffm new file mode 100644 index 0000000..fdee748 --- /dev/null +++ b/packages/playground/public/assets/examples/en.ffm @@ -0,0 +1,45 @@ +# Welcome to Markdown Playground + +Edit the **Markdown** on the left and inspect the live outputs. + +This is a fully-featured Markdown parser that supports standard Markdown syntax, including: + +## Text Formatting + +You can use *italics*, **bold**, ~~strikethrough~~, and `inline code`. + +## Lists and Tasks + +- Unordered list item 1 +- Unordered list item 2 + - Nested list item +- [ ] Todo item +- [x] Completed item + +1. Ordered list item 1 +2. Ordered list item 2 + +## Blockquotes and Code Blocks + +> This is a blockquote. +> It can contain multiple lines of text. + +```javascript +// This is a code block +function hello() { + console.log("Hello, Markdown!"); +} +``` + +## Links and Images + +Visit [Fuyeor](https://www.fuyeor.com) to learn more. + +## Tables + +| Header 1 | Header 2 | Header 3 | +| --- | --- | --- | +| Cell 1 | Cell 2 | Cell 3 | +| Cell 4 | Cell 5 | Cell 6 | + +Switch the tabs on the right to view the Vue rendered preview, JSON (AST), and serialized HTML output. diff --git a/packages/playground/public/assets/examples/zh-hans.ffm b/packages/playground/public/assets/examples/zh-hans.ffm new file mode 100644 index 0000000..4cf4064 --- /dev/null +++ b/packages/playground/public/assets/examples/zh-hans.ffm @@ -0,0 +1,45 @@ +# 欢迎使用 Markdown 演练场 + +在左侧编辑**Markdown**,实时查看输出结果。 + +这是一个功能齐全的 Markdown 解析器,支持标准的 Markdown 语法,包括: + +## 文本格式化 + +你可以使用 *斜体*、**粗体**、~~删除线~~,以及 `内联代码`。 + +## 列表与任务 + +- 无序列表项 1 +- 无序列表项 2 + - 嵌套列表项 +- [ ] 待办事项 +- [x] 已完成事项 + +1. 有序列表项 1 +2. 有序列表项 2 + +## 引用与代码块 + +> 这是一个引用块。 +> 它可以包含多行文本。 + +```javascript +// 这是一个代码块 +function hello() { + console.log("Hello, Markdown!"); +} +``` + +## 链接与图片 + +访问 [Fuyeor](https://www.fuyeor.com) 了解更多。 + +## 表格 + +| 标题 1 | 标题 2 | 标题 3 | +| --- | --- | --- | +| 单元格 1 | 单元格 2 | 单元格 3 | +| 单元格 4 | 单元格 5 | 单元格 6 | + +切换右侧的标签页,你可以分别查看 Vue 渲染预览、JSON (AST) 和序列化的 HTML 结果。 diff --git a/packages/playground/favicon.svg b/packages/playground/public/favicon.svg similarity index 100% rename from packages/playground/favicon.svg rename to packages/playground/public/favicon.svg diff --git a/packages/playground/public/robots.txt b/packages/playground/public/robots.txt new file mode 100644 index 0000000..26b4d70 --- /dev/null +++ b/packages/playground/public/robots.txt @@ -0,0 +1,2 @@ +User-Agent: * +Allow: / \ No newline at end of file diff --git a/packages/playground/src/App.vue b/packages/playground/src/App.vue new file mode 100644 index 0000000..395a7f2 --- /dev/null +++ b/packages/playground/src/App.vue @@ -0,0 +1,23 @@ + + + + diff --git a/packages/playground/src/api/examples.ts b/packages/playground/src/api/examples.ts new file mode 100644 index 0000000..b06e81f --- /dev/null +++ b/packages/playground/src/api/examples.ts @@ -0,0 +1,11 @@ +// @/api/examples.ts +import apiClient from './index'; + +export async function fetchExample(locale: string): Promise { + try { + return await apiClient.get(`assets/examples/${locale}.ffm`); + } catch (error) { + // Fallback to English example if the requested locale is not found + return await apiClient.get('assets/examples/en.ffm'); + } +} diff --git a/packages/playground/src/api/index.ts b/packages/playground/src/api/index.ts new file mode 100644 index 0000000..549b061 --- /dev/null +++ b/packages/playground/src/api/index.ts @@ -0,0 +1,9 @@ +// @/api/index.ts +import { HttpClient } from '@fuyeor/commons'; + +const apiClient = new HttpClient({ + baseURL: '/', + timeout: 10000, +}); + +export default apiClient; diff --git a/packages/playground/src/components/Playground/DocumentHistory.vue b/packages/playground/src/components/Playground/DocumentHistory.vue new file mode 100644 index 0000000..6843dac --- /dev/null +++ b/packages/playground/src/components/Playground/DocumentHistory.vue @@ -0,0 +1,291 @@ + + + + + + diff --git a/packages/playground/src/components/Playground/DocumentStatsBar.vue b/packages/playground/src/components/Playground/DocumentStatsBar.vue new file mode 100644 index 0000000..3fda9f2 --- /dev/null +++ b/packages/playground/src/components/Playground/DocumentStatsBar.vue @@ -0,0 +1,55 @@ + + + + + + diff --git a/packages/playground/src/components/Playground/MarkdownToolbar.vue b/packages/playground/src/components/Playground/MarkdownToolbar.vue new file mode 100644 index 0000000..1961202 --- /dev/null +++ b/packages/playground/src/components/Playground/MarkdownToolbar.vue @@ -0,0 +1,127 @@ + + + + + + diff --git a/packages/playground/src/components/Playground/PlaygroundEditor.vue b/packages/playground/src/components/Playground/PlaygroundEditor.vue new file mode 100644 index 0000000..e90b377 --- /dev/null +++ b/packages/playground/src/components/Playground/PlaygroundEditor.vue @@ -0,0 +1,245 @@ + +