Răsfoiți Sursa

introduce vanila components

Daniel Bohry 1 lună în urmă
părinte
comite
6e2c75dc5c

+ 18 - 96
src/main/resources/static/404.html

@@ -10,16 +10,11 @@
     <meta name="mobile-web-app-capable" content="yes">
     <meta name="mobile-web-app-capable" content="yes">
     <meta name="application-name" content="kNotes">
     <meta name="application-name" content="kNotes">
     <title>Page Not Found - kNotes</title>
     <title>Page Not Found - kNotes</title>
-    <link rel="stylesheet" href="style.css">
+    <link rel="stylesheet" href="css/style.css">
+    <link rel="icon" type="image/x-icon" href="img/favicon.ico">
 </head>
 </head>
 <body>
 <body>
-<div class="header">
-    <div class="title" onclick="window.location.href='/'" style="cursor: pointer;"><img src="logo.png" alt="kNotes logo"/> kNotes</div>
-    <div class="header-right">
-        <div class="theme-switch" id="themeSwitch" onclick="toggleTheme()" title="Toggle dark/light theme"></div>
-        <button class="new-btn" onclick="window.location.href='/'">Home</button>
-    </div>
-</div>
+<div id="headerContainer"></div>
 
 
 <div class="content">
 <div class="content">
     <div class="error-content">
     <div class="error-content">
@@ -29,98 +24,25 @@
             The page you're looking for doesn't exist. It might have been moved, deleted,
             The page you're looking for doesn't exist. It might have been moved, deleted,
             or you entered the wrong URL.
             or you entered the wrong URL.
         </p>
         </p>
+        <div class="error-actions">
+            <button class="dialog-btn primary" onclick="window.location.href='/'">
+                Go Home
+            </button>
+            <button class="dialog-btn secondary" onclick="showIdInput()">
+                Open Note
+            </button>
+        </div>
     </div>
     </div>
 </div>
 </div>
 
 
-<script>
-    function initializeTheme() {
-        const savedTheme = localStorage.getItem('theme') || 'light';
-        const body = document.body;
-        const themeSwitch = document.getElementById('themeSwitch');
-
-        if (!themeSwitch) return;
-
-        if (savedTheme === 'dark') {
-            body.setAttribute('data-theme', 'dark');
-            themeSwitch.classList.add('dark');
-        } else {
-            body.removeAttribute('data-theme');
-            themeSwitch.classList.remove('dark');
-        }
-
-        updateThemeColor();
-    }
-
-    function toggleTheme() {
-        const body = document.body;
-        const themeSwitch = document.getElementById('themeSwitch');
-
-        if (!themeSwitch) return;
-
-        const currentTheme = body.getAttribute('data-theme');
-
-        if (currentTheme === 'dark') {
-            body.removeAttribute('data-theme');
-            themeSwitch.classList.remove('dark');
-            localStorage.setItem('theme', 'light');
-        } else {
-            body.setAttribute('data-theme', 'dark');
-            themeSwitch.classList.add('dark');
-            localStorage.setItem('theme', 'dark');
-        }
+<div id="modalContainer"></div>
 
 
-        updateThemeColor();
-    }
-
-    function updateThemeColor() {
-        const themeColorMeta = document.querySelector('meta[name="theme-color"]');
-        const currentTheme = document.body.getAttribute('data-theme');
-
-        if (themeColorMeta) {
-            if (currentTheme === 'dark') {
-                themeColorMeta.setAttribute('content', '#2d2d2d');
-            } else {
-                themeColorMeta.setAttribute('content', '#007bff');
-            }
-        }
-    }
-
-    function hideIdInput() {
-        const idInputOverlay = document.getElementById('idInputOverlay');
-        const noteIdInput = document.getElementById('noteIdInput');
-
-        if (idInputOverlay) {
-            idInputOverlay.classList.add('hidden');
-        }
-
-        if (noteIdInput) {
-            noteIdInput.value = '';
-        }
-    }
-
-    function loadNoteFromInput() {
-        const noteIdInput = document.getElementById('noteIdInput');
-        if (!noteIdInput) return;
-
-        const id = noteIdInput.value.trim();
-        if (id) {
-            hideIdInput();
-            window.location.href = `/${id}`;
-        }
-    }
-
-    document.addEventListener('DOMContentLoaded', function () {
-        initializeTheme();
-
-        const noteIdInput = document.getElementById('noteIdInput');
-        if (noteIdInput) {
-            noteIdInput.addEventListener('keypress', function (e) {
-                if (e.key === 'Enter') {
-                    loadNoteFromInput();
-                }
-            });
-        }
-    });
+<script src="js/components.js"></script>
+<script src="js/script.js"></script>
+<script>
+document.addEventListener('DOMContentLoaded', async () => {
+    await initPage('error');
+});
 </script>
 </script>
 </body>
 </body>
 </html>
 </html>

