From fa7b37d0c343c20bb1f96d3cca3470f78c3218dd Mon Sep 17 00:00:00 2001 From: Jan Barfuss Date: Sat, 28 Dec 2024 00:08:26 +0100 Subject: [PATCH] Some structure for the dashboard and correction to the README.md --- README.md | 2 +- assets/components/accounts.html | 2 + assets/components/entry.html | 2 + assets/components/overview.html | 2 + assets/css/master.css | 352 ++++++++++---------------------- assets/scripts/dashboard.js | 139 +++++++++++++ assets/scripts/login.js | 10 + views/dashboard.html | 42 ++++ views/index.html | 105 ++++------ 9 files changed, 348 insertions(+), 308 deletions(-) create mode 100644 assets/components/accounts.html create mode 100644 assets/components/entry.html create mode 100644 assets/components/overview.html create mode 100644 assets/scripts/dashboard.js create mode 100644 assets/scripts/login.js create mode 100644 views/dashboard.html diff --git a/README.md b/README.md index 6a6bbc1..a9d6850 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # Bookholder APP ## Build CSS -npx tailwindcss -i ./public/css/input.css -o ./public/css/master.css --watch \ No newline at end of file +npx tailwindcss -i ./assets/css/input.css -o ./assets/css/master.css --watch \ No newline at end of file diff --git a/assets/components/accounts.html b/assets/components/accounts.html new file mode 100644 index 0000000..086c1f8 --- /dev/null +++ b/assets/components/accounts.html @@ -0,0 +1,2 @@ +

Accounts

+

This is the Accounts content.

diff --git a/assets/components/entry.html b/assets/components/entry.html new file mode 100644 index 0000000..04e057a --- /dev/null +++ b/assets/components/entry.html @@ -0,0 +1,2 @@ +

Entry

+

This is the Entry content.

diff --git a/assets/components/overview.html b/assets/components/overview.html new file mode 100644 index 0000000..45c4572 --- /dev/null +++ b/assets/components/overview.html @@ -0,0 +1,2 @@ +

Overview

+

This is the Overview content.

