simata/huggingmes
1
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="UTF-8">5<meta name="viewport" content="width=device-width, initial-scale=1.0">6<title>HuggingMes · ENV Builder</title>7<link rel="preconnect" href="https://fonts.googleapis.com">8<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>9<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Syne:wght@400;500;600;700;800&display=swap" rel="stylesheet">10 11<style>12*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }13 14:root {15 --bg: #0b0c0f;16 --bg2: #111318;17 --bg3: #181c23;18 --bg4: #1e2330;19 --border: #252b38;20 --border2: #2e3648;21 --amber: #f5a623;22 --amber2: #ffbe55;23 --amber-dim: rgba(245,166,35,.12);24 --amber-glow:rgba(245,166,35,.22);25 --green: #3dd68c;26 --red: #f05f5f;27 --blue: #5b8af5;28 --text: #e4e8f0;29 --text2: #8d97ad;30 --text3: #535f76;31 --mono: 'JetBrains Mono', monospace;32 --sans: 'Syne', sans-serif;33 --r: 8px;34 --r2: 12px;35 --sidebar-w: 220px;36 --panel-w: 340px;37}38 39html { scroll-behavior: smooth; height: 100%; }40 41body {42 font-family: var(--sans);43 background: var(--bg);44 color: var(--text);45 height: 100vh;46 overflow: hidden;47 display: flex;48 flex-direction: column;49}50 51.topbar {52 position: sticky;53 top: 0;54 z-index: 100;55 height: 52px;56 background: rgba(11,12,15,.9);57 backdrop-filter: blur(14px);58 border-bottom: 1px solid var(--border);59 display: flex;60 align-items: center;61 padding: 0 20px;62 gap: 16px;63 flex-shrink: 0;64}65 66.topbar-logo {67 display: flex;68 align-items: center;69 gap: 10px;70 flex-shrink: 0;71}72 73.topbar-logo .logo-emoji { font-size: 24px; line-height: 1; }74 75.topbar-wordmark {76 font-weight: 800;77 font-size: 14px;78 letter-spacing: -.2px;79 color: var(--text);80 white-space: nowrap;81}82 83.topbar-wordmark em {84 color: var(--amber);85 font-style: normal;86}87 88.topbar-divider {89 width: 1px;90 height: 22px;91 background: var(--border2);92}93 94.topbar-title {95 font-size: 12px;96 font-weight: 600;97 color: var(--text2);98 letter-spacing: .5px;99 text-transform: uppercase;100}101 102.topbar-spacer { flex: 1; }103 104.topbar-pill {105 font-family: var(--mono);106 font-size: 10px;107 color: var(--amber);108 background: var(--amber-dim);109 border: 1px solid var(--amber-glow);110 border-radius: 20px;111 padding: 3px 10px;112 letter-spacing: .5px;113}114 115.layout {116 display: flex;117 flex: 1;118 min-height: 0;119 height: calc(100vh - 52px);120}121 122.sidebar-wrap {123 width: var(--sidebar-w);124 flex-shrink: 0;125 border-right: 1px solid var(--border);126 background: var(--bg2);127 display: flex;128 flex-direction: column;129 overflow: hidden;130}131 132.sidebar-scroll {133 flex: 1;134 overflow-y: auto;135 padding: 14px 10px;136}137 138.sidebar-scroll::-webkit-scrollbar { width: 4px; }139.sidebar-scroll::-webkit-scrollbar-track { background: transparent; }140.sidebar-scroll::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 4px; }141 142.sb-label {143 font-size: 9px;144 font-weight: 700;145 text-transform: uppercase;146 letter-spacing: 1.2px;147 color: var(--text3);148 padding: 0 8px 10px;149}150 151.nav-btn {152 width: 100%;153 display: flex;154 align-items: center;155 gap: 8px;156 padding: 8px 10px;157 border: none;158 background: transparent;159 cursor: pointer;160 border-radius: var(--r);161 text-align: left;162 color: var(--text2);163 font-family: var(--sans);164 font-size: 12.5px;165 font-weight: 500;166 transition: background .15s, color .15s;167 margin-bottom: 2px;168}169 170.nav-btn:hover { background: var(--bg3); color: var(--text); }171.nav-btn.active {172 background: var(--amber-dim);173 color: var(--amber);174 border: 1px solid var(--amber-glow);175}176 177.nav-icon { font-size: 13px; flex-shrink: 0; }178.nav-label { flex: 1; }179.nav-count {180 font-family: var(--mono);181 font-size: 10px;182 font-weight: 600;183 color: var(--text3);184 background: var(--bg3);185 border-radius: 10px;186 padding: 1px 6px;187 min-width: 20px;188 text-align: center;189 transition: background .2s, color .2s;190}191.nav-btn.active .nav-count {192 background: var(--amber-glow);193 color: var(--amber2);194}195 196.main {197 flex: 1;198 display: flex;199 flex-direction: column;200 min-width: 0;201 overflow: hidden;202}203 204.toolbar {205 display: flex;206 align-items: center;207 gap: 10px;208 padding: 12px 20px;209 border-bottom: 1px solid var(--border);210 background: var(--bg2);211 flex-shrink: 0;212 flex-wrap: wrap;213}214 215.search-wrap {216 position: relative;217 flex: 1;218 min-width: 160px;219 max-width: 340px;220}221 222.search-icon {223 position: absolute;224 left: 10px;225 top: 50%;226 transform: translateY(-50%);227 color: var(--text3);228 pointer-events: none;229 font-size: 12px;230}231 232#search {233 width: 100%;234 background: var(--bg3);235 border: 1px solid var(--border2);236 border-radius: var(--r);237 padding: 7px 10px 7px 30px;238 font-family: var(--mono);239 font-size: 12px;240 color: var(--text);241 outline: none;242 transition: border-color .15s;243}244 245#search:focus { border-color: var(--amber); }246#search::placeholder { color: var(--text3); }247 248.tb-sep {249 width: 1px;250 height: 24px;251 background: var(--border2);252}253 254.btn {255 display: inline-flex;256 align-items: center;257 gap: 5px;258 padding: 6px 13px;259 border-radius: var(--r);260 border: 1px solid var(--border2);261 background: var(--bg3);262 color: var(--text2);263 font-family: var(--sans);264 font-size: 11.5px;265 font-weight: 600;266 cursor: pointer;267 transition: all .15s;268 white-space: nowrap;269}270 271.btn:hover { background: var(--bg4); color: var(--text); border-color: var(--border2); }272 273.btn-amber {274 background: var(--amber);275 color: #0b0c0f;276 border-color: var(--amber);277}278.btn-amber:hover { background: var(--amber2); border-color: var(--amber2); }279 280.btn-ghost {281 background: transparent;282 border-color: transparent;283 color: var(--text3);284}285.btn-ghost:hover { background: var(--bg3); color: var(--text2); border-color: var(--border2); }286 287.content-wrap {288 flex: 1;289 display: flex;290 min-height: 0;291 overflow: hidden;292}293 294.sections-scroll {295 flex: 1;296 overflow-y: auto;297 padding: 16px 20px 80px;298 min-width: 0;299}300 301.sections-scroll::-webkit-scrollbar { width: 5px; }302.sections-scroll::-webkit-scrollbar-track { background: transparent; }303.sections-scroll::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 4px; }304 305.sec { margin-bottom: 28px; }306.sec.sec-hidden { display: none !important; }307 308.sec-header {309 display: flex;310 align-items: center;311 gap: 8px;312 margin-bottom: 12px;313}314 315.sec-icon { font-size: 14px; }316.sec-title {317 font-size: 11px;318 font-weight: 700;319 text-transform: uppercase;320 letter-spacing: 1.2px;321 color: var(--text3);322}323 324.sec-line {325 flex: 1;326 height: 1px;327 background: var(--border);328}329 330.cards {331 display: grid;332 grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));333 gap: 10px;334}335 336.env-card {337 background: var(--bg2);338 border: 1px solid var(--border);339 border-radius: var(--r2);340 padding: 12px;341 transition: border-color .2s, background .2s;342}343 344.env-card:hover { border-color: var(--border2); }345.env-card.hidden { display: none; }346 347.env-card.selected {348 border-color: var(--amber-glow);349 background: linear-gradient(135deg, var(--bg2) 80%, rgba(245,166,35,.04));350}351 352.card-top {353 display: flex;354 align-items: flex-start;355 gap: 9px;356 margin-bottom: 9px;357}358 359.card-check {360 width: 15px;361 height: 15px;362 accent-color: var(--amber);363 flex-shrink: 0;364 margin-top: 2px;365 cursor: pointer;366}367 368.card-info { flex: 1; min-width: 0; }369 370.card-key {371 font-family: var(--mono);372 font-size: 11.5px;373 font-weight: 600;374 color: var(--text);375 letter-spacing: .3px;376 white-space: nowrap;377 overflow: hidden;378 text-overflow: ellipsis;379}380 381.card-lbl {382 font-size: 11px;383 color: var(--text3);384 margin-top: 2px;385 line-height: 1.35;386}387 388.badge {389 flex-shrink: 0;390 font-family: var(--mono);391 font-size: 9px;392 font-weight: 700;393 text-transform: uppercase;394 letter-spacing: .6px;395 padding: 2px 7px;396 border-radius: 20px;397}398 399/* Tag badge styles */400.badge-critical { background: rgba(240,80,80,.14); color: #f05f5f; border: 1px solid rgba(240,80,80,.3); }401.badge-credential{ background: rgba(220,140,60,.13); color: #e09040; border: 1px solid rgba(220,140,60,.28); }402.badge-feature { background: rgba(70,140,250,.12); color: #5a9eff; border: 1px solid rgba(70,140,250,.25); }403.badge-optional { background: rgba(61,214,140,.10); color: #3dd68c; border: 1px solid rgba(61,214,140,.22); }404.badge-advanced { background: rgba(160,100,230,.12);color: #b07ae0; border: 1px solid rgba(160,100,230,.25); }405.badge-build { background: rgba(240,185,60,.12); color: #e0b030; border: 1px solid rgba(240,185,60,.28); }406 407/* Card left-border accents */408.env-card:has(.badge-critical) { border-left: 3px solid rgba(240,80,80,.4); }409.env-card:has(.badge-critical):hover { border-left-color: rgba(240,80,80,.7); }410.env-card:has(.badge-critical).selected { border-left-color: #f05f5f; }411.env-card:has(.badge-credential){ border-left: 3px solid rgba(220,140,60,.3); }412 413/* Section count badge */414.sec-count {415 font-family: var(--mono);416 font-size: 10px;417 color: var(--text3);418 background: var(--bg3);419 border: 1px solid var(--border);420 border-radius: 10px;421 padding: 1px 7px;422}423 424/* Tag legend */425.tag-legend {426 margin-bottom: 14px;427 background: var(--bg2);428 border: 1px solid var(--border);429 border-radius: var(--r);430 overflow: hidden;431}432.legend-summary {433 display: flex;434 align-items: center;435 gap: 10px;436 padding: 7px 12px;437 cursor: pointer;438 list-style: none;439 user-select: none;440 outline: none;441}442.legend-summary::-webkit-details-marker { display: none; }443.legend-chips { display: flex; gap: 5px; flex-wrap: wrap; flex: 1; }444.legend-hint { font-size: 10px; color: var(--text3); white-space: nowrap; flex-shrink: 0; }445.tag-legend[open] .legend-hint { opacity: 0; }446.legend-body {447 padding: 8px 12px 10px;448 border-top: 1px solid var(--border);449 display: flex;450 flex-direction: column;451 gap: 6px;452}453.legend-row { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--text2); }454.legend-row .badge { flex-shrink: 0; width: 74px; text-align: center; }455.legend-tip { font-size: 9.5px; color: var(--text3); margin-top: 4px; padding-top: 6px; border-top: 1px solid var(--border); }456.toolbar-hint { color: var(--text3); font-size: 12px; margin-right: 6px; white-space: nowrap; }457 458.card-input { position: relative; }459 460.card-input input[type="text"],461.card-input input[type="password"],462.card-input input[type="number"],463.card-input textarea,464.card-input select {465 width: 100%;466 background: var(--bg3);467 border: 1px solid var(--border);468 border-radius: var(--r);469 padding: 7px 10px;470 font-family: var(--mono);471 font-size: 11.5px;472 color: var(--text);473 outline: none;474 transition: border-color .15s;475 resize: vertical;476}477 478.card-input input[type="text"]:focus,479.card-input input[type="password"]:focus,480.card-input input[type="number"]:focus,481.card-input textarea:focus,482.card-input select:focus {483 border-color: var(--amber);484}485 486.card-input textarea { min-height: 64px; }487.card-input select {488 cursor: pointer;489 appearance: none;490 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238d97ad' d='M6 8L1 3h10z'/%3E%3C/svg%3E");491 background-repeat: no-repeat;492 background-position: right 10px center;493 padding-right: 28px;494}495 496.card-input optgroup { color: var(--text2); font-weight: 600; }497.card-input option { color: var(--text); background: var(--bg3); }498 499.toggle-shell { display: flex; align-items: center; gap: 8px; }500.tog {501 padding: 5px 14px;502 border-radius: 20px;503 border: 1px solid var(--border2);504 background: var(--bg3);505 color: var(--text3);506 font-family: var(--mono);507 font-size: 11px;508 font-weight: 700;509 cursor: pointer;510 transition: all .18s;511 letter-spacing: .5px;512}513.tog.on {514 background: rgba(61,214,140,.15);515 border-color: rgba(61,214,140,.4);516 color: var(--green);517}518 519.picker-shell { display: flex; flex-direction: column; gap: 6px; }520.picker-row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }521 522.picker-select {523 flex: 1;524 min-width: 0;525 padding: 6px 28px 6px 8px !important;526 font-size: 11px !important;527}528 529.mini-btn {530 padding: 5px 9px;531 border-radius: var(--r);532 border: 1px solid var(--border2);533 background: var(--bg3);534 color: var(--text2);535 font-family: var(--mono);536 font-size: 10px;537 font-weight: 600;538 cursor: pointer;539 transition: all .15s;540 white-space: nowrap;541}542.mini-btn:hover { background: var(--bg4); color: var(--text); }543 544.right-panel {545 width: var(--panel-w);546 flex-shrink: 0;547 border-left: 1px solid var(--border);548 background: var(--bg2);549 display: flex;550 flex-direction: column;551 overflow: hidden;552}553 554.panel-scroll {555 flex: 1;556 overflow-y: auto;557 padding: 16px;558 display: flex;559 flex-direction: column;560 gap: 16px;561}562 563.panel-scroll::-webkit-scrollbar { width: 4px; }564.panel-scroll::-webkit-scrollbar-track { background: transparent; }565.panel-scroll::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 4px; }566 567.pblock {568 background: var(--bg3);569 border: 1px solid var(--border);570 border-radius: var(--r2);571 overflow: hidden;572}573 574.pblock-head {575 display: flex;576 align-items: center;577 justify-content: space-between;578 padding: 10px 14px;579 border-bottom: 1px solid var(--border);580}581 582.pblock-title {583 font-size: 10.5px;584 font-weight: 700;585 text-transform: uppercase;586 letter-spacing: 1px;587 color: var(--text3);588 display: flex;589 align-items: center;590 gap: 6px;591}592 593.pblock-body { padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }594 595.pblock-body textarea,596.pblock-body input[type="text"] {597 width: 100%;598 background: var(--bg);599 border: 1px solid var(--border);600 border-radius: var(--r);601 padding: 8px 10px;602 font-family: var(--mono);603 font-size: 10.5px;604 color: var(--text2);605 outline: none;606 resize: vertical;607 transition: border-color .15s;608}609 610.pblock-body textarea:focus,611.pblock-body input[type="text"]:focus {612 border-color: var(--amber);613 color: var(--text);614}615 616#importText { min-height: 80px; }617#bundleOut { min-height: 60px; color: var(--amber2); }618#envLineOut { font-size: 10px; }619 620.row-btns { display: flex; gap: 6px; flex-wrap: wrap; }621 622#summary {623 font-size: 11.5px;624 color: var(--text2);625 line-height: 1.6;626}627 628#summary strong {629 font-size: 15px;630 color: var(--amber);631 font-family: var(--mono);632}633 634.sum-keys {635 margin-top: 8px;636 display: flex;637 flex-wrap: wrap;638 gap: 4px;639}640 641.sum-key {642 font-family: var(--mono);643 font-size: 9.5px;644 color: var(--text2);645 background: var(--bg4);646 border: 1px solid var(--border2);647 border-radius: 4px;648 padding: 2px 6px;649}650 651#customSec { margin-top: 8px; }652 653.custom-row {654 display: flex;655 gap: 8px;656 align-items: center;657 margin-bottom: 8px;658}659 660.custom-row input {661 flex: 1;662 background: var(--bg3);663 border: 1px solid var(--border);664 border-radius: var(--r);665 padding: 7px 10px;666 font-family: var(--mono);667 font-size: 11px;668 color: var(--text);669 outline: none;670 transition: border-color .15s;671 min-width: 0;672}673 674.custom-row input:focus { border-color: var(--amber); }675.custom-row input:first-child { flex: 0 0 40%; }676 677#toast {678 position: fixed;679 bottom: 24px;680 left: 50%;681 transform: translateX(-50%) translateY(20px);682 background: var(--bg4);683 border: 1px solid var(--border2);684 color: var(--amber);685 font-family: var(--mono);686 font-size: 12px;687 font-weight: 600;688 padding: 9px 20px;689 border-radius: 30px;690 z-index: 9999;691 opacity: 0;692 transition: opacity .2s, transform .2s;693 pointer-events: none;694 box-shadow: 0 8px 32px rgba(0,0,0,.5);695}696 697#toast.show {698 opacity: 1;699 transform: translateX(-50%) translateY(0);700}701 702::-webkit-scrollbar { width: 6px; height: 6px; }703::-webkit-scrollbar-track { background: transparent; }704::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 4px; }705 706@media (max-width: 900px) {707 :root { --panel-w: 280px; --sidebar-w: 180px; }708}709 710@media (max-width: 700px) {711 .right-panel { display: none; }712 :root { --sidebar-w: 160px; }713}714 715@media (max-width: 520px) {716 .sidebar-wrap { display: none; }717 .topbar-divider, .topbar-title { display: none; }718}719</style>720</head>721 722<body>723 724<header class="topbar">725 <div class="topbar-logo">726 <span class="logo-emoji">🪽</span>727 <span class="topbar-wordmark">Hugging<em>Mes</em></span>728 </div>729 <div class="topbar-divider"></div>730 <span class="topbar-title">ENV Builder</span>731 <div class="topbar-spacer"></div>732 <span class="topbar-pill">v2025</span>733</header>734 735<div class="layout">736 737 <aside class="sidebar-wrap">738 <div class="sidebar-scroll">739 <div id="sidebar"></div>740 </div>741 </aside>742 743 <main class="main">744 745 <div class="toolbar">746 <span class="toolbar-hint">Tip: Start with <strong>⚡ Required</strong>, then fill keys and click <strong># Generate Bundle</strong>.</span>747 <div class="search-wrap">748 <span class="search-icon">⌕</span>749 <input id="search" type="text" placeholder="Search variables…" autocomplete="off" spellcheck="false">750 </div>751 752 <div class="tb-sep"></div>753 754 <button id="selectRequired" class="btn">⚡ Required</button>755 <button id="selectCommon" class="btn">★ Common</button>756 <button id="selectVisible" class="btn">☑ Visible</button>757 <button id="clearAll" class="btn btn-ghost">✕ Clear</button>758 </div>759 760 <div class="content-wrap">761 762 <div class="sections-scroll">763 764 <details class="tag-legend">765 <summary class="legend-summary">766 <div class="legend-chips">767 <span class="badge badge-critical">critical</span>768 <span class="badge badge-credential">credential</span>769 <span class="badge badge-feature">feature</span>770 <span class="badge badge-optional">optional</span>771 <span class="badge badge-advanced">advanced</span>772 <span class="badge badge-build">build</span>773 </div>774 <span class="legend-hint">▸ Tag legend</span>775 </summary>776 <div class="legend-body">777 <div class="legend-row"><span class="badge badge-critical">critical</span> Required for the space to function at all</div>778 <div class="legend-row"><span class="badge badge-credential">credential</span> API keys, tokens, secrets — keep private</div>779 <div class="legend-row"><span class="badge badge-feature">feature</span> Unlocks an optional feature or integration</div>780 <div class="legend-row"><span class="badge badge-optional">optional</span> Useful but not required; has a default</div>781 <div class="legend-row"><span class="badge badge-advanced">advanced</span> Fine-tuning for specific deployments</div>782 <div class="legend-row"><span class="badge badge-build">build</span> Affects Docker build, not runtime</div>783 <div class="legend-tip">Use <strong>⚡ Required</strong> to auto-select all critical fields, then fill in credential keys.</div>784 </div>785 </details>786 787 <div id="sections"></div>788 789 <div id="customSec" class="sec" data-section="Custom Env">790 <div class="sec-header">791 <span class="sec-icon">🔧</span>792 <span class="sec-title">Custom Env</span>793 <div class="sec-line"></div>794 </div>795 <div id="customRows"></div>796 <button id="addCustom" class="btn" style="margin-top:6px;">+ Add variable</button>797 </div>798 </div>799 800 <aside class="right-panel">801 <div class="panel-scroll">802 803 <div class="pblock">804 <div class="pblock-head">805 <span class="pblock-title">📊 Summary</span>806 </div>807 <div class="pblock-body">808 <div id="summary">No variables selected yet.</div>809 </div>810 </div>811 812 <div class="pblock">813 <div class="pblock-head">814 <span class="pblock-title">📦 Bundle Output</span>815 </div>816 <div class="pblock-body">817 <textarea id="bundleOut" placeholder="Select variables and click # Generate Bundle…" readonly spellcheck="false"></textarea>818 <input type="text" id="envLineOut" placeholder="HUGGINGMES_ENV_BUNDLE=…" readonly spellcheck="false">819 <div class="row-btns">820 <button id="generateBundle" class="btn btn-amber" style="width:100%;"># Generate Bundle</button>821 </div>822 <div class="row-btns">823 <button id="copyBundle" class="btn btn-amber">⎘ Bundle</button>824 <button id="copyEnvLine" class="btn">⎘ Env Line</button>825 <button id="copyJson" class="btn">⎘ JSON</button>826 <button id="applyBundle" class="btn btn-ghost">↺ Apply</button>827 </div>828 </div>829 </div>830 831 <div class="pblock">832 <div class="pblock-head">833 <span class="pblock-title">📥 Import</span>834 </div>835 <div class="pblock-body">836 <textarea id="importText" placeholder="Paste .env, JSON, or HUGGINGMES_ENV_BUNDLE=… here" spellcheck="false"></textarea>837 <button id="applyImport" class="btn btn-amber" style="width:100%;">↓ Import & Apply</button>838 </div>839 </div>840 841 </div>842 </aside>843 844 </div>845 </main>846</div>847 848<div id="toast">Copied ✓</div>849 850<script src="env-builder.js"></script>851 852</body>853</html>854 