Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cb0cd7c
refactor(playground): Rebuild playground with Vue [skip ci]
Aug 22, 2026
726d000
feat(locale): Localize playground [skip ci]
Aug 22, 2026
76004df
fix(playground): Improve locale routing [skip ci]
Aug 22, 2026
3b93c2d
refactor(playground): Align layout with reference [skip ci]
Aug 22, 2026
8378d12
Fix markdown playground
Fuyeors Aug 22, 2026
f71836c
feat(playground): Add markdown editing toolbar [skip ci]
Aug 22, 2026
5c1de09
feat(playground): Load examples via HttpClient API [skip ci]
Aug 22, 2026
29d368a
feat(playground): Integrate markdown formatter [skip ci]
Aug 22, 2026
83117fc
refactor(playground): Extract editor toolbar component [skip ci]
Aug 22, 2026
8ea81e8
fix(playground): Preserve scroll position on format [skip ci]
Aug 22, 2026
a1fee81
fix(playground): Support native undo and toggle wrap for toolbar [ski…
Aug 22, 2026
263d743
build(playground): Generate production locales in Docker [skip ci]
Aug 22, 2026
ee904cd
feat(playground): Add share functionality with Compression API [skip ci]
Aug 22, 2026
347535b
feat: Beautify playground
Fuyeors Aug 22, 2026
a11dcd1
feat(playground): Add line numbers and syntax highlighting [skip ci]
Aug 22, 2026
658c313
fix(playground): Enable text selection on syntax highlighter [skip ci]
Aug 22, 2026
f440a09
feat(playground): Use CSS Custom Highlight API [skip ci]
Aug 22, 2026
a73f6cf
feat(playground): Add IndexedDB document history [skip ci]
Aug 22, 2026
a5ce8b6
refactor(playground): Split document history and editor layout [skip ci]
Aug 22, 2026
87fbd92
fix(playground): Restore example on empty history [skip ci]
Aug 23, 2026
e2bb578
feat: Adjust design [skip ci]
Fuyeors Aug 23, 2026
e81efc2
refactor(playground): Use router-link for document history [skip ci]
Aug 23, 2026
726d87a
refactor(playground): Manage document history navigation locally [ski…
Aug 23, 2026
140261a
fix(playground): Reset document route from sidebar [skip ci]
Aug 23, 2026
eec40f7
feat: Optimize editor and preview styles
Fuyeors Aug 23, 2026
ace21f7
feat(playground): Add document statistics [skip ci]
Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
**/dist
**/out
**/tests.failed.json
packages/playground/public/assets/locale/*
14 changes: 14 additions & 0 deletions .localerc.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@fuyeor:registry=https://fpm.fuyeor.com/v1/
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions packages/markdown-parser-vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @fuyeor/markdown-parser-vue/src/index.ts
export { renderToVue } from './render';
132 changes: 113 additions & 19 deletions packages/playground/index.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,114 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, viewport-fit=cover" />
<title>@fuyeor/markdown-parser</title>

<link rel="icon" href="/favicon.svg" sizes="any" />
<!DOCTYPE html>
<html lang="">

<head>
<script>
// IIFE for instant application and change listening, optimized for readability and size.
(function () {
const root = document.documentElement;
const storageKey = 'appearance';
const dark = window.matchMedia('(prefers-color-scheme: dark)');
const contrast = window.matchMedia('(prefers-contrast: high)');
const fontSizeMap = { smallest: .8, small: .9, medium: 1, large: 1.1, largest: 1.2 };

function apply() {
try {
const settings = JSON.parse(localStorage.getItem(storageKey) || '{}');
// Apply Theme: user setting > contrast > dark
const theme = (settings.theme && settings.theme !== 'auto' && settings.theme) || (contrast.matches && 'contrast') || (dark.matches && 'dark');
theme ? root.setAttribute('data-theme', theme) : root.removeAttribute('data-theme');
// Apply Font Size
const size = fontSizeMap[settings.fontSize];
root.style.fontSize = size ? `${size}rem` : '';
} catch { }
}

function handleThemeChange() {
try {
// Only apply system changes if user setting is 'auto' or unset
const settings = JSON.parse(localStorage.getItem(storageKey) || '{}');
if (settings.theme === 'auto' || !settings.theme) apply();
} catch { }
}

dark.addEventListener('change', handleThemeChange);
contrast.addEventListener('change', handleThemeChange);
window.addEventListener('storage', e => { if (e.key === storageKey) apply() });

apply(); // Initial application
})();
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover">

<!-- preconnect and preload access -->
<link rel="preconnect" href="https://deliver.fuyeor.net" crossorigin>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<link rel="dns-prefetch" href="//depend.fuyeor.net">
<link rel="dns-prefetch" href="//cdnjs.cloudflare.com">

<link rel="preload" href="__interactify-css__" as="style">
<link rel="preload" href="/assets/css/style.css" as="style">
<!-- main-js-preload-placeholder -->

<!-- default website information -->
<title>Fuyeor Flavored Markdown Playground</title>
<meta name="description"
content="Fuyeor Flavored Markdown (FFM) is a cross-platform, live-standard markdown specification adapted to modern typography.">

<!-- theme color on mobile -->
<meta name="theme-color" content="#aea4e4" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#18191a" media="(prefers-color-scheme: dark)">

<!-- brand favicon -->
<link rel="icon" href="/favicon.svg" sizes="any">

<link rel="stylesheet" href="__interactify-css__">
<link rel="stylesheet" href="/assets/css/style.css">

<script src="src/main.ts" type="module"></script>
<style>
body {
margin: 0 auto;
}
</style>
</head>

<body>
<markdown-playground></markdown-playground>
</body>
</html>
</head>

<body id="app">

<noscript>
<img class="no-script-logo" src="https://deliver.fuyeor.net/@fu/trademark/tm/official.png">
<h2>JavaScript is not available</h2>
<strong>The site cannot load due to a missing JavaScript environment.</strong>

<style>
body,
html {
height: 100%;
display: flex;
justify-content: center;
align-items: center
}

noscript {
max-width: 660px;
padding: 20px;

.no-script-logo {
max-width: 100px;
margin-bottom: 10px
}

h2,
strong {
color: #586577
}
}

/* hide splash screen when JS is unavailable */
.splash-screen {
display: none !important;
}
</style>
</noscript>

</body>

</html>
29 changes: 18 additions & 11 deletions packages/playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,32 @@
"license": "MIT",
"author": "Fuyeor <https://www.fuyeor.com/@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"
}
}
99 changes: 99 additions & 0 deletions packages/playground/public/assets/css/style.css
Original file line number Diff line number Diff line change
@@ -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);
}
}
45 changes: 45 additions & 0 deletions packages/playground/public/assets/examples/en.ffm
Original file line number Diff line number Diff line change
@@ -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.
Loading