|
|
@@ -1,5 +1,42 @@
|
|
|
{{showFile "templates/design/sections/head.tmpl"}}
|
|
|
<body class="bg-zinc-950 text-zinc-200 h-screen overflow-hidden flex">
|
|
|
+
|
|
|
+{{/* DELETE CONFIRMATION MODAL */}}
|
|
|
+<div id="delete-modal" class="fixed inset-0 z-50 flex items-center justify-center hidden">
|
|
|
+ {{/* Backdrop */}}
|
|
|
+ <div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="hideDeleteModal()"></div>
|
|
|
+
|
|
|
+ {{/* Modal box */}}
|
|
|
+ <div class="relative z-10 bg-zinc-900 border border-zinc-700 rounded-lg shadow-2xl w-80 p-5 flex flex-col gap-4">
|
|
|
+ <div class="flex items-start gap-3">
|
|
|
+ {{/* Warning icon */}}
|
|
|
+ <div class="shrink-0 text-red-400 mt-0.5">
|
|
|
+ <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">
|
|
|
+ <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
|
|
+ <line x1="12" y1="9" x2="12" y2="13"/>
|
|
|
+ <line x1="12" y1="17" x2="12.01" y2="17"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <p class="text-sm font-medium text-zinc-100">Confirm Delete</p>
|
|
|
+ <p id="delete-modal-message" class="text-xs text-zinc-400 mt-1"></p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="flex justify-end gap-2">
|
|
|
+ <button onclick="hideDeleteModal()"
|
|
|
+ class="px-3 py-1.5 text-xs rounded border border-zinc-700 text-zinc-400 hover:text-zinc-100 hover:bg-zinc-800 transition-colors">
|
|
|
+ Cancel
|
|
|
+ </button>
|
|
|
+ <button id="delete-modal-confirm"
|
|
|
+ class="px-3 py-1.5 text-xs rounded bg-red-500/20 border border-red-500/50 text-red-400 hover:bg-red-500/30 hover:text-red-300 transition-colors">
|
|
|
+ Delete
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</div>
|
|
|
+
|
|
|
{{showFile "templates/design/sections/nav_small.tmpl"}}
|
|
|
|
|
|
{{template "nav_big.tmpl" .Folders}}
|
|
|
@@ -10,104 +47,159 @@
|
|
|
|
|
|
<div class="flex-1 flex">
|
|
|
<section class="flex-1 overflow-y-auto custom-scrollbar p-12">
|
|
|
- <div class="w-full grid grid-cols-2 gap-0 border border-zinc-700">
|
|
|
|
|
|
+{{if .Notepath}}
|
|
|
+
|
|
|
+ {{/* NOTE ACTION BAR */}}
|
|
|
+ <div class="w-full mb-4 flex items-center justify-between gap-4 border border-zinc-700 bg-zinc-900/40 px-4 py-3">
|
|
|
+ <div class="min-w-0">
|
|
|
+ <p class="text-xs uppercase tracking-widest text-zinc-500">Opened Note</p>
|
|
|
+ <p class="text-sm text-zinc-200 truncate">{{.Notepath}}</p>
|
|
|
+ </div>
|
|
|
|
|
|
+ <div class="flex items-center gap-2 shrink-0">
|
|
|
+ <form id="save-note-form" method="POST" action="/api/update_note">
|
|
|
+ <input type="hidden" name="path" value="{{.Notepath}}">
|
|
|
+ <textarea id="hidden-note-content" name="notita" class="hidden"></textarea>
|
|
|
+
|
|
|
+ <button type="submit"
|
|
|
+ class="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded border border-emerald-500/40 bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20 hover:text-emerald-300 transition-colors">
|
|
|
+ <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24"
|
|
|
+ fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
|
|
+ <polyline points="17 21 17 13 7 13 7 21"/>
|
|
|
+ <polyline points="7 3 7 8 15 8"/>
|
|
|
+ </svg>
|
|
|
+ Save Note
|
|
|
+ </button>
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{/* Editor + Preview */}}
|
|
|
+ <div class="w-full grid grid-cols-2 gap-0 border border-zinc-700">
|
|
|
<div class="h-[85vh] bg-[#446454]">
|
|
|
<textarea
|
|
|
id="editor"
|
|
|
placeholder="Start typing..."
|
|
|
class="p-6 w-full h-full bg-transparent text-zinc-100 text-[14px] focus:outline-none resize-none custom-scrollbar"
|
|
|
- ></textarea>
|
|
|
+ >{{.Continut}}</textarea>
|
|
|
</div>
|
|
|
<div id="preview" class="border-r border-zinc-700 h-[85vh] bg-[#454644] p-2 text-zinc-100 overflow-y-auto font-sans prose prose-invert prose-zinc max-w-none
|
|
|
- /* --- Code Blocks (Pre) --- */
|
|
|
- [&_pre]:bg-zinc-900/80 [&_pre]:p-4 [&_pre]:rounded-lg [&_pre]:border [&_pre]:border-zinc-700
|
|
|
- [&_pre]:my-6 [&_pre]:overflow-x-auto [&_pre]:shadow-inner
|
|
|
-
|
|
|
- /* --- Inline Code (<code>) --- */
|
|
|
- [&_code]:font-mono [&_code]:text-indigo-300 [&_code]:bg-zinc-800/50
|
|
|
- [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-[0.9em]
|
|
|
- /* Evităm background-ul dublu când codul este în interiorul unui <pre> */
|
|
|
- [&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:text-zinc-200 [&_pre_code]:text-[0.85em]
|
|
|
-
|
|
|
- /* --- Stiluri Blockquote --- */
|
|
|
- [&_blockquote]:border-l-4 [&_blockquote]:border-indigo-500 [&_blockquote]:bg-zinc-800/30
|
|
|
- [&_blockquote]:py-2 [&_blockquote]:px-5 [&_blockquote]:my-4 [&_blockquote]:italic [&_blockquote]:text-zinc-300
|
|
|
-
|
|
|
- /* --- Stiluri Bold & Italic --- */
|
|
|
- [&_strong]:text-white [&_strong]:font-bold
|
|
|
- [&_em]:text-indigo-200 [&_em]:italic
|
|
|
-
|
|
|
- /* --- Stiluri pentru Tabele --- */
|
|
|
- [&_table]:w-full [&_table]:my-6 [&_table]:border-collapse [&_table]:border [&_table]:border-zinc-600
|
|
|
- [&_thead]:bg-zinc-800/50
|
|
|
- [&_th]:border [&_th]:border-zinc-600 [&_th]:p-3 [&_th]:text-left [&_th]:text-indigo-300 [&_th]:uppercase [&_th]:text-[11px]
|
|
|
- [&_td]:border [&_td]:border-zinc-600 [&_td]:p-3 [&_td]:text-sm
|
|
|
- [&_tr:nth-child(even)]:bg-zinc-700/30
|
|
|
-
|
|
|
- /* --- Stiluri pentru Liste & Headings --- */
|
|
|
- [&_ul]:list-disc [&_ul]:ml-6 [&_ol]:list-decimal [&_ol]:ml-6
|
|
|
- [&_h1]:text-3xl [&_h1]:font-bold [&_h1]:border-b [&_h1]:border-zinc-600 [&_h1]:pb-2 [&_h1]:mb-4
|
|
|
- [&_h2]:text-xl [&_h2]:font-semibold [&_h2]:text-indigo-400 [&_h2]:mt-6 custom-scrollbar">
|
|
|
- Your preview will appear here...
|
|
|
- </div>
|
|
|
+/* --- Code Blocks (Pre) --- */
|
|
|
+[&_pre]:bg-zinc-900/80 [&_pre]:p-4 [&_pre]:rounded-lg [&_pre]:border [&_pre]:border-zinc-700
|
|
|
+[&_pre]:my-6 [&_pre]:overflow-x-auto [&_pre]:shadow-inner
|
|
|
+/* --- Inline Code (<code>) --- */
|
|
|
+[&_code]:font-mono [&_code]:text-indigo-300 [&_code]:bg-zinc-800/50
|
|
|
+[&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-[0.9em]
|
|
|
+/* Evităm background-ul dublu când codul este în interiorul unui <pre> */
|
|
|
+[&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:text-zinc-200 [&_pre_code]:text-[0.85em]
|
|
|
+
|
|
|
+/* --- Stiluri Blockquote --- */
|
|
|
+[&_blockquote]:border-l-4 [&_blockquote]:border-indigo-500 [&_blockquote]:bg-zinc-800/30
|
|
|
+[&_blockquote]:py-2 [&_blockquote]:px-5 [&_blockquote]:my-4 [&_blockquote]:italic [&_blockquote]:text-zinc-300
|
|
|
+/* --- Stiluri Bold & Italic --- */
|
|
|
+[&_strong]:text-white [&_strong]:font-bold
|
|
|
+[&_em]:text-indigo-200 [&_em]:italic
|
|
|
+
|
|
|
+/* --- Stiluri pentru Tabele --- */
|
|
|
+[&_table]:w-full [&_table]:my-6 [&_table]:border-collapse [&_table]:border [&_table]:border-zinc-600
|
|
|
+[&_thead]:bg-zinc-800/50
|
|
|
+[&_th]:border [&_th]:border-zinc-600 [&_th]:p-3 [&_th]:text-left [&_th]:text-indigo-300 [&_th]:uppercase [&_th]:text-[11px]
|
|
|
+[&_td]:border [&_td]:border-zinc-600 [&_td]:p-3 [&_td]:text-sm
|
|
|
+[&_tr:nth-child(even)]:bg-zinc-700/30
|
|
|
+
|
|
|
+/* --- Stiluri pentru Liste & Headings --- */
|
|
|
+[&_ul]:list-disc [&_ul]:ml-6 [&_ol]:list-decimal [&_ol]:ml-6
|
|
|
+[&_h1]:text-3xl [&_h1]:font-bold [&_h1]:border-b [&_h1]:border-zinc-600 [&_h1]:pb-2 [&_h1]:mb-4
|
|
|
+[&_h2]:text-xl [&_h2]:font-semibold [&_h2]:text-indigo-400 [&_h2]:mt-6 custom-scrollbar">
|
|
|
+Your preview will appear here...
|
|
|
+</div>
|
|
|
+ </div>
|
|
|
+{{else}}
|
|
|
+ {{/* EMPTY STATE */}}
|
|
|
+ <div class="flex-1 flex flex-col items-center justify-center gap-4 text-center h-[85vh]">
|
|
|
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24"
|
|
|
+ fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
|
|
|
+ class="text-zinc-700">
|
|
|
+ <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
|
|
|
+ <polyline points="14 2 14 8 20 8"/>
|
|
|
+ </svg>
|
|
|
+ <p class="text-zinc-600 text-sm">No note open</p>
|
|
|
+ <p class="text-zinc-700 text-xs">Select a file from the navigator or create a new one</p>
|
|
|
</div>
|
|
|
+{{end}}
|
|
|
+
|
|
|
</section>
|
|
|
|
|
|
|
|
|
</div>
|
|
|
</main>
|
|
|
|
|
|
+
|
|
|
+
|
|
|
<script>
|
|
|
const editor = document.getElementById('editor');
|
|
|
-const preview = document.getElementById('preview');
|
|
|
-
|
|
|
-// Debounce helper
|
|
|
-function debounce(func, delay) {
|
|
|
- let timeout;
|
|
|
- return function(...args) {
|
|
|
- clearTimeout(timeout);
|
|
|
- timeout = setTimeout(() => func.apply(this, args), delay);
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-// The API Call
|
|
|
-const updatePreview = async () => {
|
|
|
- const content = editor.value;
|
|
|
-
|
|
|
- try {
|
|
|
- const response = await fetch('/live_preview/', {
|
|
|
- method: 'POST',
|
|
|
- headers: { 'Content-Type': 'application/json' },
|
|
|
- body: JSON.stringify({ markdown: content })
|
|
|
- });
|
|
|
-
|
|
|
- if (response.ok) {
|
|
|
- const htmlResult = await response.text();
|
|
|
- preview.innerHTML = htmlResult;
|
|
|
-
|
|
|
- // 1. Aplică etichetele de limbaj (codul de mai devreme)
|
|
|
- preview.querySelectorAll('pre code').forEach((codeBlock) => {
|
|
|
- const pre = codeBlock.parentElement;
|
|
|
- const langClass = Array.from(codeBlock.classList).find(c => c.startsWith('language-'));
|
|
|
- if (langClass) {
|
|
|
- pre.setAttribute('data-language', langClass.replace('language-', ''));
|
|
|
- }
|
|
|
+ const preview = document.getElementById('preview');
|
|
|
+ const saveForm = document.getElementById('save-note-form');
|
|
|
+ const hiddenNoteContent = document.getElementById('hidden-note-content');
|
|
|
+
|
|
|
+ if (editor && preview){
|
|
|
+ // Debounce helper
|
|
|
+ function debounce(func, delay) {
|
|
|
+ let timeout;
|
|
|
+ return function(...args) {
|
|
|
+ clearTimeout(timeout);
|
|
|
+ timeout = setTimeout(() => func.apply(this, args), delay);
|
|
|
+ };
|
|
|
+ }
|
|
|
|
|
|
- // 2. Declanșează evidențierea sintaxei
|
|
|
- hljs.highlightElement(codeBlock);
|
|
|
+ // The API Call
|
|
|
+ const updatePreview = async () => {
|
|
|
+ const content = editor.value;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await fetch('/live_preview/', {
|
|
|
+ method: 'POST',
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
+ body: JSON.stringify({ markdown: content })
|
|
|
+ });
|
|
|
+
|
|
|
+ if (response.ok) {
|
|
|
+ const htmlResult = await response.text();
|
|
|
+ preview.innerHTML = htmlResult;
|
|
|
+
|
|
|
+ preview.querySelectorAll('pre code').forEach((codeBlock) => {
|
|
|
+ const pre = codeBlock.parentElement;
|
|
|
+ const langClass = Array.from(codeBlock.classList).find(c => c.startsWith('language-'));
|
|
|
+ if (langClass) {
|
|
|
+ pre.setAttribute('data-language', langClass.replace('language-', ''));
|
|
|
+ }
|
|
|
+ hljs.highlightElement(codeBlock);
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log("Remote Preview & Highlighting Updated!");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Error:", error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Listen for input
|
|
|
+ editor.addEventListener('input', debounce(updatePreview, 100));
|
|
|
+
|
|
|
+ // sync editor content into hidden form field before save
|
|
|
+ if (saveForm && hiddenNoteContent) {
|
|
|
+ saveForm.addEventListener('submit', function () {
|
|
|
+ hiddenNoteContent.value = editor.value;
|
|
|
});
|
|
|
+ }
|
|
|
|
|
|
- console.log("Remote Preview & Highlighting Updated!");
|
|
|
+ // initial preview
|
|
|
+ if (editor.value.trim() !== '') {
|
|
|
+ updatePreview();
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error("Error:", error);
|
|
|
}
|
|
|
-};
|
|
|
-
|
|
|
-// Listen for input, trigger every 500ms of "pause"
|
|
|
-editor.addEventListener('input', debounce(updatePreview, 100));
|
|
|
</script>
|
|
|
|
|
|
</body>
|