play.wenpai.net/play/index.html
elementary-qa e62d72702b
All checks were successful
Deploy play.wenpai.net / deploy (push) Successful in 2s
fix: 体验走查 P2 收尾 — skip-link / mobile-hint / 移除误导 loading
- 添加 skip-to-content 无障碍跳转链接
- mobile-hint 提示文案更友好
- 移除按钮点击 4 秒 loading 态(target=_blank 新标签,loading 无意义)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:55:09 +08:00

628 lines
23 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文派体验场 — play.wenpai.net</title>
<meta name="description" content="在浏览器中即时体验 WordPress 插件,无需安装任何软件">
<meta property="og:title" content="文派体验场">
<meta property="og:description" content="在浏览器中即时体验 WordPress 插件">
<meta property="og:url" content="https://play.wenpai.net/">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>&#9654;</text></svg>">
<link rel="apple-touch-icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>&#9654;</text></svg>">
<style>
:root {
--ink: #101828;
--ink-soft: #344054;
--ink-muted: #667085;
--border: #e5e7eb;
--border-light: #f3f4f6;
--surface: #ffffff;
--surface-dim: #f9fafb;
--accent: #3858e9;
--accent-hover: #2d46b9;
--radius: 8px;
--radius-sm: 6px;
--font: -apple-system, 'PingFang SC', 'Microsoft YaHei',
'Noto Sans SC', 'Helvetica Neue', sans-serif;
--ease: cubic-bezier(0.16, 1, 0.3, 1);
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: var(--font);
background: var(--surface);
color: var(--ink);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
.container { max-width: 960px; margin: 0 auto; padding: 0 1.5rem; }
/* ── Hero ── */
.hero {
background: var(--ink);
color: var(--surface);
padding: 5rem 1.5rem 4.5rem;
text-align: center;
}
.hero-inner { max-width: 960px; margin: 0 auto; }
.hero-wp {
width: 36px; height: 36px;
margin: 0 auto 1.5rem;
opacity: 0.5;
}
.hero-wp svg { width: 100%; height: 100%; }
.hero h1 {
font-size: 2.5rem;
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.15;
margin-bottom: 0.75rem;
}
.hero p {
font-size: 1.0625rem;
color: rgba(255,255,255,0.7);
line-height: 1.6;
font-weight: 400;
}
.hero-icons {
display: flex;
justify-content: center;
gap: 1rem;
margin-top: 2.5rem;
}
.hero-icon-dot {
width: 36px; height: 36px;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
background: rgba(255,255,255,0.12);
background: color-mix(in srgb, var(--dot-color, #fff) 20%, transparent);
opacity: 0.6;
transition: opacity 0.4s var(--ease);
}
.hero:hover .hero-icon-dot { opacity: 0.85; }
.hero-icon-dot svg { width: 18px; height: 18px; stroke: #fff; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* ── Mobile hint ── */
.mobile-hint {
display: none;
background: var(--ink);
color: rgba(255,255,255,0.6);
text-align: center;
padding: 0.5rem 1rem;
font-size: 0.75rem;
}
@media (max-width: 768px) { .mobile-hint { display: block; } }
/* ── Featured ── */
.featured {
margin-top: 3rem;
}
.featured-card {
background: var(--ink);
color: var(--surface);
border-radius: var(--radius);
padding: 2rem 2.5rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 2rem;
transition: box-shadow 0.3s var(--ease);
}
.featured-card:hover {
box-shadow: 0 8px 30px rgba(16,24,40,0.18);
}
.featured-left {
display: flex;
align-items: center;
gap: 1.25rem;
flex: 1;
}
.featured-icon {
width: 48px; height: 48px;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
border: 1px solid rgba(255,255,255,0.12);
}
.featured-icon svg { width: 22px; height: 22px; stroke: #fff; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.featured-text h2 {
font-size: 1.125rem;
font-weight: 600;
letter-spacing: -0.01em;
margin-bottom: 0.25rem;
}
.featured-text p {
font-size: 0.8125rem;
color: rgba(255,255,255,0.5);
line-height: 1.5;
}
.featured-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
/* ── Sections ── */
.section {
margin-top: 3.5rem;
}
.section-label {
font-size: 0.6875rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--ink-muted);
margin-bottom: 1.25rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--border);
}
/* ── Card grid ── */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.grid-wide {
grid-template-columns: 1fr;
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.5rem;
transition: transform 0.3s var(--ease),
box-shadow 0.3s var(--ease),
border-color 0.3s var(--ease);
position: relative;
}
.card::before {
content: '';
position: absolute;
left: 0; top: 12px; bottom: 12px;
width: 3px;
border-radius: 0 3px 3px 0;
background: transparent;
transition: background 0.3s var(--ease);
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(16,24,40,0.08);
border-color: var(--accent);
}
.card:hover::before {
background: var(--accent);
}
.card-icon {
width: 40px; height: 40px;
border-radius: 10px;
display: flex; align-items: center; justify-content: center;
margin-bottom: 1rem;
background: var(--card-color, #101828);
transition: background 0.3s var(--ease);
}
.card:hover .card-icon { background: var(--accent); }
.card-icon svg { width: 20px; height: 20px; stroke: #fff; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.card-meta {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.card-name {
font-size: 1rem;
font-weight: 600;
letter-spacing: -0.01em;
}
.card-version {
font-size: 0.6875rem;
color: var(--ink-muted);
font-variant-numeric: tabular-nums;
}
.card-desc {
font-size: 0.8125rem;
color: var(--ink-muted);
line-height: 1.65;
margin-bottom: 1.25rem;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
min-height: 4.05em;
}
.card-actions { display: flex; gap: 0.375rem; }
/* ── Env card (wide) ── */
.card-wide {
display: flex;
align-items: center;
gap: 1.25rem;
padding: 1.25rem 1.5rem;
}
.card-wide .card-icon { margin-bottom: 0; flex-shrink: 0; }
.card-wide .card-body { flex: 1; }
.card-wide .card-meta { margin-bottom: 0.25rem; }
.card-wide .card-desc { margin-bottom: 0; }
.card-wide .card-actions { flex-shrink: 0; }
/* ── Buttons ── */
.btn {
display: inline-flex; align-items: center; gap: 0.375rem;
padding: 0.5rem 0.875rem;
border-radius: var(--radius-sm);
font-family: var(--font);
font-size: 0.8125rem; font-weight: 500;
text-decoration: none; line-height: 1;
cursor: pointer; border: none;
transition: all 0.2s var(--ease);
}
.btn svg { width: 14px; height: 14px; flex-shrink: 0; }
.btn-primary {
background: var(--accent); color: #fff;
}
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary.on-dark {
background: #fff; color: var(--ink);
}
.btn-primary.on-dark:hover { background: rgba(255,255,255,0.9); }
.btn-ghost {
background: transparent; color: var(--ink-muted);
padding: 0.5rem;
}
.btn-ghost:hover { color: var(--accent); }
.btn-ghost.on-dark { color: rgba(255,255,255,0.45); }
.btn-ghost.on-dark:hover { color: #fff; }
.btn.is-loading { opacity: 0.5; pointer-events: none; }
/* ── Footer ── */
.footer {
margin-top: 4rem;
padding: 2rem 0;
border-top: 1px solid var(--border);
}
.footer-inner {
display: flex; align-items: center;
justify-content: space-between;
font-size: 0.75rem; color: var(--ink-muted);
}
.footer a {
color: var(--ink-soft); text-decoration: none;
transition: color 0.2s;
}
.footer a:hover { color: var(--accent); }
.footer-note {
color: var(--ink-muted);
display: flex;
align-items: center;
gap: 0.375rem;
}
.footer-note svg {
width: 14px; height: 14px;
stroke: var(--ink-muted);
fill: none; stroke-width: 2;
stroke-linecap: round; stroke-linejoin: round;
flex-shrink: 0;
}
/* ── Tag badge ── */
.card-tag {
display: inline-block;
font-size: 0.625rem;
font-weight: 600;
letter-spacing: 0.04em;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
background: var(--surface-dim);
color: var(--ink-muted);
border: 1px solid var(--border);
vertical-align: middle;
margin-left: 0.375rem;
}
/* ── Featured version ── */
.featured-version {
font-weight: 400;
font-size: 0.75rem;
opacity: 0.45;
margin-left: 0.5rem;
}
/* ── Focus ── */
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.btn:focus-visible {
outline-offset: 1px;
}
/* ── Skip link ── */
.skip-link {
position: absolute;
left: -9999px;
top: 0;
z-index: 100;
padding: 0.5rem 1rem;
background: var(--accent);
color: #fff;
font-size: 0.875rem;
text-decoration: none;
border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}
.skip-link:focus {
left: 50%;
transform: translateX(-50%);
}
/* ── Animations ── */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.hero-inner { animation: fadeUp 0.5s var(--ease) both; }
.featured-card { animation: fadeUp 0.5s 0.1s var(--ease) both; }
.card { animation: fadeUp 0.4s var(--ease) both; }
.card:nth-child(1) { animation-delay: 0.15s; }
.card:nth-child(2) { animation-delay: 0.2s; }
.card:nth-child(3) { animation-delay: 0.25s; }
.card:nth-child(4) { animation-delay: 0.3s; }
.card:nth-child(5) { animation-delay: 0.35s; }
/* ── Responsive ── */
@media (max-width: 768px) {
.hero { padding: 3.5rem 1.25rem 3rem; }
.hero h1 { font-size: 1.875rem; }
.hero-icons { gap: 0.625rem; }
.grid { grid-template-columns: 1fr; }
.featured-card { flex-direction: column; align-items: flex-start; padding: 1.5rem; }
.featured-actions { width: 100%; }
.featured-actions .btn-primary { flex: 1; justify-content: center; }
.card-wide { flex-direction: column; align-items: flex-start; }
.card-wide .card-actions { width: 100%; }
.footer-inner { flex-direction: column; gap: 0.5rem; text-align: center; }
}
@media (min-width: 769px) and (max-width: 960px) {
.grid { grid-template-columns: repeat(2, 1fr); }
}
</style>
</head>
<body>
<a href="#plugins" class="skip-link">跳转到插件列表</a>
<header class="hero">
<div class="hero-inner">
<div class="hero-wp" aria-hidden="true">
<svg viewBox="0 0 122.5 122.5" xmlns="http://www.w3.org/2000/svg">
<path d="M8.7 61.3c0 20.8 12.1 38.7 29.6 47.3L13 39.6a52.3 52.3 0 0 0-4.3 21.7zm88.6-2.7c0-6.5-2.3-11-4.3-14.5-2.7-4.3-5.2-8-5.2-12.3 0-4.8 3.7-9.3 8.9-9.3h.7a52.4 52.4 0 0 0-79.4 1.4h4c6.5 0 16.6-.8 16.6-.8 3.4-.2 3.8 4.7.4 5.1 0 0-3.4.4-7.1.6l22.5 67 13.5-40.6-9.6-26.4c-3.4-.2-6.6-.6-6.6-.6-3.4-.2-3-5.3.4-5.1 0 0 10.3.8 16.4.8 6.5 0 16.6-.8 16.6-.8 3.4-.2 3.8 4.7.4 5.1 0 0-3.4.4-7.2.6l22.4 66.5 6.2-20.6c2.7-8.6 4.7-14.7 4.7-20zm-37.8 7.9L40.4 113a52.6 52.6 0 0 0 32.3 1 4.7 4.7 0 0 1-.4-.7zm47.8-32.4c.2 1.7.4 3.6.4 5.6 0 5.5-1 11.7-4.2 19.4l-16.8 48.4c16.3-9.5 27.3-27.2 27.3-47.4 0-9.6-2.5-18.6-6.7-26zM61.3 0a61.3 61.3 0 1 0 0 122.5A61.3 61.3 0 0 0 61.3 0zm0 119.7a58.5 58.5 0 1 1 0-117 58.5 58.5 0 0 1 0 117z" fill="currentColor"/>
</svg>
</div>
<h1>文派体验场</h1>
<p>在浏览器中即时体验 WordPress 插件</p>
<div class="hero-icons" id="hero-icons"></div>
</div>
</header>
<div class="mobile-hint" role="note">
<p>建议使用桌面浏览器获得最佳体验,移动端仍可浏览插件介绍。</p>
</div>
<main class="container">
<div id="featured" class="featured"></div>
<div id="plugins" class="section"></div>
<div id="combos" class="section"></div>
<div id="envs" class="section"></div>
</main>
<footer class="footer">
<div class="container">
<div class="footer-inner">
<span class="footer-note">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
临时沙盒环境,关闭页面后数据不保留
</span>
<span>
Powered by
<a href="https://wordpress.github.io/wordpress-playground/">WordPress Playground</a>
&middot;
<a href="https://wenpai.net">文派</a>
</span>
</div>
</div>
</footer>
<script>
// ── Lucide SVG icon paths (inlined, no CDN) ──
var ICONS = {
sparkles: '<path d="m12 3-1.9 5.8a2 2 0 0 1-1.3 1.3L3 12l5.8 1.9a2 2 0 0 1 1.3 1.3L12 21l1.9-5.8a2 2 0 0 1 1.3-1.3L21 12l-5.8-1.9a2 2 0 0 1-1.3-1.3Z"/><path d="M5 3v4"/><path d="M19 17v4"/><path d="M3 5h4"/><path d="M17 19h4"/>',
'circle-user': '<circle cx="12" cy="12" r="10"/><circle cx="12" cy="10" r="3"/><path d="M7 20.7A2 2 0 0 1 9 17h6a2 2 0 0 1 2 2v1.7"/>',
type: '<polyline points="4 7 4 4 20 4 20 7"/><line x1="9" x2="15" y1="20" y2="20"/><line x1="12" x2="12" y1="4" y2="20"/>',
link: '<path d="M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7l-1.8 1.7"/><path d="M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.8-1.7"/>',
'calendar-days': '<path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/><path d="M8 18h.01"/><path d="M12 18h.01"/><path d="M16 18h.01"/>',
box: '<path d="M21 8a2 2 0 0 0-1-1.7l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.7l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/>',
rocket: '<path d="M4.5 16.5c-1.5 1.3-2 5-2 5s3.7-.5 5-2c.7-.8 1-2 .5-2.8-.6-.8-1.7-1-2.5-.5a2.7 2.7 0 0 0-1 .3"/><path d="M12 13c-2 0-3.2-1.3-3.2-1.3L15 5.5a27 27 0 0 1 6.8-3.5c0 0-.8 4.5-3.5 6.8L12 15.1V13Z"/><path d="m8 17 .5-2.5"/><path d="m14.5 6.5 2 2"/>',
play: '<polygon points="5 3 19 12 5 21 5 3"/>',
globe: '<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10A15.3 15.3 0 0 1 12 2z"/>',
code: '<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',
'pen-tool': '<path d="m12 19 7-7 3 3-7 7-3-3z"/><path d="m18 13-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="m2 2 7.6 7.6"/><circle cx="11" cy="13" r="2"/>',
package: '<path d="m16.5 9.4-9-5.2"/><path d="M21 16V8a2 2 0 0 0-1-1.7l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.7l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/>',
layers: '<path d="m12.8 2.3 8.4 4.6a1 1 0 0 1 0 1.7l-8.4 4.6a2 2 0 0 1-1.6 0L2.8 8.6a1 1 0 0 1 0-1.7l8.4-4.6a2 2 0 0 1 1.6 0z"/><path d="m2.3 12.6 8.9 4.9a2 2 0 0 0 1.6 0l8.9-4.9"/><path d="m2.3 17.1 8.9 4.9a2 2 0 0 0 1.6 0l8.9-4.9"/>'
};
// Safe SVG creation via DOMParser (no innerHTML on live DOM)
var svgParser = new DOMParser();
function makeSvgEl(name, size) {
var s = size || 20;
var markup = '<svg xmlns="http://www.w3.org/2000/svg" width="' + s + '" height="' + s + '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + (ICONS[name] || '') + '</svg>';
return svgParser.parseFromString(markup, 'image/svg+xml').documentElement;
}
function playUrl(bp) {
return location.origin + '/playground.html?blueprint-url=' + location.origin + bp;
}
function playUrlRemote(bp) {
return 'https://playground.wordpress.net/?blueprint-url=' + location.origin + bp;
}
function makeBtn(cls, href, iconName, label, title) {
var a = document.createElement('a');
a.className = 'btn ' + cls;
a.href = href;
a.target = '_blank';
a.rel = 'noopener';
if (title) a.title = title;
a.appendChild(makeSvgEl(iconName, 14));
if (label) {
a.appendChild(document.createTextNode(' ' + label));
}
return a;
}
// ── Render featured banner ──
function renderFeatured(item) {
var wrap = document.getElementById('featured');
var card = document.createElement('div');
card.className = 'featured-card';
var left = document.createElement('div');
left.className = 'featured-left';
var iconWrap = document.createElement('div');
iconWrap.className = 'featured-icon';
iconWrap.appendChild(makeSvgEl(item.icon, 22));
var textWrap = document.createElement('div');
textWrap.className = 'featured-text';
var h2 = document.createElement('h2');
h2.textContent = item.name;
var verSpan = document.createElement('span');
verSpan.className = 'featured-version';
verSpan.textContent = item.version;
h2.appendChild(verSpan);
var desc = document.createElement('p');
desc.textContent = item.desc;
textWrap.appendChild(h2);
textWrap.appendChild(desc);
left.appendChild(iconWrap);
left.appendChild(textWrap);
var actions = document.createElement('div');
actions.className = 'featured-actions';
actions.appendChild(makeBtn('btn-primary on-dark', playUrl(item.blueprint), 'play', '体验'));
actions.appendChild(makeBtn('btn-ghost on-dark', playUrlRemote(item.blueprint), 'globe', '国际', '国际线路'));
card.appendChild(left);
card.appendChild(actions);
wrap.appendChild(card);
}
// ── Render section ──
function renderSection(id, label, items, wide) {
var wrap = document.getElementById(id);
var labelEl = document.createElement('h2');
labelEl.className = 'section-label';
labelEl.textContent = label;
wrap.appendChild(labelEl);
var grid = document.createElement('div');
grid.className = 'grid' + (wide ? ' grid-wide' : '');
items.forEach(function(p) {
var card = document.createElement('div');
card.className = 'card' + (wide ? ' card-wide' : '');
card.setAttribute('data-color', p.color);
var iconEl = document.createElement('div');
iconEl.className = 'card-icon';
iconEl.style.setProperty('--card-color', p.color);
iconEl.appendChild(makeSvgEl(p.icon));
var meta = document.createElement('div');
meta.className = 'card-meta';
var nameEl = document.createElement('span');
nameEl.className = 'card-name';
nameEl.textContent = p.name;
if (p.tag) {
var tagEl = document.createElement('span');
tagEl.className = 'card-tag';
tagEl.textContent = p.tag;
nameEl.appendChild(tagEl);
}
var verEl = document.createElement('span');
verEl.className = 'card-version';
verEl.textContent = p.version;
meta.appendChild(nameEl);
meta.appendChild(verEl);
var descEl = document.createElement('p');
descEl.className = 'card-desc';
descEl.textContent = p.desc;
var actions = document.createElement('div');
actions.className = 'card-actions';
actions.appendChild(makeBtn('btn-primary', playUrl(p.blueprint), 'play', '体验'));
actions.appendChild(makeBtn('btn-ghost', playUrlRemote(p.blueprint), 'globe', '国际', '国际线路'));
if (p.repo) {
actions.appendChild(makeBtn('btn-ghost', p.repo, 'code', '源码', '查看源码'));
}
if (wide) {
var body = document.createElement('div');
body.className = 'card-body';
body.appendChild(meta);
body.appendChild(descEl);
card.appendChild(iconEl);
card.appendChild(body);
card.appendChild(actions);
} else {
card.appendChild(iconEl);
card.appendChild(meta);
card.appendChild(descEl);
card.appendChild(actions);
}
grid.appendChild(card);
});
wrap.appendChild(grid);
}
// ── Hero icons ──
function renderHeroIcons(plugins) {
var el = document.getElementById('hero-icons');
plugins.forEach(function(p) {
if (p.group === 'featured') return;
var dot = document.createElement('div');
dot.className = 'hero-icon-dot';
dot.style.setProperty('--dot-color', p.color);
dot.appendChild(makeSvgEl(p.icon, 18));
el.appendChild(dot);
});
}
// ── Load ──
fetch('/plugins.json')
.then(function(r) { return r.json(); })
.then(function(plugins) {
var featured = [], pluginList = [], envList = [], comboList = [];
plugins.forEach(function(p) {
if (p.group === 'featured') featured.push(p);
else if (p.group === 'env') envList.push(p);
else if (p.group === 'combo') comboList.push(p);
else pluginList.push(p);
});
if (featured.length) renderFeatured(featured[0]);
if (pluginList.length) renderSection('plugins', '插件体验', pluginList, false);
if (comboList.length) renderSection('combos', '方案体验', comboList, false);
if (envList.length) renderSection('envs', '开发环境', envList, true);
renderHeroIcons(plugins);
})
.catch(function() {
var msg = document.createElement('p');
msg.style.cssText = 'color:var(--ink-muted);font-size:0.875rem';
msg.textContent = '加载失败,请刷新重试。';
document.getElementById('plugins').appendChild(msg);
});
</script>
</body>
</html>