Merge pull request 'refactor: style login page' (#80)
Reviewed-on: #80 Reviewed-by: Dominik <mail@dominikstahl.dev>
This commit is contained in:
commit
01c77101f9
31 changed files with 629 additions and 129 deletions
BIN
public/fonts/Comfortaa/Comfortaa-VariableFont_weight.ttf
Normal file
BIN
public/fonts/Comfortaa/Comfortaa-VariableFont_weight.ttf
Normal file
Binary file not shown.
93
public/fonts/Comfortaa/OFL.txt
Normal file
93
public/fonts/Comfortaa/OFL.txt
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2011 The Comfortaa Project Authors (https://github.com/alexeiva/comfortaa), with Reserved Font Name "Comfortaa".
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
67
public/fonts/Comfortaa/README.txt
Normal file
67
public/fonts/Comfortaa/README.txt
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
Comfortaa Variable Font
|
||||||
|
=======================
|
||||||
|
|
||||||
|
This download contains Comfortaa as both a variable font and static fonts.
|
||||||
|
|
||||||
|
Comfortaa is a variable font with this axis:
|
||||||
|
wght
|
||||||
|
|
||||||
|
This means all the styles are contained in a single file:
|
||||||
|
Comfortaa-VariableFont_wght.ttf
|
||||||
|
|
||||||
|
If your app fully supports variable fonts, you can now pick intermediate styles
|
||||||
|
that aren’t available as static fonts. Not all apps support variable fonts, and
|
||||||
|
in those cases you can use the static font files for Comfortaa:
|
||||||
|
static/Comfortaa-Light.ttf
|
||||||
|
static/Comfortaa-Regular.ttf
|
||||||
|
static/Comfortaa-Medium.ttf
|
||||||
|
static/Comfortaa-SemiBold.ttf
|
||||||
|
static/Comfortaa-Bold.ttf
|
||||||
|
|
||||||
|
Get started
|
||||||
|
-----------
|
||||||
|
|
||||||
|
1. Install the font files you want to use
|
||||||
|
|
||||||
|
2. Use your app's font picker to view the font family and all the
|
||||||
|
available styles
|
||||||
|
|
||||||
|
Learn more about variable fonts
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
|
||||||
|
https://variablefonts.typenetwork.com
|
||||||
|
https://medium.com/variable-fonts
|
||||||
|
|
||||||
|
In desktop apps
|
||||||
|
|
||||||
|
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
|
||||||
|
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
|
||||||
|
|
||||||
|
Online
|
||||||
|
|
||||||
|
https://developers.google.com/fonts/docs/getting_started
|
||||||
|
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
|
||||||
|
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
|
||||||
|
|
||||||
|
Installing fonts
|
||||||
|
|
||||||
|
MacOS: https://support.apple.com/en-us/HT201749
|
||||||
|
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
|
||||||
|
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
|
||||||
|
|
||||||
|
Android Apps
|
||||||
|
|
||||||
|
https://developers.google.com/fonts/docs/android
|
||||||
|
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
Please read the full license text (OFL.txt) to understand the permissions,
|
||||||
|
restrictions and requirements for usage, redistribution, and modification.
|
||||||
|
|
||||||
|
You can use them in your products & projects – print or digital,
|
||||||
|
commercial or otherwise.
|
||||||
|
|
||||||
|
This isn't legal advice, please consider consulting a lawyer and see the full
|
||||||
|
license for all details.
|
BIN
public/fonts/Comfortaa/static/Comfortaa-Bold.ttf
Normal file
BIN
public/fonts/Comfortaa/static/Comfortaa-Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/Comfortaa/static/Comfortaa-Light.ttf
Normal file
BIN
public/fonts/Comfortaa/static/Comfortaa-Light.ttf
Normal file
Binary file not shown.
BIN
public/fonts/Comfortaa/static/Comfortaa-Medium.ttf
Normal file
BIN
public/fonts/Comfortaa/static/Comfortaa-Medium.ttf
Normal file
Binary file not shown.
BIN
public/fonts/Comfortaa/static/Comfortaa-Regular.ttf
Normal file
BIN
public/fonts/Comfortaa/static/Comfortaa-Regular.ttf
Normal file
Binary file not shown.
BIN
public/fonts/Comfortaa/static/Comfortaa-SemiBold.ttf
Normal file
BIN
public/fonts/Comfortaa/static/Comfortaa-SemiBold.ttf
Normal file
Binary file not shown.
93
public/fonts/VarelaRound/OFL.txt
Normal file
93
public/fonts/VarelaRound/OFL.txt
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2023 The Varela Round Project Authors (https://github.com/alefalefalef/Varela-Round-Hebrew/), with Reserved Font Names 'Varela' and ‘Varela Round’.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
public/fonts/VarelaRound/VarelaRound-Regular.ttf
Normal file
BIN
public/fonts/VarelaRound/VarelaRound-Regular.ttf
Normal file
Binary file not shown.
|
@ -6,6 +6,9 @@
|
||||||
:root {
|
:root {
|
||||||
/* Custom values */
|
/* Custom values */
|
||||||
|
|
||||||
|
--font-heading: 'Comfortaa', sans-serif;
|
||||||
|
--font-label: 'Varela Round', sans-serif;
|
||||||
|
|
||||||
--transparent: transparent;
|
--transparent: transparent;
|
||||||
|
|
||||||
--neutral-000: oklch(0 0 0);
|
--neutral-000: oklch(0 0 0);
|
||||||
|
@ -14,6 +17,7 @@
|
||||||
--neutral-200: oklch(0.3407 0 0);
|
--neutral-200: oklch(0.3407 0 0);
|
||||||
--neutral-300: oklch(0.4495 0 0);
|
--neutral-300: oklch(0.4495 0 0);
|
||||||
--neutral-400: oklch(0.5486 0 0);
|
--neutral-400: oklch(0.5486 0 0);
|
||||||
|
--neutral-450: oklch(0.6 0 0);
|
||||||
--neutral-500: oklch(0.6434 0 0);
|
--neutral-500: oklch(0.6434 0 0);
|
||||||
--neutral-600: oklch(0.738 0 0);
|
--neutral-600: oklch(0.738 0 0);
|
||||||
--neutral-700: oklch(0.8266 0 0);
|
--neutral-700: oklch(0.8266 0 0);
|
||||||
|
@ -25,26 +29,29 @@
|
||||||
--base: var(--neutral-800);
|
--base: var(--neutral-800);
|
||||||
--text: var(--neutral-000);
|
--text: var(--neutral-000);
|
||||||
--text-alt: var(--neutral-900);
|
--text-alt: var(--neutral-900);
|
||||||
|
--text-input: var(--text);
|
||||||
|
--text-muted-input: var(--neutral-450);
|
||||||
|
--muted-input: var(--neutral-600);
|
||||||
--background-disabled: var(--neutral-500);
|
--background-disabled: var(--neutral-500);
|
||||||
--text-disabled: var(--neutral-700);
|
--text-disabled: var(--neutral-700);
|
||||||
--radius: 0.688rem;
|
--radius: 0.688rem;
|
||||||
|
|
||||||
--primary: oklch(0.7493 0.1551 74.95);
|
--primary: oklch(0.7493 0.1551 74.95);
|
||||||
--hover-primary: oklch(0.6568 0.1358 74.86 / 0.8);
|
--hover-primary: oklch(0.7493 0.1551 74.95 / 0.8);
|
||||||
--active-primary: oklch(0.5911 0.1135 78.29);
|
--active-primary: oklch(0.6191 0.1218 77.58);
|
||||||
--disabled-primary: oklch(0.6568 0.1358 74.86 / 0.5);
|
--disabled-primary: oklch(0.7493 0.1551 74.95 / 0.5);
|
||||||
|
|
||||||
--secondary: oklch(0.4937 0.1697 271.26);
|
--secondary: oklch(0.4937 0.1697 271.26);
|
||||||
--hover-secondary: oklch(0.4937 0.1697 271.26 / 0.8);
|
--hover-secondary: oklch(0.4937 0.1697 271.26 / 0.8);
|
||||||
--active-secondary: oklch(0.4254 0.133 272.15);
|
--active-secondary: oklch(0.4254 0.133 272.15);
|
||||||
--disabled-secondary: oklch(0.4937 0.1697 271.26 / 0.5);
|
--disabled-secondary: oklch(0.4937 0.1697 271.26 / 0.5);
|
||||||
|
|
||||||
|
--card: var(--neutral-800);
|
||||||
|
|
||||||
/* ------------------- */
|
/* ------------------- */
|
||||||
|
|
||||||
--foreground: oklch(0.13 0.028 261.692);
|
--foreground: oklch(0.13 0.028 261.692);
|
||||||
|
|
||||||
--card: oklch(1 0 0);
|
|
||||||
|
|
||||||
--card-foreground: oklch(0.13 0.028 261.692);
|
--card-foreground: oklch(0.13 0.028 261.692);
|
||||||
|
|
||||||
--popover: oklch(1 0 0);
|
--popover: oklch(1 0 0);
|
||||||
|
@ -53,6 +60,8 @@
|
||||||
|
|
||||||
--primary-foreground: oklch(0.985 0.002 247.839);
|
--primary-foreground: oklch(0.985 0.002 247.839);
|
||||||
|
|
||||||
|
--popover-hover: var(--neutral-750);
|
||||||
|
|
||||||
--secondary-foreground: oklch(0.21 0.034 264.665);
|
--secondary-foreground: oklch(0.21 0.034 264.665);
|
||||||
|
|
||||||
--muted: oklch(0.967 0.003 264.542);
|
--muted: oklch(0.967 0.003 264.542);
|
||||||
|
@ -98,8 +107,26 @@
|
||||||
--sidebar-ring: oklch(0.707 0.022 261.325);
|
--sidebar-ring: oklch(0.707 0.022 261.325);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Comfortaa';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300 700;
|
||||||
|
src: url('/fonts/Comfortaa/Comfortaa-VariableFont_weight.ttf')
|
||||||
|
format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Varela Round';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url('/fonts/VarelaRound/VarelaRound-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--transparent: var(--transpatent);
|
--font-heading: var(--font-heading);
|
||||||
|
--font-label: var(--font-label);
|
||||||
|
|
||||||
|
--transparent: var(--transparent);
|
||||||
|
|
||||||
--color-neutral-000: var(--neutral-000);
|
--color-neutral-000: var(--neutral-000);
|
||||||
--color-neutral-100: var(--neutral-100);
|
--color-neutral-100: var(--neutral-100);
|
||||||
|
@ -114,12 +141,16 @@
|
||||||
--color-neutral-800: var(--neutral-800);
|
--color-neutral-800: var(--neutral-800);
|
||||||
--color-neutral-900: var(--neutral-900);
|
--color-neutral-900: var(--neutral-900);
|
||||||
|
|
||||||
--background: var(--neutral-750);
|
--color-background: var(--neutral-750);
|
||||||
--base: var(--neutral-800);
|
--color-base: var(--neutral-800);
|
||||||
--text: var(--neutral-000);
|
--color-text: var(--text);
|
||||||
--text-alt: var(--neutral-900);
|
--color-text-alt: var(--text-alt);
|
||||||
--background-disabled: var(--neutral-500);
|
--color-text-input: var(--text-input);
|
||||||
--text-disabled: var(--neutral-700);
|
--color-text-muted-input: var(--text-muted-input);
|
||||||
|
--color-muted-input: var(--muted-input);
|
||||||
|
|
||||||
|
--color-background-disabled: var(--neutral-500);
|
||||||
|
--color-text-disabled: var(--neutral-700);
|
||||||
--radius: 0.688rem;
|
--radius: 0.688rem;
|
||||||
|
|
||||||
--color-primary: var(--primary);
|
--color-primary: var(--primary);
|
||||||
|
@ -130,7 +161,7 @@
|
||||||
--color-secondary: var(--secondary);
|
--color-secondary: var(--secondary);
|
||||||
--color-hover-secondary: var(--hover-secondary);
|
--color-hover-secondary: var(--hover-secondary);
|
||||||
--color-active-secondary: var(--active-secondary);
|
--color-active-secondary: var(--active-secondary);
|
||||||
--disabled-secondary: var(--disabled-secondary);
|
--color-disabled-secondary: var(--disabled-secondary);
|
||||||
|
|
||||||
/* Custom values */
|
/* Custom values */
|
||||||
|
|
||||||
|
@ -150,10 +181,12 @@
|
||||||
|
|
||||||
--color-card-foreground: var(--card-foreground);
|
--color-card-foreground: var(--card-foreground);
|
||||||
|
|
||||||
--color-popover: var(--popover);
|
--color-popover: var(--color-background);
|
||||||
|
|
||||||
--color-popover-foreground: var(--popover-foreground);
|
--color-popover-foreground: var(--popover-foreground);
|
||||||
|
|
||||||
|
--color-popover-hover: var(--popover-hover);
|
||||||
|
|
||||||
--color-primary: var(--primary);
|
--color-primary: var(--primary);
|
||||||
|
|
||||||
--color-primary-foreground: var(--primary-foreground);
|
--color-primary-foreground: var(--primary-foreground);
|
||||||
|
@ -166,7 +199,7 @@
|
||||||
|
|
||||||
--color-muted-foreground: var(--muted-foreground);
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
|
|
||||||
--color-accent: var(--accent);
|
--color-accent: var(--color-neutral-750);
|
||||||
|
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
|
|
||||||
|
@ -211,22 +244,26 @@
|
||||||
--transparent: transparent;
|
--transparent: transparent;
|
||||||
|
|
||||||
--neutral-000: oklch(1 0 0);
|
--neutral-000: oklch(1 0 0);
|
||||||
--neutral-100: oklch(0.9128 0 0);
|
--neutral-100: oklch(0.9702 0 0);
|
||||||
--neutral-150: oklch(0.9702 0 0);
|
--neutral-150: oklch(0.9128 0 0);
|
||||||
--neutral-200: oklch(0.8266 0 0);
|
--neutral-200: oklch(0.8266 0 0);
|
||||||
--neutral-300: oklch(0.738 0 0);
|
--neutral-300: oklch(0.738 0 0);
|
||||||
--neutral-400: oklch(0.6434 0 0);
|
--neutral-400: oklch(0.6434 0 0);
|
||||||
--neutral-600: oklch(0.4495 0 0);
|
--neutral-450: oklch(0.6 0 0);
|
||||||
--neutral-500: oklch(0.5486 0 0);
|
--neutral-500: oklch(0.5486 0 0);
|
||||||
|
--neutral-600: oklch(0.4495 0 0);
|
||||||
--neutral-700: oklch(0.3407 0 0);
|
--neutral-700: oklch(0.3407 0 0);
|
||||||
--neutral-750: oklch(0.2972 0 0);
|
--neutral-750: oklch(0.2972 0 0);
|
||||||
--neutral-800: oklch(0.2264 0 0);
|
--neutral-800: oklch(0.2264 0 0);
|
||||||
--neutral-900: oklch(0 0 0);
|
--neutral-900: oklch(0 0 0);
|
||||||
|
|
||||||
--background: var(--neutral-750);
|
--background: var(--neutral-750);
|
||||||
--base: var(--neutral-800);
|
--base: var(--neutral-750);
|
||||||
--text: var(--neutral-000);
|
--text: var(--neutral-000);
|
||||||
--text-alt: var(--neutral-900);
|
--text-alt: var(--neutral-900);
|
||||||
|
--text-input: var(--text);
|
||||||
|
--text-muted-input: var(--neutral-450);
|
||||||
|
--muted-input: var(--neutral-500);
|
||||||
--background-disabled: var(--neutral-500);
|
--background-disabled: var(--neutral-500);
|
||||||
--text-disabled: var(--neutral-700);
|
--text-disabled: var(--neutral-700);
|
||||||
|
|
||||||
|
@ -240,12 +277,12 @@
|
||||||
--active-secondary: oklch(0.4471 0.15 271.61);
|
--active-secondary: oklch(0.4471 0.15 271.61);
|
||||||
--disabled-secondary: oklch(0.6065 0.213 271.11 / 0.4);
|
--disabled-secondary: oklch(0.6065 0.213 271.11 / 0.4);
|
||||||
|
|
||||||
|
--card: var(--neutral-750);
|
||||||
|
|
||||||
/* ------------------- */
|
/* ------------------- */
|
||||||
|
|
||||||
--foreground: oklch(0.985 0.002 247.839);
|
--foreground: oklch(0.985 0.002 247.839);
|
||||||
|
|
||||||
--card: oklch(0.21 0.034 264.665);
|
|
||||||
|
|
||||||
--card-foreground: oklch(0.985 0.002 247.839);
|
--card-foreground: oklch(0.985 0.002 247.839);
|
||||||
|
|
||||||
--popover: oklch(0.21 0.034 264.665);
|
--popover: oklch(0.21 0.034 264.665);
|
||||||
|
@ -254,6 +291,8 @@
|
||||||
|
|
||||||
--primary-foreground: oklch(0.21 0.034 264.665);
|
--primary-foreground: oklch(0.21 0.034 264.665);
|
||||||
|
|
||||||
|
--popover-hover: var(--neutral-700);
|
||||||
|
|
||||||
--secondary-foreground: oklch(0.985 0.002 247.839);
|
--secondary-foreground: oklch(0.985 0.002 247.839);
|
||||||
|
|
||||||
--muted: oklch(0.278 0.033 256.848);
|
--muted: oklch(0.278 0.033 256.848);
|
||||||
|
|
|
@ -2,11 +2,17 @@ import { auth, providerMap } from '@/auth';
|
||||||
import SSOLogin from '@/components/user/sso-login-button';
|
import SSOLogin from '@/components/user/sso-login-button';
|
||||||
import LoginForm from '@/components/user/login-form';
|
import LoginForm from '@/components/user/login-form';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/custom-ui/button';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import { Separator } from '@/components/custom-ui/separator';
|
||||||
|
import Logo from '@/components/logo';
|
||||||
|
|
||||||
import '@/app/globals.css';
|
import '@/app/globals.css';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardHeader,
|
||||||
|
} from '@/components/custom-ui/login-card';
|
||||||
import { ThemePicker } from '@/components/user/theme-picker';
|
import { ThemePicker } from '@/components/user/theme-picker';
|
||||||
import {
|
import {
|
||||||
HoverCard,
|
HoverCard,
|
||||||
|
@ -28,14 +34,16 @@ export default async function LoginPage() {
|
||||||
<ThemePicker />
|
<ThemePicker />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Card className='w-[350px] max-w-screen'>
|
<Card className='w-[350px] max-w-screen;'>
|
||||||
<CardHeader>
|
<CardHeader className='grid place-items-center'>
|
||||||
<CardTitle className='text-lg text-center'>Login</CardTitle>
|
<Logo colorType='colored' logoType='secondary'></Logo>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='gap-6 flex flex-col'>
|
<CardContent className='gap-6 flex flex-col items-center'>
|
||||||
<LoginForm />
|
<LoginForm />
|
||||||
|
|
||||||
{providerMap.length > 0 && <hr />}
|
<Separator className='h-[1px] rounded-sm w-[60%] bg-neutral-000' />
|
||||||
|
|
||||||
|
{providerMap.length > 0}
|
||||||
|
|
||||||
{providerMap.map((provider) => (
|
{providerMap.map((provider) => (
|
||||||
<SSOLogin
|
<SSOLogin
|
||||||
|
@ -49,7 +57,7 @@ export default async function LoginPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<HoverCard>
|
<HoverCard>
|
||||||
<HoverCardTrigger className='text-sm text-muted-foreground hover:underline'>
|
<HoverCardTrigger className='text-sm text-neutral-000 hover:underline'>
|
||||||
<Button variant='link'>made with love</Button>
|
<Button variant='link'>made with love</Button>
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
<HoverCardContent className='flex items-center justify-center'>
|
<HoverCardContent className='flex items-center justify-center'>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { signOut } from '@/auth';
|
import { signOut } from '@/auth';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/custom-ui/button';
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/custom-ui/button';
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
|
@ -88,7 +88,7 @@ export default function SettingsPage() {
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className='pt-4'>
|
<div className='pt-4'>
|
||||||
<Button variant='destructive'>Delete Account</Button>
|
<Button variant='secondary'>Delete Account</Button>
|
||||||
<p className='text-sm text-muted-foreground pt-1'>
|
<p className='text-sm text-muted-foreground pt-1'>
|
||||||
Permanently delete your account and all associated data.
|
Permanently delete your account and all associated data.
|
||||||
</p>
|
</p>
|
||||||
|
|
16
src/assets/logo/logo-export.ts
Normal file
16
src/assets/logo/logo-export.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
export { default as logo_colored_combo_light } from '@/assets/logo/logo_colored_combo_light.svg';
|
||||||
|
export { default as logo_colored_combo_dark } from '@/assets/logo/logo_colored_combo_dark.svg';
|
||||||
|
export { default as logo_colored_primary_light } from '@/assets/logo/logo_colored_primary_light.svg';
|
||||||
|
export { default as logo_colored_primary_dark } from '@/assets/logo/logo_colored_primary_dark.svg';
|
||||||
|
export { default as logo_colored_secondary_light } from '@/assets/logo/logo_colored_secondary_light.svg';
|
||||||
|
export { default as logo_colored_secondary_dark } from '@/assets/logo/logo_colored_secondary_dark.svg';
|
||||||
|
export { default as logo_mono_combo_light } from '@/assets/logo/logo_mono_combo_light.svg';
|
||||||
|
export { default as logo_mono_combo_dark } from '@/assets/logo/logo_mono_combo_dark.svg';
|
||||||
|
export { default as logo_mono_primary_light } from '@/assets/logo/logo_mono_primary_light.svg';
|
||||||
|
export { default as logo_mono_primary_dark } from '@/assets/logo/logo_mono_primary_dark.svg';
|
||||||
|
export { default as logo_mono_secondary_light } from '@/assets/logo/logo_mono_secondary_light.svg';
|
||||||
|
export { default as logo_mono_secondary_dark } from '@/assets/logo/logo_mono_secondary_dark.svg';
|
||||||
|
export { default as logo_mono_submark_light } from '@/assets/logo/logo_mono_submark_light.svg';
|
||||||
|
export { default as logo_mono_submark_dark } from '@/assets/logo/logo_mono_submark_dark.svg';
|
||||||
|
export { default as logo_colored_submark_light } from '@/assets/logo/logo_colored_submark_light.svg';
|
||||||
|
export { default as logo_colored_submark_dark } from '@/assets/logo/logo_colored_submark_dark.svg';
|
57
src/components/custom-ui/button.tsx
Normal file
57
src/components/custom-ui/button.tsx
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Slot } from '@radix-ui/react-slot';
|
||||||
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"radius-lg inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-label transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
primary:
|
||||||
|
'bg-primary text-text shadow-xs hover:bg-hover-primary active:bg-active-primary',
|
||||||
|
secondary:
|
||||||
|
'bg-secondary text-text-alt shadow-xs hover:bg-hover-secondary active:bg-active-secondary',
|
||||||
|
outline:
|
||||||
|
'border-2 border-primary bg-transparent text-text shadow-xs hover:bg-primary hover:border-neutral-000 hover:border-1.5 hover:text-neutral-000 active:bg-active-primary',
|
||||||
|
ghost:
|
||||||
|
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
||||||
|
link: 'text-text underline-offset-4 hover:underline',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
||||||
|
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
|
||||||
|
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
|
||||||
|
icon: 'size-9',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'primary',
|
||||||
|
size: 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function Button({
|
||||||
|
className = 'font-label',
|
||||||
|
variant,
|
||||||
|
size,
|
||||||
|
asChild = false,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<'button'> &
|
||||||
|
VariantProps<typeof buttonVariants> & {
|
||||||
|
asChild?: boolean;
|
||||||
|
}) {
|
||||||
|
const Comp = asChild ? Slot : 'button';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
data-slot='button'
|
||||||
|
className={cn(buttonVariants({ variant, size }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Button, buttonVariants };
|
92
src/components/custom-ui/login-card.tsx
Normal file
92
src/components/custom-ui/login-card.tsx
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
function Card({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot='card'
|
||||||
|
className={cn(
|
||||||
|
'bg-card flex flex-col gap-6 py-6 shadow-[4px_4px_9px_9px_rgba(0,0,0,0.25)] rounded-[11px]',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot='card-header'
|
||||||
|
className={cn(
|
||||||
|
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot='card-title'
|
||||||
|
className={cn('leading-none font-semibold', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot='card-description'
|
||||||
|
className={cn('text-muted-foreground text-sm', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot='card-action'
|
||||||
|
className={cn(
|
||||||
|
'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot='card-content'
|
||||||
|
className={cn('px-6', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot='card-footer'
|
||||||
|
className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardAction,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
};
|
|
@ -16,10 +16,7 @@ function Separator({
|
||||||
data-slot='separator-root'
|
data-slot='separator-root'
|
||||||
decorative={decorative}
|
decorative={decorative}
|
||||||
orientation={orientation}
|
orientation={orientation}
|
||||||
className={cn(
|
className={cn('shrink-0', className)}
|
||||||
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/custom-ui/button';
|
||||||
|
|
||||||
import { IconProp } from '@fortawesome/fontawesome-svg-core';
|
import { IconProp } from '@fortawesome/fontawesome-svg-core';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
@ -12,7 +12,7 @@ export function IconButton({
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
} & React.ComponentProps<typeof Button>) {
|
} & React.ComponentProps<typeof Button>) {
|
||||||
return (
|
return (
|
||||||
<Button type='button' variant='default' {...props}>
|
<Button type='button' variant='secondary' {...props}>
|
||||||
<FontAwesomeIcon icon={icon} className='mr-2' />
|
<FontAwesomeIcon icon={icon} className='mr-2' />
|
||||||
{children}
|
{children}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default function LabeledInput({
|
||||||
name?: string;
|
name?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='grid grid-cols-1 gap-1 font-label'>
|
||||||
<Label htmlFor={name}>{label}</Label>
|
<Label htmlFor={name}>{label}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
|
|
101
src/components/logo.tsx
Normal file
101
src/components/logo.tsx
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import Image, { ImageProps } from 'next/image';
|
||||||
|
|
||||||
|
import * as logoAssets from '@/assets/logo/logo-export';
|
||||||
|
import { useTheme } from 'next-themes';
|
||||||
|
|
||||||
|
type ColorType = 'colored' | 'monochrome';
|
||||||
|
type LogoType = 'combo' | 'primary' | 'secondary' | 'submark';
|
||||||
|
type Theme = 'light' | 'dark';
|
||||||
|
|
||||||
|
interface LogoProps extends Omit<ImageProps, 'src' | 'alt'> {
|
||||||
|
colorType: ColorType;
|
||||||
|
logoType: LogoType;
|
||||||
|
overrideTheme?: Theme;
|
||||||
|
alt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LOGO_BASE_PATH = '/assets/logo/';
|
||||||
|
const IMAGE_EXTENSION = 'svg';
|
||||||
|
|
||||||
|
export default function Logo({
|
||||||
|
colorType,
|
||||||
|
logoType,
|
||||||
|
overrideTheme,
|
||||||
|
alt,
|
||||||
|
className = '',
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
// onError,
|
||||||
|
...imageProps
|
||||||
|
}: LogoProps) {
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
let { resolvedTheme: theme } = useTheme() as {
|
||||||
|
resolvedTheme?: Theme;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (overrideTheme) {
|
||||||
|
theme = overrideTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent rendering until mounted (theme is available)
|
||||||
|
if (!mounted && !overrideTheme) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!colorType || !logoType || !theme) {
|
||||||
|
const errorMessage =
|
||||||
|
'Logo: colorType, logoType, and theme props are required.';
|
||||||
|
console.error(errorMessage);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role='alert'
|
||||||
|
className='p-2 text-red-700 bg-red-100 border border-red-500 rounded-md text-xs'
|
||||||
|
>
|
||||||
|
Error: Missing required logo props. Check console.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width === undefined || height === undefined) {
|
||||||
|
console.warn(
|
||||||
|
`Logo: 'width' and 'height' props are required by next/image for ${logoType} logo. Path: ${LOGO_BASE_PATH}logo_${colorType}_${logoType}_${theme}.${IMAGE_EXTENSION}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorTypeInFilename = colorType === 'monochrome' ? 'mono' : colorType;
|
||||||
|
const defaultAltText = `Logo: ${colorType} ${logoType} ${theme}`;
|
||||||
|
const varName = `logo_${colorTypeInFilename}_${logoType}_${theme}` as const;
|
||||||
|
|
||||||
|
// Match the varName with the Logo-Asset name and store it in "logoVar"
|
||||||
|
const logoVar = logoAssets[varName];
|
||||||
|
|
||||||
|
if (!logoVar) {
|
||||||
|
console.error(`Logo: Could not find logo asset for ${varName}`);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role='alert'
|
||||||
|
className='p-2 text-red-700 bg-red-100 border border-red-500 rounded-md text-xs'
|
||||||
|
>
|
||||||
|
Error: Logo asset not found. Check console.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Image
|
||||||
|
src={logoVar}
|
||||||
|
alt={alt || defaultAltText}
|
||||||
|
className={className}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
{...imageProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { Slot } from '@radix-ui/react-slot';
|
|
||||||
import { cva, type VariantProps } from 'class-variance-authority';
|
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
|
|
||||||
const buttonVariants = cva(
|
|
||||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
||||||
{
|
|
||||||
variants: {
|
|
||||||
variant: {
|
|
||||||
default:
|
|
||||||
'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
|
|
||||||
destructive:
|
|
||||||
'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
|
||||||
outline:
|
|
||||||
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
|
|
||||||
secondary:
|
|
||||||
'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
|
|
||||||
ghost:
|
|
||||||
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
|
||||||
link: 'text-primary underline-offset-4 hover:underline',
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
|
||||||
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
|
|
||||||
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
|
|
||||||
icon: 'size-9',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultVariants: {
|
|
||||||
variant: 'default',
|
|
||||||
size: 'default',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
function Button({
|
|
||||||
className,
|
|
||||||
variant,
|
|
||||||
size,
|
|
||||||
asChild = false,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<'button'> &
|
|
||||||
VariantProps<typeof buttonVariants> & {
|
|
||||||
asChild?: boolean;
|
|
||||||
}) {
|
|
||||||
const Comp = asChild ? Slot : 'button';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Comp
|
|
||||||
data-slot='button'
|
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export { Button, buttonVariants };
|
|
|
@ -42,7 +42,7 @@ function DropdownMenuContent({
|
||||||
data-slot='dropdown-menu-content'
|
data-slot='dropdown-menu-content'
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
|
'bg-popover text-text data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -74,7 +74,7 @@ function DropdownMenuItem({
|
||||||
data-inset={inset}
|
data-inset={inset}
|
||||||
data-variant={variant}
|
data-variant={variant}
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus:bg-popover-hover focus:text-text data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
||||||
type={type}
|
type={type}
|
||||||
data-slot='input'
|
data-slot='input'
|
||||||
className={cn(
|
className={cn(
|
||||||
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
'file:text-destructive placeholder:text-text-muted-input selection:bg-muted-input selection:text-text dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-text-input shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-label disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||||
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
||||||
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
||||||
className,
|
className,
|
||||||
|
|
|
@ -13,7 +13,7 @@ function Label({
|
||||||
<LabelPrimitive.Root
|
<LabelPrimitive.Root
|
||||||
data-slot='label'
|
data-slot='label'
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
|
'flex items-center gap-2 text-sm leading-none font-label select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -107,7 +107,7 @@ function SelectItem({
|
||||||
<SelectPrimitive.Item
|
<SelectPrimitive.Item
|
||||||
data-slot='select-item'
|
data-slot='select-item'
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
"focus:bg-accent focus:text-text [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { signIn } from '@/auth';
|
import { signIn } from '@/auth';
|
||||||
import LabeledInput from '@/components/labeled-input';
|
import LabeledInput from '@/components/labeled-input';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/custom-ui/button';
|
||||||
import { AuthError } from 'next-auth';
|
import { AuthError } from 'next-auth';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
|
|
||||||
|
@ -25,22 +25,23 @@ export default function LoginForm() {
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
type='email'
|
type='email'
|
||||||
label='E-Mail or Username'
|
label='E-Mail or Username'
|
||||||
placeholder='What you are known as.'
|
placeholder='What you are known as'
|
||||||
name='email'
|
name='email'
|
||||||
/>
|
/>
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
type='password'
|
type='password'
|
||||||
label='Password'
|
label='Password'
|
||||||
placeholder="Let's hope you remember it."
|
placeholder="Let's hope you remember it"
|
||||||
name='password'
|
name='password'
|
||||||
/>
|
/>
|
||||||
<Button
|
<div className='grid grid-rows-2 gap-2'>
|
||||||
className='hover:bg-blue-600 hover:text-white'
|
<Button type='submit' variant='primary'>
|
||||||
type='submit'
|
Login
|
||||||
variant='secondary'
|
</Button>
|
||||||
>
|
<Button type='submit' variant='outline'>
|
||||||
Login
|
Sign Up
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button } from '../ui/button';
|
import { Button } from '../custom-ui/button';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export function RedirectButton({
|
export function RedirectButton({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { signIn } from '@/auth';
|
import { signIn } from '@/auth';
|
||||||
import { Button } from '@/components/ui/button';
|
import { IconButton } from '@/components/icon-button';
|
||||||
import { Fingerprint } from 'lucide-react';
|
import { faOpenid } from '@fortawesome/free-brands-svg-icons';
|
||||||
|
|
||||||
export default function SSOLogin({
|
export default function SSOLogin({
|
||||||
provider,
|
provider,
|
||||||
|
@ -17,19 +17,14 @@ export default function SSOLogin({
|
||||||
await signIn(provider);
|
await signIn(provider);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<IconButton
|
||||||
className='w-full flex items-center'
|
className='w-full'
|
||||||
type='submit'
|
type='submit'
|
||||||
variant='default'
|
variant='secondary'
|
||||||
|
icon={faOpenid}
|
||||||
>
|
>
|
||||||
<div className='flex justify-center'>
|
Login with {providerDisplayName}
|
||||||
<Fingerprint />
|
</IconButton>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='flex justify-center'>
|
|
||||||
Login with {providerDisplayName}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from 'react';
|
||||||
import { Moon, Sun } from 'lucide-react';
|
import { Moon, Sun } from 'lucide-react';
|
||||||
import { useTheme } from 'next-themes';
|
import { useTheme } from 'next-themes';
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/custom-ui/button';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
|
|
|
@ -2,6 +2,6 @@ export { auth as middleware } from '@/auth';
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
matcher: [
|
matcher: [
|
||||||
'/((?!api|_next/static|_next/image|site\.webmanifest|web-app-manifest-(?:192x192|512x512)\.png|favicon(?:-(?:dark|light))?\.(?:png|svg|ico)).*)',
|
'/((?!api|_next/static|_next/image|site\.webmanifest|web-app-manifest-(?:192x192|512x512)\.png|favicon(?:-(?:dark|light))?\.(?:png|svg|ico)|fonts).*)',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue