diff --git a/public/fonts/Comfortaa/Comfortaa-VariableFont_weight.ttf b/public/fonts/Comfortaa/Comfortaa-VariableFont_weight.ttf new file mode 100644 index 0000000..9918535 Binary files /dev/null and b/public/fonts/Comfortaa/Comfortaa-VariableFont_weight.ttf differ diff --git a/public/fonts/Comfortaa/OFL.txt b/public/fonts/Comfortaa/OFL.txt new file mode 100644 index 0000000..5c7930b --- /dev/null +++ b/public/fonts/Comfortaa/OFL.txt @@ -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. diff --git a/public/fonts/Comfortaa/README.txt b/public/fonts/Comfortaa/README.txt new file mode 100644 index 0000000..1d01eab --- /dev/null +++ b/public/fonts/Comfortaa/README.txt @@ -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. diff --git a/public/fonts/Comfortaa/static/Comfortaa-Bold.ttf b/public/fonts/Comfortaa/static/Comfortaa-Bold.ttf new file mode 100644 index 0000000..e64de93 Binary files /dev/null and b/public/fonts/Comfortaa/static/Comfortaa-Bold.ttf differ diff --git a/public/fonts/Comfortaa/static/Comfortaa-Light.ttf b/public/fonts/Comfortaa/static/Comfortaa-Light.ttf new file mode 100644 index 0000000..2310cd2 Binary files /dev/null and b/public/fonts/Comfortaa/static/Comfortaa-Light.ttf differ diff --git a/public/fonts/Comfortaa/static/Comfortaa-Medium.ttf b/public/fonts/Comfortaa/static/Comfortaa-Medium.ttf new file mode 100644 index 0000000..2a98021 Binary files /dev/null and b/public/fonts/Comfortaa/static/Comfortaa-Medium.ttf differ diff --git a/public/fonts/Comfortaa/static/Comfortaa-Regular.ttf b/public/fonts/Comfortaa/static/Comfortaa-Regular.ttf new file mode 100644 index 0000000..abc4409 Binary files /dev/null and b/public/fonts/Comfortaa/static/Comfortaa-Regular.ttf differ diff --git a/public/fonts/Comfortaa/static/Comfortaa-SemiBold.ttf b/public/fonts/Comfortaa/static/Comfortaa-SemiBold.ttf new file mode 100644 index 0000000..1746b9f Binary files /dev/null and b/public/fonts/Comfortaa/static/Comfortaa-SemiBold.ttf differ diff --git a/public/fonts/VarelaRound/OFL.txt b/public/fonts/VarelaRound/OFL.txt new file mode 100644 index 0000000..cca0a98 --- /dev/null +++ b/public/fonts/VarelaRound/OFL.txt @@ -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. diff --git a/public/fonts/VarelaRound/VarelaRound-Regular.ttf b/public/fonts/VarelaRound/VarelaRound-Regular.ttf new file mode 100644 index 0000000..9d01812 Binary files /dev/null and b/public/fonts/VarelaRound/VarelaRound-Regular.ttf differ diff --git a/src/app/globals.css b/src/app/globals.css index a7bbb2b..79a25a9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -6,6 +6,9 @@ :root { /* Custom values */ + --font-heading: 'Comfortaa', sans-serif; + --font-label: 'Varela Round', sans-serif; + --transparent: transparent; --neutral-000: oklch(0 0 0); @@ -14,6 +17,7 @@ --neutral-200: oklch(0.3407 0 0); --neutral-300: oklch(0.4495 0 0); --neutral-400: oklch(0.5486 0 0); + --neutral-450: oklch(0.6 0 0); --neutral-500: oklch(0.6434 0 0); --neutral-600: oklch(0.738 0 0); --neutral-700: oklch(0.8266 0 0); @@ -25,26 +29,29 @@ --base: var(--neutral-800); --text: var(--neutral-000); --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); --text-disabled: var(--neutral-700); --radius: 0.688rem; --primary: oklch(0.7493 0.1551 74.95); - --hover-primary: oklch(0.6568 0.1358 74.86 / 0.8); - --active-primary: oklch(0.5911 0.1135 78.29); - --disabled-primary: oklch(0.6568 0.1358 74.86 / 0.5); + --hover-primary: oklch(0.7493 0.1551 74.95 / 0.8); + --active-primary: oklch(0.6191 0.1218 77.58); + --disabled-primary: oklch(0.7493 0.1551 74.95 / 0.5); --secondary: oklch(0.4937 0.1697 271.26); --hover-secondary: oklch(0.4937 0.1697 271.26 / 0.8); --active-secondary: oklch(0.4254 0.133 272.15); --disabled-secondary: oklch(0.4937 0.1697 271.26 / 0.5); + --card: var(--neutral-800); + /* ------------------- */ --foreground: oklch(0.13 0.028 261.692); - --card: oklch(1 0 0); - --card-foreground: oklch(0.13 0.028 261.692); --popover: oklch(1 0 0); @@ -53,6 +60,8 @@ --primary-foreground: oklch(0.985 0.002 247.839); + --popover-hover: var(--neutral-750); + --secondary-foreground: oklch(0.21 0.034 264.665); --muted: oklch(0.967 0.003 264.542); @@ -98,8 +107,26 @@ --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 { - --transparent: var(--transpatent); + --font-heading: var(--font-heading); + --font-label: var(--font-label); + + --transparent: var(--transparent); --color-neutral-000: var(--neutral-000); --color-neutral-100: var(--neutral-100); @@ -114,12 +141,16 @@ --color-neutral-800: var(--neutral-800); --color-neutral-900: var(--neutral-900); - --background: var(--neutral-750); - --base: var(--neutral-800); - --text: var(--neutral-000); - --text-alt: var(--neutral-900); - --background-disabled: var(--neutral-500); - --text-disabled: var(--neutral-700); + --color-background: var(--neutral-750); + --color-base: var(--neutral-800); + --color-text: var(--text); + --color-text-alt: var(--text-alt); + --color-text-input: var(--text-input); + --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; --color-primary: var(--primary); @@ -130,7 +161,7 @@ --color-secondary: var(--secondary); --color-hover-secondary: var(--hover-secondary); --color-active-secondary: var(--active-secondary); - --disabled-secondary: var(--disabled-secondary); + --color-disabled-secondary: var(--disabled-secondary); /* Custom values */ @@ -150,10 +181,12 @@ --color-card-foreground: var(--card-foreground); - --color-popover: var(--popover); + --color-popover: var(--color-background); --color-popover-foreground: var(--popover-foreground); + --color-popover-hover: var(--popover-hover); + --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); @@ -166,7 +199,7 @@ --color-muted-foreground: var(--muted-foreground); - --color-accent: var(--accent); + --color-accent: var(--color-neutral-750); --color-accent-foreground: var(--accent-foreground); @@ -211,22 +244,26 @@ --transparent: transparent; --neutral-000: oklch(1 0 0); - --neutral-100: oklch(0.9128 0 0); - --neutral-150: oklch(0.9702 0 0); + --neutral-100: oklch(0.9702 0 0); + --neutral-150: oklch(0.9128 0 0); --neutral-200: oklch(0.8266 0 0); --neutral-300: oklch(0.738 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-600: oklch(0.4495 0 0); --neutral-700: oklch(0.3407 0 0); --neutral-750: oklch(0.2972 0 0); --neutral-800: oklch(0.2264 0 0); --neutral-900: oklch(0 0 0); --background: var(--neutral-750); - --base: var(--neutral-800); + --base: var(--neutral-750); --text: var(--neutral-000); --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); --text-disabled: var(--neutral-700); @@ -240,12 +277,12 @@ --active-secondary: oklch(0.4471 0.15 271.61); --disabled-secondary: oklch(0.6065 0.213 271.11 / 0.4); + --card: var(--neutral-750); + /* ------------------- */ --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); --popover: oklch(0.21 0.034 264.665); @@ -254,6 +291,8 @@ --primary-foreground: oklch(0.21 0.034 264.665); + --popover-hover: var(--neutral-700); + --secondary-foreground: oklch(0.985 0.002 247.839); --muted: oklch(0.278 0.033 256.848); diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 1786e82..f49fb8f 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -2,11 +2,17 @@ import { auth, providerMap } from '@/auth'; import SSOLogin from '@/components/user/sso-login-button'; import LoginForm from '@/components/user/login-form'; import { redirect } from 'next/navigation'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/custom-ui/button'; import Image from 'next/image'; +import { Separator } from '@/components/custom-ui/separator'; +import Logo from '@/components/logo'; 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 { HoverCard, @@ -28,14 +34,16 @@ export default async function LoginPage() {
- - - Login + + + - + - {providerMap.length > 0 &&
} + + + {providerMap.length > 0} {providerMap.map((provider) => (
- + diff --git a/src/app/logout/page.tsx b/src/app/logout/page.tsx index 15f29aa..c819a45 100644 --- a/src/app/logout/page.tsx +++ b/src/app/logout/page.tsx @@ -1,5 +1,5 @@ import { signOut } from '@/auth'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/custom-ui/button'; import { Card, CardContent, diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index 45974fb..70e198d 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -1,4 +1,4 @@ -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/custom-ui/button'; import { Card, CardContent, @@ -88,7 +88,7 @@ export default function SettingsPage() {
- +

Permanently delete your account and all associated data.

diff --git a/src/assets/logo/logo-export.ts b/src/assets/logo/logo-export.ts new file mode 100644 index 0000000..44681d3 --- /dev/null +++ b/src/assets/logo/logo-export.ts @@ -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'; diff --git a/src/components/custom-ui/button.tsx b/src/components/custom-ui/button.tsx new file mode 100644 index 0000000..f45fcd7 --- /dev/null +++ b/src/components/custom-ui/button.tsx @@ -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 & { + asChild?: boolean; + }) { + const Comp = asChild ? Slot : 'button'; + + return ( + + ); +} + +export { Button, buttonVariants }; diff --git a/src/components/custom-ui/login-card.tsx b/src/components/custom-ui/login-card.tsx new file mode 100644 index 0000000..616a45c --- /dev/null +++ b/src/components/custom-ui/login-card.tsx @@ -0,0 +1,92 @@ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +function Card({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardDescription({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardAction({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardContent({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +}; diff --git a/src/components/ui/separator.tsx b/src/components/custom-ui/separator.tsx similarity index 69% rename from src/components/ui/separator.tsx rename to src/components/custom-ui/separator.tsx index 39eb020..3b4f1ef 100644 --- a/src/components/ui/separator.tsx +++ b/src/components/custom-ui/separator.tsx @@ -16,10 +16,7 @@ function Separator({ data-slot='separator-root' decorative={decorative} orientation={orientation} - className={cn( - '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, - )} + className={cn('shrink-0', className)} {...props} /> ); diff --git a/src/components/icon-button.tsx b/src/components/icon-button.tsx index 8888b6b..ad67eaa 100644 --- a/src/components/icon-button.tsx +++ b/src/components/icon-button.tsx @@ -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 { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -12,7 +12,7 @@ export function IconButton({ children: React.ReactNode; } & React.ComponentProps) { return ( - diff --git a/src/components/labeled-input.tsx b/src/components/labeled-input.tsx index 7a416d4..a16f26a 100644 --- a/src/components/labeled-input.tsx +++ b/src/components/labeled-input.tsx @@ -15,7 +15,7 @@ export default function LabeledInput({ name?: string; }) { return ( -
+
{ + 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 ( +
+ Error: Missing required logo props. Check console. +
+ ); + } + + 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 ( +
+ Error: Logo asset not found. Check console. +
+ ); + } + + return ( + {alt + ); +} diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx deleted file mode 100644 index 657477e..0000000 --- a/src/components/ui/button.tsx +++ /dev/null @@ -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 & { - asChild?: boolean; - }) { - const Comp = asChild ? Slot : 'button'; - - return ( - - ); -} - -export { Button, buttonVariants }; diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx index 7a8804e..ca93e14 100644 --- a/src/components/ui/dropdown-menu.tsx +++ b/src/components/ui/dropdown-menu.tsx @@ -42,7 +42,7 @@ function DropdownMenuContent({ data-slot='dropdown-menu-content' sideOffset={sideOffset} 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, )} {...props} @@ -74,7 +74,7 @@ function DropdownMenuItem({ data-inset={inset} data-variant={variant} 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, )} {...props} diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 485626a..65fbc93 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) { type={type} data-slot='input' 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]', 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive', className, diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx index 6bc5f71..3364d98 100644 --- a/src/components/ui/label.tsx +++ b/src/components/ui/label.tsx @@ -13,7 +13,7 @@ function Label({ - +
+ + +
); } diff --git a/src/components/user/redirect-button.tsx b/src/components/user/redirect-button.tsx index c4bf997..e4f8a62 100644 --- a/src/components/user/redirect-button.tsx +++ b/src/components/user/redirect-button.tsx @@ -1,4 +1,4 @@ -import { Button } from '../ui/button'; +import { Button } from '../custom-ui/button'; import Link from 'next/link'; export function RedirectButton({ diff --git a/src/components/user/sso-login-button.tsx b/src/components/user/sso-login-button.tsx index c1bd0e2..76eac83 100644 --- a/src/components/user/sso-login-button.tsx +++ b/src/components/user/sso-login-button.tsx @@ -1,6 +1,6 @@ import { signIn } from '@/auth'; -import { Button } from '@/components/ui/button'; -import { Fingerprint } from 'lucide-react'; +import { IconButton } from '@/components/icon-button'; +import { faOpenid } from '@fortawesome/free-brands-svg-icons'; export default function SSOLogin({ provider, @@ -17,19 +17,14 @@ export default function SSOLogin({ await signIn(provider); }} > - + Login with {providerDisplayName} + ); } diff --git a/src/components/user/theme-picker.tsx b/src/components/user/theme-picker.tsx index 5341c3c..37a2ceb 100644 --- a/src/components/user/theme-picker.tsx +++ b/src/components/user/theme-picker.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { Moon, Sun } from 'lucide-react'; import { useTheme } from 'next-themes'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/custom-ui/button'; import { DropdownMenu, DropdownMenuContent, diff --git a/src/middleware.ts b/src/middleware.ts index c3ab55c..b2f73cf 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -2,6 +2,6 @@ export { auth as middleware } from '@/auth'; export const config = { 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).*)', ], };