Added change email and logout
This commit is contained in:
parent
5ca02189f4
commit
4d52d73275
@ -943,6 +943,70 @@ html {
|
||||
color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.collapse:not(td):not(tr):not(colgroup) {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.collapse {
|
||||
position: relative;
|
||||
display: grid;
|
||||
overflow: hidden;
|
||||
grid-template-rows: auto 0fr;
|
||||
transition: grid-template-rows 0.2s;
|
||||
width: 100%;
|
||||
border-radius: var(--rounded-box, 1rem);
|
||||
}
|
||||
|
||||
.collapse-title,
|
||||
.collapse > input[type="checkbox"],
|
||||
.collapse > input[type="radio"],
|
||||
.collapse-content {
|
||||
grid-column-start: 1;
|
||||
grid-row-start: 1;
|
||||
}
|
||||
|
||||
.collapse > input[type="checkbox"],
|
||||
.collapse > input[type="radio"] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.collapse-content {
|
||||
visibility: hidden;
|
||||
grid-column-start: 1;
|
||||
grid-row-start: 2;
|
||||
min-height: 0px;
|
||||
transition: visibility 0.2s;
|
||||
transition: padding 0.2s ease-out,
|
||||
background-color 0.2s ease-out;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
cursor: unset;
|
||||
}
|
||||
|
||||
.collapse[open],
|
||||
.collapse-open,
|
||||
.collapse:focus:not(.collapse-close) {
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
.collapse:not(.collapse-close):has(> input[type="checkbox"]:checked),
|
||||
.collapse:not(.collapse-close):has(> input[type="radio"]:checked) {
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
.collapse[open] > .collapse-content,
|
||||
.collapse-open > .collapse-content,
|
||||
.collapse:focus:not(.collapse-close) > .collapse-content,
|
||||
.collapse:not(.collapse-close) > input[type="checkbox"]:checked ~ .collapse-content,
|
||||
.collapse:not(.collapse-close) > input[type="radio"]:checked ~ .collapse-content {
|
||||
visibility: visible;
|
||||
min-height: -moz-fit-content;
|
||||
min-height: fit-content;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
@ -1039,6 +1103,15 @@ html {
|
||||
}
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-b1,oklch(var(--b1)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-primary:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));
|
||||
@ -1051,6 +1124,78 @@ html {
|
||||
}
|
||||
}
|
||||
|
||||
.btn-outline.btn-secondary:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in oklab, black, black)) {
|
||||
.btn-outline.btn-secondary:hover {
|
||||
background-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-outline.btn-accent:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in oklab, black, black)) {
|
||||
.btn-outline.btn-accent:hover {
|
||||
background-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-outline.btn-success:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in oklab, black, black)) {
|
||||
.btn-outline.btn-success:hover {
|
||||
background-color: color-mix(in oklab, var(--fallback-su,oklch(var(--su)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-su,oklch(var(--su)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-outline.btn-info:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in oklab, black, black)) {
|
||||
.btn-outline.btn-info:hover {
|
||||
background-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-outline.btn-warning:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in oklab, black, black)) {
|
||||
.btn-outline.btn-warning:hover {
|
||||
background-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-outline.btn-error:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in oklab, black, black)) {
|
||||
.btn-outline.btn-error:hover {
|
||||
background-color: color-mix(in oklab, var(--fallback-er,oklch(var(--er)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-er,oklch(var(--er)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-disabled:hover,
|
||||
.btn[disabled]:hover,
|
||||
.btn:disabled:hover {
|
||||
@ -1395,6 +1540,30 @@ input.tab:checked + .tab-content,
|
||||
background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
|
||||
}
|
||||
|
||||
.toggle {
|
||||
flex-shrink: 0;
|
||||
--tglbg: var(--fallback-b1,oklch(var(--b1)/1));
|
||||
--handleoffset: 1.5rem;
|
||||
--handleoffsetcalculator: calc(var(--handleoffset) * -1);
|
||||
--togglehandleborder: 0 0;
|
||||
height: 1.5rem;
|
||||
width: 3rem;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border-radius: var(--rounded-badge, 1.9rem);
|
||||
border-width: 1px;
|
||||
border-color: currentColor;
|
||||
background-color: currentColor;
|
||||
color: var(--fallback-bc,oklch(var(--bc)/0.5));
|
||||
transition: background,
|
||||
box-shadow var(--animation-input, 0.2s) ease-out;
|
||||
box-shadow: var(--handleoffsetcalculator) 0 0 2px var(--tglbg) inset,
|
||||
0 0 0 2px var(--tglbg) inset,
|
||||
var(--togglehandleborder);
|
||||
}
|
||||
|
||||
.badge-neutral {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: var(--fallback-n,oklch(var(--n)/var(--tw-border-opacity)));
|
||||
@ -1449,6 +1618,10 @@ input.tab:checked + .tab-content,
|
||||
.btn-neutral {
|
||||
--btn-color: var(--fallback-n);
|
||||
}
|
||||
|
||||
.btn-error {
|
||||
--btn-color: var(--fallback-er);
|
||||
}
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in oklab, black, black)) {
|
||||
@ -1456,6 +1629,36 @@ input.tab:checked + .tab-content,
|
||||
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);
|
||||
}
|
||||
|
||||
.btn-outline.btn-secondary.btn-active {
|
||||
background-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black);
|
||||
}
|
||||
|
||||
.btn-outline.btn-accent.btn-active {
|
||||
background-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black);
|
||||
}
|
||||
|
||||
.btn-outline.btn-success.btn-active {
|
||||
background-color: color-mix(in oklab, var(--fallback-su,oklch(var(--su)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-su,oklch(var(--su)/1)) 90%, black);
|
||||
}
|
||||
|
||||
.btn-outline.btn-info.btn-active {
|
||||
background-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black);
|
||||
}
|
||||
|
||||
.btn-outline.btn-warning.btn-active {
|
||||
background-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black);
|
||||
}
|
||||
|
||||
.btn-outline.btn-error.btn-active {
|
||||
background-color: color-mix(in oklab, var(--fallback-er,oklch(var(--er)/1)) 90%, black);
|
||||
border-color: color-mix(in oklab, var(--fallback-er,oklch(var(--er)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.btn:focus-visible {
|
||||
@ -1478,6 +1681,10 @@ input.tab:checked + .tab-content,
|
||||
.btn-neutral {
|
||||
--btn-color: var(--n);
|
||||
}
|
||||
|
||||
.btn-error {
|
||||
--btn-color: var(--er);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-neutral {
|
||||
@ -1486,6 +1693,12 @@ input.tab:checked + .tab-content,
|
||||
outline-color: var(--fallback-n,oklch(var(--n)/1));
|
||||
}
|
||||
|
||||
.btn-error {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));
|
||||
outline-color: var(--fallback-er,oklch(var(--er)/1));
|
||||
}
|
||||
|
||||
.btn.glass {
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
@ -1514,6 +1727,25 @@ input.tab:checked + .tab-content,
|
||||
background-color: var(--fallback-bc,oklch(var(--bc)/0.2));
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
border-color: currentColor;
|
||||
background-color: transparent;
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
|
||||
--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);
|
||||
}
|
||||
|
||||
.btn-outline.btn-active {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-b1,oklch(var(--b1)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-primary {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity)));
|
||||
@ -1524,6 +1756,66 @@ input.tab:checked + .tab-content,
|
||||
color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-secondary {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-s,oklch(var(--s)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-secondary.btn-active {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-accent {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-a,oklch(var(--a)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-accent.btn-active {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-success {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-su,oklch(var(--su)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-success.btn-active {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-info {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-in,oklch(var(--in)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-info.btn-active {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-warning {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-wa,oklch(var(--wa)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-warning.btn-active {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-error {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-er,oklch(var(--er)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn-outline.btn-error.btn-active {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
.btn.btn-disabled,
|
||||
.btn[disabled],
|
||||
.btn:disabled {
|
||||
@ -1623,6 +1915,130 @@ input.tab:checked + .tab-content,
|
||||
}
|
||||
}
|
||||
|
||||
details.collapse {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
details.collapse summary {
|
||||
position: relative;
|
||||
display: block;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
details.collapse summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapse:focus-visible {
|
||||
outline-style: solid;
|
||||
outline-width: 2px;
|
||||
outline-offset: 2px;
|
||||
outline-color: var(--fallback-bc,oklch(var(--bc)/1));
|
||||
}
|
||||
|
||||
.collapse:has(.collapse-title:focus-visible),
|
||||
.collapse:has(> input[type="checkbox"]:focus-visible),
|
||||
.collapse:has(> input[type="radio"]:focus-visible) {
|
||||
outline-style: solid;
|
||||
outline-width: 2px;
|
||||
outline-offset: 2px;
|
||||
outline-color: var(--fallback-bc,oklch(var(--bc)/1));
|
||||
}
|
||||
|
||||
.collapse-arrow > .collapse-title:after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: 0.5rem;
|
||||
width: 0.5rem;
|
||||
--tw-translate-y: -100%;
|
||||
--tw-rotate: 45deg;
|
||||
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));
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
transition-duration: 0.2s;
|
||||
top: 1.9rem;
|
||||
inset-inline-end: 1.4rem;
|
||||
content: "";
|
||||
transform-origin: 75% 75%;
|
||||
box-shadow: 2px 2px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.collapse-plus > .collapse-title:after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: 0.5rem;
|
||||
width: 0.5rem;
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
top: 0.9rem;
|
||||
inset-inline-end: 1.4rem;
|
||||
content: "+";
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.collapse:not(.collapse-open):not(.collapse-close) > input[type="checkbox"],
|
||||
.collapse:not(.collapse-open):not(.collapse-close) > input[type="radio"]:not(:checked),
|
||||
.collapse:not(.collapse-open):not(.collapse-close) > .collapse-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapse:focus:not(.collapse-open):not(.collapse-close):not(.collapse[open]) > .collapse-title {
|
||||
cursor: unset;
|
||||
}
|
||||
|
||||
.collapse-title {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:where(.collapse > input[type="checkbox"]),
|
||||
:where(.collapse > input[type="radio"]) {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.collapse-title,
|
||||
:where(.collapse > input[type="checkbox"]),
|
||||
:where(.collapse > input[type="radio"]) {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
padding-inline-end: 3rem;
|
||||
min-height: 3.75rem;
|
||||
transition: background-color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.collapse[open] > :where(.collapse-content),
|
||||
.collapse-open > :where(.collapse-content),
|
||||
.collapse:focus:not(.collapse-close) > :where(.collapse-content),
|
||||
.collapse:not(.collapse-close) > :where(input[type="checkbox"]:checked ~ .collapse-content),
|
||||
.collapse:not(.collapse-close) > :where(input[type="radio"]:checked ~ .collapse-content) {
|
||||
padding-bottom: 1rem;
|
||||
transition: padding 0.2s ease-out,
|
||||
background-color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.collapse[open].collapse-arrow > .collapse-title:after,
|
||||
.collapse-open.collapse-arrow > .collapse-title:after,
|
||||
.collapse-arrow:focus:not(.collapse-close) > .collapse-title:after,
|
||||
.collapse-arrow:not(.collapse-close) > input[type="checkbox"]:checked ~ .collapse-title:after,
|
||||
.collapse-arrow:not(.collapse-close) > input[type="radio"]:checked ~ .collapse-title:after {
|
||||
--tw-translate-y: -50%;
|
||||
--tw-rotate: 225deg;
|
||||
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));
|
||||
}
|
||||
|
||||
.collapse[open].collapse-plus > .collapse-title:after,
|
||||
.collapse-open.collapse-plus > .collapse-title:after,
|
||||
.collapse-plus:focus:not(.collapse-close) > .collapse-title:after,
|
||||
.collapse-plus:not(.collapse-close) > input[type="checkbox"]:checked ~ .collapse-title:after,
|
||||
.collapse-plus:not(.collapse-close) > input[type="radio"]:checked ~ .collapse-title:after {
|
||||
content: "−";
|
||||
}
|
||||
|
||||
.dropdown.dropdown-open .dropdown-content,
|
||||
.dropdown:focus .dropdown-content,
|
||||
.dropdown:focus-within .dropdown-content {
|
||||
@ -2188,6 +2604,57 @@ input.tab:checked + .tab-content,
|
||||
}
|
||||
}
|
||||
|
||||
[dir="rtl"] .toggle {
|
||||
--handleoffsetcalculator: calc(var(--handleoffset) * 1);
|
||||
}
|
||||
|
||||
.toggle:focus-visible {
|
||||
outline-style: solid;
|
||||
outline-width: 2px;
|
||||
outline-offset: 2px;
|
||||
outline-color: var(--fallback-bc,oklch(var(--bc)/0.2));
|
||||
}
|
||||
|
||||
.toggle:hover {
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
.toggle:checked,
|
||||
.toggle[aria-checked="true"] {
|
||||
background-image: none;
|
||||
--handleoffsetcalculator: var(--handleoffset);
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
|
||||
}
|
||||
|
||||
[dir="rtl"] .toggle:checked, [dir="rtl"] .toggle[aria-checked="true"] {
|
||||
--handleoffsetcalculator: calc(var(--handleoffset) * -1);
|
||||
}
|
||||
|
||||
.toggle:indeterminate {
|
||||
--tw-text-opacity: 1;
|
||||
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
|
||||
box-shadow: calc(var(--handleoffset) / 2) 0 0 2px var(--tglbg) inset,
|
||||
calc(var(--handleoffset) / -2) 0 0 2px var(--tglbg) inset,
|
||||
0 0 0 2px var(--tglbg) inset;
|
||||
}
|
||||
|
||||
[dir="rtl"] .toggle:indeterminate {
|
||||
box-shadow: calc(var(--handleoffset) / 2) 0 0 2px var(--tglbg) inset,
|
||||
calc(var(--handleoffset) / -2) 0 0 2px var(--tglbg) inset,
|
||||
0 0 0 2px var(--tglbg) inset;
|
||||
}
|
||||
|
||||
.toggle:disabled {
|
||||
cursor: not-allowed;
|
||||
--tw-border-opacity: 1;
|
||||
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
|
||||
background-color: transparent;
|
||||
opacity: 0.3;
|
||||
--togglehandleborder: 0 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset,
|
||||
var(--handleoffsetcalculator) 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset;
|
||||
}
|
||||
|
||||
.badge-md {
|
||||
height: 1.25rem;
|
||||
font-size: 0.875rem;
|
||||
@ -2391,6 +2858,10 @@ input.tab:checked + .tab-content,
|
||||
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));
|
||||
}
|
||||
|
||||
.collapse {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
.static {
|
||||
position: static;
|
||||
}
|
||||
@ -2412,6 +2883,10 @@ input.tab:checked + .tab-content,
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.ml-auto {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.mt-10 {
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
@ -2491,6 +2966,10 @@ input.tab:checked + .tab-content,
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.max-w-2xl {
|
||||
max-width: 42rem;
|
||||
}
|
||||
|
||||
.max-w-4xl {
|
||||
max-width: 56rem;
|
||||
}
|
||||
@ -2511,6 +2990,12 @@ input.tab:checked + .tab-content,
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.select-none {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
@ -2543,10 +3028,20 @@ input.tab:checked + .tab-content,
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.gap-3 {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.gap-5 {
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.space-y-3 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.overflow-auto {
|
||||
overflow: auto;
|
||||
}
|
||||
@ -2597,10 +3092,19 @@ input.tab:checked + .tab-content,
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.py-5 {
|
||||
padding-top: 1.25rem;
|
||||
padding-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.pb-10 {
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.pl-2 {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.pt-2 {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
@ -2628,6 +3132,10 @@ input.tab:checked + .tab-content,
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.font-normal {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
@ -13,18 +13,27 @@ use dioxus::prelude::*;
|
||||
#[component]
|
||||
pub fn Global() -> Element {
|
||||
let user = use_resource(get_user_from_cookie);
|
||||
let mut user_state: Signal<Option<User>> = use_signal(|| None);
|
||||
|
||||
use_context_provider(|| user);
|
||||
use_context_provider(|| user_state);
|
||||
|
||||
use_effect(move || {
|
||||
if let Some(Ok(u)) = &*user.read_unchecked() {
|
||||
user_state.set(Some(u.clone()));
|
||||
};
|
||||
});
|
||||
|
||||
rsx! {
|
||||
match &*user.read_unchecked() {
|
||||
Some(Ok(_)) => rsx! {
|
||||
if user_state().is_some() {
|
||||
crate::components::layout::topbar::Topbar {}
|
||||
main {
|
||||
class: "h-full overflow-y-auto",
|
||||
class: "h-full overflow-y-auto flex justify-center px-2 py-5",
|
||||
Outlet::<Route> {}
|
||||
}
|
||||
crate::components::layout::navbar::Navbar {}
|
||||
}
|
||||
},
|
||||
Some(Err(_)) => rsx! {
|
||||
Auth { }
|
||||
@ -38,8 +47,7 @@ pub fn Global() -> Element {
|
||||
|
||||
#[server]
|
||||
async fn get_user_from_cookie() -> Result<User, ServerFnError> {
|
||||
let token = Session::get_token_from_cookie().await?;
|
||||
let user = Session::fetch_user_from_token(token).await?;
|
||||
let user = Session::fetch_current_user().await?;
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
|
@ -1,10 +1,158 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::util::model::{session::Session, user::User};
|
||||
|
||||
#[component]
|
||||
pub fn Settings() -> Element {
|
||||
rsx! {
|
||||
div {
|
||||
h1 { class: "text-xl font-bold text-primary", "Settings" }
|
||||
class: "w-full max-w-2xl space-y-3",
|
||||
Account {},
|
||||
Password {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn Account() -> Element {
|
||||
let user_state = use_context::<Signal<Option<User>>>();
|
||||
let user = user_state().unwrap();
|
||||
|
||||
let mut is_open = use_signal(|| false);
|
||||
let mut input_email = use_signal(|| user.email);
|
||||
|
||||
let submit = move |_| async move {
|
||||
if let Ok(_) = change_email(input_email()).await {
|
||||
tracing::info!("User email changed");
|
||||
};
|
||||
};
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
class: "collapse collapse-arrow bg-base-200",
|
||||
class: if is_open() { "collapse-open" },
|
||||
div {
|
||||
class: "collapse-title text-lg font-medium hover:cursor-pointer select-none",
|
||||
onclick: move |_| is_open.toggle(),
|
||||
"Account",
|
||||
},
|
||||
div {
|
||||
class: "collapse-content",
|
||||
div {
|
||||
class: "pl-2 flex flex-col gap-3",
|
||||
label {
|
||||
class: "form-control w-full",
|
||||
div {
|
||||
class: "label",
|
||||
span { class: "label-text", "Account ID" }
|
||||
}
|
||||
b { "{user.id}" },
|
||||
}
|
||||
label {
|
||||
class: "form-control w-full",
|
||||
div {
|
||||
class: "label",
|
||||
span { class: "label-text", "Email" }
|
||||
}
|
||||
input {
|
||||
r#type: "text",
|
||||
class: "input input-bordered w-full",
|
||||
oninput: move |event| input_email.set(event.value()),
|
||||
value: "{input_email}",
|
||||
}
|
||||
}
|
||||
div {
|
||||
class: "w-full flex mt-5",
|
||||
button {
|
||||
class: "btn btn-outline btn-error",
|
||||
onclick: move |_| async move {
|
||||
if let Ok(_) = logout().await {
|
||||
let window = web_sys::window().expect("Could not find window");
|
||||
window.location().reload().expect("Could not reload window");
|
||||
}
|
||||
},
|
||||
"Uitloggen",
|
||||
}
|
||||
button {
|
||||
class: "ml-auto btn btn-primary",
|
||||
onclick: submit,
|
||||
"Opslaan",
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[server]
|
||||
async fn logout() -> Result<(), ServerFnError> {
|
||||
let session_token = Session::get_token_from_cookie().await?;
|
||||
Session::delete_session(session_token).await?;
|
||||
Session::delete_cookie().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[server]
|
||||
async fn change_email(new_email: String) -> Result<(), ServerFnError> {
|
||||
let user = Session::fetch_current_user().await?;
|
||||
|
||||
user.change_email(new_email).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn Password() -> Element {
|
||||
let mut is_open = use_signal(|| false);
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
class: "collapse collapse-arrow bg-base-200",
|
||||
class: if is_open() { "collapse-open" },
|
||||
div {
|
||||
class: "collapse-title text-lg font-medium hover:cursor-pointer select-none",
|
||||
onclick: move |_| is_open.toggle(),
|
||||
"Wachtwoord",
|
||||
},
|
||||
div {
|
||||
class: "collapse-content",
|
||||
div {
|
||||
class: "pl-2 space-y-3",
|
||||
label {
|
||||
class: "form-control w-full",
|
||||
div {
|
||||
class: "label",
|
||||
span { class: "label-text", "Huidig wachtwoord" }
|
||||
}
|
||||
input {
|
||||
r#type: "text",
|
||||
class: "input input-bordered w-full",
|
||||
}
|
||||
}
|
||||
label {
|
||||
class: "form-control w-full",
|
||||
div {
|
||||
class: "label",
|
||||
span { class: "label-text", "Nieuw wachtwoord" }
|
||||
}
|
||||
input {
|
||||
r#type: "text",
|
||||
class: "input input-bordered w-full",
|
||||
}
|
||||
}
|
||||
label {
|
||||
class: "form-control w-full",
|
||||
div {
|
||||
class: "label",
|
||||
span { class: "label-text", "Herhaal nieuw wachtwoord" }
|
||||
}
|
||||
input {
|
||||
r#type: "text",
|
||||
class: "input input-bordered w-full",
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,6 @@ impl Member {
|
||||
|
||||
let members: Vec<Self> = res.take(0)?;
|
||||
|
||||
tracing::info!("{:?}", members);
|
||||
|
||||
Ok(members)
|
||||
}
|
||||
|
||||
|
@ -81,4 +81,44 @@ impl Session {
|
||||
None => Err(crate::Error::NoSessionCookie),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_cookie() -> Result<(), crate::Error> {
|
||||
use axum::http::{header, HeaderValue};
|
||||
use axum_extra::extract::cookie::{Cookie, SameSite};
|
||||
use dioxus::prelude::server_context;
|
||||
use time::Duration;
|
||||
|
||||
let mut cookie = Cookie::build(("session_token", ""))
|
||||
.max_age(Duration::seconds(1))
|
||||
.build();
|
||||
|
||||
cookie.set_same_site(SameSite::Strict);
|
||||
|
||||
server_context()
|
||||
.response_parts_mut()
|
||||
.unwrap()
|
||||
.headers
|
||||
.insert(
|
||||
header::SET_COOKIE,
|
||||
HeaderValue::from_str(&cookie.to_string())?,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_session(user_id: String) -> Result<(), crate::Error> {
|
||||
DB.query("DELETE ONLY session WHERE user = type::thing('user', $user_id)")
|
||||
.bind(("user_id", user_id))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Fetches the current user from cookie headers
|
||||
pub async fn fetch_current_user() -> Result<User, crate::Error> {
|
||||
let session_token = Self::get_token_from_cookie().await?;
|
||||
let user = Self::fetch_user_from_token(session_token).await?;
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use surrealdb::sql::statements::{BeginStatement, CommitStatement};
|
||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
||||
pub struct User {
|
||||
pub id: String,
|
||||
email: String,
|
||||
pub email: String,
|
||||
password: Option<String>,
|
||||
}
|
||||
|
||||
@ -60,4 +60,19 @@ impl User {
|
||||
None => Err(crate::Error::NoDocument),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn change_email(&self, new_email: String) -> Result<String, crate::Error> {
|
||||
let mut res = DB
|
||||
.query("UPDATE type::thing('user', $user_id) SET email = $email RETURN VALUE email")
|
||||
.bind(("user_id", self.id.to_string()))
|
||||
.bind(("email", new_email))
|
||||
.await?;
|
||||
|
||||
let email: Option<String> = res.take(0)?;
|
||||
|
||||
match email {
|
||||
Some(e) => Ok(e),
|
||||
None => Err(crate::Error::NoDocument),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user