feat: per-page copy-link button for compact URLs + shareable force-language links
Deploy / deploy (push) Successful in 0s
Deploy / deploy (push) Successful in 0s
- Copy-link pill in each page's top bar copies its compact URL (SEC-01/AGT-01, /, /privacy) - ?lang= / #lang= forces the page language over saved/browser default (EN/DE, FA); hash form survives the compact-URL 302 - add .gitignore (keeps local CLAUDE.md out of the public repo)
This commit is contained in:
@@ -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)
|
||||
<header class="masthead wrap">
|
||||
|
||||
<div class="langbar" role="group"
|
||||
data-en-aria="Language" data-de-aria="Sprache" aria-label="Language">
|
||||
data-en-aria="Language and link" data-de-aria="Sprache und Link" aria-label="Language and link">
|
||||
<button type="button" class="copylink" data-copy-url="https://tutorials.pouyalab.de/AGT-01"
|
||||
data-en-aria="Copy link to this guide" data-de-aria="Link zu dieser Anleitung kopieren"
|
||||
aria-label="Copy link to this guide">
|
||||
<span class="cl-idle">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 15l6-6M10.5 6.5l1-1a4.95 4.95 0 0 1 7 7l-1 1M13.5 17.5l-1 1a4.95 4.95 0 0 1-7-7l1-1"/></svg>
|
||||
<span data-i18n data-en="Copy link" data-de="Link kopieren">Copy link</span>
|
||||
</span>
|
||||
<span class="cl-done">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg>
|
||||
<span data-i18n data-en="Copied" data-de="Kopiert">Copied</span>
|
||||
</span>
|
||||
</button>
|
||||
<span class="lglabel" data-i18n data-en="Language" data-de="Sprache">Language</span>
|
||||
<div class="langseg">
|
||||
<button type="button" id="lang-en" data-lang="en" aria-pressed="true"
|
||||
@@ -1420,7 +1450,21 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent)
|
||||
var ariaNodes = document.querySelectorAll('[data-en-aria],[data-de-aria]');
|
||||
var buttons = document.querySelectorAll('.langseg button[data-lang]');
|
||||
|
||||
// A shareable ?lang= / #lang= in the URL forces the language, beating any
|
||||
// saved choice — so a link can open straight in DE without defaulting to EN.
|
||||
// The hash form survives the compact-URL 302 redirect (the browser reattaches
|
||||
// the fragment), so /AGT-01#lang=de 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(l === 'en' || l === 'de') return l; }
|
||||
}catch(e){}
|
||||
return null;
|
||||
}
|
||||
|
||||
function decideInitial(){
|
||||
var forced = urlLang();
|
||||
if(forced) return forced;
|
||||
try{
|
||||
var saved = localStorage.getItem(STORE);
|
||||
if(saved === 'en' || saved === 'de') return saved;
|
||||
@@ -1469,6 +1513,34 @@ footer .sig .dot{width:6px;height:6px;border-radius:50%;background:var(--accent)
|
||||
}, {rootMargin:'0px 0px -8% 0px', threshold:.08});
|
||||
els.forEach(function(e){io.observe(e)});
|
||||
})();
|
||||
|
||||
/* Copy-link — copies the page's compact URL, with a brief "Copied" confirm.
|
||||
Falls back to execCommand on non-secure contexts / older browsers. */
|
||||
(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); }
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user