diff --git a/index.html b/index.html index bcd4d3d..93f4237 100644 --- a/index.html +++ b/index.html @@ -38,6 +38,10 @@ body { background:var(--bg); color:var(--text); font-family:-apple-system,BlinkM .nav-badge.blk { background:var(--red-soft); color:var(--red); } .s-reset { margin:6px 14px 0; padding:5px 10px; background:var(--surface3); border:1px solid var(--border); border-radius:5px; font-size:10px; color:var(--text-dim); cursor:pointer; text-align:center; } .s-reset:hover { color:var(--red); border-color:var(--red); } +.s-io { display:flex; gap:6px; margin:6px 14px 0; } +.s-io-btn { flex:1; text-align:center; padding:5px 0; background:var(--surface3); border:1px solid var(--border); border-radius:5px; font-size:10px; color:var(--text-dim); cursor:pointer; } +.s-io-btn:hover { color:var(--teal); border-color:var(--teal); } +.s-io-btn.import:hover { color:var(--amber); border-color:var(--amber); } .s-actions { display:flex; gap:6px; padding:10px 14px 0; } .s-add-btn { flex:1; text-align:center; padding:5px 0; background:var(--surface2); border:1px solid var(--border2); border-radius:5px; font-size:10.5px; color:var(--text-dim); cursor:pointer; } .s-add-btn:hover { color:var(--accent); border-color:var(--accent); } @@ -393,6 +397,11 @@ body { background:var(--bg); color:var(--text); font-family:-apple-system,BlinkM
+ Gruppe
↺ Reset
+
+
↓ Export
+
↑ Import
+
+
@@ -825,6 +834,42 @@ const DEFAULTS = { {id:'done', label:'Done', tasks:[{t:'Schema-Diff: source_type, author, year, isbn',note:'Frontmatter-Schema + Template dokumentiert'}]}, ] }, + tiefgang: { + name:'Tiefgang', goal:'', + wipLimit:3, throughput:2, sle:{days:14,p:85}, + cols:[ + {id:'ready', label:'Ready', tasks:[]}, + {id:'wip', label:'In Progress', tasks:[]}, + {id:'done', label:'Done', tasks:[]}, + ] + }, + mdimmusic: { + name:'MDIM', goal:'mydrugismusic — Label & Artist-Kollektiv.', + wipLimit:3, throughput:2, sle:{days:14,p:85}, + cols:[ + {id:'ready', label:'Ready', tasks:[]}, + {id:'wip', label:'In Progress', tasks:[]}, + {id:'done', label:'Done', tasks:[]}, + ] + }, + droii: { + name:'DROII', goal:'', + wipLimit:3, throughput:2, sle:{days:14,p:85}, + cols:[ + {id:'ready', label:'Ready', tasks:[]}, + {id:'wip', label:'In Progress', tasks:[]}, + {id:'done', label:'Done', tasks:[]}, + ] + }, + soloprojekt: { + name:'Soloprojekt', goal:'', + wipLimit:3, throughput:2, sle:{days:14,p:85}, + cols:[ + {id:'ready', label:'Ready', tasks:[]}, + {id:'wip', label:'In Progress', tasks:[]}, + {id:'done', label:'Done', tasks:[]}, + ] + }, }; // ── BOARD META (group + color + ring for defaults) ──────────────────────── @@ -845,16 +890,21 @@ const BOARD_META = { degoogle: {group:'Privat', color:'#60a5fa', ring:'1p'}, bibliothek:{group:'Privat', color:'#7c6af7', ring:'1p'}, aikb: {group:'Privat', color:'#4ade80', ring:'1w'}, + tiefgang: {group:'Musik', color:'#2dd4bf', ring:'1p'}, + mdimmusic: {group:'Musik', color:'#c084fc', ring:'1p'}, + droii: {group:'Musik', color:'#f87171', ring:'1p'}, + soloprojekt:{group:'Musik', color:'#fbbf24', ring:'1p'}, }; const RINGS = ['0','1p','1w','2','3','?']; const RING_LABELS = {'0':'R0','1p':'R1p','1w':'R1w','2':'R2','3':'R3','?':'?'}; const PICK_COLORS = ['#f87171','#fb923c','#fbbf24','#4ade80','#2dd4bf','#60a5fa','#7c6af7','#c084fc']; -let GROUPS = ['Meta','Code','Beruflich','Web','Privat']; +let GROUPS = ['Meta','Code','Beruflich','Web','Privat','Musik']; function loadGroups() { try { const g = JSON.parse(localStorage.getItem('kanban_groups')); if (Array.isArray(g)) GROUPS = g; } catch {} - if (!GROUPS.includes('Meta')) { GROUPS.unshift('Meta'); saveGroups(); } + if (!GROUPS.includes('Meta')) { GROUPS.unshift('Meta'); saveGroups(); } + if (!GROUPS.includes('Musik')) { GROUPS.push('Musik'); saveGroups(); } } function saveGroups() { localStorage.setItem('kanban_groups', JSON.stringify(GROUPS)); } @@ -2326,6 +2376,33 @@ loadIdeas(); renderIdeas(); show('doener'); setView('overview'); + +// ── EXPORT / IMPORT ────────────────────────────────────────────────────────── +function exportState() { + const keys = ['kanban_v2','kanban_groups','kanban_board_order','kanban_ideas','kanban_ideas_seeded']; + const snap = {}; + keys.forEach(k => { const v = localStorage.getItem(k); if (v !== null) snap[k] = v; }); + const blob = new Blob([JSON.stringify(snap, null, 2)], {type:'application/json'}); + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.download = `kanban-backup-${new Date().toISOString().slice(0,10)}.json`; + a.click(); +} + +function importState(input) { + const file = input.files[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = e => { + try { + const snap = JSON.parse(e.target.result); + Object.entries(snap).forEach(([k, v]) => localStorage.setItem(k, v)); + input.value = ''; + location.reload(); + } catch { alert('Ungültige Backup-Datei.'); } + }; + reader.readAsText(file); +}