webcake-landing-mcp 1.0.22 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,11 @@
1
1
  [
2
+ {
3
+ "v": "1.0.23",
4
+ "d": "07/06/2026",
5
+ "type": "Added",
6
+ "en": "The GET / guide page now includes a dark/light theme toggle button in the header; the preference is saved in localStorage and applied before the…",
7
+ "vi": "Trang hướng dẫn GET / nay có nút chuyển chế độ sáng/tối trong header; lựa chọn được lưu vào localStorage và áp dụng trước khi trang hiển thị để…"
8
+ },
2
9
  {
3
10
  "v": "1.0.22",
4
11
  "d": "07/06/2026",
@@ -33,12 +40,5 @@
33
40
  "type": "Changed",
34
41
  "en": "new_element for list-product now seeds a default styles.colorBtn (rgba(246,4,87,1)) so generated product-list button labels have a visible accent…",
35
42
  "vi": "new_element cho list-product nay gán sẵn styles.colorBtn mặc định (rgba(246,4,87,1)) để nhãn nút của danh sách sản phẩm có màu nhấn nhìn thấy được…"
36
- },
37
- {
38
- "v": "1.0.17",
39
- "d": "07/06/2026",
40
- "type": "Fixed",
41
- "en": "get_element and get_generation_guide no longer suggest https://picsum.photos as an alternative image placeholder; agents are now directed to use…",
42
- "vi": "get_element và get_generation_guide không còn gợi ý https://picsum.photos làm ảnh placeholder thay thế; agent nay được hướng dẫn chỉ dùng…"
43
43
  }
44
44
  ]
package/dist/web-guide.js CHANGED
@@ -24,6 +24,9 @@
24
24
  import { readFileSync } from "node:fs";
25
25
  import { ICON_SVG } from "./branding.js";
26
26
  const MCP_REMOTE_URL = "https://webcake.io/mcp-remote";
27
+ // The "configure every IDE" one-liner — rendered as a code block (with a copy
28
+ // button) rather than long inline code, which wrapped messily on mobile.
29
+ const INSTALL_ALL_CMD = "npx -y webcake-landing-mcp install --ide all --env prod --jwt <TOKEN>";
27
30
  const GITHUB_URL = "https://github.com/vuluu2k/webcake-landing-mcp";
28
31
  const NPM_URL = "https://www.npmjs.com/package/webcake-landing-mcp";
29
32
  const DOCS_URL = `${GITHUB_URL}#readme`;
@@ -61,6 +64,8 @@ const ICONS = {
61
64
  bulb: '<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/>',
62
65
  server: '<rect width="20" height="8" x="2" y="2" rx="2"/><rect width="20" height="8" x="2" y="14" rx="2"/><path d="M6 6h.01"/><path d="M6 18h.01"/>',
63
66
  window: '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="M2 9h20"/><path d="M6 6.5h.01"/><path d="M9 6.5h.01"/>',
67
+ moon: '<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>',
68
+ sun: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',
64
69
  };