+ 23 - 0
src/main/resources/static/components/base.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+    <meta name="theme-color" content="#007bff">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="apple-mobile-web-app-status-bar-style" content="default">
+    <meta name="apple-mobile-web-app-title" content="kNotes">
+    <meta name="mobile-web-app-capable" content="yes">
+    <meta name="application-name" content="kNotes">
+    <title>{{PAGE_TITLE}}</title>
+    <link rel="stylesheet" href="css/style.css">
+    <link rel="icon" type="image/x-icon" href="img/favicon.ico">
+</head>
+<body>
+{{PAGE_CONTENT}}
+
+<script src="js/components.js"></script>
+<script src="js/script.js"></script>
+{{PAGE_SCRIPT}}
+</body>
+</html>

+ 8 - 0
src/main/resources/static/components/header.html

@@ -0,0 +1,8 @@
+<div class="header">
+    <div class="title" onclick="window.location.href='/'" style="cursor: pointer;">
+        <img src="img/logo.png" alt="kNotes logo"/> kNotes
+    </div>
+    <div class="header-right">
+        {{HEADER_CONTENT}}
+    </div>
+</div>

+ 10 - 0
src/main/resources/static/components/modal.html

@@ -0,0 +1,10 @@
+<div id="idInputOverlay" class="id-input-overlay hidden">
+    <div class="id-input-dialog">
+        <h3>Open Note</h3>
+        <input type="text" id="noteIdInput" class="id-input" placeholder="Enter note ID"/>
+        <div class="dialog-buttons">
+            <button class="dialog-btn secondary" onclick="hideIdInput()">Cancel</button>
+            <button class="dialog-btn primary" onclick="loadNoteFromInput()">Open</button>
+        </div>
+    </div>
+</div>

+ 0 - 0
src/main/resources/static/style.css → src/main/resources/static/css/style.css


+ 12 - 63
src/main/resources/static/home.html

@@ -10,86 +10,35 @@
     <meta name="mobile-web-app-capable" content="yes">
     <meta name="mobile-web-app-capable" content="yes">
     <meta name="application-name" content="kNotes">
     <meta name="application-name" content="kNotes">
     <title>kNotes - Simple Note Taking</title>
     <title>kNotes - Simple Note Taking</title>
-    <link rel="stylesheet" href="style.css">
+    <link rel="stylesheet" href="css/style.css">
+    <link rel="icon" type="image/x-icon" href="img/favicon.ico">
 </head>
 </head>
 <body>
 <body>
-<div class="header">
-    <div class="title" onclick="window.location.href='/'" style="cursor: pointer;"><img src="logo.png"
-                                                                                        alt="kNotes logo"/> kNotes
-    </div>
-    <div class="header-right">
-        <div class="theme-switch" id="themeSwitch" onclick="toggleTheme()" title="Toggle dark/light theme"></div>
-    </div>
-</div>
+<div id="headerContainer"></div>
 
 
 <div class="content">
 <div class="content">
     <div class="error-content">
     <div class="error-content">
         <div class="error-icon">📝</div>
         <div class="error-icon">📝</div>
         <h1 class="error-title">Welcome to kNotes</h1>
         <h1 class="error-title">Welcome to kNotes</h1>
         <div class="error-actions">
         <div class="error-actions">
-            <button class="dialog-btn primary" onclick="createNewNote()">
-                Create New
+            <button class="dialog-btn primary" onclick="window.location.href='/index.html'">
+                Create New Note
             </button>
             </button>
             <button class="dialog-btn secondary" onclick="showIdInput()">
             <button class="dialog-btn secondary" onclick="showIdInput()">
-                Open Existing
+                Open Existing Note
             </button>
             </button>
         </div>
         </div>
     </div>
     </div>
 </div>
 </div>
 
 
-<div id="idInputOverlay" class="id-input-overlay hidden">
-    <div class="id-input-dialog">
-        <h3>Open Note</h3>
-        <input type="text" id="noteIdInput" class="id-input" placeholder="Enter note ID"/>
-        <div class="dialog-buttons">
-            <button class="dialog-btn secondary" onclick="hideIdInput()">Cancel</button>
-            <button class="dialog-btn primary" onclick="loadNoteFromInput()">Open</button>
-        </div>
-    </div>
-</div>
+<div id="modalContainer"></div>
 
 
-<script src="script.js"></script>
+<script src="js/components.js"></script>
+<script src="js/script.js"></script>
 <script>
 <script>
-    function createNewNote() {
-        window.location.href = '/index.html';
-    }
-
-    function hideIdInput() {
-        const idInputOverlay = document.getElementById('idInputOverlay');
-        const noteIdInput = document.getElementById('noteIdInput');
-
-        if (idInputOverlay) {
-            idInputOverlay.classList.add('hidden');
-        }
-
-        if (noteIdInput) {
-            noteIdInput.value = '';
-        }
-    }
-
-    function loadNoteFromInput() {
-        const noteIdInput = document.getElementById('noteIdInput');
-        if (!noteIdInput) return;
-
-        const id = noteIdInput.value.trim();
-        if (id) {
-            hideIdInput();
-            window.location.href = `/${id}`;
-        }
-    }
-
-    document.addEventListener('DOMContentLoaded', function () {
-        initializeTheme();
-
-        const noteIdInput = document.getElementById('noteIdInput');
-        if (noteIdInput) {
-            noteIdInput.addEventListener('keypress', function (e) {
-                if (e.key === 'Enter') {
-                    loadNoteFromInput();
-                }
-            });
-        }
-    });
+document.addEventListener('DOMContentLoaded', async () => {
+    await initPage('home');
+});
 </script>
 </script>
 </body>
 </body>
 </html>
 </html>

+ 0 - 0
src/main/resources/static/favicon.ico → src/main/resources/static/img/favicon.ico


+ 0 - 0
src/main/resources/static/logo.png → src/main/resources/static/img/logo.png


+ 12 - 22
src/main/resources/static/index.html

@@ -10,38 +10,28 @@
     <meta name="mobile-web-app-capable" content="yes">
     <meta name="mobile-web-app-capable" content="yes">
     <meta name="application-name" content="kNotes">
     <meta name="application-name" content="kNotes">
     <title>kNotes</title>
     <title>kNotes</title>
-    <link rel="stylesheet" href="style.css">
+    <link rel="stylesheet" href="css/style.css">
+    <link rel="icon" type="image/x-icon" href="img/favicon.ico">
 </head>
 </head>
 <body>
 <body>
-<div class="header">
-    <div class="title" onclick="window.location.href='/'" style="cursor: pointer;"><img src="logo.png" alt="kNotes logo"/> kNotes</div>
-    <div class="header-right">
-        <span class="note-id" id="noteIdDisplay" style="display: none; cursor: pointer;" onclick="copyNoteLink()" title="Click to copy note link"></span>
-        <div class="theme-switch" id="themeSwitch" onclick="toggleTheme()" title="Toggle dark/light theme"></div>
-        <button class="new-btn" onclick="showIdInput()">Open</button>
-        <button class="new-btn" onclick="newNote()">New</button>
-    </div>
-</div>
+<div id="headerContainer"></div>
 
 
 <div id="updateToast" class="update-toast hidden">
 <div id="updateToast" class="update-toast hidden">
-    Note was updated
+    📄 Note was updated
 </div>
 </div>
 
 
 <div class="content">
 <div class="content">
     <textarea class="note-area" id="noteContent" placeholder="Start typing your note..."></textarea>
     <textarea class="note-area" id="noteContent" placeholder="Start typing your note..."></textarea>
 </div>
 </div>
 
 
-<div id="idInputOverlay" class="id-input-overlay hidden">
-    <div class="id-input-dialog">
-        <h3>Open Note</h3>
-        <input type="text" id="noteIdInput" class="id-input" placeholder="Enter note ID"/>
-        <div class="dialog-buttons">
-            <button class="dialog-btn secondary" onclick="hideIdInput()">Cancel</button>
-            <button class="dialog-btn primary" onclick="loadNoteFromInput()">Open</button>
-        </div>
-    </div>
-</div>
+<div id="modalContainer"></div>
 
 
-<script src="script.js"></script>
+<script src="js/components.js"></script>
+<script src="js/script.js"></script>
+<script>
+document.addEventListener('DOMContentLoaded', async () => {
+    await initPage('editor');
+});
+</script>
 </body>
 </body>
 </html>
 </html>

