talas-group/talas-wiki/templates/base.html
senke 1db6d066c0 nettoyage repo : réorganisation fichiers en vrac, ajout body solidworks + studio mic ref
- Body SolidWorks v1 → 02_PRODUITS_PHYSIQUES/Microphone/Conception/
- Studio Mic KiCAD (DIYPerks) → 02_PRODUITS_PHYSIQUES/R&D_References/DIY/
- cleanup_ports.sh → 04_INFRA_DEPLOIEMENT/
- mockup_jeu_ux → 11_RECHERCHE_&_LAB/
- Printables → 12_DOCUMENTATION/Imprimables/
- Screenshots, ideas, one.html → _BROUILLON/
- all-talas (23Go) → 13_ARCHIVES/
- Supprimé all-talas.zip (20Go doublon), lock files LibreOffice
- Nettoyé .gitignore
- Remote → Forgejo (10.0.20.105:3000)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:31:26 +02:00

317 lines
16 KiB
HTML

{{define "base"}}
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{template "title" .}}</title>
<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=Inter:wght@300;400;600&family=Space+Grotesk:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/static/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github-dark.min.css" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
<link rel="alternate" type="application/rss+xml" title="Talas Wiki RSS" href="/rss">
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
</head>
<body data-page-path="{{template "pagePath" .}}">
<div class="scroll-progress" id="scroll-progress"></div>
<div class="cmd-palette" id="cmd-palette" style="display:none">
<input type="text" class="cmd-input" id="cmd-input" placeholder="Chercher une page, commande..." autocomplete="off">
<div class="cmd-results" id="cmd-results"></div>
</div>
<div class="cmd-overlay" id="cmd-overlay" style="display:none"></div>
<div class="layout">
<button class="sidebar-toggle" onclick="document.querySelector('.sidebar').classList.toggle('open')" aria-label="Menu">
<span></span><span></span><span></span>
</button>
<aside class="sidebar">
<div class="sidebar-header">
<a href="/" class="logo">>_ talas<span class="logo-dot">.</span>wiki</a>
</div>
<div class="sidebar-search">
<div class="search-wrapper">
<input type="text" id="search-input" placeholder="rechercher..." class="search-input" autocomplete="off" value="{{template "searchQuery" .}}">
<div id="search-suggestions" class="search-suggestions"></div>
</div>
</div>
<nav class="sidebar-nav">
{{range .Domains}}
<a href="/wiki/{{encodeURL .FullDir}}" class="nav-domain" style="border-left-color:{{.Color}}">{{.Number}} {{.Name}}</a>
{{end}}
<div class="nav-separator"></div>
<a href="/graph" class="nav-link">graph</a>
<a href="/dashboard" class="nav-link">dashboard</a>
<a href="/tags" class="nav-link">tags</a>
<a href="/timeline" class="nav-link">timeline</a>
<a href="/domaindeps" class="nav-link">dependencies</a>
<a href="/reviews" class="nav-link">reviews</a>
<a href="/activity" class="nav-link">activite</a>
{{if not .ReadOnly}}
<a href="/new" class="nav-link nav-new">+ nouveau</a>
{{end}}
</nav>
</aside>
<main class="main">
{{template "content" .}}
</main>
</div>
<div class="shortcuts-overlay" id="shortcuts-help">
<h4>Raccourcis</h4>
<div class="shortcut-row"><span>Rechercher</span><span class="shortcut-key">/</span></div>
<div class="shortcut-row"><span>Editer</span><span class="shortcut-key">e</span></div>
<div class="shortcut-row"><span>Graph</span><span class="shortcut-key">g</span></div>
<div class="shortcut-row"><span>Dashboard</span><span class="shortcut-key">d</span></div>
<div class="shortcut-row"><span>Nouveau</span><span class="shortcut-key">n</span></div>
<div class="shortcut-row"><span>Aide</span><span class="shortcut-key">?</span></div>
<div class="shortcut-row"><span>Fermer</span><span class="shortcut-key">Esc</span></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script>
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
mermaid.initialize({
theme: 'base',
themeVariables: {
primaryColor: isDark ? '#161618' : '#EAE6DF',
primaryTextColor: isDark ? '#E8E3DB' : '#1A1A1E',
lineColor: isDark ? '#0098B5' : '#006B7F',
secondaryColor: isDark ? '#3A352D' : '#D1CFC9',
tertiaryColor: isDark ? '#0D0D0F' : '#F2EDE6'
}
});
</script>
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/contrib/auto-render.min.js"></script>
<script>document.addEventListener('DOMContentLoaded',function(){renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}]})});</script>
<script>
// Live search suggestions
(function(){
var input = document.getElementById('search-input');
var box = document.getElementById('search-suggestions');
var timer = null;
if(!input || !box) return;
input.addEventListener('input', function(){
clearTimeout(timer);
var q = this.value.trim();
if(q.length < 2){ box.innerHTML=''; box.style.display='none'; return; }
timer = setTimeout(function(){
fetch('/api/suggest?q='+encodeURIComponent(q))
.then(function(r){return r.json()})
.then(function(items){
if(!items.length){ box.innerHTML=''; box.style.display='none'; return; }
box.innerHTML = items.map(function(item){
return '<a class="suggestion" href="/wiki/'+encodeURIComponent(item.path).replace(/%2F/g,'/')+'"><span class="sug-title">'+item.title+'</span><span class="sug-domain">'+item.domain+'</span></a>';
}).join('');
box.style.display='block';
});
}, 150);
});
input.addEventListener('keydown', function(e){
if(e.key==='Enter'){
e.preventDefault();
var first = box.querySelector('.suggestion');
if(first && box.style.display==='block'){ window.location = first.href; }
else { window.location = '/search?q='+encodeURIComponent(this.value); }
}
if(e.key==='Escape'){ box.innerHTML=''; box.style.display='none'; }
});
document.addEventListener('click', function(e){ if(!e.target.closest('.search-wrapper')){ box.innerHTML=''; box.style.display='none'; }});
})();
// Scroll progress bar
window.addEventListener('scroll', function(){
var h = document.documentElement.scrollHeight - window.innerHeight;
var pct = h > 0 ? (window.scrollY / h) * 100 : 0;
document.getElementById('scroll-progress').style.width = pct + '%';
});
// Command palette (Ctrl+K / Cmd+K)
var cmdPalette = document.getElementById('cmd-palette');
var cmdOverlay = document.getElementById('cmd-overlay');
var cmdInput = document.getElementById('cmd-input');
var cmdResults = document.getElementById('cmd-results');
var cmdTimer = null;
function openCmdPalette() {
cmdPalette.style.display = 'block';
cmdOverlay.style.display = 'block';
cmdInput.value = '';
cmdResults.innerHTML = '';
cmdInput.focus();
}
function closeCmdPalette() {
cmdPalette.style.display = 'none';
cmdOverlay.style.display = 'none';
}
cmdOverlay.addEventListener('click', closeCmdPalette);
cmdInput.addEventListener('input', function() {
clearTimeout(cmdTimer);
var q = this.value.trim();
if (q.length < 1) { cmdResults.innerHTML = ''; return; }
// Commands
var cmds = [
{title: 'Nouvelle page', action: '/new', match: 'new nouveau creer'},
{title: 'Graph', action: '/graph', match: 'graph graphe'},
{title: 'Dashboard', action: '/dashboard', match: 'dashboard tableau'},
{title: 'Timeline', action: '/timeline', match: 'timeline temps'},
{title: 'Tags', action: '/tags', match: 'tags'},
{title: 'Activite', action: '/activity', match: 'activite recent'},
{title: 'Export', action: '/export', match: 'export telecharger'},
];
var ql = q.toLowerCase();
var cmdMatches = cmds.filter(function(c) { return c.match.indexOf(ql) >= 0 || c.title.toLowerCase().indexOf(ql) >= 0; });
cmdTimer = setTimeout(function() {
fetch('/api/suggest?q=' + encodeURIComponent(q))
.then(function(r) { return r.json(); })
.then(function(pages) {
var html = '';
cmdMatches.forEach(function(c) {
html += '<a class="cmd-result" href="' + c.action + '"><span class="cmd-result-title">' + c.title + '</span><span class="cmd-result-type">commande</span></a>';
});
pages.forEach(function(p) {
html += '<a class="cmd-result" href="/wiki/' + encodeURIComponent(p.path).replace(/%2F/g,'/') + '"><span class="cmd-result-title">' + p.title + '</span><span class="cmd-result-type">' + p.domain + '</span></a>';
});
cmdResults.innerHTML = html || '<div class="cmd-empty">Aucun resultat</div>';
});
}, 100);
});
cmdInput.addEventListener('keydown', function(e) {
if (e.key === 'Escape') { closeCmdPalette(); }
if (e.key === 'Enter') {
var first = cmdResults.querySelector('.cmd-result');
if (first) { window.location = first.href; }
}
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault();
var items = cmdResults.querySelectorAll('.cmd-result');
var active = cmdResults.querySelector('.cmd-result.active');
var idx = -1;
items.forEach(function(el, i) { if (el === active) idx = i; });
if (active) active.classList.remove('active');
if (e.key === 'ArrowDown') idx = Math.min(idx + 1, items.length - 1);
else idx = Math.max(idx - 1, 0);
if (items[idx]) items[idx].classList.add('active');
}
});
// Global keyboard shortcuts
document.addEventListener('keydown', function(e){
// Cmd+K or Ctrl+K opens command palette anywhere
if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); openCmdPalette(); return; }
if(e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA'||e.target.isContentEditable) return;
var help = document.getElementById('shortcuts-help');
if(e.key==='/'){e.preventDefault();openCmdPalette();return;}
if(e.key==='e'){var p=document.body.dataset.pagePath;if(p)window.location='/edit/'+p;return;}
if(e.key==='g'){window.location='/graph';return;}
if(e.key==='d'){window.location='/dashboard';return;}
if(e.key==='n'){window.location='/new';return;}
if(e.key==='?'){help.classList.toggle('visible');return;}
if(e.key==='Escape'){
closeCmdPalette();
help.classList.remove('visible');
document.querySelector('.sidebar').classList.remove('open');
var box=document.getElementById('search-suggestions');if(box){box.innerHTML='';box.style.display='none';}
}
});
// Content enhancements (code copy, table sort, anchor copy, lightbox)
document.addEventListener('DOMContentLoaded', function() {
// Code block copy buttons
document.querySelectorAll('pre code').forEach(function(block) {
var btn = document.createElement('button');
btn.className = 'code-copy-btn';
btn.textContent = 'copier';
btn.addEventListener('click', function() {
navigator.clipboard.writeText(block.textContent).then(function() {
btn.textContent = 'copie!';
setTimeout(function() { btn.textContent = 'copier'; }, 1500);
});
});
block.parentElement.style.position = 'relative';
block.parentElement.appendChild(btn);
});
// Heading anchor copy
document.querySelectorAll('.page-content h1[id], .page-content h2[id], .page-content h3[id]').forEach(function(h) {
h.style.cursor = 'pointer';
h.title = 'Copier le lien';
h.addEventListener('click', function() {
var url = window.location.origin + window.location.pathname + '#' + h.id;
navigator.clipboard.writeText(url);
h.style.color = 'var(--cyan)';
setTimeout(function() { h.style.color = ''; }, 1000);
});
});
// Sortable tables
document.querySelectorAll('.page-content table').forEach(function(table) {
var headers = table.querySelectorAll('th');
headers.forEach(function(th, colIdx) {
th.style.cursor = 'pointer';
th.title = 'Cliquer pour trier';
var asc = true;
th.addEventListener('click', function() {
var tbody = table.querySelector('tbody') || table;
var rows = Array.from(tbody.querySelectorAll('tr')).filter(function(r) { return r.querySelector('td'); });
rows.sort(function(a, b) {
var aText = (a.cells[colIdx] || {}).textContent || '';
var bText = (b.cells[colIdx] || {}).textContent || '';
return asc ? aText.localeCompare(bText, 'fr') : bText.localeCompare(aText, 'fr');
});
rows.forEach(function(r) { tbody.appendChild(r); });
asc = !asc;
headers.forEach(function(h) { h.classList.remove('sorted-asc', 'sorted-desc'); });
th.classList.add(asc ? 'sorted-desc' : 'sorted-asc');
});
});
});
// Image lightbox
document.querySelectorAll('.page-content img').forEach(function(img) {
img.style.cursor = 'zoom-in';
img.addEventListener('click', function() {
var overlay = document.createElement('div');
overlay.className = 'lightbox-overlay';
var clone = img.cloneNode();
clone.className = 'lightbox-img';
overlay.appendChild(clone);
overlay.addEventListener('click', function() { overlay.remove(); });
document.body.appendChild(overlay);
});
});
// TOC active section highlighting
var tocLinks = document.querySelectorAll('.toc a');
if (tocLinks.length > 0) {
var headingEls = [];
tocLinks.forEach(function(link) {
var id = link.getAttribute('href').substring(1);
var el = document.getElementById(id);
if (el) headingEls.push({el: el, link: link});
});
window.addEventListener('scroll', function() {
var scrollPos = window.scrollY + 100;
var active = null;
headingEls.forEach(function(item) {
if (item.el.offsetTop <= scrollPos) active = item;
});
tocLinks.forEach(function(l) { l.classList.remove('toc-active'); });
if (active) active.link.classList.add('toc-active');
});
}
});
</script>
{{template "scripts" .}}
</body>
</html>
{{end}}
{{define "title"}}Talas Wiki{{end}}
{{define "searchQuery"}}{{end}}
{{define "pagePath"}}{{end}}
{{define "scripts"}}{{end}}