65
70
  function icon(name) {
66
71
  return `<svg class="i" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${ICONS[name] ?? ""}</svg>`;
@@ -183,7 +188,7 @@ const T = {
183
188
  '<b>Làm theo hỏi đáp:</b> chọn môi trường (<code class="inl">prod</code>) → đăng nhập Webcake qua trình duyệt (hoặc dán JWT) → chọn IDE (Claude Desktop / Cursor / Claude Code…).',
184
189
  '<b>Khởi động lại IDE</b> → thấy <code class="inl">webcake-landing</code> trong danh sách MCP là xong.',
185
190
  ],
186
- m1Note: 'Muốn cấu hình mọi IDE một phát: <code class="inl">npx -y webcake-landing-mcp install --ide all --env prod --jwt &lt;TOKEN&gt;</code>',
191
+ m1Note: "Muốn cấu hình mọi IDE một phát:",
187
192
  m2Tag: "Cách ② · URL remote — không cần cài gì",
188
193
  m2Sub: "Hợp khi máy không có Node.js, dùng theo nhóm, hoặc dùng claude.ai trên web.",
189
194
  m2Steps: [
@@ -261,7 +266,7 @@ const T = {
261
266
  '<b>Follow the prompts:</b> pick an environment (<code class="inl">prod</code>) → sign in to Webcake in the browser (or paste a JWT) → pick your IDE (Claude Desktop / Cursor / Claude Code…).',
262
267
  '<b>Restart your IDE</b> → see <code class="inl">webcake-landing</code> in the MCP list and you\'re done.',
263
268
  ],
264
- m1Note: 'Configure every IDE at once: <code class="inl">npx -y webcake-landing-mcp install --ide all --env prod --jwt &lt;TOKEN&gt;</code>',
269
+ m1Note: "Configure every IDE at once:",
265
270
  m2Tag: "Way ② · Remote URL — nothing to install",
266
271
  m2Sub: "Best when you have no Node.js, work in a team, or use claude.ai on the web.",
267
272
  m2Steps: [
@@ -373,6 +378,7 @@ export function guideHtml(origin, lang = "vi") {
373
378
  <html lang="${L}"><head>
374
379
  <meta charset="utf-8">
375
380
  <meta name="viewport" content="width=device-width,initial-scale=1">
381
+ <script>(function(){try{var t=localStorage.getItem('wc-theme');if(t==='dark'||t==='light')document.documentElement.setAttribute('data-theme',t);}catch(e){}})();</script>
376
382
  <title>${m.title}</title>
377
383
  <meta name="description" content="${m.desc}">
378
384
  <meta name="keywords" content="${m.keywords}">
@@ -400,10 +406,15 @@ export function guideHtml(origin, lang = "vi") {
400
406
  <meta name="twitter:image" content="${ogImage}">
401
407
  <script type="application/ld+json">${jsonLdScript}</script>
402
408
  <style>
409
+ /* Light defaults. Dark applies via OS preference OR a forced [data-theme="dark"]
410
+ (the toggle); [data-theme="light"] forces light even on a dark OS. */
403
411
  :root{--g:#1DB954;--g7:#178f43;--ink:#11231b;--mut:#5e6d65;--bg:#f5f9f7;--card:#ffffff;
404
- --line:rgba(16,40,30,.09);--glass-hi:transparent;--shadow:0 1px 2px rgba(16,40,30,.05),0 6px 20px -12px rgba(16,40,30,.18);--code:#0e1714}
405
- @media(prefers-color-scheme:dark){:root{--ink:#e8f0ec;--mut:#9aaba2;--bg:#0b110e;--card:#141b17;
406
- --line:rgba(255,255,255,.07);--glass-hi:transparent;--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.7);--code:#070f0b;--g7:#5ee08a}}
412
+ --line:rgba(16,40,30,.09);--shadow:0 1px 2px rgba(16,40,30,.05),0 6px 20px -12px rgba(16,40,30,.18);--code:#0e1714;
413
+ --ic-fg:#178f43;--btn-hover:#178f43}
414
+ @media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--ink:#e8f0ec;--mut:#9aaba2;--bg:#0b110e;--card:#141b17;
415
+ --line:rgba(255,255,255,.07);--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.7);--code:#070f0b;--g7:#5ee08a;--ic-fg:#6fe79a;--btn-hover:#21c264}}
416
+ :root[data-theme="dark"]{--ink:#e8f0ec;--mut:#9aaba2;--bg:#0b110e;--card:#141b17;
417
+ --line:rgba(255,255,255,.07);--shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px -14px rgba(0,0,0,.7);--code:#070f0b;--g7:#5ee08a;--ic-fg:#6fe79a;--btn-hover:#21c264}
407
418
  *{box-sizing:border-box}
408
419
  html{scroll-behavior:smooth}
409
420
  body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;color:var(--ink);
@@ -424,9 +435,15 @@ export function guideHtml(origin, lang = "vi") {
424
435
  header .logo{width:50px;height:50px;border-radius:14px;overflow:hidden;flex:0 0 auto;
425
436
  box-shadow:0 6px 16px -4px rgba(29,185,84,.4)}
426
437
  header .logo svg{width:100%;height:100%;display:block}
427
- .langsw{margin-left:auto;align-self:flex-start;font-size:.82rem;font-weight:700;color:var(--g7);text-decoration:none;
438
+ .hgrow{flex:1 1 auto;min-width:0}
439
+ .controls{margin-left:auto;flex:0 0 auto;display:flex;align-items:center;gap:8px}
440
+ .langsw{font-size:.82rem;font-weight:700;color:var(--g7);text-decoration:none;white-space:nowrap;
428
441
  border:1px solid var(--line);background:var(--card);padding:7px 12px;border-radius:999px;display:inline-flex;align-items:center;gap:6px}
429
442
  .langsw:hover{border-color:var(--g)}
443
+ .iconbtn{width:36px;height:36px;flex:0 0 auto;display:grid;place-items:center;cursor:pointer;color:var(--g7);
444
+ border:1px solid var(--line);background:var(--card);border-radius:10px;transition:border-color .15s ease,color .15s ease}
445
+ .iconbtn:hover{border-color:var(--g)}
446
+ .iconbtn svg{width:17px;height:17px}
430
447
  h1{font-size:1.78rem;margin:0;font-weight:800;letter-spacing:-.02em}
431
448
  .sub{color:var(--mut);margin:3px 0 0;font-size:.98rem}
432
449
  .lead{font-size:1.16rem;margin:20px 0 18px;max-width:60ch}
@@ -439,9 +456,8 @@ export function guideHtml(origin, lang = "vi") {
439
456
  .dot{width:8px;height:8px;border-radius:50%;background:var(--g);box-shadow:0 0 0 0 rgba(29,185,84,.5);animation:pulse 2s infinite}
440
457
  @keyframes pulse{70%{box-shadow:0 0 0 7px rgba(29,185,84,0)}100%{box-shadow:0 0 0 0 rgba(29,185,84,0)}}
441
458
  h2{font-size:1.32rem;margin:46px 0 16px;font-weight:800;letter-spacing:-.01em}
442
- .ic{width:42px;height:42px;border-radius:12px;display:grid;place-items:center;flex:0 0 auto;color:var(--g7);
459
+ .ic{width:42px;height:42px;border-radius:12px;display:grid;place-items:center;flex:0 0 auto;color:var(--ic-fg);
443
460
  background:rgba(29,185,84,.11);border:1px solid var(--line);transition:transform .2s ease}
444
- @media(prefers-color-scheme:dark){.ic{color:#6fe79a}}
445
461
  .ic .i{width:22px;height:22px}
446
462
  .grid{display:grid;gap:16px;grid-template-columns:1fr 1fr 1fr}
447
463
  @media(max-width:720px){.grid{grid-template-columns:1fr}}
@@ -450,11 +466,20 @@ export function guideHtml(origin, lang = "vi") {
450
466
  .card h3{margin:0 0 6px;font-size:1.04rem}
451
467
  .card p{color:var(--mut);font-size:.93rem;margin:0}
452
468
  .tag{display:inline-flex;align-items:center;gap:9px;font-size:.82rem;font-weight:800;color:var(--g7);
453
- text-transform:uppercase;letter-spacing:.04em}
469
+ text-transform:uppercase;letter-spacing:.04em;flex-wrap:wrap}
454
470
  .tag .ic{width:30px;height:30px;border-radius:9px}
455
471
  .tag .ic .i{width:16px;height:16px}
456
472
  pre{margin:0;background:var(--code);color:#e8f0ec;border-radius:11px;padding:12px 14px;overflow-x:auto;
457
473
  border:1px solid rgba(255,255,255,.06);font:600 .82rem/1.5 ui-monospace,SFMono-Regular,Menlo,monospace}
474
+ /* Copy button injected onto every <pre> by the inline script */
475
+ .codewrap{position:relative}
476
+ .codewrap pre{padding-right:46px}
477
+ .copy{position:absolute;top:8px;right:8px;width:30px;height:30px;display:grid;place-items:center;cursor:pointer;
478
+ border:1px solid rgba(255,255,255,.15);border-radius:8px;background:rgba(255,255,255,.06);color:#cfe9d8;
479
+ transition:background .15s ease,color .15s ease,border-color .15s ease}
480
+ .copy:hover{background:rgba(255,255,255,.13);color:#fff}
481
+ .copy svg{width:15px;height:15px}
482
+ .copy.done{color:#5ee08a;border-color:rgba(94,224,138,.55)}
458
483
  .feat{list-style:none;padding:0;margin:0;display:grid;gap:12px}
459
484
  .feat li{display:flex;gap:13px;align-items:center;font-size:.97rem;padding:13px 16px}
460
485
  .feat li b{color:var(--ink)}
@@ -484,8 +509,7 @@ export function guideHtml(origin, lang = "vi") {
484
509
  background:var(--g);color:#fff;text-decoration:none;font-weight:700;font-size:.93rem;
485
510
  box-shadow:0 4px 12px -4px rgba(29,185,84,.5);transition:transform .15s ease,background .15s ease}
486
511
  .btn .i{width:18px;height:18px}
487
- .btn:hover{transform:translateY(-1px);background:var(--g7)}
488
- @media(prefers-color-scheme:dark){.btn:hover{background:#21c264}}
512
+ .btn:hover{transform:translateY(-1px);background:var(--btn-hover)}
489
513
  .btn.ghost{background:var(--card);color:var(--ink);border:1px solid var(--line);box-shadow:none}
490
514
  .btn.ghost:hover{border-color:var(--g);background:var(--card)}
491
515
  .uses{display:grid;gap:14px;grid-template-columns:1fr 1fr;padding:0;margin:0;list-style:none}
@@ -502,15 +526,16 @@ export function guideHtml(origin, lang = "vi") {
502
526
  .msub{color:var(--mut);font-size:.92rem;margin:.5rem 0 1.2rem}
503
527
  .steps{list-style:none;margin:0;padding:0;display:grid;gap:16px}
504
528
  .steps li{display:flex;gap:14px}
505
- .steps .n{flex:0 0 auto;width:28px;height:28px;border-radius:50%;color:var(--g7);
529
+ .steps .n{flex:0 0 auto;width:28px;height:28px;border-radius:50%;color:var(--ic-fg);
506
530
  background:rgba(29,185,84,.12);border:1px solid var(--line);
507
531
  font:800 .85rem/1 system-ui;display:flex;align-items:center;justify-content:center}
508
- @media(prefers-color-scheme:dark){.steps .n{color:#6fe79a}}
509
532
  .steps .body{flex:1;min-width:0;font-size:.95rem}
510
533
  .steps .body pre{margin-top:9px}
511
534
  .steps .body .btn{margin-top:10px}
512
- code.inl{background:rgba(29,185,84,.13);color:var(--g7);padding:1px 6px;border-radius:6px;font-size:.85em;font-weight:600}
535
+ code.inl{background:rgba(29,185,84,.13);color:var(--g7);padding:1px 6px;border-radius:6px;font-size:.85em;font-weight:600;
536
+ overflow-wrap:anywhere;word-break:break-word}
513
537
  .note{font-size:.86rem;color:var(--mut);margin-top:10px}
538
+ .note + pre,.note + .codewrap{margin-top:9px}
514
539
  details{padding:2px 18px;margin-bottom:11px}
515
540
  details summary{cursor:pointer;font-weight:600;padding:15px 0;list-style:none;display:flex;align-items:center;gap:10px}
516
541
  details summary::-webkit-details-marker{display:none}
@@ -549,6 +574,31 @@ export function guideHtml(origin, lang = "vi") {
549
574
  @keyframes blink{50%{opacity:.55}}
550
575
  .cl-more{display:inline-flex;align-items:center;gap:6px;margin-top:6px;font-size:.86rem;font-weight:600;color:var(--g7);text-decoration:none}
551
576
  .cl-more:hover{gap:9px}
577
+ @media(max-width:640px){
578
+ .wrap{padding:30px 15px 56px}
579
+ /* Header: logo + controls on the top row, title drops to its own full line */
580
+ header{flex-wrap:wrap;gap:12px}
581
+ .hgrow{order:2;flex:1 1 100%}
582
+ h1{font-size:1.4rem}
583
+ h2{font-size:1.2rem;margin:34px 0 14px}
584
+ .lead{font-size:1.05rem}
585
+ .method{padding:18px 15px}
586
+ .card{padding:18px}
587
+ .cl-wrap{padding:18px 16px 10px}
588
+ .langsw{padding:6px 10px}
589
+ .uses li,.feat li{padding:14px}
590
+ /* Flow diagram: stack vertically (the horizontal row overflows narrow screens) */
591
+ .flow{flex-direction:column;align-items:stretch;overflow:visible;padding:16px}
592
+ .flow .node{flex-direction:row;width:auto;align-items:center;gap:13px;text-align:left}
593
+ .flow .node .ic{width:44px;height:44px;border-radius:13px}
594
+ .flow .node .ic .i{width:22px;height:22px}
595
+ .flow .node b{font-size:.95rem}
596
+ .flow .node span{font-size:.8rem}
597
+ .flow .wire{flex:0 0 auto;width:2px;height:20px;min-width:0;margin:3px 0 3px 21px;
598
+ background:linear-gradient(var(--line),var(--g))}
599
+ .flow .wire::after{content:none}
600
+ .flow .wire .pkt{display:none}
601
+ }
552
602
  @media(prefers-reduced-motion:no-preference){
553
603
  @supports (animation-timeline:view()){
554
604
  .reveal{animation:rise linear both;animation-timeline:view();animation-range:entry 0% entry 32%}
@@ -564,11 +614,14 @@ export function guideHtml(origin, lang = "vi") {
564
614
 
565
615
  <header class="hero-in">
566
616
  <span class="logo">${ICON_SVG}</span>
567
- <div>
617
+ <div class="hgrow">
568
618
  <h1>Webcake Landing MCP</h1>
569
619
  <p class="sub">${t.sub}</p>
570
620
  </div>
571
- <a class="langsw" href="${otherHref}" hreflang="${otherLang}" rel="alternate">${icon("globe")} ${t.switchLabel}</a>
621
+ <div class="controls">
622
+ <button class="iconbtn" id="theme" type="button" aria-label="Toggle theme" title="Theme">${icon("moon")}</button>
623
+ <a class="langsw" href="${otherHref}" hreflang="${otherLang}" rel="alternate">${icon("globe")} ${t.switchLabel}</a>
624
+ </div>
572
625
  </header>
573
626
 
574
627
  <p class="hero-in" style="display:flex;gap:9px;flex-wrap:wrap"><span class="pill"><span class="dot"></span> ${t.running}</span>${CHANGELOG[0] ? `<span class="pill">v${CHANGELOG[0].v}</span>` : ""}</p>
@@ -614,6 +667,7 @@ export function guideHtml(origin, lang = "vi") {
614
667
  ${steps(t.m1Steps.map(fill))}
615
668
  </ol>
616
669
  <p class="note">${t.m1Note}</p>
670
+ <pre>${INSTALL_ALL_CMD}</pre>
617
671
  </div>
618
672
 
619
673
  <div class="glass card method reveal">
@@ -659,7 +713,36 @@ export function guideHtml(origin, lang = "vi") {
659
713
  <a href="${selfPath === "/" ? "/health" : "/health"}">Health</a>
660
714
  </footer>
661
715
 
662
- </div></body></html>`;
716
+ </div>
717
+ <script>
718
+ (function(){
719
+ var COPY='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
720
+ var DONE='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>';
721
+ function copyText(t){
722
+ if(navigator.clipboard&&navigator.clipboard.writeText){return navigator.clipboard.writeText(t);}
723
+ return new Promise(function(res,rej){try{var ta=document.createElement('textarea');ta.value=t;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);res();}catch(e){rej(e);}});
724
+ }
725
+ document.querySelectorAll('pre').forEach(function(pre){
726
+ var w=document.createElement('div');w.className='codewrap';
727
+ pre.parentNode.insertBefore(w,pre);w.appendChild(pre);
728
+ var b=document.createElement('button');b.type='button';b.className='copy';b.title='Copy';b.setAttribute('aria-label','Copy');b.innerHTML=COPY;
729
+ b.addEventListener('click',function(){
730
+ copyText(pre.innerText).then(function(){b.classList.add('done');b.innerHTML=DONE;setTimeout(function(){b.classList.remove('done');b.innerHTML=COPY;},1400);}).catch(function(){});
731
+ });
732
+ w.appendChild(b);
733
+ });
734
+
735
+ // Dark / light toggle — overrides the OS preference and persists the choice.
736
+ var SUN='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>';
737
+ var MOON='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg>';
738
+ var html=document.documentElement, tBtn=document.getElementById('theme');
739
+ function effective(){return html.getAttribute('data-theme')||(window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light');}
740
+ function paint(){if(tBtn)tBtn.innerHTML=effective()==='dark'?SUN:MOON;}
741
+ paint();
742
+ if(tBtn)tBtn.addEventListener('click',function(){var next=effective()==='dark'?'light':'dark';html.setAttribute('data-theme',next);try{localStorage.setItem('wc-theme',next);}catch(e){}paint();});
743
+ })();
744
+ </script>
745
+ </body></html>`;
663
746
  }
664
747
  /**
665
748
  * The social-card image served at `/og.svg` and referenced by the page's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-landing-mcp",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
5
5
  "type": "module",
6
6
  "bin": {