+ 74 - 0
src/main/resources/static/js/components.js

@@ -0,0 +1,74 @@
+// Enhanced component loader
+async function loadComponent(componentPath, targetId, customizations = {}) {
+    try {
+        const response = await fetch(componentPath);
+        if (!response.ok) throw new Error(`Failed to load ${componentPath}`);
+
+        let html = await response.text();
+
+        // Apply customizations
+        Object.entries(customizations).forEach(([placeholder, value]) => {
+            html = html.replace(new RegExp(`{{${placeholder}}}`, 'g'), value);
+        });
+
+        const targetElement = document.getElementById(targetId);
+        if (targetElement) {
+            targetElement.innerHTML = html;
+        }
+    } catch (error) {
+        console.error('Component loading failed:', error);
+    }
+}
+
+// Page configurations
+const PAGE_CONFIGS = {
+    editor: {
+        header: `
+            <span class="note-id" id="noteIdDisplay" style="display: none; cursor: pointer;" onclick="copyNoteLink()" title="Click to copy note link"></span>
+            <div class="theme-switch" id="themeSwitch" onclick="toggleTheme()" title="Toggle dark/light theme"></div>
+            <button class="new-btn" onclick="showIdInput()">Open</button>
+            <button class="new-btn" onclick="newNote()">New</button>
+        `,
+        needsModal: true,
+        needsToast: true
+    },
+    home: {
+        header: `
+            <div class="theme-switch" id="themeSwitch" onclick="toggleTheme()" title="Toggle dark/light theme"></div>
+        `,
+        needsModal: true,
+        needsToast: false
+    },
+    error: {
+        header: `
+            <div class="theme-switch" id="themeSwitch" onclick="toggleTheme()" title="Toggle dark/light theme"></div>
+            <button class="new-btn" onclick="window.location.href='/'">Home</button>
+        `,
+        needsModal: true,
+        needsToast: false
+    }
+};
+
+// Initialize page components
+async function initPage(pageType) {
+    const config = PAGE_CONFIGS[pageType];
+    if (!config) {
+        console.error('Unknown page type:', pageType);
+        return;
+    }
+
+    // Load header
+    await loadComponent('/components/header.html', 'headerContainer', {
+        HEADER_CONTENT: config.header
+    });
+
+    // Load modal if needed
+    if (config.needsModal) {
+        await loadComponent('/components/modal.html', 'modalContainer');
+    }
+
+    // Initialize theme
+    if (typeof initializeTheme === 'function') {
+        initializeTheme();
+    }
+}

+ 4 - 8
src/main/resources/static/script.js → src/main/resources/static/js/script.js

@@ -13,10 +13,7 @@ function initializeTheme() {
     const body = document.body;
     const body = document.body;
     const themeSwitch = document.getElementById('themeSwitch');
     const themeSwitch = document.getElementById('themeSwitch');
 
 
-    if (!themeSwitch) {
-        console.error('Theme switch element not found');
-        return;
-    }
+    if (!themeSwitch) return;
 
 
     // Apply the theme
     // Apply the theme
     if (savedTheme === 'dark') {
     if (savedTheme === 'dark') {
@@ -26,16 +23,15 @@ function initializeTheme() {
         body.removeAttribute('data-theme');
         body.removeAttribute('data-theme');
         themeSwitch.classList.remove('dark');
         themeSwitch.classList.remove('dark');
     }
     }
+
+    updateThemeColor();
 }
 }
 
 
 function toggleTheme() {
 function toggleTheme() {
     const body = document.body;
     const body = document.body;
     const themeSwitch = document.getElementById('themeSwitch');
     const themeSwitch = document.getElementById('themeSwitch');
 
 
-    if (!themeSwitch) {
-        console.error('Theme switch element not found');
-        return;
-    }
+    if (!themeSwitch) return;
 
 
     // Toggle between light and dark themes
     // Toggle between light and dark themes
     const currentTheme = body.getAttribute('data-theme');
     const currentTheme = body.getAttribute('data-theme');