From 0177c078331cbaf54101a25c900168cf9e7f6a2b Mon Sep 17 00:00:00 2001 From: xeovalyte Date: Thu, 18 Jul 2024 17:12:27 +0200 Subject: [PATCH] Changed topbar and added navbar --- assets/tailwind.css | 295 ++++++++++++++++++++++++++++++++ src/components/layout.rs | 1 + src/components/layout/icons.rs | 82 +++++++++ src/components/layout/navbar.rs | 30 ++++ src/components/layout/topbar.rs | 15 +- src/main.rs | 21 ++- 6 files changed, 439 insertions(+), 5 deletions(-) create mode 100644 src/components/layout/icons.rs diff --git a/assets/tailwind.css b/assets/tailwind.css index adab8e1..d7ea035 100644 --- a/assets/tailwind.css +++ b/assets/tailwind.css @@ -754,6 +754,133 @@ html { --tw-contain-style: ; } +.btn { + display: inline-flex; + height: 3rem; + min-height: 3rem; + flex-shrink: 0; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + flex-wrap: wrap; + align-items: center; + justify-content: center; + border-radius: var(--rounded-btn, 0.5rem); + border-color: transparent; + border-color: oklch(var(--btn-color, var(--b2)) / var(--tw-border-opacity)); + padding-left: 1rem; + padding-right: 1rem; + text-align: center; + font-size: 0.875rem; + line-height: 1em; + gap: 0.5rem; + font-weight: 600; + text-decoration-line: none; + transition-duration: 200ms; + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); + border-width: var(--border-btn, 1px); + transition-property: color, background-color, border-color, opacity, box-shadow, transform; + --tw-text-opacity: 1; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + outline-color: var(--fallback-bc,oklch(var(--bc)/1)); + background-color: oklch(var(--btn-color, var(--b2)) / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + --tw-border-opacity: 1; +} + +.btn-disabled, + .btn[disabled], + .btn:disabled { + pointer-events: none; +} + +.btn-square { + height: 3rem; + width: 3rem; + padding: 0px; +} + +:where(.btn:is(input[type="checkbox"])), +:where(.btn:is(input[type="radio"])) { + width: auto; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.btn:is(input[type="checkbox"]):after, +.btn:is(input[type="radio"]):after { + --tw-content: attr(aria-label); + content: var(--tw-content); +} + +@media (hover: hover) { + .btn:hover { + --tw-border-opacity: 1; + border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity))); + --tw-bg-opacity: 1; + background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity))); + } + + @supports (color: color-mix(in oklab, black, black)) { + .btn:hover { + background-color: color-mix( + in oklab, + oklch(var(--btn-color, var(--b2)) / var(--tw-bg-opacity, 1)) 90%, + black + ); + border-color: color-mix( + in oklab, + oklch(var(--btn-color, var(--b2)) / var(--tw-border-opacity, 1)) 90%, + black + ); + } + } + + @supports not (color: oklch(0% 0 0)) { + .btn:hover { + background-color: var(--btn-color, var(--fallback-b2)); + border-color: var(--btn-color, var(--fallback-b2)); + } + } + + .btn.glass:hover { + --glass-opacity: 25%; + --glass-border-opacity: 15%; + } + + .btn-ghost:hover { + border-color: transparent; + } + + @supports (color: oklch(0% 0 0)) { + .btn-ghost:hover { + background-color: var(--fallback-bc,oklch(var(--bc)/0.2)); + } + } + + .btn-disabled:hover, + .btn[disabled]:hover, + .btn:disabled:hover { + --tw-border-opacity: 0; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + --tw-bg-opacity: 0.2; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); + --tw-text-opacity: 0.2; + } + + @supports (color: color-mix(in oklab, black, black)) { + .btn:is(input[type="checkbox"]:checked):hover, .btn:is(input[type="radio"]:checked):hover { + background-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); + border-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); + } + } +} + .navbar { display: flex; align-items: center; @@ -767,6 +894,83 @@ html { align-items: center; } +@media (prefers-reduced-motion: no-preference) { + .btn { + animation: button-pop var(--animation-btn, 0.25s) ease-out; + } +} + +.btn:active:hover, + .btn:active:focus { + animation: button-pop 0s ease-out; + transform: scale(var(--btn-focus-scale, 0.97)); +} + +@supports not (color: oklch(0% 0 0)) { + .btn { + background-color: var(--btn-color, var(--fallback-b2)); + border-color: var(--btn-color, var(--fallback-b2)); + } +} + +.btn:focus-visible { + outline-style: solid; + outline-width: 2px; + outline-offset: 2px; +} + +.btn.glass { + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + outline-color: currentColor; +} + +.btn.glass.btn-active { + --glass-opacity: 25%; + --glass-border-opacity: 15%; +} + +.btn-ghost { + border-width: 1px; + border-color: transparent; + background-color: transparent; + color: currentColor; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + outline-color: currentColor; +} + +.btn-ghost.btn-active { + border-color: transparent; + background-color: var(--fallback-bc,oklch(var(--bc)/0.2)); +} + +.btn.btn-disabled, + .btn[disabled], + .btn:disabled { + --tw-border-opacity: 0; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + --tw-bg-opacity: 0.2; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); + --tw-text-opacity: 0.2; +} + +.btn:is(input[type="checkbox"]:checked), +.btn:is(input[type="radio"]:checked) { + --tw-border-opacity: 1; + border-color: var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity))); + --tw-bg-opacity: 1; + background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); +} + +.btn:is(input[type="checkbox"]:checked):focus-visible, .btn:is(input[type="radio"]:checked):focus-visible { + outline-color: var(--fallback-p,oklch(var(--p)/1)); +} + @keyframes button-pop { 0% { transform: scale(var(--btn-focus-scale, 0.98)); @@ -795,6 +999,10 @@ html { } } +.join > :where(*:not(:first-child)):is(.btn) { + margin-inline-start: calc(var(--border-btn) * -1); +} + @keyframes modal-pop { 0% { opacity: 0; @@ -860,6 +1068,64 @@ html { } } +.btn-square:where(.btn-xs) { + height: 1.5rem; + width: 1.5rem; + padding: 0px; +} + +.btn-square:where(.btn-sm) { + height: 2rem; + width: 2rem; + padding: 0px; +} + +.btn-square:where(.btn-md) { + height: 3rem; + width: 3rem; + padding: 0px; +} + +.btn-square:where(.btn-lg) { + height: 4rem; + width: 4rem; + padding: 0px; +} + +.join.join-vertical > :where(*:not(:first-child)):is(.btn) { + margin-top: calc(var(--border-btn) * -1); +} + +.join.join-horizontal > :where(*:not(:first-child)):is(.btn) { + margin-inline-start: calc(var(--border-btn) * -1); +} + +.flex { + display: flex; +} + +.size-8 { + width: 2rem; + height: 2rem; +} + +.h-full { + height: 100%; +} + +.h-max { + height: -moz-max-content; + height: max-content; +} + +.h-screen { + height: 100vh; +} + +.min-h-16 { + min-height: 4rem; +} + .flex-1 { flex: 1 1 0%; } @@ -868,6 +1134,26 @@ html { flex: none; } +.flex-col { + flex-direction: column; +} + +.flex-nowrap { + flex-wrap: nowrap; +} + +.items-center { + align-items: center; +} + +.justify-around { + justify-content: space-around; +} + +.gap-1 { + gap: 0.25rem; +} + .gap-2 { gap: 0.5rem; } @@ -882,6 +1168,11 @@ html { padding-right: 0.75rem; } +.py-1 { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + .text-xl { font-size: 1.25rem; line-height: 1.75rem; @@ -891,6 +1182,10 @@ html { font-weight: 700; } +.font-normal { + font-weight: 400; +} + .text-primary { --tw-text-opacity: 1; color: var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity))); diff --git a/src/components/layout.rs b/src/components/layout.rs index f6839f1..4e19c48 100644 --- a/src/components/layout.rs +++ b/src/components/layout.rs @@ -1,2 +1,3 @@ +pub mod icons; pub mod navbar; pub mod topbar; diff --git a/src/components/layout/icons.rs b/src/components/layout/icons.rs new file mode 100644 index 0000000..a04a326 --- /dev/null +++ b/src/components/layout/icons.rs @@ -0,0 +1,82 @@ +use dioxus::prelude::*; + +#[component] +pub fn Home() -> Element { + rsx! { + svg { + "viewBox": "0 0 24 24", + "stroke-width": "1.5", + "xmlns": "http://www.w3.org/2000/svg", + "stroke": "currentColor", + "fill": "none", + class: "size-8", + path { + "stroke-linejoin": "round", + "stroke-linecap": "round", + "d": "m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" + } + } + } +} + +#[component] +pub fn Newspaper() -> Element { + rsx! { + svg { + "stroke": "currentColor", + "viewBox": "0 0 24 24", + "fill": "none", + "xmlns": "http://www.w3.org/2000/svg", + "stroke-width": "1.5", + class: "size-8", + path { + "stroke-linecap": "round", + "stroke-linejoin": "round", + "d": "M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 0 1-2.25 2.25M16.5 7.5V18a2.25 2.25 0 0 0 2.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 0 0 2.25 2.25h13.5M6 7.5h3v3H6v-3Z" + } + } + } +} + +#[component] +pub fn Calendar() -> Element { + rsx! { + svg { + "stroke": "currentColor", + "xmlns": "http://www.w3.org/2000/svg", + "viewBox": "0 0 24 24", + "fill": "none", + "stroke-width": "1.5", + class: "size-8", + path { + "stroke-linejoin": "round", + "stroke-linecap": "round", + "d": "M6.75 2.994v2.25m10.5-2.25v2.25m-14.252 13.5V7.491a2.25 2.25 0 0 1 2.25-2.25h13.5a2.25 2.25 0 0 1 2.25 2.25v11.251m-18 0a2.25 2.25 0 0 0 2.25 2.25h13.5a2.25 2.25 0 0 0 2.25-2.25m-18 0v-7.5a2.25 2.25 0 0 1 2.25-2.25h13.5a2.25 2.25 0 0 1 2.25 2.25v7.5m-6.75-6h2.25m-9 2.25h4.5m.002-2.25h.005v.006H12v-.006Zm-.001 4.5h.006v.006h-.006v-.005Zm-2.25.001h.005v.006H9.75v-.006Zm-2.25 0h.005v.005h-.006v-.005Zm6.75-2.247h.005v.005h-.005v-.005Zm0 2.247h.006v.006h-.006v-.006Zm2.25-2.248h.006V15H16.5v-.005Z" + } + } + } +} + +#[component] +pub fn Cog() -> Element { + rsx! { + svg { + "stroke": "currentColor", + "fill": "none", + "xmlns": "http://www.w3.org/2000/svg", + "viewBox": "0 0 24 24", + "stroke-width": "1.5", + class: "size-8", + path { + "d": "M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z", + "stroke-linecap": "round", + "stroke-linejoin": "round" + } + path { + "stroke-linecap": "round", + "stroke-linejoin": "round", + "d": "M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" + } + } + } +} diff --git a/src/components/layout/navbar.rs b/src/components/layout/navbar.rs index 8b13789..0daeedf 100644 --- a/src/components/layout/navbar.rs +++ b/src/components/layout/navbar.rs @@ -1 +1,31 @@ +use dioxus::prelude::*; +use super::icons; +use crate::Route; + +#[component] +pub fn Navbar() -> Element { + rsx! { + div { + class: "bg-base-200 min-h-16 flex items-center justify-around", + Link { + to: Route::Home {}, + class: "btn btn-ghost flex-col flex-nowrap py-1 gap-1 font-normal h-max", + icons::Home {}, + "Home" + }, + Link { + to: Route::Home {}, + class: "btn btn-ghost flex-col flex-nowrap py-1 gap-1 font-normal h-max", + icons::Newspaper {}, + div { class: "font-normal", "Nieuws" } + }, + Link { + to: Route::Home {}, + class: "btn btn-ghost flex-col flex-nowrap py-1 gap-1 font-normal h-max", + icons::Calendar {}, + span { class: "font-normal", "Agenda" } + }, + } + } +} diff --git a/src/components/layout/topbar.rs b/src/components/layout/topbar.rs index 2fb5fda..6522774 100644 --- a/src/components/layout/topbar.rs +++ b/src/components/layout/topbar.rs @@ -1,5 +1,8 @@ +use crate::Route; use dioxus::prelude::*; +use super::icons; + #[component] pub fn Topbar() -> Element { rsx! { @@ -11,8 +14,16 @@ pub fn Topbar() -> Element { } div { class: "flex-none gap-2", - span { "Admin" } - span { "Settings" } + Link { + class: "btn btn-ghost font-normal", + to: Route::Home {}, + "Administration" + } + Link { + class: "btn btn-square btn-ghost", + to: Route::Home {}, + icons::Cog {} + } } } } diff --git a/src/main.rs b/src/main.rs index ba35e20..d968510 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,8 @@ use tracing::{info, Level}; use components::home::Home; #[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)] -enum Route { +pub enum Route { + #[layout(Wrapper)] #[route("/")] Home {}, } @@ -22,9 +23,23 @@ fn main() { launch(App); } -fn App() -> Element { +#[component] +fn Wrapper() -> Element { rsx! { components::layout::topbar::Topbar {} - Router:: {} + main { + class: "h-full", + Outlet:: {} + } + components::layout::navbar::Navbar {} + } +} + +fn App() -> Element { + rsx! { + div { + class: "h-screen flex flex-col", + Router:: {} + } } }