diff --git a/TOOLS.md b/TOOLS.md index 1876708..aefd564 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -31,11 +31,17 @@ python3 tools/email_send.py "dest@email.com" "Subiect" "Corp mesaj" - **API:** `kanban/api.py` - **Update task:** `python3 kanban/update_task.py` -### YouTube Notes -- **Folder:** `notes/youtube/` +### Notes (toate tipurile) +- **Folder:** `notes/` (subdirectoare: `youtube/`, `retete/`, etc.) - **Update index:** `python3 tools/update_notes_index.py` +- **Pagina web:** https://moltbot.tailf7372d.ts.net/echo/notes.html - **Tags domeniu:** `@work`, `@health`, `@growth`, `@sprijin`, `@scout` +**IMPORTANT:** Când salvez orice notă (rețete, youtube, etc.), trebuie să: +1. Salvez în subdirectorul potrivit din `notes/` +2. Rulez `python3 tools/update_notes_index.py` pentru a actualiza indexul +3. Dau link-ul către pagina notes.html + ### Git - **Repo:** ~/clawd → gitea.romfast.ro/romfast/clawd - **Commit script:** `python3 tools/git_commit.py --push` diff --git a/kanban/index.html b/kanban/index.html index fd99942..da5d965 100644 --- a/kanban/index.html +++ b/kanban/index.html @@ -15,7 +15,7 @@ } .page-header { - margin-bottom: var(--space-5); + margin-bottom: var(--space-4); } .page-title { @@ -30,11 +30,131 @@ color: var(--text-muted); } + /* Status bar */ + .status-bar { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + margin-bottom: var(--space-4); + overflow: hidden; + } + + .status-header { + display: flex; + align-items: center; + gap: var(--space-3); + padding: var(--space-3) var(--space-4); + background: linear-gradient(135deg, rgba(34, 197, 94, 0.15), rgba(22, 163, 74, 0.1)); + border-bottom: 1px solid var(--border); + cursor: pointer; + user-select: none; + } + + .status-header:hover { + filter: brightness(1.05); + } + + .status-title { + display: flex; + align-items: center; + gap: var(--space-2); + font-weight: 600; + font-size: var(--text-sm); + color: var(--text-primary); + } + + .status-title svg { + width: 16px; + height: 16px; + color: #22c55e; + } + + .status-summary { + flex: 1; + font-size: var(--text-xs); + color: var(--text-muted); + text-align: right; + } + + .status-toggle { + width: 16px; + height: 16px; + color: var(--text-muted); + transition: transform var(--transition-fast); + } + + .status-bar.collapsed .status-toggle { + transform: rotate(-90deg); + } + + .status-bar.collapsed .status-content { + display: none; + } + + .status-content { + padding: var(--space-3) var(--space-4); + } + + .status-row { + display: flex; + flex-wrap: wrap; + gap: var(--space-4); + margin-bottom: var(--space-2); + } + + .status-item { + display: flex; + align-items: center; + gap: var(--space-1); + font-size: var(--text-sm); + } + + .status-label { + color: var(--text-muted); + } + + .status-value { + font-weight: 600; + color: var(--text-primary); + } + + .status-value.ok { color: #22c55e; } + .status-value.warning { color: #f59e0b; } + .status-value.error { color: #ef4444; } + + .status-time { + font-size: var(--text-xs); + color: var(--text-muted); + margin-left: var(--space-1); + } + + .cron-row { + display: flex; + align-items: center; + gap: var(--space-2); + font-size: var(--text-sm); + padding-top: var(--space-2); + border-top: 1px solid var(--border); + } + + .cron-label { + color: var(--text-muted); + } + + .cron-list { + color: var(--text-secondary); + } + + .cron-done { + color: var(--text-muted); + text-decoration: line-through; + } + /* Two-column dashboard */ .dashboard-grid { display: grid; grid-template-columns: 1fr 1fr; - gap: var(--space-5); + gap: var(--space-4); } @media (max-width: 900px) { @@ -57,6 +177,18 @@ justify-content: space-between; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border); + cursor: pointer; + user-select: none; + } + + .panel-header:hover { + filter: brightness(1.05); + } + + .panel-header-left { + display: flex; + align-items: center; + gap: var(--space-2); } .panel-title { @@ -73,14 +205,37 @@ height: 18px; } + .panel-toggle { + width: 16px; + height: 16px; + color: var(--text-muted); + transition: transform var(--transition-fast); + } + + .panel.collapsed .panel-toggle { + transform: rotate(-90deg); + } + + .panel.collapsed .panel-body { + display: none; + } + .panel-actions { display: flex; gap: var(--space-2); } + .panel-count { + font-size: var(--text-xs); + color: var(--text-muted); + background: var(--bg-elevated); + padding: 2px 8px; + border-radius: var(--radius-sm); + } + .panel-body { padding: var(--space-3); - max-height: 600px; + max-height: 500px; overflow-y: auto; } @@ -189,11 +344,11 @@ /* Issues panel */ .issues-panel .panel-header { - background: linear-gradient(135deg, rgba(34, 197, 94, 0.15), rgba(22, 163, 74, 0.1)); + background: linear-gradient(135deg, rgba(249, 115, 22, 0.15), rgba(234, 88, 12, 0.1)); } .issues-panel .panel-title svg { - color: #22c55e; + color: #f97316; } .issues-filters { @@ -222,7 +377,7 @@ } .priority-group { - margin-bottom: var(--space-4); + margin-bottom: var(--space-3); } .priority-header { @@ -234,6 +389,11 @@ color: var(--text-muted); margin-bottom: var(--space-2); cursor: pointer; + padding: var(--space-1) 0; + } + + .priority-header:hover { + color: var(--text-secondary); } .priority-header svg { @@ -491,25 +651,6 @@ margin-bottom: var(--space-3); opacity: 0.5; } - - /* Old kanban link */ - .legacy-link { - font-size: var(--text-xs); - color: var(--text-muted); - text-decoration: none; - display: flex; - align-items: center; - gap: var(--space-1); - } - - .legacy-link:hover { - color: var(--accent); - } - - .legacy-link svg { - width: 12px; - height: 12px; - } @@ -523,10 +664,6 @@ Dashboard - - - Kanban - Notes @@ -544,18 +681,55 @@
+ + +
+
+
+ + Status +
+
Se încarcă...
+ +
+
+
+
+ ANAF: + - +
+
+ Git: + - +
+
+ Raport: + - + +
+
+
+ Cron azi: + - +
+
-
-
-
- - Clawdbot Activity +
+
+
+ +
+ + Activity +
+ 0
-
+
@@ -570,13 +744,17 @@
-
-
-
- - Issues +
+
+
+ +
+ + Issues +
+ 0
-
+
- - - -
- -
-
-
- - Status -
-
Se încarcă...
- -
-
-
-
- ANAF: - OK -
-
- Git: - curat -
-
- Raport: - - - -
-
-
- Azi: - - -
-
-
- - - - - -
- -
-
- -
- - - - diff --git a/kanban/notes-data b/kanban/notes-data new file mode 120000 index 0000000..1a485a3 --- /dev/null +++ b/kanban/notes-data @@ -0,0 +1 @@ +../notes \ No newline at end of file diff --git a/kanban/notes.html b/kanban/notes.html index 92462e3..81e12c0 100644 --- a/kanban/notes.html +++ b/kanban/notes.html @@ -482,7 +482,7 @@ const notesCache = {}; let notesIndex = []; - const notesBasePath = "youtube-notes/"; + const notesBasePath = "notes-data/"; const indexPath = notesBasePath + "index.json"; // Load notes index from JSON diff --git a/notes/index.json b/notes/index.json new file mode 100644 index 0000000..b4e30ad --- /dev/null +++ b/notes/index.json @@ -0,0 +1,179 @@ +{ + "notes": [ + { + "file": "youtube/2026-01-30_clawdbot-personal-os-kitze.md", + "title": "How I Use Clawdbot to Run My Business and Life 24/7", + "date": "2026-01-30", + "tags": [ + "clawdbot", + "productivity", + "personas", + "automation" + ], + "domains": [ + "work", + "growth" + ], + "video": "https://youtu.be/YRhGtHfs1Lw", + "tldr": "Kitze folosește **UN SINGUR gateway Clawdbot** cu **MULTIPLE PERSONAS** pe Telegram/Discord. Fiecare personă are:\n- Personalitate diferită (avatar, stil de vorbit)\n- Skills diferite (acces la tool-uri...", + "category": "youtube" + }, + { + "file": "youtube/2026-01-29_remotion-skill-claude-code.md", + "title": "How people are generating videos with Claude Code (Remotion Skill)", + "date": "2026-01-29", + "tags": [ + "remotion", + "claude-code", + "video", + "automation" + ], + "domains": [ + "work" + ], + "video": "https://youtu.be/7OR-L0AySn8", + "tldr": "Remotion Skill permite generarea de videouri programatic cu Claude Code. Funcționează prin React components → video export. Demo live: Claude creează animații YouTube (like, subscribe, cursor) doar di...", + "category": "youtube" + }, + { + "file": "youtube/2026-01-29_gsd-framework-claude-code.md", + "title": "Forget Ralph Loops: The New GSD Framework for Claude Code", + "date": "2026-01-29", + "tags": [ + "claude-code", + "gsd", + "framework", + "sub-agents", + "automation" + ], + "domains": [ + "work" + ], + "video": "https://www.youtube.com/watch?v=l94A53kIUB0", + "tldr": "GSD (Get Shit Done) este un framework open-source pentru Claude Code care orchestrează sub-agenți pentru a completa proiecte urmând spec-driven development. Rezolvă problema \"context bloat\" prin rular...", + "category": "youtube" + }, + { + "file": "youtube/2026-01-29_greseli-post-apa.md", + "title": "Greșeli frecvente în timpul postului doar cu apă", + "date": "2026-01-29", + "tags": [ + "post", + "water-fasting", + "sănătate", + "detox" + ], + "domains": [ + "health" + ], + "video": "https://youtu.be/4QjkI0sf64M", + "tldr": "Greșelile frecvente pe care le fac oamenii când țin post terapeutic cu apă și cum să le eviți. Puncte cheie: pregătire corectă, curățarea colonului, calitatea apei, și importanța scopului spiritual.", + "category": "youtube" + }, + { + "file": "youtube/2026-01-29_cloudflare-tunnel-localhost-public.md", + "title": "Cloudflare Tunnel: Make Localhost Public Without Port Forwarding", + "date": "2026-01-29", + "tags": [ + "cloudflare", + "tunnel", + "localhost", + "networking", + "devops" + ], + "domains": [ + "work" + ], + "video": "https://youtu.be/etluT8UC-nw", + "tldr": "Cloudflare Tunnel permite expunerea unui server local (localhost) pe internet printr-un domeniu public, fără port forwarding, fără configurare router, fără expunerea IP-ului public. App-ul rămâne pe m...", + "category": "youtube" + }, + { + "file": "youtube/2026-01-29_clawdbot-security-vulnerabilities.md", + "title": "It Got Worse (Clawdbot) - Security Vulnerabilities", + "date": "2026-01-29", + "tags": [ + "clawdbot", + "security", + "vulnerabilities", + "hacking" + ], + "domains": [ + "work" + ], + "video": "https://youtu.be/rPAKq2oQVBs", + "tldr": "Video critic despre vulnerabilitățile de securitate ale Clawdbot - sute/mii de instanțe au fost compromise. Probleme principale: porturi default, parole lipsă, reverse proxy misconfigurat, skills mali...", + "category": "youtube" + }, + { + "file": "youtube/2025-01-30_clawdbot-5-use-cases.md", + "title": "5 Insane ClawdBot Use Cases You Need To Do Immediately", + "date": "2025-01-30", + "tags": [ + "clawdbot", + "automation", + "productivity", + "ai-assistant" + ], + "domains": [ + "work" + ], + "video": "https://www.youtube.com/watch?v=b-l9sGh1-UY", + "tldr": "5 use case-uri pentru ClawdBot care îl transformă dintr-un simplu chatbot într-un asistent proactiv care lucrează pentru tine chiar și când dormi.", + "category": "youtube" + }, + { + "file": "youtube/2025-01-30_claude-code-do-work-pattern.md", + "title": "The Most Powerful Claude Code Pattern I've Found", + "date": "2025-01-30", + "tags": [ + "claude-code", + "skills", + "workflow", + "automation", + "do-work" + ], + "domains": [ + "work" + ], + "video": "https://youtu.be/I9-tdhxiH7w", + "tldr": "Un pattern puternic pentru Claude Code: **Do Work** - o coadă de task-uri pe care Claude le procesează automat, unul câte unul, în sub-agenți cu context curat. Ideea cheie: **construiește tool-uri pen...", + "category": "youtube" + }, + { + "file": "retete/ciorba-burta-falsa-cu-pui.md", + "title": "Ciorbă de Burtă Falsă cu Pui și Ciuperci Pleurotus", + "date": "", + "tags": [], + "domains": [], + "video": "", + "tldr": "", + "category": "retete" + } + ], + "stats": { + "total": 9, + "by_domain": { + "work": 7, + "health": 1, + "growth": 1, + "sprijin": 0, + "scout": 0 + }, + "by_category": { + "youtube": 8, + "retete": 1 + } + }, + "domains": [ + "work", + "health", + "growth", + "sprijin", + "scout" + ], + "categories": [ + "youtube", + "retete" + ] +} \ No newline at end of file diff --git a/tools/update_notes_index.py b/tools/update_notes_index.py index 3070501..044e371 100644 --- a/tools/update_notes_index.py +++ b/tools/update_notes_index.py @@ -2,6 +2,7 @@ """ Generează index.json pentru notes din fișierele .md Extrage titlu, dată, tags, și domenii (@work, @health, etc.) +Scanează TOATE subdirectoarele din notes/ (youtube, retete, etc.) """ import os @@ -9,8 +10,11 @@ import re import json from pathlib import Path -NOTES_DIR = Path(__file__).parent.parent / "notes" / "youtube" -INDEX_FILE = NOTES_DIR / "index.json" +NOTES_ROOT = Path(__file__).parent.parent / "notes" +INDEX_FILE = NOTES_ROOT / "index.json" + +# Subdirectoare de scanat (adaugă altele aici) +SCAN_DIRS = ['youtube', 'retete'] # Domenii de agenți VALID_DOMAINS = ['work', 'health', 'growth', 'sprijin', 'scout'] @@ -66,27 +70,43 @@ def extract_metadata(filepath): } def generate_index(): - """Generează index.json din toate fișierele .md""" + """Generează index.json din toate fișierele .md din toate subdirectoarele""" notes = [] # Stats per domeniu domain_stats = {d: 0 for d in VALID_DOMAINS} + # Stats per categorie + category_stats = {} - for filepath in sorted(NOTES_DIR.glob("*.md"), reverse=True): - if filepath.name == 'index.json': + for subdir in SCAN_DIRS: + notes_dir = NOTES_ROOT / subdir + if not notes_dir.exists(): + print(f" (skipping {subdir}/ - not found)") continue - try: - metadata = extract_metadata(filepath) - notes.append(metadata) - # Update domain stats - for d in metadata['domains']: - domain_stats[d] += 1 - - domains_str = ' '.join([f'@{d}' for d in metadata['domains']]) if metadata['domains'] else '(no domain)' - print(f" + {metadata['title'][:40]}... {domains_str}") - except Exception as e: - print(f" ! Error processing {filepath.name}: {e}") + print(f"Scanning notes/{subdir}/...") + category_stats[subdir] = 0 + + for filepath in sorted(notes_dir.glob("*.md"), reverse=True): + if filepath.name == 'index.json': + continue + try: + metadata = extract_metadata(filepath) + # Adaugă categoria (subdirectorul) + metadata['category'] = subdir + # Modifică path-ul fișierului să includă subdirectorul + metadata['file'] = f"{subdir}/{filepath.name}" + notes.append(metadata) + + # Update stats + category_stats[subdir] += 1 + for d in metadata['domains']: + domain_stats[d] += 1 + + domains_str = ' '.join([f'@{d}' for d in metadata['domains']]) if metadata['domains'] else '' + print(f" + {metadata['title'][:40]}... {domains_str}") + except Exception as e: + print(f" ! Error processing {filepath.name}: {e}") # Sortează după dată descrescător notes.sort(key=lambda x: x['date'], reverse=True) @@ -96,9 +116,11 @@ def generate_index(): "notes": notes, "stats": { "total": len(notes), - "by_domain": domain_stats + "by_domain": domain_stats, + "by_category": category_stats }, - "domains": VALID_DOMAINS + "domains": VALID_DOMAINS, + "categories": SCAN_DIRS } with open(INDEX_FILE, 'w', encoding='utf-8') as f: @@ -106,8 +128,8 @@ def generate_index(): print(f"\n✅ Generated {INDEX_FILE} with {len(notes)} notes") print(f" Domains: {domain_stats}") + print(f" Categories: {category_stats}") return output if __name__ == "__main__": - print("Scanning notes/youtube/...") generate_index()