Added auth menu

This commit is contained in:
xeovalyte 2024-09-20 08:22:15 +02:00
parent 4ca0661efa
commit ba7b6399e1
Signed by: xeovalyte
SSH Key Fingerprint: SHA256:kSQDrQDmKzljJzfGYcd3m9RqHi4h8rSwkZ3sQ9kBURo
6 changed files with 490 additions and 13 deletions

View File

@ -755,6 +755,20 @@ html {
}
@media (hover:hover) {
.label a:hover {
--tw-text-opacity: 1;
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
}
.tab:hover {
--tw-text-opacity: 1;
}
.tabs-boxed :is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):hover, .tabs-boxed :is(input:checked):hover {
--tw-text-opacity: 1;
color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));
}
.table tr.hover:hover,
.table tr.hover:nth-child(even):hover {
--tw-bg-opacity: 1;
@ -838,6 +852,25 @@ html {
outline-offset: 2px;
}
.card-body {
display: flex;
flex: 1 1 auto;
flex-direction: column;
padding: var(--padding-card, 2rem);
gap: 0.5rem;
}
.card-body :where(p) {
flex-grow: 1;
}
.card-actions {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 0.5rem;
}
.card figure {
display: flex;
align-items: center;
@ -1007,6 +1040,13 @@ html {
--tw-scale-y: 1;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.tab[disabled],
.tab[disabled]:hover {
cursor: not-allowed;
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
--tw-text-opacity: 0.2;
}
}
.dropdown:is(details) summary::-webkit-details-marker {
@ -1067,6 +1107,24 @@ html {
animation: button-pop var(--animation-btn, 0.25s) ease-out;
}
.form-control {
display: flex;
flex-direction: column;
}
.label {
display: flex;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
align-items: center;
justify-content: space-between;
padding-left: 0.25rem;
padding-right: 0.25rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.input {
flex-shrink: 1;
-webkit-appearance: none;
@ -1196,6 +1254,72 @@ html {
min-width: 4rem;
}
.tabs {
display: grid;
align-items: flex-end;
}
.tabs-lifted:has(.tab-content[class^="rounded-"])
.tab:first-child:not(:is(.tab-active, [aria-selected="true"])), .tabs-lifted:has(.tab-content[class*=" rounded-"])
.tab:first-child:not(:is(.tab-active, [aria-selected="true"])) {
border-bottom-color: transparent;
}
.tab {
position: relative;
grid-row-start: 1;
display: inline-flex;
height: 2rem;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
flex-wrap: wrap;
align-items: center;
justify-content: center;
text-align: center;
font-size: 0.875rem;
line-height: 1.25rem;
line-height: 2;
--tab-padding: 1rem;
--tw-text-opacity: 0.5;
--tab-color: var(--fallback-bc,oklch(var(--bc)/1));
--tab-bg: var(--fallback-b1,oklch(var(--b1)/1));
--tab-border-color: var(--fallback-b3,oklch(var(--b3)/1));
color: var(--tab-color);
padding-inline-start: var(--tab-padding, 1rem);
padding-inline-end: var(--tab-padding, 1rem);
}
.tab:is(input[type="radio"]) {
width: auto;
border-bottom-right-radius: 0px;
border-bottom-left-radius: 0px;
}
.tab:is(input[type="radio"]):after {
--tw-content: attr(aria-label);
content: var(--tw-content);
}
.tab:not(input):empty {
cursor: default;
grid-column-start: span 9999;
}
:checked + .tab-content:nth-child(2),
:is(.tab-active, [aria-selected="true"]) + .tab-content:nth-child(2) {
border-start-start-radius: 0px;
}
input.tab:checked + .tab-content,
:is(.tab-active, [aria-selected="true"]) + .tab-content {
display: block;
}
.table {
position: relative;
width: 100%;
@ -1239,6 +1363,11 @@ html {
--tw-text-opacity: 0.2;
}
.btm-nav > * .label {
font-size: 1rem;
line-height: 1.5rem;
}
@media (prefers-reduced-motion: no-preference) {
.btn {
animation: button-pop var(--animation-btn, 0.25s) ease-out;
@ -1472,6 +1601,13 @@ html {
--tw-text-opacity: 0.2;
}
.label-text {
font-size: 0.875rem;
line-height: 1.25rem;
--tw-text-opacity: 1;
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
}
.input input {
--tw-bg-opacity: 1;
background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));
@ -1487,6 +1623,10 @@ html {
line-height: 1em;
}
.input-bordered {
border-color: var(--fallback-bc,oklch(var(--bc)/0.2));
}
.input:focus,
.input:focus-within {
box-shadow: none;
@ -1782,6 +1922,140 @@ html {
color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));
}
.tabs-lifted > .tab:focus-visible {
border-end-end-radius: 0;
border-end-start-radius: 0;
}
.tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]), .tab:is(input:checked) {
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
--tw-border-opacity: 1;
--tw-text-opacity: 1;
}
.tab:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
.tab:focus-visible {
outline: 2px solid currentColor;
outline-offset: -5px;
}
.tab-disabled,
.tab[disabled] {
cursor: not-allowed;
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
--tw-text-opacity: 0.2;
}
.tabs-bordered > .tab {
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
--tw-border-opacity: 0.2;
border-style: solid;
border-bottom-width: calc(var(--tab-border, 1px) + 1px);
}
.tabs-lifted > .tab {
border: var(--tab-border, 1px) solid transparent;
border-width: 0 0 var(--tab-border, 1px) 0;
border-start-start-radius: var(--tab-radius, 0.5rem);
border-start-end-radius: var(--tab-radius, 0.5rem);
border-bottom-color: var(--tab-border-color);
padding-inline-start: var(--tab-padding, 1rem);
padding-inline-end: var(--tab-padding, 1rem);
padding-top: var(--tab-border, 1px);
}
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]), .tabs-lifted > .tab:is(input:checked) {
background-color: var(--tab-bg);
border-width: var(--tab-border, 1px) var(--tab-border, 1px) 0 var(--tab-border, 1px);
border-inline-start-color: var(--tab-border-color);
border-inline-end-color: var(--tab-border-color);
border-top-color: var(--tab-border-color);
padding-inline-start: calc(var(--tab-padding, 1rem) - var(--tab-border, 1px));
padding-inline-end: calc(var(--tab-padding, 1rem) - var(--tab-border, 1px));
padding-bottom: var(--tab-border, 1px);
padding-top: 0;
}
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked):before {
z-index: 1;
content: "";
display: block;
position: absolute;
width: calc(100% + var(--tab-radius, 0.5rem) * 2);
height: var(--tab-radius, 0.5rem);
bottom: 0;
background-size: var(--tab-radius, 0.5rem);
background-position: top left,
top right;
background-repeat: no-repeat;
--tab-grad: calc(69% - var(--tab-border, 1px));
--radius-start: radial-gradient(
circle at top left,
transparent var(--tab-grad),
var(--tab-border-color) calc(var(--tab-grad) + 0.25px),
var(--tab-border-color) calc(var(--tab-grad) + var(--tab-border, 1px)),
var(--tab-bg) calc(var(--tab-grad) + var(--tab-border, 1px) + 0.25px)
);
--radius-end: radial-gradient(
circle at top right,
transparent var(--tab-grad),
var(--tab-border-color) calc(var(--tab-grad) + 0.25px),
var(--tab-border-color) calc(var(--tab-grad) + var(--tab-border, 1px)),
var(--tab-bg) calc(var(--tab-grad) + var(--tab-border, 1px) + 0.25px)
);
background-image: var(--radius-start), var(--radius-end);
}
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):first-child:before, .tabs-lifted > .tab:is(input:checked):first-child:before {
background-image: var(--radius-end);
background-position: top right;
}
[dir="rtl"] .tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):first-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):first-child:before {
background-image: var(--radius-start);
background-position: top left;
}
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):last-child:before, .tabs-lifted > .tab:is(input:checked):last-child:before {
background-image: var(--radius-start);
background-position: top left;
}
[dir="rtl"] .tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):last-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):last-child:before {
background-image: var(--radius-end);
background-position: top right;
}
.tabs-lifted
> :is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled])
+ .tabs-lifted
:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked) + .tabs-lifted .tab:is(input:checked):before {
background-image: var(--radius-end);
background-position: top right;
}
.tabs-boxed {
border-radius: var(--rounded-btn, 0.5rem);
--tw-bg-opacity: 1;
background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
padding: 0.25rem;
}
.tabs-boxed .tab {
border-radius: var(--rounded-btn, 0.5rem);
}
.tabs-boxed :is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]), .tabs-boxed :is(input:checked) {
--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)));
}
.table:where([dir="rtl"], [dir="rtl"] *) {
text-align: right;
}
@ -1915,10 +2189,52 @@ html {
grid-template-rows: repeat(1, minmax(0, 1fr));
}
.tabs-md :where(.tab) {
height: 2rem;
font-size: 0.875rem;
line-height: 1.25rem;
line-height: 2;
--tab-padding: 1rem;
}
.tabs-lg :where(.tab) {
height: 3rem;
font-size: 1.125rem;
line-height: 1.75rem;
line-height: 2;
--tab-padding: 1.25rem;
}
.tabs-sm :where(.tab) {
height: 1.5rem;
font-size: 0.875rem;
line-height: .75rem;
--tab-padding: 0.75rem;
}
.tabs-xs :where(.tab) {
height: 1.25rem;
font-size: 0.75rem;
line-height: .75rem;
--tab-padding: 0.5rem;
}
.card-compact .card-body {
padding: 1rem;
font-size: 0.875rem;
line-height: 1.25rem;
}
.card-compact .card-title {
margin-bottom: 0.25rem;
}
.card-normal .card-body {
padding: var(--padding-card, 2rem);
font-size: 1rem;
line-height: 1.5rem;
}
.card-normal .card-title {
margin-bottom: 0.75rem;
}
@ -1999,6 +2315,10 @@ html {
margin-bottom: 0.25rem;
}
.mb-10 {
margin-bottom: 2.5rem;
}
.mb-5 {
margin-bottom: 1.25rem;
}
@ -2007,10 +2327,18 @@ html {
margin-top: 2.5rem;
}
.mt-20 {
margin-top: 5rem;
}
.mt-5 {
margin-top: 1.25rem;
}
.mt-8 {
margin-top: 2rem;
}
.flex {
display: flex;
}
@ -2126,6 +2454,11 @@ html {
background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
}
.bg-base-300 {
--tw-bg-opacity: 1;
background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)));
}
.p-5 {
padding: 1.25rem;
}
@ -2154,6 +2487,15 @@ html {
padding-bottom: 2.5rem;
}
.text-center {
text-align: center;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
@ -2172,6 +2514,12 @@ html {
color: var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity)));
}
.shadow-xl {
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}

