All checks were successful
Deploy play.wenpai.net / deploy (push) Successful in 2s
- 添加 skip-to-content 无障碍跳转链接 - mobile-hint 提示文案更友好 - 移除按钮点击 4 秒 loading 态(target=_blank 新标签,loading 无意义) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
628 lines
23 KiB
HTML
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'>▶</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'>▶</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>
|
|
·
|
|
<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>
|