mozkovna - create project

This commit is contained in:
Lukáš Kaňka 2025-05-30 09:05:43 +02:00
parent 1e1969f6dd
commit 4ab0c8a043
2 changed files with 641 additions and 0 deletions

306
browserEdition/browser.html Normal file
View File

@ -0,0 +1,306 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mozkovna</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<script type="module">
// DOM Elements
const notesContainer = document.getElementById('notesContainer');
const newNoteInput = document.getElementById('newNoteInput');
const addNoteButton = document.getElementById('addNoteButton');
const loadingIndicator = document.getElementById('loadingIndicator');
const authStatus = document.getElementById('authStatus');
const userIdDisplay = document.getElementById('userIdDisplay');
const saveStatus = document.getElementById('saveStatus');
// --- Notes Logic ---
let localNotesCache = [];
function renderNotes(notes) {
notesContainer.innerHTML = ''; // Clear existing notes
const notesMap = new Map(notes.map(note => [note.createdAt, { ...note, children: [] }]));
const rootNotes = [];
notesMap.forEach(note => {
if (note.parentId && notesMap.has(note.parentId)) {
notesMap.get(note.parentId).children.push(note);
} else {
rootNotes.push(note);
}
});
notesMap.forEach(note => {
note.children.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
});
rootNotes.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
if (rootNotes.length === 0 && notes.length > 0 && !notes.some(n => !n.parentId)) {
notes.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt))
.forEach(note => notesContainer.appendChild(createNoteElement(note, 0, notesMap)));
} else if (rootNotes.length === 0) {
notesContainer.innerHTML = '<p class="text-gray-500 text-center py-4">Zatím žádné poznámky. Přidejte první!</p>';
} else {
rootNotes.forEach(note => notesContainer.appendChild(createNoteElement(note, 0, notesMap)));
}
}
function createNoteElement(note, level, notesMap) {
const li = document.createElement('li');
li.className = `mb-2 p-3 rounded-lg shadow bg-white group relative transition-all duration-150 ease-in-out hover:shadow-md`;
li.style.marginLeft = `${level * 20}px`;
li.dataset.id = note.createdAt;
const textSpan = document.createElement('span');
textSpan.textContent = note.text;
textSpan.className = 'flex-grow break-words cursor-text focus:outline-none focus:ring-2 focus:ring-blue-500 rounded px-1 py-0.5';
textSpan.contentEditable = true;
let saveTimeout;
textSpan.addEventListener('input', () => {
clearTimeout(saveTimeout);
showSaveStatus('Ukládám...');
saveTimeout = setTimeout(() => {
try {
const updatedNote = { ...note, text: textSpan.textContent };
localNotesCache = localNotesCache.map(n => n.createdAt === note.createdAt ? updatedNote : n);
localStorage.setItem('notes', JSON.stringify(localNotesCache));
showSaveStatus('Uloženo!', true);
} catch (error) {
console.error("Chyba při aktualizaci poznámky:", error);
showSaveStatus('Chyba ukládání', false, true);
}
}, 1000); // Debounce saving
});
textSpan.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
textSpan.blur(); // Save on Enter
}
});
const controlsDiv = document.createElement('div');
controlsDiv.className = 'flex items-center space-x-2 mt-2 opacity-0 group-hover:opacity-100 transition-opacity duration-150 ease-in-out';
const addChildButton = document.createElement('button');
addChildButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-green-600 hover:text-green-800">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
<span class="sr-only">Přidat podúkol</span>`;
addChildButton.title = "Přidat podúkol";
addChildButton.className = 'p-1 rounded hover:bg-green-100';
addChildButton.onclick = () => addNote(note.createdAt);
const deleteButton = document.createElement('button');
deleteButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-red-500 hover:text-red-700">
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
<line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
<span class="sr-only">Smazat</span>`;
deleteButton.title = "Smazat poznámku";
deleteButton.className = 'p-1 rounded hover:bg-red-100';
deleteButton.onclick = () => deleteNoteWithChildren(note.createdAt, notesMap);
const indentButton = document.createElement('button');
indentButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-blue-500 hover:text-blue-700">
<polyline points="15 18 21 12 15 6"></polyline><polyline points="3 18 9 12 3 6"></polyline>
</svg>
<span class="sr-only">Odsadit</span>`;
indentButton.title = "Odsadit (učinit podúkolem předchozího sourozence)";
indentButton.className = 'p-1 rounded hover:bg-blue-100';
indentButton.onclick = () => indentNote(note.createdAt, notesMap);
const outdentButton = document.createElement('button');
outdentButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-purple-500 hover:text-purple-700">
<polyline points="9 18 3 12 9 6"></polyline><polyline points="21 18 15 12 21 6"></polyline>
</svg>
<span class="sr-only">Předsadit</span>`;
outdentButton.title = "Předsadit (stát se sourozencem rodiče)";
outdentButton.className = 'p-1 rounded hover:bg-purple-100';
outdentButton.onclick = () => outdentNote(note.createdAt, notesMap);
if (!note.parentId) outdentButton.disabled = true; // Cannot outdent root notes
controlsDiv.appendChild(addChildButton);
controlsDiv.appendChild(indentButton);
controlsDiv.appendChild(outdentButton);
controlsDiv.appendChild(deleteButton);
li.appendChild(textSpan);
li.appendChild(controlsDiv);
if (note.children && note.children.length > 0) {
const childrenUl = document.createElement('ul');
childrenUl.className = 'mt-2';
note.children.forEach(childNote => childrenUl.appendChild(createNoteElement(childNote, level + 1, notesMap)));
li.appendChild(childrenUl);
}
return li;
}
function addNote(parentId = null) {
const text = newNoteInput.value.trim();
if (!text) {
alert("Text poznámky nemůže být prázdný.");
newNoteInput.focus();
return;
}
newNoteInput.value = ''; // Clear input
const note = {
text: text,
parentId: parentId,
createdAt: new Date().toISOString()
};
showSaveStatus('Přidávám...');
try {
localNotesCache.push(note);
localStorage.setItem('notes', JSON.stringify(localNotesCache));
showSaveStatus('Poznámka přidána!', true);
loadNotes();
} catch (error) {
console.error("Chyba při přidávání poznámky:", error);
showSaveStatus('Chyba přidávání', false, true);
alert("Nepodařilo se přidat poznámku: " + error.message);
}
}
function deleteNoteWithChildren(createdAt, notesMap) {
if (!confirm("Opravdu chcete smazat tuto poznámku a všechny její podpoznámky?")) return;
showSaveStatus('Mažu...');
try {
localNotesCache = localNotesCache.filter(note => note.createdAt !== createdAt);
localStorage.setItem('notes', JSON.stringify(localNotesCache));
showSaveStatus('Smazáno!', true);
loadNotes();
} catch (error) {
console.error("Chyba při mazání poznámky:", error);
showSaveStatus('Chyba mazání', false, true);
alert("Nepodařilo se smazat poznámku: " + error.message);
}
}
function loadNotes() {
try {
localNotesCache = JSON.parse(localStorage.getItem('notes') || '[]');
renderNotes(localNotesCache);
} catch (error) {
console.error("Chyba při načítání poznámek:", error);
notesContainer.innerHTML = `<p class="text-red-500">Chyba načítání poznámek: ${error.message}</p>`;
}
}
let statusTimeout;
function showSaveStatus(message, success = false, error = false) {
saveStatus.textContent = message;
saveStatus.classList.remove('hidden', 'text-green-600', 'text-red-600', 'text-gray-600');
if (success) {
saveStatus.classList.add('text-green-600');
} else if (error) {
saveStatus.classList.add('text-red-600');
} else {
saveStatus.classList.add('text-gray-600');
}
clearTimeout(statusTimeout);
statusTimeout = setTimeout(() => {
saveStatus.classList.add('hidden');
}, 3000);
}
// --- Event Listeners ---
addNoteButton.addEventListener('click', () => addNote()); // Add root note
newNoteInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addNote(); // Add root note
}
});
// Initialize
loadNotes();
</script>
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #f0f2f5; /* Světle šedé pozadí */
}
/* Custom scrollbar for notes container */
#notesContainer::-webkit-scrollbar {
width: 8px;
}
#notesContainer::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
#notesContainer::-webkit-scrollbar-thumb {
background: #cbd5e1; /* Tailwind gray-300 */
border-radius: 10px;
}
#notesContainer::-webkit-scrollbar-thumb:hover {
background: #94a3b8; /* Tailwind gray-400 */
}
.group:hover .opacity-0 { /* Show controls on hover */
opacity: 1;
}
/* Styling for contenteditable focus */
[contenteditable]:focus {
outline: 2px solid #3b82f6; /* blue-500 */
border-radius: 4px;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5);
}
</style>
</head>
<body class="bg-slate-100 min-h-screen flex flex-col items-center pt-8 px-4">
<div class="w-full max-w-3xl bg-white shadow-xl rounded-xl p-6 md:p-8">
<header class="mb-6 text-center">
<h1 class="text-4xl font-bold text-slate-800">Mozkovna</h1>
<p class="text-slate-600">Tvoje digitální nástěnka pro poznámky a nápady.</p>
<div id="authStatusContainer" class="mt-3 text-sm text-slate-500">
<span id="authStatus">Inicializace...</span>
<span id="userIdDisplay" class="font-mono bg-slate-200 px-2 py-1 rounded text-xs hidden"></span>
</div>
</header>
<div id="loadingIndicator" class="text-center py-4">
<svg class="animate-spin h-8 w-8 text-blue-600 mx-auto" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<p class="mt-2 text-slate-600">Načítám poznámky...</p>
</div>
<div id="saveStatus" class="text-sm text-center mb-2 hidden transition-all duration-300"></div>
<div class="mb-6 flex items-center gap-3">
<input type="text" id="newNoteInput" placeholder="Napsat novou hlavní poznámku..."
class="flex-grow p-3 border border-slate-300 rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-shadow">
<button id="addNoteButton"
class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg shadow-md hover:shadow-lg transition-all duration-150 ease-in-out disabled:opacity-50 disabled:cursor-not-allowed">
Přidat
</button>
</div>
<main>
<ul id="notesContainer" class="space-y-2 max-h-[60vh] overflow-y-auto pr-2">
</ul>
</main>
<footer class="mt-8 text-center text-xs text-slate-400">
<p>&copy; <span id="currentYear"></span> Mozkovna App. Kankys 2025.</p>
</footer>
</div>
<script>
document.getElementById('currentYear').textContent = new Date().getFullYear();
</script>
</body>
</html>