diff --git a/assets/css/master.css b/assets/css/master.css index ec898aa..3327fe4 100644 --- a/assets/css/master.css +++ b/assets/css/master.css @@ -554,22 +554,14 @@ video { display: none; } -.row-start-2 { - grid-row-start: 2; -} - -.row-start-3 { - grid-row-start: 3; +.m-4 { + margin: 1rem; } .mb-2 { margin-bottom: 0.5rem; } -.mb-3 { - margin-bottom: 0.75rem; -} - .mb-4 { margin-bottom: 1rem; } @@ -582,60 +574,67 @@ video { display: block; } -.inline-block { - display: inline-block; -} - .flex { display: flex; } -.grid { - display: grid; +.contents { + display: contents; } -.h-10 { - height: 2.5rem; +.hidden { + display: none; } .h-screen { height: 100vh; } -.min-h-screen { - min-height: 100vh; +.h-\[10\%\] { + height: 10%; } -.w-full { - width: 100%; +.h-\[20\%\] { + height: 20%; +} + +.h-max { + height: -moz-max-content; + height: max-content; +} + +.h-full { + height: 100%; } .w-80 { width: 20rem; } -.max-w-xs { - max-width: 20rem; +.w-full { + width: 100%; } -.appearance-none { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; +.w-\[15\%\] { + width: 15%; } -.grid-rows-\[20px_1fr_20px\] { - grid-template-rows: 20px 1fr 20px; +.w-\[20\%\] { + width: 20%; +} + +.flex-1 { + flex: 1 1 0%; +} + +.cursor-pointer { + cursor: pointer; } .flex-col { flex-direction: column; } -.flex-wrap { - flex-wrap: wrap; -} - .place-items-end { place-items: end; } @@ -652,40 +651,18 @@ video { justify-content: space-between; } -.justify-items-center { - justify-items: center; +.justify-evenly { + justify-content: space-evenly; } -.gap-1 { - gap: 0.25rem; +.space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); } -.gap-16 { - gap: 4rem; -} - -.gap-2 { - gap: 0.5rem; -} - -.gap-4 { - gap: 1rem; -} - -.gap-6 { - gap: 1.5rem; -} - -.gap-8 { - gap: 2rem; -} - -.rounded { - border-radius: 0.25rem; -} - -.rounded-full { - border-radius: 9999px; +.overflow-auto { + overflow: auto; } .rounded-lg { @@ -696,21 +673,12 @@ video { border-width: 1px; } -.border-solid { - border-style: solid; +.border-b { + border-bottom-width: 1px; } -.border-black\/\[\.08\] { - border-color: rgb(0 0 0 / .08); -} - -.border-transparent { - border-color: transparent; -} - -.border-red-500 { - --tw-border-opacity: 1; - border-color: rgb(239 68 68 / var(--tw-border-opacity, 1)); +.border-b-2 { + border-bottom-width: 2px; } .border-black { @@ -718,18 +686,18 @@ video { border-color: rgb(0 0 0 / var(--tw-border-opacity, 1)); } -.bg-foreground { - background-color: var(--foreground); +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity, 1)); } -.bg-blue-500 { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1)); +.border-transparent { + border-color: transparent; } -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); +.border-blue-500 { + --tw-border-opacity: 1; + border-color: rgb(59 130 246 / var(--tw-border-opacity, 1)); } .bg-black { @@ -742,14 +710,33 @@ video { background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1)); } -.p-8 { - padding: 2rem; +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1)); +} + +.bg-gray-300 { + --tw-bg-opacity: 1; + background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1)); } .p-6 { padding: 1.5rem; } +.p-2 { + padding: 0.5rem; +} + +.p-4 { + padding: 1rem; +} + .px-3 { padding-left: 0.75rem; padding-right: 0.75rem; @@ -765,110 +752,57 @@ video { padding-bottom: 0.5rem; } -.px-8 { - padding-left: 2rem; - padding-right: 2rem; -} - -.pb-20 { - padding-bottom: 5rem; -} - -.pb-8 { - padding-bottom: 2rem; -} - -.pt-6 { - padding-top: 1.5rem; -} - .text-center { text-align: center; } -.align-baseline { - vertical-align: baseline; -} - -.font-\[family-name\:var\(--font-geist-sans\)\] { - font-family: var(--font-geist-sans); -} - -.text-3xl { - font-size: 1.875rem; - line-height: 2.25rem; -} - -.text-sm { - font-size: 0.875rem; - line-height: 1.25rem; -} - -.text-xs { - font-size: 0.75rem; - line-height: 1rem; -} - .text-2xl { font-size: 1.5rem; line-height: 2rem; } +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + .font-bold { font-weight: 700; } -.italic { - font-style: italic; -} - -.leading-tight { - line-height: 1.25; -} - -.text-background { - color: var(--background); -} - .text-black { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity, 1)); } -.text-blue-500 { - --tw-text-opacity: 1; - color: rgb(59 130 246 / var(--tw-text-opacity, 1)); -} - -.text-gray-500 { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity, 1)); -} - .text-gray-700 { --tw-text-opacity: 1; color: rgb(55 65 81 / var(--tw-text-opacity, 1)); } -.text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity, 1)); -} - -.text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity, 1)); -} - .text-gray-800 { --tw-text-opacity: 1; color: rgb(31 41 55 / var(--tw-text-opacity, 1)); } -.shadow { - --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity, 1)); +} + +.text-red-500 { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity, 1)); +} + +.text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity, 1)); } .shadow-md { @@ -883,12 +817,6 @@ video { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.transition-colors { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - :root { --background: #ffffff; --foreground: #171717; @@ -907,23 +835,9 @@ body { font-family: Arial, Helvetica, sans-serif; } -.hover\:border-transparent:hover { - border-color: transparent; -} - -.hover\:bg-\[\#383838\]:hover { - --tw-bg-opacity: 1; - background-color: rgb(56 56 56 / var(--tw-bg-opacity, 1)); -} - -.hover\:bg-\[\#f2f2f2\]:hover { - --tw-bg-opacity: 1; - background-color: rgb(242 242 242 / var(--tw-bg-opacity, 1)); -} - -.hover\:bg-blue-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(29 78 216 / var(--tw-bg-opacity, 1)); +.focus-within\:border-blue-500:focus-within { + --tw-border-opacity: 1; + border-color: rgb(59 130 246 / var(--tw-border-opacity, 1)); } .hover\:bg-gray-200:hover { @@ -936,17 +850,19 @@ body { background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1)); } -.hover\:text-blue-800:hover { +.hover\:bg-gray-300:hover { + --tw-bg-opacity: 1; + background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1)); +} + +.hover\:text-red-500:hover { --tw-text-opacity: 1; - color: rgb(30 64 175 / var(--tw-text-opacity, 1)); + color: rgb(239 68 68 / var(--tw-text-opacity, 1)); } -.hover\:underline:hover { - text-decoration-line: underline; -} - -.hover\:underline-offset-4:hover { - text-underline-offset: 4px; +.focus\:border-blue-500:focus { + --tw-border-opacity: 1; + border-color: rgb(59 130 246 / var(--tw-border-opacity, 1)); } .focus\:outline-none:focus { @@ -965,51 +881,3 @@ body { --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity, 1)); } -@media (min-width: 640px) { - .sm\:h-12 { - height: 3rem; - } - - .sm\:min-w-44 { - min-width: 11rem; - } - - .sm\:flex-row { - flex-direction: row; - } - - .sm\:items-start { - align-items: flex-start; - } - - .sm\:p-20 { - padding: 5rem; - } - - .sm\:px-5 { - padding-left: 1.25rem; - padding-right: 1.25rem; - } - - .sm\:text-base { - font-size: 1rem; - line-height: 1.5rem; - } -} - -@media (prefers-color-scheme: dark) { - .dark\:border-white\/\[\.145\] { - border-color: rgb(255 255 255 / .145); - } - - .dark\:hover\:bg-\[\#1a1a1a\]:hover { - --tw-bg-opacity: 1; - background-color: rgb(26 26 26 / var(--tw-bg-opacity, 1)); - } - - .dark\:hover\:bg-\[\#ccc\]:hover { - --tw-bg-opacity: 1; - background-color: rgb(204 204 204 / var(--tw-bg-opacity, 1)); - } -} - diff --git a/assets/scripts/dashboard.js b/assets/scripts/dashboard.js new file mode 100644 index 0000000..dba54cc --- /dev/null +++ b/assets/scripts/dashboard.js @@ -0,0 +1,139 @@ +document.addEventListener('DOMContentLoaded', () => { + const navLinks = document.querySelectorAll('.nav-link'); + const logoutButton = document.querySelector('.logout-button'); + const tabHeader = document.getElementById('tab-header'); + const tabContent = document.getElementById('tab-content'); + const componentsDirectory = 'assets/components/'; + + // Track open tabs + const openTabs = new Map(); + + // Handle navigation links + navLinks.forEach((link) => { + link.addEventListener('click', async (event) => { + event.preventDefault(); + + const fileName = link.dataset.file; + const tabName = fileName.replace('.html', ''); + + // Check if the tab is already open + if (openTabs.has(tabName)) { + // If the tab is already open, activate it + activateTab(tabName); + return; + } + + // Remove placeholder if it's the first tab + const placeholderTab = document.querySelector('.placeholder-tab'); + const placeholderContent = document.querySelector('.placeholder-content'); + if (placeholderTab) placeholderTab.remove(); + if (placeholderContent) placeholderContent.remove(); + + // Create a new tab + const newTab = document.createElement('div'); + newTab.className = 'flex items-center space-x-2 py-2 px-4 border-b-2 border-transparent cursor-pointer'; + newTab.id = `tab-${tabName}`; + + // Tab name (acts as a button) + const tabLabel = document.createElement('button'); + tabLabel.className = 'focus:outline-none'; + tabLabel.textContent = tabName; + + // Switch to this tab when clicked + tabLabel.addEventListener('click', () => { + activateTab(tabName); + }); + + // Close button + const closeButton = document.createElement('button'); + closeButton.className = 'text-gray-400 hover:text-red-500 focus:outline-none'; + closeButton.textContent = 'X'; + closeButton.title = 'Close Tab'; + + // Close tab logic + closeButton.addEventListener('click', () => { + // Remove tab and content + newTab.remove(); + const relatedContent = document.getElementById(`content-${tabName}`); + if (relatedContent) relatedContent.remove(); + + // Remove from openTabs tracker + openTabs.delete(tabName); + + // If no tabs are open, show placeholder + if (openTabs.size === 0) { + const placeholder = document.createElement('div'); + placeholder.className = 'flex items-center space-x-2 placeholder-tab'; + //placeholder.innerHTML = 'Placeholder'; + tabHeader.appendChild(placeholder); + + const placeholderContent = document.createElement('p'); + placeholderContent.className = 'placeholder-content'; + placeholderContent.textContent = + 'This is the placeholder content. Click a link from the navbar to replace this content.'; + tabContent.appendChild(placeholderContent); + } + }); + + newTab.appendChild(tabLabel); + newTab.appendChild(closeButton); + tabHeader.appendChild(newTab); + + // Create content for the new tab + const newContent = document.createElement('div'); + newContent.id = `content-${tabName}`; + newContent.className = 'tab-content-item hidden'; + + // Load content from the file + try { + const response = await fetch(componentsDirectory + fileName); + if (!response.ok) { + throw new Error(`Failed to load ${fileName}`); + } + newContent.innerHTML = await response.text(); + } catch (error) { + newContent.innerHTML = `

Error loading content: ${error.message}

`; + } + + tabContent.appendChild(newContent); + + // Hide other contents and show this one + activateTab(tabName); + + // Track the open tab + openTabs.set(tabName, newTab); + }); + }); + + // Activate a tab and show its content + function activateTab(tabName) { + // Deactivate all tabs + document.querySelectorAll('#tab-header > div').forEach((tab) => { + tab.classList.remove('border-blue-500'); + tab.classList.add('border-transparent'); + }); + + // Hide all content + document.querySelectorAll('.tab-content-item').forEach((content) => { + content.classList.add('hidden'); + }); + + // Activate the current tab + const activeTab = document.getElementById(`tab-${tabName}`); + const activeContent = document.getElementById(`content-${tabName}`); + if (activeTab && activeContent) { + activeTab.classList.add('border-blue-500'); + activeTab.classList.remove('border-transparent'); + activeContent.classList.remove('hidden'); + } + } + + // Handle logout button separately + logoutButton.addEventListener('click', (event) => { + event.preventDefault(); + alert('You have been logged out.'); + // Uncomment the following line to redirect to a login page + // window.location.href = '/login'; + }); + }); + \ No newline at end of file diff --git a/assets/scripts/login.js b/assets/scripts/login.js new file mode 100644 index 0000000..9375baf --- /dev/null +++ b/assets/scripts/login.js @@ -0,0 +1,10 @@ +function login() { + const username = document.getElementById('username').value; + const password = document.getElementById('password').value; + + if (username && password) { + alert(`Logging in with\nUsername: ${username}\nPassword: ${password}`); + } else { + alert('Please fill in both fields.'); + } +} diff --git a/views/dashboard.html b/views/dashboard.html new file mode 100644 index 0000000..0eea89b --- /dev/null +++ b/views/dashboard.html @@ -0,0 +1,42 @@ + + + + + Bookholder + + + + + +
+ +
+

Bookholder

+ +
+ + +
+ +
+
+ +
+
+ + +
+

This is the placeholder content. Click a link from the navbar to replace + this content.

+
+
+
+ + + + \ No newline at end of file diff --git a/views/index.html b/views/index.html index c4a3065..b6b707f 100644 --- a/views/index.html +++ b/views/index.html @@ -1,72 +1,47 @@ - - Bookholder - - - -
- -

Bookholder

- -
-
- - -
-
- - -
-
- - -
-
-
- + - if (username && password) { - alert(`Logging in with\nUsername: ${username}\nPassword: ${password}`); - } else { - alert('Please fill in both fields.'); - } - } + +
+

Bookholder

- function register() { +
+
+ + +
+
+ + +
+
+ + + +
+
+
+ - + } + + + \ No newline at end of file