Download scripts/guide-template.html from smlflg/archify-hai: direct link, hf CLI and curl.
- Browser
- Download file 32.6 kB
-
https://huggingface.co/smlflg/archify-hai/resolve/main/scripts/guide-template.html
- Command line
-
hf download hf://smlflg/archify-hai/scripts/guide-template.html
-
curl -L -o guide-template.html https://huggingface.co/smlflg/archify-hai/resolve/main/scripts/guide-template.html
32.6 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta name="generator" content="archify guide [[ARCHIFY_VERSION]]"> | |
| <title>Archify Scenario Guide — Choose the Right Diagram</title> | |
| <meta name="description" content="Describe the technical question you need to answer. Archify recommends a bounded diagram recipe, evidence checklist, and copy-ready prompt."> | |
| <meta name="theme-color" content="#eff2f1"> | |
| <link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 28'><polygon points='14,2 26,8 26,20 14,26 2,20 2,8' fill='%23083344' stroke='%2322d3ee' stroke-width='1.5'/><circle cx='14' cy='15' r='2.5' fill='%2322d3ee'/></svg>"> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,500;1,9..144,400&family=Inter:wght@400;450;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="assets/site-navigation.css"> | |
| <style> | |
| :root { | |
| /* Drafted-sheet palette — shared with the project page */ | |
| --paper:#eff2f1; --paper-raised:#f8faf9; | |
| --ink:#15181b; --ink-soft:#363c41; --muted:#60686d; --dim:#929a9e; | |
| --line:rgba(20,23,26,0.14); --line-hi:rgba(20,23,26,0.3); | |
| --accent:#e14a0e; --accent-soft:rgba(225,74,14,0.08); | |
| --plate:#0f1216; | |
| --emerald:#047857; --rose:#be123c; --violet:#6d28d9; | |
| --font-display:'Fraunces','Songti SC','STSong',Georgia,serif; | |
| --font-body:'Inter',-apple-system,BlinkMacSystemFont,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif; | |
| --font-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace; | |
| --ease-out:cubic-bezier(.22,1,.36,1); | |
| } | |
| *,*::before,*::after { margin:0; padding:0; box-sizing:border-box; } | |
| html { scroll-behavior:smooth; } | |
| body { | |
| font-family:var(--font-body); | |
| -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; | |
| background:var(--paper); color:var(--ink); min-height:100vh; overflow-x:hidden; | |
| } | |
| body::after { | |
| content:''; position:fixed; inset:0; z-index:1000; pointer-events:none; | |
| opacity:.05; mix-blend-mode:multiply; | |
| background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='140' height='140' filter='url(%23n)'/></svg>"); | |
| } | |
| ::selection { background:rgba(225,74,14,.18); color:var(--ink); } | |
| button,textarea { font:inherit; } | |
| button { color:inherit; } | |
| a { color:inherit; } | |
| :focus-visible { outline:2px solid var(--accent); outline-offset:3px; border-radius:4px; } | |
| .grid-bg { | |
| position:fixed; inset:0; z-index:0; pointer-events:none; | |
| background-image:linear-gradient(rgba(20,23,26,.045) 1px,transparent 1px),linear-gradient(90deg,rgba(20,23,26,.045) 1px,transparent 1px); | |
| background-size:56px 56px; | |
| -webkit-mask-image:radial-gradient(ellipse 95% 62% at 50% -6%, black 12%, transparent 75%); | |
| mask-image:radial-gradient(ellipse 95% 62% at 50% -6%, black 12%, transparent 75%); | |
| } | |
| .btn { display:inline-flex; align-items:center; gap:.5rem; padding:.55rem 1.15rem; border-radius:6px; font-family:var(--font-body); font-size:.8125rem; font-weight:500; letter-spacing:-.005em; cursor:pointer; text-decoration:none; transition:all .2s var(--ease-out); border:1px solid transparent; } | |
| .btn-primary { background:var(--ink); color:var(--paper); } | |
| .btn-primary:hover { background:#272c31; transform:translateY(-1px); } | |
| .shell { position:relative; z-index:1; width:min(1180px,calc(100% - 48px)); margin:0 auto; } | |
| /* HERO */ | |
| .hero { padding:10rem 0 4rem; display:grid; grid-template-columns:minmax(0,1.35fr) minmax(280px,.65fr); gap:4.5rem; align-items:end; } | |
| .lead-label { display:flex; align-items:center; gap:.875rem; margin-bottom:1.5rem; font-family:var(--font-mono); font-size:.625rem; font-weight:500; letter-spacing:.2em; color:var(--muted); text-transform:uppercase; } | |
| .lead-label::before { content:''; width:2.75rem; height:1px; background:var(--line-hi); } | |
| h1 { max-width:770px; font-family:var(--font-display); font-optical-sizing:auto; font-size:clamp(2.5rem,5vw,4.25rem); font-weight:400; line-height:1.06; letter-spacing:-.028em; color:var(--ink); text-wrap:balance; } | |
| h1 em { font-style:italic; color:var(--accent); } | |
| .lede { max-width:680px; margin-top:1.5rem; color:var(--muted); font-size:.9375rem; line-height:1.72; text-wrap:pretty; } | |
| .metrics { display:grid; gap:1px; background:var(--line); border:1px solid var(--line-hi); border-radius:12px; overflow:hidden; } | |
| .metric { display:flex; justify-content:space-between; align-items:center; gap:1rem; padding:1rem 1.25rem; background:var(--paper-raised); } | |
| .metric strong { font-family:var(--font-display); font-style:italic; font-optical-sizing:auto; font-weight:400; font-size:1.625rem; line-height:1; color:var(--ink); } | |
| .metric span { color:var(--dim); font-family:var(--font-mono); font-size:.5625rem; letter-spacing:.14em; text-transform:uppercase; line-height:1.5; text-align:right; } | |
| /* CHOOSER */ | |
| .chooser { padding:1.75rem 2rem 2rem; border:1px solid var(--line-hi); border-radius:14px; background:var(--paper-raised); position:relative; } | |
| .chooser-head { display:flex; align-items:flex-start; justify-content:space-between; gap:1.25rem; margin-bottom:1.125rem; } | |
| .chooser-head h2 { margin-bottom:.375rem; font-family:var(--font-display); font-optical-sizing:auto; font-size:1.5rem; font-weight:500; letter-spacing:-.02em; } | |
| .chooser-head p { color:var(--muted); font-size:.8125rem; line-height:1.6; } | |
| .kbd { flex:none; border:1px solid var(--line-hi); border-radius:5px; padding:.3rem .5rem; color:var(--dim); font-family:var(--font-mono); font-size:.5625rem; background:var(--paper); } | |
| textarea { width:100%; min-height:104px; resize:vertical; border:1px solid var(--line-hi); border-radius:10px; padding:.9rem 1rem; background:var(--paper); color:var(--ink); outline:none; font-family:var(--font-mono); font-size:.75rem; line-height:1.7; transition:border-color .18s var(--ease-out),box-shadow .18s var(--ease-out); } | |
| textarea::placeholder { color:var(--dim); } | |
| textarea:focus { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); } | |
| .sample-row { margin:.875rem 0 1.125rem; display:flex; gap:.45rem; flex-wrap:wrap; } | |
| .chip { border:1px solid var(--line); border-radius:999px; background:var(--paper); color:var(--muted); padding:.45rem .75rem; font-family:var(--font-mono); font-size:.5625rem; letter-spacing:.06em; cursor:pointer; transition:all .18s var(--ease-out); } | |
| .chip:hover { color:var(--accent); border-color:var(--accent); } | |
| .actions { display:flex; align-items:center; gap:.625rem; } | |
| .primary,.secondary { min-height:44px; border-radius:8px; padding:.65rem 1.15rem; border:1px solid transparent; font-size:.8125rem; font-weight:500; cursor:pointer; transition:all .2s var(--ease-out); } | |
| .primary { background:var(--ink); color:var(--paper); border-color:var(--ink); } | |
| .primary:hover { background:var(--accent); border-color:var(--accent); } | |
| .secondary { background:transparent; border-color:var(--line-hi); color:var(--ink-soft); } | |
| .secondary:hover { color:var(--ink); border-color:var(--ink); } | |
| /* RESULT */ | |
| .result { margin-top:1.25rem; border:1px solid var(--line-hi); border-radius:14px; background:var(--paper-raised); overflow:hidden; display:none; } | |
| .result.visible { display:block; animation:reveal .3s var(--ease-out); } | |
| @keyframes reveal { from { opacity:0; transform:translateY(6px); } } | |
| .result-main { padding:1.75rem 2rem; display:grid; grid-template-columns:minmax(0,1.1fr) minmax(260px,.9fr); gap:2rem; } | |
| .result-kicker { color:var(--accent); font-family:var(--font-mono); font-size:.5625rem; font-weight:600; letter-spacing:.16em; text-transform:uppercase; } | |
| .result h3 { margin:.5rem 0 .375rem; font-family:var(--font-display); font-optical-sizing:auto; font-size:1.625rem; font-weight:500; letter-spacing:-.02em; } | |
| .result-question { color:var(--ink-soft); font-size:.875rem; font-weight:500; line-height:1.6; } | |
| .result-summary { margin-top:.875rem; color:var(--muted); font-size:.8125rem; line-height:1.7; } | |
| .proof-link { display:inline-flex; align-items:center; margin-top:1.125rem; padding:.5rem .75rem; border:1px solid rgba(4,120,87,.35); border-radius:999px; background:rgba(4,120,87,.06); color:var(--emerald); text-decoration:none; font-family:var(--font-mono); font-size:.5625rem; font-weight:600; letter-spacing:.12em; text-transform:uppercase; transition:all .18s var(--ease-out); } | |
| .proof-link:hover { border-color:var(--emerald); background:rgba(4,120,87,.1); } | |
| .boundary { display:grid; gap:1rem; align-content:start; } | |
| .boundary-item small { display:block; margin-bottom:.375rem; color:var(--emerald); font-family:var(--font-mono); font-size:.5625rem; font-weight:600; letter-spacing:.14em; text-transform:uppercase; } | |
| .boundary-item.avoid small { color:var(--rose); } | |
| .boundary-item p { color:var(--muted); font-size:.8125rem; line-height:1.65; } | |
| .result-grid { display:grid; grid-template-columns:minmax(230px,.7fr) minmax(0,1.3fr); border-top:1px solid var(--line); } | |
| .checklist,.prompt-box { padding:1.5rem 2rem; } | |
| .checklist { border-right:1px solid var(--line); } | |
| .mini-heading { margin-bottom:.875rem; color:var(--dim); font-family:var(--font-mono); font-size:.5625rem; font-weight:500; letter-spacing:.16em; text-transform:uppercase; } | |
| .checklist ul { list-style:none; display:grid; gap:.55rem; } | |
| .checklist li { color:var(--muted); font-size:.75rem; line-height:1.55; display:flex; gap:.5rem; } | |
| .checklist li::before { content:'✓'; color:var(--emerald); flex:0 0 auto; } | |
| .presentation { display:flex; flex-wrap:wrap; gap:.4rem; margin-top:1.125rem; } | |
| .tag { padding:.35rem .6rem; border-radius:999px; border:1px solid var(--line); background:var(--paper); color:var(--muted); font-family:var(--font-mono); font-size:.5625rem; letter-spacing:.06em; } | |
| .prompt-bar { display:flex; align-items:center; justify-content:space-between; gap:.75rem; margin-bottom:.75rem; } | |
| .copy { border:0; background:none; color:var(--accent); padding:0; font-family:var(--font-mono); font-size:.5625rem; font-weight:600; letter-spacing:.12em; text-transform:uppercase; cursor:pointer; } | |
| .copy:hover { color:var(--ink); } | |
| .prompt-text { color:var(--ink-soft); font-family:var(--font-mono); font-size:.6875rem; line-height:1.75; white-space:pre-wrap; } | |
| .alternatives { padding:.9rem 2rem; border-top:1px solid var(--line); color:var(--dim); font-size:.75rem; } | |
| .alternatives button { margin-left:.5rem; padding:0; border:0; background:none; color:var(--muted); cursor:pointer; font-size:.75rem; text-decoration:underline; text-underline-offset:3px; text-decoration-color:var(--line-hi); } | |
| .alternatives button:hover { color:var(--accent); text-decoration-color:var(--accent); } | |
| /* LIBRARY */ | |
| .library { padding:5rem 0 6rem; } | |
| .section-head { display:flex; align-items:end; justify-content:space-between; gap:1.75rem; margin-bottom:1.75rem; } | |
| .section-head h2 { margin-top:.5rem; font-family:var(--font-display); font-optical-sizing:auto; font-size:clamp(1.75rem,3vw,2.5rem); font-weight:400; letter-spacing:-.026em; } | |
| .section-head p { max-width:440px; color:var(--muted); font-size:.8125rem; line-height:1.7; } | |
| .filters { display:flex; flex-wrap:wrap; gap:.45rem; margin-bottom:1.25rem; } | |
| .filter { border:1px solid var(--line-hi); border-radius:999px; background:transparent; color:var(--muted); padding:.5rem .85rem; font-family:var(--font-mono); font-size:.5625rem; font-weight:500; letter-spacing:.1em; text-transform:uppercase; cursor:pointer; transition:all .18s var(--ease-out); } | |
| .filter:hover { color:var(--ink); border-color:var(--ink); } | |
| .filter.active { color:var(--paper); background:var(--ink); border-color:var(--ink); } | |
| .cards { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:14px; } | |
| .card { min-width:0; min-height:206px; padding:1.375rem 1.5rem; text-align:left; border:1px solid var(--line-hi); border-radius:12px; background:var(--paper-raised); cursor:pointer; transition:transform .22s var(--ease-out),border-color .22s var(--ease-out),box-shadow .22s var(--ease-out); position:relative; font-family:inherit; } | |
| .card:hover,.card:focus-visible { transform:translateY(-3px); border-color:var(--ink); box-shadow:0 14px 36px rgba(20,23,26,.1); outline:none; } | |
| .card-type { color:var(--type-color,var(--accent)); font-family:var(--font-mono); font-size:.5625rem; font-weight:600; letter-spacing:.14em; text-transform:uppercase; } | |
| .card h3 { margin:.875rem 0 .5rem; font-family:var(--font-display); font-optical-sizing:auto; font-size:1.125rem; font-weight:500; letter-spacing:-.015em; color:var(--ink); } | |
| .card-question { color:var(--ink-soft); font-size:.75rem; line-height:1.6; } | |
| .card-summary { margin:.75rem 0 0; color:var(--dim); font-size:.6875rem; line-height:1.6; } | |
| .card-foot { position:absolute; left:1.5rem; right:1.5rem; bottom:1.125rem; display:flex; justify-content:space-between; gap:.75rem; color:var(--dim); font-family:var(--font-mono); font-size:.5625rem; letter-spacing:.06em; } | |
| .card { padding-bottom:2.75rem; } | |
| footer { border-top:1px solid var(--line); padding:1.75rem 0 2.5rem; color:var(--dim); font-family:var(--font-mono); font-size:.625rem; letter-spacing:.04em; } | |
| footer .shell { display:flex; justify-content:space-between; gap:1rem; } | |
| /* ENTRANCE */ | |
| @keyframes rise { from { opacity:0; transform:translateY(14px); } to { opacity:1; transform:none; } } | |
| .hero, .chooser, .library { animation:rise .7s var(--ease-out) both; } | |
| .chooser { animation-delay:.08s; } | |
| .library { animation-delay:.16s; } | |
| @media(max-width:900px) { | |
| .hero { grid-template-columns:1fr; gap:2.25rem; padding-top:8.5rem; } | |
| .metrics { grid-template-columns:repeat(3,1fr); } | |
| .metric { display:grid; gap:.4rem; } | |
| .metric span { text-align:left; } | |
| .cards { grid-template-columns:repeat(2,minmax(0,1fr)); } | |
| .result-main,.result-grid { grid-template-columns:1fr; } | |
| .checklist { border-right:0; border-bottom:1px solid var(--line); } | |
| } | |
| @media(max-width:620px) { | |
| .shell { width:min(100% - 28px,1180px); } | |
| .hero { padding:7.5rem 0 2.5rem; } | |
| h1 { font-size:2.2rem; } | |
| .lede { font-size:.875rem; } | |
| .metrics { grid-template-columns:1fr; } | |
| .metric { display:flex; } | |
| .metric span { text-align:right; } | |
| .chooser { padding:1.25rem; } | |
| .chooser-head .kbd { display:none; } | |
| .sample-row { flex-wrap:nowrap; overflow:auto; padding-bottom:4px; } | |
| .chip { white-space:nowrap; } | |
| .result-main { padding:1.25rem; } | |
| .checklist,.prompt-box { padding:1.125rem 1.25rem; } | |
| .cards { grid-template-columns:1fr; } | |
| .section-head { align-items:flex-start; flex-direction:column; } | |
| .library { padding:3.5rem 0 4.5rem; } | |
| footer .shell { flex-direction:column; } | |
| } | |
| @media (prefers-reduced-motion:reduce) { | |
| html { scroll-behavior:auto; } | |
| .hero, .chooser, .library, .result.visible { animation:none; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="grid-bg" aria-hidden="true"></div> | |
| <nav class="site-nav" aria-label="Primary navigation"> | |
| <a class="nav-logo" href="./" aria-label="Archify home"> | |
| <span class="nav-logo-text">Archify</span> | |
| <span class="nav-logo-path" data-en="/ guide" data-zh="/ 场景指南">/ guide</span> | |
| </a> | |
| <div class="nav-right"> | |
| <a class="nav-link" href="guide.html" aria-current="page" data-i18n="navGuide">Guide</a> | |
| <a class="nav-link" href="gallery.html" data-i18n="navProof">Proof Lab</a> | |
| <a class="nav-link" href="start.html" data-i18n="navStart">Start</a> | |
| <a class="nav-link" href="https://github.com/tt-a1i/archify" target="_blank" rel="noopener">GitHub</a> | |
| <button class="btn-lang" id="language" type="button" aria-label="Switch language">中文</button> | |
| <a class="btn btn-primary nav-cta" href="start.html" data-i18n="navInstall">Install Skill</a> | |
| </div> | |
| </nav> | |
| <main class="shell"> | |
| <section class="hero"> | |
| <div> | |
| <div class="lead-label" data-i18n="eyebrow">Question-first diagramming</div> | |
| <h1 data-i18n-html="headline">Choose the question.<br>Get the <em>right diagram.</em></h1> | |
| <p class="lede" data-i18n="lede">Describe what your audience needs to understand. Archify recommends one bounded visual recipe—plus the evidence it must contain, when not to use it, and a prompt you can copy.</p> | |
| </div> | |
| <div class="metrics" aria-label="Guide metrics"> | |
| <div class="metric"><strong>[[RECIPE_COUNT]]</strong><span data-i18n-html="metricRecipes">real-world<br>recipes</span></div> | |
| <div class="metric"><strong>5</strong><span data-i18n-html="metricModes">typed diagram<br>modes</span></div> | |
| <div class="metric"><strong>0</strong><span data-i18n-html="metricRuntime">runtime<br>dependencies</span></div> | |
| </div> | |
| </section> | |
| <section class="chooser" aria-labelledby="chooser-title"> | |
| <div class="chooser-head"> | |
| <div><h2 id="chooser-title" data-i18n="chooserTitle">What must the diagram explain?</h2><p data-i18n="chooserBody">Write a situation, not a diagram type. Specific system facts produce a stronger recommendation.</p></div> | |
| <span class="kbd">⌘ / Ctrl + Enter</span> | |
| </div> | |
| <textarea id="scenario" data-i18n-placeholder="placeholder" placeholder="Example: Show an API request with JWT auth, a Redis cache miss, database fallback, and async tracing."></textarea> | |
| <div class="sample-row" id="samples"></div> | |
| <div class="actions"> | |
| <button class="primary" id="recommend" type="button" data-i18n="recommend">Recommend a recipe →</button> | |
| <button class="secondary" id="clear" type="button" data-i18n="clear">Clear</button> | |
| </div> | |
| <div class="result" id="result" aria-live="polite"></div> | |
| </section> | |
| <section class="library" id="library"> | |
| <div class="section-head"> | |
| <div><div class="lead-label" data-i18n="libraryEyebrow">Recipe library</div><h2 data-i18n="libraryTitle">Eleven small, opinionated starting points.</h2></div> | |
| <p data-i18n="libraryBody">Each recipe answers one technical question. That boundary keeps the result legible, reviewable, and honest about missing evidence.</p> | |
| </div> | |
| <div class="filters" id="filters" aria-label="Filter recipes"></div> | |
| <div class="cards" id="cards"></div> | |
| </section> | |
| </main> | |
| <footer><div class="shell"><span data-i18n="footerLeft">Generated from the same recipe source as the Archify CLI.</span><span>archify guide "your scenario"</span><span data-i18n="versionLabel">Scenario guide / development / v[[ARCHIFY_VERSION]]</span></div></footer> | |
| <script id="guide-data" type="application/json">[[GUIDE_JSON]]</script> | |
| <script src="assets/site-language.js"></script> | |
| <script> | |
| (function () { | |
| 'use strict'; | |
| var recipes = JSON.parse(document.getElementById('guide-data').textContent); | |
| var types = [[DIAGRAM_TYPES_JSON]]; | |
| var colors = { architecture:'#0891b2', workflow:'#047857', sequence:'#6d28d9', dataflow:'#b45309', lifecycle:'#be123c' }; | |
| var language = ArchifySiteLanguage.read(); | |
| var activeType = 'all'; | |
| var lastRecipe = null; | |
| var copy = { | |
| en: { | |
| navGuide:'Guide',navProof:'Proof Lab',navStart:'Start',navInstall:'Install Skill',versionLabel:'Scenario guide / development / v[[ARCHIFY_VERSION]]',eyebrow:'Question-first diagramming', headline:'Choose the question.<br>Get the <em>right diagram.</em>', lede:'Describe what your audience needs to understand. Archify recommends one bounded visual recipe—plus the evidence it must contain, when not to use it, and a prompt you can copy.', | |
| metricRecipes:'real-world<br>recipes',metricModes:'typed diagram<br>modes',metricRuntime:'runtime<br>dependencies',chooserTitle:'What must the diagram explain?',chooserBody:'Write a situation, not a diagram type. Specific system facts produce a stronger recommendation.',placeholder:'Example: Show an API request with JWT auth, a Redis cache miss, database fallback, and async tracing.',recommend:'Recommend a recipe →',clear:'Clear',libraryEyebrow:'Recipe library',libraryTitle:'Eleven small, opinionated starting points.',libraryBody:'Each recipe answers one technical question. That boundary keeps the result legible, reviewable, and honest about missing evidence.',footerLeft:'Generated from the same recipe source as the Archify CLI.',all:'All recipes',recommended:'Recommended recipe',use:'Use when',avoid:'Avoid when',must:'Evidence to include',presentation:'Presentation',prompt:'Copy-ready prompt',copyPrompt:'Copy prompt',copied:'Copied',alternatives:'Other possible fits:',confidence:'confidence',open:'Open recipe',proofReady:'Verified proof',proofLink:'Open verified example ↗', | |
| samples:[['API + cache miss','Show an API request with JWT auth, a Redis cache miss, database fallback, and async tracing.'],['Kafka + DLQ','Map Kafka topics, ordered processors, consumer groups, replay, state stores, and the dead-letter queue.'],['Incident response','Show how responders detect, triage, mitigate, escalate, communicate, and verify recovery.']] | |
| }, | |
| zh: { | |
| navGuide:'场景指南',navProof:'验证作品集',navStart:'快速上手',navInstall:'安装技能',versionLabel:'场景指南 / 开发版 / v[[ARCHIFY_VERSION]]',eyebrow:'先问题,后图表',headline:'先选对问题,<br>再得到<em>对的图。</em>',lede:'描述受众真正需要理解的内容。Archify 会推荐一个有边界的视觉配方,同时给出证据清单、禁用条件和可复制提示词。', | |
| metricRecipes:'个真实场景<br>配方',metricModes:'种类型化<br>图表模式',metricRuntime:'个运行时<br>依赖',chooserTitle:'这张图必须解释什么?',chooserBody:'写清场景,不要只写图表类型。系统事实越具体,推荐越可靠。',placeholder:'例如:展示带 JWT 鉴权、Redis 缓存未命中、数据库回退和异步追踪的 API 请求。',recommend:'推荐配方 →',clear:'清空',libraryEyebrow:'配方库',libraryTitle:'十一个小而专的起点。',libraryBody:'每个配方只回答一个技术问题。清晰的边界让图更易读、可评审,也不会掩盖证据缺口。',footerLeft:'网页与 Archify CLI 使用同一份配方数据生成。',all:'全部配方',recommended:'推荐配方',use:'适合',avoid:'不要这样用',must:'必须包含的证据',presentation:'表现建议',prompt:'可直接复制的提示词',copyPrompt:'复制提示词',copied:'已复制',alternatives:'其他可能:',confidence:'置信度',open:'打开配方',proofReady:'已验证成品',proofLink:'打开验证成品 ↗', | |
| samples:[['API + 缓存未命中','展示带 JWT 鉴权、Redis 缓存未命中、数据库回退和异步追踪的 API 请求。'],['Kafka + 死信','梳理 Kafka Topic、有序处理器、消费者组、重放、状态存储和死信队列。'],['事故处置','展示响应者如何发现、分诊、缓解、升级、沟通并验证恢复。']] | |
| } | |
| }; | |
| function t(key) { return copy[language][key]; } | |
| function local(recipe) { return Object.assign({}, recipe, recipe[language]); } | |
| function normalize(value) { return String(value || '').normalize('NFKC').toLowerCase().replace(/[\\s_]+/g,' ').trim(); } | |
| function rank(query) { | |
| var text = normalize(query); | |
| return recipes.map(function (recipe,index) { | |
| var score = 0, matched = []; | |
| if (text === recipe.id || text === recipe.id.replace(/-/g,' ')) { score = 100; matched = [recipe.id]; } | |
| else recipe.signals.forEach(function (signal) { if (text.includes(normalize(signal[0]))) { score += signal[1]; matched.push(signal[0]); } }); | |
| return { recipe:recipe, score:score, matched:matched, index:index }; | |
| }).sort(function (a,b) { return b.score - a.score || a.index - b.index; }); | |
| } | |
| function recommendation(query) { | |
| var ranked = rank(query), winner = ranked[0].score > 0 ? ranked[0] : { recipe:recipes[0], score:0, matched:[] }; | |
| return { recipe:winner.recipe, confidence:winner.score >= 14 ? 'high' : winner.score >= 7 ? 'medium' : 'low', alternatives:ranked.filter(function (entry) { return entry.recipe.id !== winner.recipe.id && entry.score > 0; }).slice(0,2) }; | |
| } | |
| function escapeHtml(value) { var node = document.createElement('span'); node.textContent = String(value); return node.innerHTML; } | |
| function renderSamples() { | |
| document.getElementById('samples').innerHTML = t('samples').map(function (sample) { return '<button class="chip" type="button" data-query="'+escapeHtml(sample[1])+'">'+escapeHtml(sample[0])+'</button>'; }).join(''); | |
| } | |
| function renderFilters() { | |
| var labels = [[DIAGRAM_TYPE_LABELS_JSON]]; | |
| document.getElementById('filters').innerHTML = ['all'].concat(types).map(function (type) { return '<button class="filter '+(activeType === type ? 'active':'')+'" type="button" data-filter="'+type+'">'+escapeHtml(type === 'all' ? t('all') : labels[language][type])+'</button>'; }).join(''); | |
| } | |
| function renderCards() { | |
| var visible = recipes.filter(function (recipe) { return activeType === 'all' || recipe.type === activeType; }); | |
| document.getElementById('cards').innerHTML = visible.map(function (raw) { | |
| var recipe = local(raw); | |
| return '<button class="card" type="button" data-recipe="'+recipe.id+'" style="--type-color:'+colors[recipe.type]+'"><span class="card-type">'+escapeHtml(recipe.type)+'</span><h3>'+escapeHtml(recipe.title)+'</h3><p class="card-question">'+escapeHtml(recipe.question)+'</p><p class="card-summary">'+escapeHtml(recipe.summary)+'</p><span class="card-foot"><span>'+escapeHtml(recipe.presentation.preset)+' · '+escapeHtml(recipe.presentation.motion)+'</span><span>'+escapeHtml(recipe.proof ? t('proofReady') : t('open'))+' ↗</span></span></button>'; | |
| }).join(''); | |
| } | |
| function renderResult(rawRecipe, confidence, alternatives) { | |
| var recipe = local(rawRecipe); | |
| lastRecipe = rawRecipe; | |
| var alt = alternatives || []; | |
| var html = '<div class="result-main"><div><span class="result-kicker">'+escapeHtml(t('recommended'))+' · '+escapeHtml(confidence)+' '+escapeHtml(t('confidence'))+'</span><h3>'+escapeHtml(recipe.title)+'</h3><p class="result-question">'+escapeHtml(recipe.question)+'</p><p class="result-summary">'+escapeHtml(recipe.summary)+'</p>'+(recipe.proof ? '<a class="proof-link" href="gallery.html#proof-'+encodeURIComponent(recipe.proof)+'">'+escapeHtml(t('proofLink'))+'</a>' : '')+'</div><div class="boundary"><div class="boundary-item"><small>'+escapeHtml(t('use'))+'</small><p>'+escapeHtml(recipe.useWhen)+'</p></div><div class="boundary-item avoid"><small>'+escapeHtml(t('avoid'))+'</small><p>'+escapeHtml(recipe.avoidWhen)+'</p></div></div></div>'; | |
| html += '<div class="result-grid"><div class="checklist"><div class="mini-heading">'+escapeHtml(t('must'))+'</div><ul>'+recipe.include.map(function (item) { return '<li>'+escapeHtml(item)+'</li>'; }).join('')+'</ul><div class="presentation"><span class="tag">'+escapeHtml(recipe.type)+'</span><span class="tag">'+escapeHtml(recipe.presentation.preset)+'</span><span class="tag">'+escapeHtml(recipe.presentation.motion)+'</span><span class="tag">views '+escapeHtml(recipe.presentation.views)+'</span></div></div>'; | |
| html += '<div class="prompt-box"><div class="prompt-bar"><div class="mini-heading" style="margin:0">'+escapeHtml(t('prompt'))+'</div><button class="copy" id="copy-prompt" type="button">'+escapeHtml(t('copyPrompt'))+'</button></div><p class="prompt-text">'+escapeHtml(recipe.prompt)+'</p></div></div>'; | |
| if (alt.length) html += '<div class="alternatives">'+escapeHtml(t('alternatives'))+alt.map(function (entry) { var item=local(entry.recipe); return '<button type="button" data-alt="'+item.id+'">'+escapeHtml(item.title)+' ['+item.type+']</button>'; }).join('')+'</div>'; | |
| var result = document.getElementById('result'); | |
| result.innerHTML = html; | |
| result.classList.add('visible'); | |
| } | |
| function runRecommendation() { | |
| var query = document.getElementById('scenario').value.trim(); | |
| if (!query) { document.getElementById('scenario').focus(); return; } | |
| var picked = recommendation(query); | |
| renderResult(picked.recipe,picked.confidence,picked.alternatives); | |
| } | |
| function applyLanguage(next) { | |
| language = ArchifySiteLanguage.write(next); | |
| document.documentElement.lang = language === 'zh' ? 'zh-CN' : 'en'; | |
| document.getElementById('language').textContent = language === 'zh' ? 'EN' : '中文'; | |
| document.getElementById('language').setAttribute('aria-label', language === 'zh' ? 'Switch to English' : '切换到中文'); | |
| document.querySelectorAll('[data-en][data-zh]').forEach(function (node) { node.textContent=node.getAttribute(language === 'zh' ? 'data-zh' : 'data-en'); }); | |
| document.querySelectorAll('[data-i18n]').forEach(function (node) { node.textContent=t(node.dataset.i18n); }); | |
| document.querySelectorAll('[data-i18n-html]').forEach(function (node) { node.innerHTML=t(node.dataset.i18nHtml); }); | |
| document.querySelectorAll('[data-i18n-placeholder]').forEach(function (node) { node.placeholder=t(node.dataset.i18nPlaceholder); }); | |
| renderSamples(); renderFilters(); renderCards(); | |
| if (lastRecipe) renderResult(lastRecipe,'selected',[]); | |
| } | |
| async function copyPrompt() { | |
| if (!lastRecipe) return; | |
| var text = local(lastRecipe).prompt, button = document.getElementById('copy-prompt'); | |
| try { await navigator.clipboard.writeText(text); } catch (_) { | |
| var area=document.createElement('textarea'); area.value=text; document.body.appendChild(area); area.select(); document.execCommand('copy'); area.remove(); | |
| } | |
| button.textContent=t('copied'); setTimeout(function () { if (button.isConnected) button.textContent=t('copyPrompt'); },1200); | |
| } | |
| document.getElementById('recommend').addEventListener('click',runRecommendation); | |
| document.getElementById('clear').addEventListener('click',function () { document.getElementById('scenario').value=''; document.getElementById('result').classList.remove('visible'); lastRecipe=null; }); | |
| document.getElementById('language').addEventListener('click',function () { applyLanguage(language === 'en' ? 'zh':'en'); }); | |
| document.getElementById('scenario').addEventListener('keydown',function (event) { if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') runRecommendation(); }); | |
| document.getElementById('samples').addEventListener('click',function (event) { var chip=event.target.closest('[data-query]'); if (!chip) return; document.getElementById('scenario').value=chip.dataset.query; runRecommendation(); }); | |
| document.getElementById('filters').addEventListener('click',function (event) { var filter=event.target.closest('[data-filter]'); if (!filter) return; activeType=filter.dataset.filter; renderFilters(); renderCards(); }); | |
| document.getElementById('cards').addEventListener('click',function (event) { var card=event.target.closest('[data-recipe]'); if (!card) return; var recipe=recipes.find(function (item) { return item.id === card.dataset.recipe; }); renderResult(recipe,'selected',[]); document.getElementById('result').scrollIntoView({behavior:'smooth',block:'center'}); }); | |
| document.getElementById('result').addEventListener('click',function (event) { if (event.target.id === 'copy-prompt') copyPrompt(); var alt=event.target.closest('[data-alt]'); if (alt) renderResult(recipes.find(function (item) { return item.id === alt.dataset.alt; }),'selected',[]); }); | |
| applyLanguage(language); | |
| }()); | |
| </script> | |
| </body> | |
| </html> | |