From dbe5cbdccdd812385c4e2424b472cb4d90ce6683 Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Wed, 25 Dec 2024 10:36:49 +0100 Subject: [PATCH] Introduce a "enhanced" theme selector for user settings --- .../UserSettings/ThemeSelector.module.css | 145 ++++++++++++++++++ .../components/UserSettings/ThemeSelector.tsx | 85 ++++++++++ .../components/UserSettings/UserSettings.tsx | 33 +--- app/styles/variables.css | 29 ++-- 4 files changed, 251 insertions(+), 41 deletions(-) create mode 100644 app/routes/users/components/UserSettings/ThemeSelector.module.css create mode 100644 app/routes/users/components/UserSettings/ThemeSelector.tsx diff --git a/app/routes/users/components/UserSettings/ThemeSelector.module.css b/app/routes/users/components/UserSettings/ThemeSelector.module.css new file mode 100644 index 0000000000..4faaceaad6 --- /dev/null +++ b/app/routes/users/components/UserSettings/ThemeSelector.module.css @@ -0,0 +1,145 @@ +.label { + font-size: var(--font-size-lg); + margin-bottom: var(--spacing-xs); +} + +.themes { + margin-bottom: var(--spacing-md); +} + +.optionWrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--spacing-xs); +} + +.themeOption { + position: relative; + width: 100px; + height: 100px; + cursor: pointer; + border: 1.5px solid var(--border-gray); + border-radius: var(--border-radius-md); + transition: border-color var(--easing-fast); + overflow: hidden; +} + +.themeOption[data-selected='true'], +.themeOption:hover:not(:disabled), +.themeOption:focus:not(:disabled) { + border-color: var(--color-gray-4); +} + +.previewContent { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; +} + +.previewBackground { + position: absolute; + inset: 0; + z-index: 0; +} + +.previewCard { + position: relative; + margin: var(--spacing-sm); + flex-grow: 1; + border-radius: var(--border-radius-sm); + display: flex; + align-items: center; + justify-content: center; +} + +.previewText { + font-size: var(--font-size-lg); + font-weight: 500; +} + +.auto .previewBackground { + background: linear-gradient( + 135deg, + var(--light-background-color) 0%, + var(--light-background-color) 50%, + var(--dark-background-color) 50%, + var(--dark-background-color) 100% + ); +} + +.auto .previewCard { + background: linear-gradient( + 135deg, + var(--light-card-color) 0%, + var(--light-card-color) 50%, + var(--dark-card-color) 50%, + var(--dark-card-color) 100% + ); +} + +.auto .previewText { + background: linear-gradient( + 135deg, + var(--light-font-color) 0%, + var(--light-font-color) 50%, + var(--dark-font-color) 50%, + var(--dark-font-color) 100% + ); + background-clip: text; + color: transparent; +} + +.light .previewBackground { + background-color: var(--light-background-color); +} + +.light .previewCard { + background-color: var(--light-card-color); +} + +.light .previewText { + color: var(--light-font-color); +} + +.dark .previewBackground { + background-color: var(--dark-background-color); +} + +.dark .previewCard { + background-color: var(--dark-card-color); +} + +.dark .previewText { + color: var(--dark-font-color); +} + +.checkIcon { + position: absolute; + bottom: var(--spacing-xs); + right: var(--spacing-xs); + padding: calc(var(--spacing-xs) / 2); + border-radius: 50%; + opacity: 0; + transition: opacity var(--easing-fast); +} + +.light .checkIcon { + color: var(--dark-font-color); + background: var(--dark-card-color); +} + +.auto .checkIcon, +.dark .checkIcon { + color: var(--light-font-color); + background: var(--light-card-color); +} + +.themeOption[data-selected='true'] .checkIcon { + opacity: 1; +} + +.optionLabel { + font-size: var(--font-size-sm); +} diff --git a/app/routes/users/components/UserSettings/ThemeSelector.tsx b/app/routes/users/components/UserSettings/ThemeSelector.tsx new file mode 100644 index 0000000000..053fee8ebe --- /dev/null +++ b/app/routes/users/components/UserSettings/ThemeSelector.tsx @@ -0,0 +1,85 @@ +import { Flex, Icon } from '@webkom/lego-bricks'; +import cx from 'classnames'; +import { Check, MoonStar, Sun, SunMoon } from 'lucide-react'; +import { useEffect } from 'react'; +import { Field, useForm } from 'react-final-form'; +import { useTheme } from 'app/utils/themeUtils'; +import styles from './ThemeSelector.module.css'; +import type { ReactNode } from 'react'; + +type ThemeOption = { + icon: ReactNode; + label: string; + value: 'dark' | 'light' | 'auto'; +}; + +const themeOptions: ThemeOption[] = [ + { + icon: , + label: 'Auto', + value: 'auto', + }, + { + icon: , + label: 'Lyst', + value: 'light', + }, + { + icon: , + label: 'Mørkt', + value: 'dark', + }, +]; + +const ThemeSelector = () => { + const form = useForm(); + const theme = useTheme(); + + useEffect(() => { + form.change('selectedTheme', theme); + }, [form, theme]); + + return ( +
+ + + {themeOptions.map((option) => ( + + {({ input }) => ( +
+
input.onChange(option.value)} + > +
+
+
+
Aa
+
+
+ } + size={16} + className={styles.checkIcon} + /> +
+ + +
{option.label}
+
+
+ )} + + ))} + +
+ ); +}; + +export default ThemeSelector; diff --git a/app/routes/users/components/UserSettings/UserSettings.tsx b/app/routes/users/components/UserSettings/UserSettings.tsx index 8cae2fe164..d86f904474 100644 --- a/app/routes/users/components/UserSettings/UserSettings.tsx +++ b/app/routes/users/components/UserSettings/UserSettings.tsx @@ -3,13 +3,7 @@ import { usePreparedEffect } from '@webkom/react-prepare'; import { Field } from 'react-final-form'; import { useNavigate, useParams } from 'react-router-dom'; import { fetchUser, updateUser } from 'app/actions/UserActions'; -import { - TextInput, - MultiSelectGroup, - RadioButton, - PhoneNumberInput, - SelectInput, -} from 'app/components/Form'; +import { TextInput, PhoneNumberInput, SelectInput } from 'app/components/Form'; import LegoFinalForm from 'app/components/Form/LegoFinalForm'; import SubmissionError from 'app/components/Form/SubmissionError'; import { SubmitButton } from 'app/components/Form/SubmitButton'; @@ -32,6 +26,7 @@ import { } from 'app/utils/validation'; import AllergiesOrPreferencesField from '../AllergiesOrPreferencesField'; import ChangePassword from './ChangePassword'; +import ThemeSelector from './ThemeSelector'; import UserImage from './UserImage'; import styles from './UserSettings.module.css'; import type { CurrentUser } from 'app/store/models/User'; @@ -198,29 +193,7 @@ const UserSettings = () => { />
- - - - - + {showAbakusMembership && (