feat(docs): sync Used by logos and polish playground

Inline README Used by grid on the docs homepage, refine playground layout and live output behavior, and drop the unused build-used-by script from package scripts.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Yang Jun
2026-06-23 13:41:56 +08:00
co-authored by Cursor
parent c0ec9fcb66
commit 8b617a5ecf
9 changed files with 184 additions and 103 deletions
-2
View File
@@ -6,8 +6,6 @@
"version": "7.3.0"
},
"scripts": {
"prebuild": "npm --prefix .. run build:docs-liquid && npm --prefix .. run build:contributors",
"prestart": "npm --prefix .. run build:docs-liquid && npm --prefix .. run build:contributors",
"build": "hexo generate",
"start": "hexo serve",
"lint": "eslint .",
+13 -13
View File
@@ -14,19 +14,6 @@
</div>
</div>
</div>
<div id="contributors-wrap">
<div class="wrapper">
<div class="inner inner-content">
<div class="section-header">
<h3>{{__('index.contributors.title')}}</h3>
<p class="description">{{__('index.contributors.description')}}</p>
</div>
<div class="contributors">
{{ partial('partial/all-contributors') }}
</div>
</div>
</div>
</div>
<div id="used-by-wrap">
<div class="wrapper">
<div class="inner inner-content">
@@ -53,3 +40,16 @@
</div>
</div>
</div>
<div id="contributors-wrap">
<div class="wrapper">
<div class="inner inner-content">
<div class="section-header">
<h3>{{__('index.contributors.title')}}</h3>
<p class="description">{{__('index.contributors.description')}}</p>
</div>
<div class="contributors">
{{ partial('partial/all-contributors') }}
</div>
</div>
</div>
</div>
+1
View File
@@ -3,6 +3,7 @@
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src-min/ace.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src-min/mode-liquid.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src-min/mode-json.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src-min/mode-html.js"></script>
<script>ace.config.set('basePath', 'https://cdn.jsdelivr.net/npm/[email protected]/src-min/');</script>
{% endif %}
+4 -6
View File
@@ -12,7 +12,7 @@
<div class="playground-workspace">
<div class="playground-pane area-tpl">
<div class="pane-head">
<span class="pane-indicator" aria-hidden="true"></span>
<span class="pane-indicator" data-state="idle" aria-hidden="true"></span>
<h2>Template</h2>
</div>
<div class="pane-body">
@@ -21,7 +21,7 @@
</div>
<div class="playground-pane area-data">
<div class="pane-head">
<span class="pane-indicator" aria-hidden="true"></span>
<span class="pane-indicator" data-state="idle" aria-hidden="true"></span>
<h2>Context</h2>
</div>
<div class="pane-body">
@@ -30,13 +30,11 @@
</div>
<div class="playground-pane area-output">
<div class="pane-head">
<span class="pane-indicator" aria-hidden="true"></span>
<span class="pane-indicator" data-state="idle" aria-hidden="true"></span>
<h2>Output</h2>
</div>
<div class="pane-body">
<div class="output-preview" id="previewEl">
<pre class="highlight"><code class="language-markup" id="previewCode">{{__('playground.loading')}}</code></pre>
</div>
<div class="editor output-editor" id="previewEl"></div>
</div>
</div>
</div>
+2 -2
View File
@@ -166,7 +166,7 @@
&:hover
color: var(--color-link-hover)
#used-by-wrap, #sponsors-wrap
#sponsors-wrap
background: var(--color-content-bg)
.inner
h3
@@ -181,7 +181,7 @@
#contributors-wrap
border: none
overflow: hidden;
overflow: hidden
.contributors
tr
+77 -50
View File
@@ -90,21 +90,18 @@
grid-row: 1
grid-column: 1
min-height: 0
.pane-indicator
background: var(--color-link)
--pane-dot: var(--color-link)
.area-data
grid-row: 2
grid-column: 1
min-height: 0
.pane-indicator
background: var(--highlight-orange)
--pane-dot: var(--highlight-orange)
.area-output
grid-column: 2
grid-row: 1 / -1
min-height: 0
min-width: 0
.pane-indicator
background: var(--highlight-green)
--pane-dot: var(--highlight-green)
@media mq-mobile
grid-row: auto
grid-column: 1
@@ -145,6 +142,66 @@
height: 8px
border-radius: 50%
flex-shrink: 0
background: unquote('color-mix(in srgb, var(--pane-dot) 38%, var(--color-border))')
transition: background 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease
&[data-state="active"]
background: var(--pane-dot)
animation: playground-dot-typing 0.85s ease-in-out infinite
&[data-state="pending"]
background: var(--highlight-yellow)
&[data-state="ok"]
background: var(--highlight-green)
animation: playground-dot-ok 0.45s ease-out
&[data-state="error"]
background: var(--highlight-red)
animation: playground-dot-error 0.35s ease-out
.area-output .pane-indicator
&[data-state="pending"]
animation: playground-dot-pending 0.55s ease-in-out infinite
@keyframes playground-dot-typing
0%, 100%
transform: scale(1)
box-shadow: 0 0 0 0 unquote('color-mix(in srgb, var(--pane-dot) 0%, transparent)')
50%
transform: scale(1.2)
box-shadow: 0 0 0 4px unquote('color-mix(in srgb, var(--pane-dot) 28%, transparent)')
@keyframes playground-dot-pending
0%, 100%
transform: scale(1)
opacity: 0.75
50%
transform: scale(1.12)
opacity: 1
@keyframes playground-dot-ok
0%
transform: scale(0.85)
box-shadow: 0 0 0 0 unquote('color-mix(in srgb, var(--highlight-green) 50%, transparent)')
70%
transform: scale(1.15)
box-shadow: 0 0 0 5px unquote('color-mix(in srgb, var(--highlight-green) 0%, transparent)')
100%
transform: scale(1)
box-shadow: none
@keyframes playground-dot-error
0%, 100%
transform: translateX(0)
20%
transform: translateX(-2px)
40%
transform: translateX(2px)
60%
transform: translateX(-1px)
80%
transform: translateX(1px)
.pane-body
flex: 1 1 auto
@@ -156,27 +213,33 @@
background: var(--highlight-background)
.area-tpl .pane-body,
.area-data .pane-body
.area-data .pane-body,
.area-output .pane-body
padding: var(--playground-inset)
box-sizing: border-box
@media mq-mobile
padding: 12px
.area-tpl .ace_gutter,
.area-data .ace_gutter
display: none !important
width: 0 !important
min-width: 0 !important
.area-data .ace_gutter,
.area-output .ace_gutter
display: none
width: 0
min-width: 0
.area-tpl .ace_editor,
.area-data .ace_editor,
.area-output .ace_editor,
.area-tpl .ace_scroller,
.area-data .ace_scroller,
.area-output .ace_scroller,
.area-tpl .ace_content,
.area-data .ace_content,
.area-output .ace_content,
.area-tpl .ace_text-layer,
.area-data .ace_text-layer
background: transparent !important
.area-data .ace_text-layer,
.area-output .ace_text-layer
background: transparent
.editor
flex: 1 1 auto
@@ -186,45 +249,9 @@
@media mq-mobile
min-height: 180px
.output-preview
flex: 1 1 auto
min-height: 0
min-width: 0
width: 100%
overflow: auto
.output-editor
@media mq-mobile
min-height: 120px
pre.highlight
margin: 0
min-height: 100%
width: 100%
box-sizing: border-box
padding: var(--playground-inset)
border: none
box-shadow: none
border-radius: 0
background: transparent
color: var(--highlight-foreground)
overflow-x: hidden
overflow-y: auto
white-space: pre-wrap
overflow-wrap: break-word
@media mq-mobile
padding: 12px
code
display: block
width: 100%
box-sizing: border-box
font-family: font-mono
font-size: 14px
line-height: 1.55
color: var(--highlight-foreground)
background: transparent
padding: 0
white-space: inherit
overflow-wrap: inherit
@media mq-mobile
font-size: 13px
.ace_editor
font-family: font-mono
+62 -16
View File
@@ -48,11 +48,15 @@
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
const editor = createEditor('editorEl', 'liquid');
const dataEditor = createEditor('dataEl', 'json');
const previewCode = document.getElementById('previewCode');
const previewEditor = createEditor('previewEl', 'html', { readOnly: true });
const indicatorTpl = document.querySelector('.area-tpl .pane-indicator');
const indicatorData = document.querySelector('.area-data .pane-indicator');
const indicatorOutput = document.querySelector('.area-output .pane-indicator');
const editors = [editor, dataEditor];
const editors = [editor, dataEditor, previewEditor];
let previewValue = '';
let hadPreview = false;
let renderTimer = null;
const RENDER_DELAY = 180;
colorScheme.addEventListener('change', function() {
editors.forEach(applyEditorTheme);
if (previewValue) setPreview(previewValue);
@@ -63,9 +67,11 @@
editor.setValue(init.tpl, 1);
dataEditor.setValue(init.data, 1);
}
editor.on('change', update);
dataEditor.on('change', update);
update();
editor.on('change', onTemplateChange);
dataEditor.on('change', onContextChange);
editor.on('focus', function () { setIndicator(indicatorTpl, 'active'); });
dataEditor.on('focus', function () { setIndicator(indicatorData, 'active'); });
scheduleUpdate();
ready();
function ready() {
@@ -91,7 +97,8 @@
editor.container.style.background = 'transparent';
}
function createEditor(id, lang) {
function createEditor(id, lang, options) {
options = options || {};
const editor = ace.edit(id);
applyEditorTheme(editor);
editor.setOptions({
@@ -110,6 +117,10 @@
editor.renderer.$gutter.style.display = 'none';
}
editor.renderer.setScrollMargin(0, 0, 0, 0);
if (options.readOnly) {
editor.setReadOnly(true);
editor.getSession().setUseWrapMode(true);
}
bindClipboard(editor);
return editor;
}
@@ -166,23 +177,58 @@
return utoa(obj.tpl) + ',' + utoa(obj.data);
}
function setPreview (value) {
previewValue = value
previewCode.textContent = value
function setPreview(value) {
previewValue = value;
previewEditor.setValue(value, -1);
previewEditor.clearSelection();
}
function setIndicator(indicator, state) {
if (indicator) indicator.dataset.state = state;
}
function onTemplateChange() {
setIndicator(indicatorTpl, 'active');
if (indicatorData.dataset.state !== 'error') setIndicator(indicatorData, 'idle');
setIndicator(indicatorOutput, 'pending');
scheduleUpdate();
}
function onContextChange() {
setIndicator(indicatorData, 'active');
if (indicatorTpl.dataset.state !== 'error') setIndicator(indicatorTpl, 'idle');
setIndicator(indicatorOutput, 'pending');
scheduleUpdate();
}
function scheduleUpdate() {
clearTimeout(renderTimer);
renderTimer = setTimeout(update, RENDER_DELAY);
}
async function update() {
const tpl = editor.getValue();
const data = dataEditor.getValue();
history.replaceState({}, '', '#' + serializeArgs({tpl, data}));
let parsed;
try {
const html = await engine.parseAndRender(tpl, JSON.parse(data));
if (html !== '' || !hadPreview) {
setPreview(html);
if (html !== '') hadPreview = true;
}
parsed = JSON.parse(data);
} catch (err) {
// keep last successful output while template or context is invalid
setIndicator(indicatorData, 'error');
setIndicator(indicatorTpl, 'idle');
setIndicator(indicatorOutput, 'error');
return;
}
try {
const html = await engine.parseAndRender(tpl, parsed);
setPreview(html);
setIndicator(indicatorTpl, 'idle');
setIndicator(indicatorData, 'idle');
setIndicator(indicatorOutput, 'ok');
} catch (err) {
setIndicator(indicatorTpl, 'error');
setIndicator(indicatorData, 'idle');
setIndicator(indicatorOutput, 'error');
}
}