335
local.html Normal file
View File

@ -0,0 +1,335 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mozkovna</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<script type="module">
// DOM Elements
const notesContainer = document.getElementById('notesContainer');
const newNoteInput = document.getElementById('newNoteInput');
const addNoteButton = document.getElementById('addNoteButton');
const exportButton = document.getElementById('exportButton');
const importButton = document.getElementById('importButton');
const fileInput = document.getElementById('fileInput');
const saveStatus = document.getElementById('saveStatus');
let localNotesCache = [];
function renderNotes(notes) {
notesContainer.innerHTML = ''; // Clear existing notes
const notesMap = new Map(notes.map(note => [note.createdAt, { ...note, children: [] }]));
const rootNotes = [];
notesMap.forEach(note => {
if (note.parentId && notesMap.has(note.parentId)) {
notesMap.get(note.parentId).children.push(note);
} else {
rootNotes.push(note);
}
});
notesMap.forEach(note => {
note.children.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
});
rootNotes.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
if (rootNotes.length === 0 && notes.length > 0 && !notes.some(n => !n.parentId)) {
notes.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt))
.forEach(note => notesContainer.appendChild(createNoteElement(note, 0, notesMap)));
} else if (rootNotes.length === 0) {
notesContainer.innerHTML = '<p class="text-gray-500 text-center py-4">Zatím žádné poznámky. Přidejte první!</p>';
} else {
rootNotes.forEach(note => notesContainer.appendChild(createNoteElement(note, 0, notesMap)));
}
}
function createNoteElement(note, level, notesMap) {
const li = document.createElement('li');
li.className = `mb-2 p-3 rounded-lg shadow bg-white group relative transition-all duration-150 ease-in-out hover:shadow-md`;
li.style.marginLeft = `${level * 20}px`;
li.dataset.id = note.createdAt;
const textSpan = document.createElement('span');
textSpan.textContent = note.text;
textSpan.className = 'flex-grow break-words cursor-text focus:outline-none focus:ring-2 focus:ring-blue-500 rounded px-1 py-0.5';
textSpan.contentEditable = true;
let saveTimeout;
textSpan.addEventListener('input', () => {
clearTimeout(saveTimeout);
showSaveStatus('Ukládám...');
saveTimeout = setTimeout(() => {
try {
const updatedNote = { ...note, text: textSpan.textContent };
localNotesCache = localNotesCache.map(n => n.createdAt === note.createdAt ? updatedNote : n);
localStorage.setItem('notes', JSON.stringify(localNotesCache));
showSaveStatus('Uloženo!', true);
} catch (error) {
console.error("Chyba při aktualizaci poznámky:", error);
showSaveStatus('Chyba ukládání', false, true);
}
}, 1000); // Debounce saving
});
textSpan.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
textSpan.blur(); // Save on Enter
}
});
const controlsDiv = document.createElement('div');
controlsDiv.className = 'flex items-center space-x-2 mt-2 opacity-0 group-hover:opacity-100 transition-opacity duration-150 ease-in-out';
const addChildButton = document.createElement('button');
addChildButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-green-600 hover:text-green-800">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
<span class="sr-only">Přidat podúkol</span>`;
addChildButton.title = "Přidat podúkol";
addChildButton.className = 'p-1 rounded hover:bg-green-100';
addChildButton.onclick = () => addNote(note.createdAt);
const deleteButton = document.createElement('button');
deleteButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-red-500 hover:text-red-700">
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
<line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
<span class="sr-only">Smazat</span>`;
deleteButton.title = "Smazat poznámku";
deleteButton.className = 'p-1 rounded hover:bg-red-100';
deleteButton.onclick = () => deleteNoteWithChildren(note.createdAt, notesMap);
const indentButton = document.createElement('button');
indentButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-blue-500 hover:text-blue-700">
<polyline points="15 18 21 12 15 6"></polyline><polyline points="3 18 9 12 3 6"></polyline>
</svg>
<span class="sr-only">Odsadit</span>`;
indentButton.title = "Odsadit (učinit podúkolem předchozího sourozence)";
indentButton.className = 'p-1 rounded hover:bg-blue-100';
indentButton.onclick = () => indentNote(note.createdAt, notesMap);
const outdentButton = document.createElement('button');
outdentButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-purple-500 hover:text-purple-700">
<polyline points="9 18 3 12 9 6"></polyline><polyline points="21 18 15 12 21 6"></polyline>
</svg>
<span class="sr-only">Předsadit</span>`;
outdentButton.title = "Předsadit (stát se sourozencem rodiče)";
outdentButton.className = 'p-1 rounded hover:bg-purple-100';
outdentButton.onclick = () => outdentNote(note.createdAt, notesMap);
if (!note.parentId) outdentButton.disabled = true;
controlsDiv.appendChild(addChildButton);
controlsDiv.appendChild(indentButton);
controlsDiv.appendChild(outdentButton);
controlsDiv.appendChild(deleteButton);
li.appendChild(textSpan);
li.appendChild(controlsDiv);
if (note.children && note.children.length > 0) {
const childrenUl = document.createElement('ul');
childrenUl.className = 'mt-2';
note.children.forEach(childNote => childrenUl.appendChild(createNoteElement(childNote, level + 1, notesMap)));
li.appendChild(childrenUl);
}
return li;
}
function addNote(parentId = null) {
const text = newNoteInput.value.trim();
if (!text) {
alert("Text poznámky nemůže být prázdný.");
newNoteInput.focus();
return;
}
newNoteInput.value = ''; // Clear input
const note = {
text: text,
parentId: parentId,
createdAt: new Date().toISOString()
};
showSaveStatus('Přidávám...');
try {
localNotesCache.push(note);
localStorage.setItem('notes', JSON.stringify(localNotesCache));
showSaveStatus('Poznámka přidána!', true);
loadNotes();
} catch (error) {
console.error("Chyba při přidávání poznámky:", error);
showSaveStatus('Chyba přidávání', false, true);
alert("Nepodařilo se přidat poznámku: " + error.message);
}
}
function deleteNoteWithChildren(createdAt, notesMap) {
if (!confirm("Opravdu chcete smazat tuto poznámku a všechny její podpoznámky?")) return;
showSaveStatus('Mažu...');
try {
localNotesCache = localNotesCache.filter(note => note.createdAt !== createdAt);
localStorage.setItem('notes', JSON.stringify(localNotesCache));
showSaveStatus('Smazáno!', true);
loadNotes();
} catch (error) {
console.error("Chyba při mazání poznámky:", error);
showSaveStatus('Chyba mazání', false, true);
alert("Nepodařilo se smazat poznámku: " + error.message);
}
}
function loadNotes() {
try {
localNotesCache = JSON.parse(localStorage.getItem('notes') || '[]');
renderNotes(localNotesCache);
} catch (error) {
console.error("Chyba při načítání poznámek:", error);
notesContainer.innerHTML = `<p class="text-red-500">Chyba načítání poznámek: ${error.message}</p>`;
}
}
function exportNotes() {
const blob = new Blob([JSON.stringify(localNotesCache, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'notes.json';
a.click();
URL.revokeObjectURL(url);
}
function importNotes(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
try {
const importedNotes = JSON.parse(e.target.result);
localNotesCache = importedNotes;
localStorage.setItem('notes', JSON.stringify(localNotesCache));
loadNotes();
} catch (error) {
console.error("Chyba při importu poznámek:", error);
alert("Nepodařilo se importovat poznámky: " + error.message);
}
};
reader.readAsText(file);
}
let statusTimeout;
function showSaveStatus(message, success = false, error = false) {
saveStatus.textContent = message;
saveStatus.classList.remove('hidden', 'text-green-600', 'text-red-600', 'text-gray-600');
if (success) {
saveStatus.classList.add('text-green-600');
} else if (error) {
saveStatus.classList.add('text-red-600');
} else {
saveStatus.classList.add('text-gray-600');
}
clearTimeout(statusTimeout);
statusTimeout = setTimeout(() => {
saveStatus.classList.add('hidden');
}, 3000);
}
// --- Event Listeners ---
addNoteButton.addEventListener('click', () => addNote());
newNoteInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addNote();
}
});
exportButton.addEventListener('click', exportNotes);
importButton.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', importNotes);
// Initialize
loadNotes();
</script>
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #f0f2f5;
}
#notesContainer::-webkit-scrollbar {
width: 8px;
}
#notesContainer::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
#notesContainer::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 10px;
}
#notesContainer::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
.group:hover .opacity-0 {
opacity: 1;
}
[contenteditable]:focus {
outline: 2px solid #3b82f6;
border-radius: 4px;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5);
}
</style>
</head>
<body class="bg-slate-100 min-h-screen flex flex-col items-center pt-8 px-4">
<div class="w-full max-w-3xl bg-white shadow-xl rounded-xl p-6 md:p-8">
<header class="mb-6 text-center">
<h1 class="text-4xl font-bold text-slate-800">Mozkovna</h1>
<p class="text-slate-600">Tvoje digitální nástěnka pro poznámky a nápady.</p>
</header>
<div id="saveStatus" class="text-sm text-center mb-2 hidden transition-all duration-300"></div>
<div class="mb-6 flex items-center gap-3">
<input type="text" id="newNoteInput" placeholder="Napsat novou hlavní poznámku..."
class="flex-grow p-3 border border-slate-300 rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-shadow">
<button id="addNoteButton"
class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg shadow-md hover:shadow-lg transition-all duration-150 ease-in-out disabled:opacity-50 disabled:cursor-not-allowed">
Přidat
</button>
</div>
<main>
<ul id="notesContainer" class="space-y-2 max-h-[60vh] overflow-y-auto pr-2">
</ul>
</main>
<div class="mt-6 flex justify-between">
<button id="exportButton"
class="bg-green-600 hover:bg-green-700 text-white font-semibold py-2 px-4 rounded-lg shadow-md hover:shadow-lg transition-all duration-150 ease-in-out">
Exportovat
</button>
<input type="file" id="fileInput" accept=".json" class="hidden">
<button id="importButton"
class="bg-yellow-600 hover:bg-yellow-700 text-white font-semibold py-2 px-4 rounded-lg shadow-md hover:shadow-lg transition-all duration-150 ease-in-out">
Importovat
</button>
</div>
<footer class="mt-8 text-center text-xs text-slate-400">
<p>&copy; <span id="currentYear"></span> Mozkovna App. Kankys 2025.</p>
</footer>
</div>
<script>
document.getElementById('currentYear').textContent = new Date().getFullYear();
</script>
</body>
</html>