diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7521f89 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Local-only assistant notes — this repo is PUBLIC, keep these out of git. +CLAUDE.md +.claude/ + +# Editor / OS cruft +.DS_Store +*.swp diff --git a/agentic-setup/agentic-setup-overview.html b/agentic-setup/agentic-setup-overview.html index a54adfa..eadede8 100644 --- a/agentic-setup/agentic-setup-overview.html +++ b/agentic-setup/agentic-setup-overview.html @@ -197,7 +197,7 @@ code{font-family:var(--mono);font-size:.88em;background:var(--surface-2); /* ---- language selector (segmented pill, matches mono label system) ----- */ .langbar{ position:absolute;top:clamp(1rem,3vw,1.8rem);right:clamp(1.1rem,4vw,3rem); - display:flex;align-items:center;gap:.55rem;z-index:5; + display:flex;align-items:center;gap:.55rem;z-index:5;flex-wrap:wrap;justify-content:flex-end; } .langbar .lglabel{ font-family:var(--mono);font-size:.6rem;letter-spacing:.18em;text-transform:uppercase; @@ -228,6 +228,24 @@ code{font-family:var(--mono);font-size:.88em;background:var(--surface-2); .langbar{top:.7rem;right:.9rem} } +/* ---- copy-link control (shares the segmented-pill language) ------- */ +.copylink{ + appearance:none;cursor:pointer;display:inline-flex;align-items:center; + font-family:var(--mono);font-size:.72rem;font-weight:700;letter-spacing:.1em; + text-transform:uppercase;line-height:1;color:var(--muted);background:var(--surface); + border:1px solid var(--border-strong);border-radius:99px;padding:.42em .85em; + box-shadow:var(--shadow); + transition:color .16s ease, border-color .16s ease, background-color .16s ease; +} +.copylink:hover{color:var(--accent-ink);border-color:var(--accent)} +.copylink:focus-visible{outline:2.5px solid var(--accent);outline-offset:2px} +.copylink svg{width:13px;height:13px;flex:none} +.copylink .cl-idle,.copylink .cl-done{display:inline-flex;align-items:center;gap:.45em} +.copylink .cl-done{display:none} +.copylink.copied{color:var(--good);border-color:var(--good);background:var(--accent-wash)} +.copylink.copied .cl-idle{display:none} +.copylink.copied .cl-done{display:inline-flex} + /* ========================================================================= SECTION SHELL ========================================================================= */ @@ -695,7 +713,19 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent)
+ data-en-aria="Language and link" data-de-aria="Sprache und Link" aria-label="Language and link"> + Language
+
Language
@@ -1850,6 +1880,7 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) themebar_aria:"Theme and language", lang_group_aria:"Language", lang_label:"Language", lang_select_aria:"Choose language", theme_group_aria:"Colour theme", theme_label:"Theme", + copy_label:"Copy link", copy_done:"Copied", copy_aria:"Copy link to this guide", theme_light:"LIGHT", theme_dark:"DARK", theme_light_aria:"Light theme", theme_dark_aria:"Dark theme", coach_kicker:"Languages", @@ -2067,6 +2098,7 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) themebar_aria:"Design und Sprache", lang_group_aria:"Sprache", lang_label:"Sprache", lang_select_aria:"Sprache wählen", theme_group_aria:"Farbdesign", theme_label:"Design", + copy_label:"Link kopieren", copy_done:"Kopiert", copy_aria:"Link zu dieser Anleitung kopieren", theme_light:"HELL", theme_dark:"DUNKEL", theme_light_aria:"Helles Design", theme_dark_aria:"Dunkles Design", coach_kicker:"Sprachen", @@ -2284,6 +2316,7 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) themebar_aria:"تم و زبان", lang_group_aria:"زبان", lang_label:"زبان", lang_select_aria:"انتخاب زبان", theme_group_aria:"تم رنگی", theme_label:"تم", + copy_label:"کپی لینک", copy_done:"کپی شد", copy_aria:"کپی لینک این راهنما", theme_light:"روشن", theme_dark:"تیره", theme_light_aria:"تم روشن", theme_dark_aria:"تم تیره", coach_kicker:"زبان‌ها", @@ -2548,7 +2581,20 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) } window.__setLang = setLang; - // initial language: localStorage -> navigator.language -> en + // A shareable ?lang= / #lang= in the URL forces the language, beating any + // saved choice — so a link can open straight in DE/FA without defaulting to + // EN. The hash form survives the compact-URL 302 redirect (the browser + // reattaches the fragment), so /SEC-01#lang=fa works with no server change. + function urlLang(){ + try{ + var m = (location.search + location.hash).match(/[?&#]lang=([a-z]{2})\b/i); + if(m){ var l = m[1].toLowerCase(); if(I18N[l]) return l; } + }catch(e){} + return null; + } + + // initial language: URL ?lang=/#lang= -> localStorage -> navigator.language -> en + var forcedLang = urlLang(); var initLang = null; try{ initLang = localStorage.getItem(LANG_STORE); }catch(e){} if(!I18N[initLang]){ @@ -2557,12 +2603,14 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) else if(nav.indexOf('fa') === 0 || nav.indexOf('pe') === 0) initLang = 'fa'; else initLang = 'en'; } + if(forcedLang) initLang = forcedLang; function wire(){ document.querySelectorAll('.langseg [data-lang-set]').forEach(function(b){ b.addEventListener('click', function(){ setLang(b.getAttribute('data-lang-set'), true); }); }); - setLang(I18N[initLang] ? initLang : 'en', false); + // Persist only when the language came from the URL, so a shared link sticks. + setLang(I18N[initLang] ? initLang : 'en', !!forcedLang); } if(document.readyState === 'loading'){ document.addEventListener('DOMContentLoaded', wire); @@ -2798,6 +2846,37 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) setTimeout(show, 1200); })(); + +/* ========================================================================= + COPY-LINK — copies the page's compact URL to the clipboard, with a brief + "Copied" confirmation (label is translated via the i18n dict). Falls back + to execCommand where the async clipboard API is unavailable. + ========================================================================= */ +(function(){ + function fallback(text, cb){ + try{ + var ta = document.createElement('textarea'); + ta.value = text; ta.setAttribute('readonly',''); + ta.style.position = 'fixed'; ta.style.top = '-9999px'; + document.body.appendChild(ta); ta.focus(); ta.select(); + document.execCommand('copy'); document.body.removeChild(ta); cb(); + }catch(e){} + } + document.querySelectorAll('.copylink').forEach(function(b){ + var t = null; + b.addEventListener('click', function(){ + var url = b.getAttribute('data-copy-url'); if(!url) return; + var done = function(){ + b.classList.add('copied'); + if(t) clearTimeout(t); + t = setTimeout(function(){ b.classList.remove('copied'); }, 1700); + }; + if(navigator.clipboard && navigator.clipboard.writeText){ + navigator.clipboard.writeText(url).then(done).catch(function(){ fallback(url, done); }); + } else { fallback(url, done); } + }); + }); +})(); diff --git a/index.html b/index.html index 781a7e2..d26a673 100644 --- a/index.html +++ b/index.html @@ -244,6 +244,24 @@ code{font-family:var(--mono);font-size:.88em;background:var(--surface-2); .themebar{top:.7rem;right:.9rem} } +/* ---- copy-link control (shares the segmented-pill language) ------- */ +.copylink{ + appearance:none;cursor:pointer;display:inline-flex;align-items:center; + font-family:var(--mono);font-size:.72rem;font-weight:700;letter-spacing:.1em; + text-transform:uppercase;line-height:1;color:var(--muted);background:var(--surface); + border:1px solid var(--border-strong);border-radius:99px;padding:.42em .85em; + box-shadow:var(--shadow); + transition:color .16s ease, border-color .16s ease, background-color .16s ease; +} +.copylink:hover{color:var(--accent-ink);border-color:var(--accent)} +.copylink:focus-visible{outline:2.5px solid var(--accent);outline-offset:2px} +.copylink svg{width:13px;height:13px;flex:none} +.copylink .cl-idle,.copylink .cl-done{display:inline-flex;align-items:center;gap:.45em} +.copylink .cl-done{display:none} +.copylink.copied{color:var(--good);border-color:var(--good);background:var(--good-wash)} +.copylink.copied .cl-idle{display:none} +.copylink.copied .cl-done{display:inline-flex} + /* ========================================================================= SECTION SHELL ========================================================================= */ @@ -514,7 +532,17 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent)
-
+
+
Theme
@@ -851,6 +879,37 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) }, { rootMargin: '0px 0px -8% 0px', threshold: 0.08 }); els.forEach(function(el){ io.observe(el); }); })(); + +/* ========================================================================= + COPY-LINK — copies the page's compact URL to the clipboard, with a brief + "Copied" confirmation. Falls back to execCommand where the async clipboard + API is unavailable (older browsers / non-secure contexts). + ========================================================================= */ +(function(){ + function fallback(text, cb){ + try{ + var ta = document.createElement('textarea'); + ta.value = text; ta.setAttribute('readonly',''); + ta.style.position = 'fixed'; ta.style.top = '-9999px'; + document.body.appendChild(ta); ta.focus(); ta.select(); + document.execCommand('copy'); document.body.removeChild(ta); cb(); + }catch(e){} + } + document.querySelectorAll('.copylink').forEach(function(b){ + var t = null; + b.addEventListener('click', function(){ + var url = b.getAttribute('data-copy-url'); if(!url) return; + var done = function(){ + b.classList.add('copied'); + if(t) clearTimeout(t); + t = setTimeout(function(){ b.classList.remove('copied'); }, 1700); + }; + if(navigator.clipboard && navigator.clipboard.writeText){ + navigator.clipboard.writeText(url).then(done).catch(function(){ fallback(url, done); }); + } else { fallback(url, done); } + }); + }); +})(); diff --git a/privacy.html b/privacy.html index bd8faf6..0ca0a8c 100644 --- a/privacy.html +++ b/privacy.html @@ -244,6 +244,24 @@ code{font-family:var(--mono);font-size:.88em;background:var(--surface-2); .themebar{top:.7rem;right:.9rem} } +/* ---- copy-link control (shares the segmented-pill language) ------- */ +.copylink{ + appearance:none;cursor:pointer;display:inline-flex;align-items:center; + font-family:var(--mono);font-size:.72rem;font-weight:700;letter-spacing:.1em; + text-transform:uppercase;line-height:1;color:var(--muted);background:var(--surface); + border:1px solid var(--border-strong);border-radius:99px;padding:.42em .85em; + box-shadow:var(--shadow); + transition:color .16s ease, border-color .16s ease, background-color .16s ease; +} +.copylink:hover{color:var(--accent-ink);border-color:var(--accent)} +.copylink:focus-visible{outline:2.5px solid var(--accent);outline-offset:2px} +.copylink svg{width:13px;height:13px;flex:none} +.copylink .cl-idle,.copylink .cl-done{display:inline-flex;align-items:center;gap:.45em} +.copylink .cl-done{display:none} +.copylink.copied{color:var(--good);border-color:var(--good);background:var(--good-wash)} +.copylink.copied .cl-idle{display:none} +.copylink.copied .cl-done{display:inline-flex} + /* ========================================================================= SECTION SHELL (matches index.html) ========================================================================= */ @@ -407,7 +425,17 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent)
-
+
+
Theme
@@ -621,6 +649,37 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent) }, { rootMargin: '0px 0px -8% 0px', threshold: 0.08 }); els.forEach(function(el){ io.observe(el); }); })(); + +/* ========================================================================= + COPY-LINK — copies the page's compact URL to the clipboard, with a brief + "Copied" confirmation. Falls back to execCommand where the async clipboard + API is unavailable (older browsers / non-secure contexts). + ========================================================================= */ +(function(){ + function fallback(text, cb){ + try{ + var ta = document.createElement('textarea'); + ta.value = text; ta.setAttribute('readonly',''); + ta.style.position = 'fixed'; ta.style.top = '-9999px'; + document.body.appendChild(ta); ta.focus(); ta.select(); + document.execCommand('copy'); document.body.removeChild(ta); cb(); + }catch(e){} + } + document.querySelectorAll('.copylink').forEach(function(b){ + var t = null; + b.addEventListener('click', function(){ + var url = b.getAttribute('data-copy-url'); if(!url) return; + var done = function(){ + b.classList.add('copied'); + if(t) clearTimeout(t); + t = setTimeout(function(){ b.classList.remove('copied'); }, 1700); + }; + if(navigator.clipboard && navigator.clipboard.writeText){ + navigator.clipboard.writeText(url).then(done).catch(function(){ fallback(url, done); }); + } else { fallback(url, done); } + }); + }); +})();