View File

@ -1,3 +1,39 @@
pub mod auth;
pub mod icons;
pub mod navbar;
pub mod topbar;
use crate::Route;
use auth::Auth;
use dioxus::prelude::*;
#[component]
pub fn Global() -> Element {
let user = use_resource(get_user_from_cookie);
use_context_provider(|| user);
rsx! {
match &*user.read_unchecked() {
Some(Ok(_)) => rsx! {
crate::components::layout::topbar::Topbar {}
main {
class: "h-full overflow-y-auto",
Outlet::<Route> {}
}
crate::components::layout::navbar::Navbar {}
},
Some(Err(_)) => rsx! {
Auth { }
},
None => rsx! {
div { "Loading..." }
}
}
}
}
#[server]
async fn get_user_from_cookie() -> Result<(), ServerFnError> {
Err(ServerFnError::new("Not authenticated"))
}

View File

@ -0,0 +1,102 @@
use dioxus::prelude::*;
pub fn Auth() -> Element {
let mut register = use_signal(|| false);
rsx! {
div {
class: "flex flex-col items-center",
h1 { class: "font-bold text-primary text-center text-2xl mt-20", "Waddinxveense Reddingsbrigade" },
div {
class: "card bg-base-200 mt-20 w-full max-w-lg shadow-xl",
div {
class: "card-body",
div {
role: "tablist",
class: "tabs tabs-boxed bg-base-300 mx-auto w-full mb-10",
button {
onclick: move |_| register.set(false),
role: "tab",
class: "tab",
class: if !register() { "tab-active" },
"Inloggen"
},
button {
onclick: move |_| register.set(true),
role: "tab",
class: "tab",
class: if register() { "tab-active" },
"Registreren"
},
}
if !register() {
Login { }
} else {
Register { }
}
}
}
}
}
}
fn Login() -> Element {
rsx! {
form {
label {
class: "form-control w-full",
div {
class: "label",
span { class: "label-text", "Email" },
}
input {
r#type: "email",
class: "input input-bordered w-full",
},
}
label {
class: "form-control w-full mt-5",
div {
class: "label",
span { class: "label-text", "Password" },
}
input {
r#type: "password",
class: "input input-bordered w-full",
},
}
div {
class: "card-actions mt-8",
button {
class: "btn btn-wide btn-primary",
"Inloggen"
}
}
}
}
}
fn Register() -> Element {
rsx! {
form {
label {
class: "form-control w-full",
div {
class: "label",
span { class: "label-text", "Registratie code" },
}
input {
r#type: "text",
class: "input input-bordered w-full",
},
}
div {
class: "card-actions mt-8",
button {
class: "btn btn-primary",
"Registreren"
}
}
}
}
}

View File

@ -10,12 +10,13 @@ use tracing::Level;
use components::admin::members::migration::Migration;
use components::agenda::Agenda;
use components::home::Home;
use components::layout::Global;
use components::news::News;
use components::settings::Settings;
#[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Route {
#[layout(Wrapper)]
#[layout(Global)]
#[route("/")]
Home {},
#[route("/agenda")]
@ -67,18 +68,6 @@ fn main() {
launch(App);
}
#[component]
fn Wrapper() -> Element {
rsx! {
components::layout::topbar::Topbar {}
main {
class: "h-full overflow-y-auto",
Outlet::<Route> {}
}
components::layout::navbar::Navbar {}
}
}
fn App() -> Element {
rsx! {
div {

View File

@ -1 +1,2 @@
pub mod member;
pub mod user;

1
src/util/model/user.rs Normal file
View File

@ -0,0 +1 @@