Initial commit - workspace setup
- AGENTS.md, SOUL.md, USER.md, IDENTITY.md - ANAF monitor (declarații fiscale) - Kanban board + Notes UI - Email tools - Memory system
This commit is contained in:
772
kanban/notes.html
Normal file
772
kanban/notes.html
Normal file
@@ -0,0 +1,772 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ro">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Echo · Notes</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
|
||||
<script src="swipe-nav.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<style>
|
||||
.main {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: var(--space-5);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-6);
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
/* Date sections (accordion) */
|
||||
.date-section {
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.date-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
[data-theme="light"] .date-header {
|
||||
border-color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.date-header:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
/* Section colors */
|
||||
[data-section="today"] .date-header {
|
||||
background: linear-gradient(135deg, rgba(59, 130, 246, 0.25), rgba(37, 99, 235, 0.15));
|
||||
border-left: 3px solid #3b82f6;
|
||||
}
|
||||
|
||||
[data-section="yesterday"] .date-header {
|
||||
background: linear-gradient(135deg, rgba(139, 92, 246, 0.25), rgba(124, 58, 237, 0.15));
|
||||
border-left: 3px solid #8b5cf6;
|
||||
}
|
||||
|
||||
[data-section="thisWeek"] .date-header {
|
||||
background: linear-gradient(135deg, rgba(20, 184, 166, 0.25), rgba(13, 148, 136, 0.15));
|
||||
border-left: 3px solid #14b8a6;
|
||||
}
|
||||
|
||||
[data-section="older"] .date-header {
|
||||
background: linear-gradient(135deg, rgba(249, 115, 22, 0.25), rgba(234, 88, 12, 0.15));
|
||||
border-left: 3px solid #f97316;
|
||||
}
|
||||
|
||||
.date-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.date-header-left svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: var(--text-muted);
|
||||
transition: transform var(--transition-fast);
|
||||
}
|
||||
|
||||
.date-section.collapsed .date-header-left svg {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.date-label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.date-sublabel {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-muted);
|
||||
margin-left: var(--space-2);
|
||||
}
|
||||
|
||||
.date-section.collapsed .date-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.date-content {
|
||||
padding: var(--space-4) 0;
|
||||
}
|
||||
|
||||
/* Notes grid inside sections */
|
||||
.notes-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.note-card {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-4);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-base);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
[data-theme="light"] .note-card {
|
||||
border-color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.note-card:hover {
|
||||
border-color: var(--accent);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.note-title {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.note-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
/* Empty section */
|
||||
.empty-section {
|
||||
padding: var(--space-4);
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
/* Note viewer overlay */
|
||||
.note-viewer {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
z-index: 200;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.note-viewer.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.note-viewer-content {
|
||||
max-width: 800px;
|
||||
margin: var(--space-5) auto;
|
||||
background: var(--bg-base);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
min-height: calc(100vh - var(--space-10));
|
||||
}
|
||||
|
||||
.note-viewer-header {
|
||||
padding: var(--space-4) var(--space-5);
|
||||
border-bottom: 1px solid var(--border);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: var(--bg-base);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.note-viewer-header h2 {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.note-viewer-body {
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
/* Markdown */
|
||||
.markdown-body {
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
font-size: 1.8rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-4);
|
||||
padding-bottom: var(--space-3);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.markdown-body h2 {
|
||||
font-size: 1.3rem;
|
||||
color: var(--accent);
|
||||
margin-top: var(--space-6);
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.markdown-body h3 {
|
||||
font-size: 1.1rem;
|
||||
color: var(--text-primary);
|
||||
margin-top: var(--space-5);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.markdown-body p { margin-bottom: var(--space-4); }
|
||||
|
||||
.markdown-body ul, .markdown-body ol {
|
||||
margin-bottom: var(--space-4);
|
||||
padding-left: var(--space-6);
|
||||
}
|
||||
|
||||
.markdown-body li { margin-bottom: var(--space-2); }
|
||||
|
||||
.markdown-body a {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body a:hover { text-decoration: underline; }
|
||||
|
||||
.markdown-body code {
|
||||
background: var(--bg-surface);
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
background: var(--bg-surface);
|
||||
padding: var(--space-4);
|
||||
border-radius: var(--radius-md);
|
||||
overflow-x: auto;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.markdown-body pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body blockquote {
|
||||
border-left: 3px solid var(--accent);
|
||||
padding-left: var(--space-4);
|
||||
color: var(--text-muted);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.markdown-body strong { color: var(--text-primary); }
|
||||
|
||||
/* Tag filter pills */
|
||||
.tag-filter {
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
|
||||
.tag-filter-label {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-muted);
|
||||
margin-bottom: var(--space-2);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tag-pills {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.tag-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: var(--radius-full);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
[data-theme="light"] .tag-pill {
|
||||
border-color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.tag-pill:hover {
|
||||
background: var(--bg-surface-hover);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.tag-pill.active {
|
||||
background: var(--accent);
|
||||
border-color: var(--accent);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tag-pill-count {
|
||||
font-size: var(--text-xs);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.clear-filters {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-muted);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: var(--space-2);
|
||||
margin-left: var(--space-2);
|
||||
}
|
||||
|
||||
.clear-filters:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* No results */
|
||||
.no-results {
|
||||
text-align: center;
|
||||
padding: var(--space-10);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.no-results svg {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-bottom: var(--space-4);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.search-bar { width: 100%; }
|
||||
|
||||
.notes-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.note-viewer-content {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
<a href="index.html" class="logo">
|
||||
<i data-lucide="circle-dot"></i>
|
||||
Echo
|
||||
</a>
|
||||
<nav class="nav">
|
||||
<a href="index.html" class="nav-item">
|
||||
<i data-lucide="layout-list"></i>
|
||||
<span>Tasks</span>
|
||||
</a>
|
||||
<a href="notes.html" class="nav-item active">
|
||||
<i data-lucide="file-text"></i>
|
||||
<span>Notes</span>
|
||||
</a>
|
||||
<a href="files.html" class="nav-item">
|
||||
<i data-lucide="folder"></i>
|
||||
<span>Files</span>
|
||||
</a>
|
||||
<button class="theme-toggle" onclick="toggleTheme()" title="Schimbă tema">
|
||||
<i data-lucide="sun" id="themeIcon"></i>
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="main">
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Notes</h1>
|
||||
<div class="search-bar">
|
||||
<input type="text" class="input" id="searchInput" placeholder="Caută în notițe..." oninput="filterNotes()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tag-filter">
|
||||
<span class="tag-filter-label">Filtrează după tags:</span>
|
||||
<div class="tag-pills" id="tagPills"></div>
|
||||
</div>
|
||||
|
||||
<div id="notesContainer">
|
||||
<div class="no-results">
|
||||
<i data-lucide="loader"></i>
|
||||
<p>Se încarcă...</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Note viewer overlay -->
|
||||
<div class="note-viewer" id="noteViewer" onclick="if(event.target === this) closeNote()">
|
||||
<div class="note-viewer-content">
|
||||
<div class="note-viewer-header">
|
||||
<h2 id="viewerTitle">Titlu</h2>
|
||||
<button class="btn btn-ghost" onclick="closeNote()">
|
||||
<i data-lucide="x"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="note-viewer-body">
|
||||
<div id="viewerContent" class="markdown-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Theme
|
||||
function initTheme() {
|
||||
const saved = localStorage.getItem('theme') || 'dark';
|
||||
document.documentElement.setAttribute('data-theme', saved);
|
||||
updateThemeIcon(saved);
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
const current = document.documentElement.getAttribute('data-theme') || 'dark';
|
||||
const next = current === 'dark' ? 'light' : 'dark';
|
||||
document.documentElement.setAttribute('data-theme', next);
|
||||
localStorage.setItem('theme', next);
|
||||
updateThemeIcon(next);
|
||||
}
|
||||
|
||||
function updateThemeIcon(theme) {
|
||||
const icon = document.getElementById('themeIcon');
|
||||
if (icon) {
|
||||
icon.setAttribute('data-lucide', theme === 'dark' ? 'sun' : 'moon');
|
||||
lucide.createIcons();
|
||||
}
|
||||
}
|
||||
|
||||
initTheme();
|
||||
lucide.createIcons();
|
||||
|
||||
const notesCache = {};
|
||||
|
||||
const notesIndex = [
|
||||
{
|
||||
"file": "2026-01-29_remotion-skill-claude-code.md",
|
||||
"title": "How people are generating videos with Claude Code",
|
||||
"date": "2026-01-29",
|
||||
"tags": ["claude", "remotion", "video", "automation"]
|
||||
},
|
||||
{
|
||||
"file": "2026-01-29_gsd-framework-claude-code.md",
|
||||
"title": "Forget Ralph Loops: The New GSD Framework for Claude",
|
||||
"date": "2026-01-29",
|
||||
"tags": ["claude-code", "gsd", "framework", "sub-agents"]
|
||||
},
|
||||
{
|
||||
"file": "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"]
|
||||
},
|
||||
{
|
||||
"file": "2026-01-29_clawdbot-security-vulnerabilities.md",
|
||||
"title": "It Got Worse (Clawdbot) - Security Vulnerabilities",
|
||||
"date": "2026-01-29",
|
||||
"tags": ["clawdbot", "security", "vulnerabilities"]
|
||||
},
|
||||
{
|
||||
"file": "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"]
|
||||
},
|
||||
{
|
||||
"file": "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"]
|
||||
}
|
||||
];
|
||||
|
||||
const notesBasePath = "youtube-notes/";
|
||||
let selectedTags = new Set();
|
||||
|
||||
// Extract all tags with counts
|
||||
function getAllTags() {
|
||||
const tagCounts = {};
|
||||
notesIndex.forEach(note => {
|
||||
note.tags.forEach(tag => {
|
||||
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
|
||||
});
|
||||
});
|
||||
// Sort by count descending
|
||||
return Object.entries(tagCounts)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map(([tag, count]) => ({ tag, count }));
|
||||
}
|
||||
|
||||
// Render tag pills
|
||||
function renderTagPills() {
|
||||
const container = document.getElementById('tagPills');
|
||||
const tags = getAllTags();
|
||||
|
||||
let html = tags.map(({ tag, count }) => `
|
||||
<span class="tag-pill ${selectedTags.has(tag) ? 'active' : ''}"
|
||||
onclick="toggleTag('${tag}')">
|
||||
${tag} <span class="tag-pill-count">(${count})</span>
|
||||
</span>
|
||||
`).join('');
|
||||
|
||||
if (selectedTags.size > 0) {
|
||||
html += `<button class="clear-filters" onclick="clearTagFilters()">✕ Clear</button>`;
|
||||
}
|
||||
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
// Toggle tag selection
|
||||
function toggleTag(tag) {
|
||||
if (selectedTags.has(tag)) {
|
||||
selectedTags.delete(tag);
|
||||
} else {
|
||||
selectedTags.add(tag);
|
||||
}
|
||||
renderTagPills();
|
||||
filterNotes();
|
||||
}
|
||||
|
||||
// Clear all tag filters
|
||||
function clearTagFilters() {
|
||||
selectedTags.clear();
|
||||
renderTagPills();
|
||||
filterNotes();
|
||||
}
|
||||
|
||||
// Filter notes by search and tags
|
||||
function filterNotes() {
|
||||
const query = document.getElementById('searchInput').value.toLowerCase().trim();
|
||||
|
||||
let filtered = notesIndex;
|
||||
|
||||
// Filter by selected tags (AND logic)
|
||||
if (selectedTags.size > 0) {
|
||||
filtered = filtered.filter(note =>
|
||||
[...selectedTags].every(tag => note.tags.includes(tag))
|
||||
);
|
||||
}
|
||||
|
||||
// Filter by search query
|
||||
if (query) {
|
||||
filtered = filtered.filter(note => {
|
||||
const titleMatch = note.title.toLowerCase().includes(query);
|
||||
const tagsMatch = note.tags.some(t => t.toLowerCase().includes(query));
|
||||
const contentMatch = (notesCache[note.file] || '').toLowerCase().includes(query);
|
||||
return titleMatch || tagsMatch || contentMatch;
|
||||
});
|
||||
}
|
||||
|
||||
renderNotesAccordion(filtered);
|
||||
}
|
||||
|
||||
// Group notes by date category
|
||||
function groupNotesByDate(notes) {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
const weekAgo = new Date(today);
|
||||
weekAgo.setDate(weekAgo.getDate() - 7);
|
||||
|
||||
const groups = {
|
||||
today: { label: 'Azi', sublabel: formatDate(today), notes: [], expanded: true },
|
||||
yesterday: { label: 'Ieri', sublabel: formatDate(yesterday), notes: [], expanded: false },
|
||||
thisWeek: { label: 'Săptămâna aceasta', sublabel: '', notes: [], expanded: false },
|
||||
older: { label: 'Mai vechi', sublabel: '', notes: [], expanded: false }
|
||||
};
|
||||
|
||||
notes.forEach(note => {
|
||||
const noteDate = new Date(note.date);
|
||||
noteDate.setHours(0, 0, 0, 0);
|
||||
|
||||
if (noteDate.getTime() === today.getTime()) {
|
||||
groups.today.notes.push(note);
|
||||
} else if (noteDate.getTime() === yesterday.getTime()) {
|
||||
groups.yesterday.notes.push(note);
|
||||
} else if (noteDate >= weekAgo) {
|
||||
groups.thisWeek.notes.push(note);
|
||||
} else {
|
||||
groups.older.notes.push(note);
|
||||
}
|
||||
});
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
function formatDate(date) {
|
||||
return date.toLocaleDateString('ro-RO', { day: 'numeric', month: 'short', year: 'numeric' });
|
||||
}
|
||||
|
||||
function renderNotesAccordion(notes = notesIndex) {
|
||||
const container = document.getElementById('notesContainer');
|
||||
|
||||
if (notes.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="no-results">
|
||||
<i data-lucide="search-x"></i>
|
||||
<p>Nicio notiță găsită</p>
|
||||
</div>
|
||||
`;
|
||||
lucide.createIcons();
|
||||
return;
|
||||
}
|
||||
|
||||
const groups = groupNotesByDate(notes);
|
||||
let html = '';
|
||||
|
||||
Object.entries(groups).forEach(([key, group]) => {
|
||||
if (group.notes.length === 0) return;
|
||||
|
||||
const collapsed = group.expanded ? '' : 'collapsed';
|
||||
|
||||
html += `
|
||||
<div class="date-section ${collapsed}" data-section="${key}">
|
||||
<div class="date-header" onclick="toggleSection('${key}')">
|
||||
<div class="date-header-left">
|
||||
<i data-lucide="chevron-down"></i>
|
||||
<span class="date-label">${group.label}</span>
|
||||
<span class="date-sublabel">${group.sublabel}</span>
|
||||
</div>
|
||||
<span class="badge">${group.notes.length}</span>
|
||||
</div>
|
||||
<div class="date-content">
|
||||
<div class="notes-grid">
|
||||
${group.notes.map(note => renderNoteCard(note)).join('')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
lucide.createIcons();
|
||||
}
|
||||
|
||||
function renderNoteCard(note) {
|
||||
return `
|
||||
<div class="note-card" onclick="openNote('${note.file}')">
|
||||
<div class="note-title">${note.title}</div>
|
||||
<div class="note-tags">
|
||||
${note.tags.map(t => `<span class="tag">${t}</span>`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function toggleSection(sectionKey) {
|
||||
const section = document.querySelector(`[data-section="${sectionKey}"]`);
|
||||
section.classList.toggle('collapsed');
|
||||
}
|
||||
|
||||
async function openNote(file) {
|
||||
const note = notesIndex.find(n => n.file === file);
|
||||
if (!note) return;
|
||||
|
||||
document.getElementById('viewerTitle').textContent = note.title;
|
||||
document.getElementById('viewerContent').innerHTML = '<p style="color: var(--text-muted)">Se încarcă...</p>';
|
||||
document.getElementById('noteViewer').classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
// Update URL
|
||||
const noteId = file.replace(/^\d{4}-\d{2}-\d{2}_/, '').replace(/\.md$/, '');
|
||||
history.replaceState(null, '', '#' + noteId);
|
||||
|
||||
try {
|
||||
let content = notesCache[file];
|
||||
if (!content) {
|
||||
const response = await fetch(notesBasePath + file);
|
||||
content = await response.text();
|
||||
notesCache[file] = content;
|
||||
}
|
||||
document.getElementById('viewerContent').innerHTML = marked.parse(content);
|
||||
} catch (error) {
|
||||
document.getElementById('viewerContent').innerHTML = `<p style="color: var(--error)">Eroare: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
function closeNote() {
|
||||
document.getElementById('noteViewer').classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
history.replaceState(null, '', window.location.pathname);
|
||||
}
|
||||
|
||||
async function preloadNotes() {
|
||||
for (const note of notesIndex) {
|
||||
try {
|
||||
const response = await fetch(notesBasePath + note.file);
|
||||
notesCache[note.file] = await response.text();
|
||||
} catch (e) {
|
||||
notesCache[note.file] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// searchNotes replaced by filterNotes above
|
||||
|
||||
// Handle hash for deep links
|
||||
function checkHash() {
|
||||
if (window.location.hash) {
|
||||
const id = window.location.hash.slice(1);
|
||||
const note = notesIndex.find(n => {
|
||||
const noteId = n.file.replace(/^\d{4}-\d{2}-\d{2}_/, '').replace(/\.md$/, '');
|
||||
return noteId === id;
|
||||
});
|
||||
if (note) {
|
||||
openNote(note.file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ESC to close
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.key === 'Escape') closeNote();
|
||||
});
|
||||
|
||||
// Init
|
||||
renderTagPills();
|
||||
renderNotesAccordion();
|
||||
preloadNotes();
|
||||
checkHash();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user