From 473c6ca38fdbc98aa6bdc9fb3ba0d4aba6655641 Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Wed, 14 Dec 2022 17:41:12 -0800 Subject: [PATCH 1/6] Preliminary theme changing capabilities --- client/public/service-worker.js | 2 +- client/src/App.tsx | 14 +++++++++++ .../components/firebase/SgyInitResults.tsx | 10 ++++---- client/src/components/layout/Badge.tsx | 2 +- client/src/components/layout/HeaderPage.tsx | 2 +- .../src/components/layout/OutlineButton.tsx | 4 ++-- client/src/components/layout/Wave.tsx | 23 ++++++++++++------- .../components/lists/ClubComponentModal.tsx | 6 ++--- .../src/components/lists/CourseComponent.tsx | 6 ++--- .../src/components/lists/StaffComponent.tsx | 6 ++--- client/src/contexts/UserDataContext.ts | 21 ++++++++++++++++- client/src/pages/Testing.tsx | 4 ++-- client/src/pages/settings/Appearance.tsx | 10 ++++++++ client/tailwind.config.js | 2 ++ 14 files changed, 82 insertions(+), 30 deletions(-) diff --git a/client/public/service-worker.js b/client/public/service-worker.js index 62eac214..53ab2dc5 100644 --- a/client/public/service-worker.js +++ b/client/public/service-worker.js @@ -1,7 +1,7 @@ // This dummy service worker is to hopefully migrate all users stuck on the old service worker URL // (`/service-worker.js`) to the new URL (`/sw.js`). The old service worker cannot detect the new service worker // because the URL has changed, so it will stop giving updated app versions and fall behind. This dummy worker -// attempts to remedy that by sending an update to the old service worker telling it to self destruct, which will +// attempts to remedy that by sending an update to the old service worker telling it to self-destruct, which will // hopefully cause the new worker to install itself. // Not sure if this is needed because the old service worker logic should already call `skipWaiting()` for us, but diff --git a/client/src/App.tsx b/client/src/App.tsx index 80cb6eae..1d538546 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -48,6 +48,7 @@ import {getRedirectResult} from 'firebase/auth'; import {useAlternates} from './hooks/useAlternates'; import {useLocalStorageData} from './hooks/useLocalStorageData'; import {firestoreInit} from './util/firestore'; +import {hexToRgb} from "@watt/client/src/util/progressBarColor"; // Lazy-loaded pages const Testing = lazy(() => import('./pages/Testing')); @@ -121,6 +122,19 @@ export default function App() { + + navigator.serviceWorker.getRegistration().then(res => res?.update())}/> {signInCheckResult?.signedIn && } diff --git a/client/src/components/firebase/SgyInitResults.tsx b/client/src/components/firebase/SgyInitResults.tsx index 74580b2e..ab6a0134 100644 --- a/client/src/components/firebase/SgyInitResults.tsx +++ b/client/src/components/firebase/SgyInitResults.tsx @@ -4,7 +4,7 @@ import {Dialog} from '@headlessui/react'; // Components import CenteredModal from '../layout/CenteredModal'; -import OutlineButton, {DangerOutlineButton, SuccessOutlineButton} from '../layout/OutlineButton'; +import OutlineButton, {ThemeOutlineButton, SuccessOutlineButton} from '../layout/OutlineButton'; import Loading from '../layout/Loading'; // Auth @@ -98,16 +98,16 @@ export default function SgyInitResults() {
{results && (confirmDisable ? (<> - + Yes, Disable Schoology - + setConfirm(false)}> Take Me Back! ) : (<> - setConfirm(true)}> + setConfirm(true)}> Disable Schoology - + Looks Good! diff --git a/client/src/components/layout/Badge.tsx b/client/src/components/layout/Badge.tsx index 2b4e4006..10e60625 100644 --- a/client/src/components/layout/Badge.tsx +++ b/client/src/components/layout/Badge.tsx @@ -4,7 +4,7 @@ import {ReactNode} from 'react'; type BadgeProps = {children: ReactNode}; export default function Badge(props: BadgeProps) { return ( - + {props.children} ) diff --git a/client/src/components/layout/HeaderPage.tsx b/client/src/components/layout/HeaderPage.tsx index 280682bd..bc77e74a 100644 --- a/client/src/components/layout/HeaderPage.tsx +++ b/client/src/components/layout/HeaderPage.tsx @@ -28,7 +28,7 @@ export default function HeaderPage(props: HeaderPageProps) { export function Header(props: {children: ReactNode}) { return ( -
+
{props.children}
) diff --git a/client/src/components/layout/OutlineButton.tsx b/client/src/components/layout/OutlineButton.tsx index cad58714..f8538d90 100644 --- a/client/src/components/layout/OutlineButton.tsx +++ b/client/src/components/layout/OutlineButton.tsx @@ -19,11 +19,11 @@ export default function OutlineButton(props: OutlineButtonProps) { ) } -export function DangerOutlineButton(props: OutlineButtonProps) { +export function ThemeOutlineButton(props: OutlineButtonProps) { const {children, ...buttonProps} = props; return ( - ) diff --git a/client/src/components/layout/Wave.tsx b/client/src/components/layout/Wave.tsx index 2cbe7e7d..8857b347 100644 --- a/client/src/components/layout/Wave.tsx +++ b/client/src/components/layout/Wave.tsx @@ -1,6 +1,13 @@ +import {useContext} from 'react'; +import UserDataContext from '../../contexts/UserDataContext'; + + export default function Wave() { - const leftColor = 'ff594c'; - const rightColor = 'eb144c'; + const userData = useContext(UserDataContext); + + const colors = userData.options.theme === 'dark' ? userData.colors.dark : userData.colors.light + const leftColor = colors.theme; + const rightColor = colors.accent; return ( // Constrain the width between 800px and 100vw as a hack for phone aspect ratio. @@ -9,8 +16,8 @@ export default function Wave() { - - + + - - + + - - + + Check In - setIsOpen(false)}> + setIsOpen(false)}> Close - +
) diff --git a/client/src/components/lists/CourseComponent.tsx b/client/src/components/lists/CourseComponent.tsx index c4231875..a30e22b0 100644 --- a/client/src/components/lists/CourseComponent.tsx +++ b/client/src/components/lists/CourseComponent.tsx @@ -4,7 +4,7 @@ import {Course} from '@watt/shared/data/courses'; // Components import CenteredModal from '../layout/CenteredModal'; -import {DangerOutlineButton} from '../layout/OutlineButton'; +import {ThemeOutlineButton} from '../layout/OutlineButton'; export default function CourseComponent(props: Course) { @@ -58,9 +58,9 @@ export default function CourseComponent(props: Course) {
- setModal(false)}> + setModal(false)}> Close - +
diff --git a/client/src/components/lists/StaffComponent.tsx b/client/src/components/lists/StaffComponent.tsx index 8e7feaf5..51880ad4 100644 --- a/client/src/components/lists/StaffComponent.tsx +++ b/client/src/components/lists/StaffComponent.tsx @@ -4,7 +4,7 @@ import {Staff} from '@watt/shared/data/staff'; // Components import CenteredModal from '../layout/CenteredModal'; -import OutlineButton, {DangerOutlineButton} from '../layout/OutlineButton'; +import OutlineButton, {ThemeOutlineButton} from '../layout/OutlineButton'; import PillClubComponent from './PillClubComponent'; // Context @@ -87,9 +87,9 @@ export default function StaffComponent(props: Staff & {id: string}) { Add to my list )} - setModal(false)}> + setModal(false)}> Close - + diff --git a/client/src/contexts/UserDataContext.ts b/client/src/contexts/UserDataContext.ts index b5a89a67..cdbc28de 100644 --- a/client/src/contexts/UserDataContext.ts +++ b/client/src/contexts/UserDataContext.ts @@ -27,7 +27,14 @@ export type UserData = { 5: SgyPeriodData, 6: SgyPeriodData, 7: SgyPeriodData, 8: SgyPeriodData, P: SgyPeriodData, S: SgyPeriodData, H: SgyPeriodData }, - options: {theme: string, time: string, period0: boolean, period8: boolean, clock: boolean, sgy: boolean}, + options: { + theme: string, time: string, period0: boolean, period8: boolean, + clock: boolean, sgy: boolean + }, + colors: { + dark: { theme: string, accent: string, shadow: string }, + light: { theme: string, accent: string, shadow: string } + } id: string, gradYear: number, // The year (eg. 2023) or `0` if unset sgy: { @@ -68,6 +75,18 @@ export const defaultUserData: UserData = { clock: true, sgy: false }, + colors: { + dark: { + theme: "#ff594c", + accent: "#eb144c", + shadow: "#b91c1c" + }, + light: { + theme: "#a51618", + accent: "#b91c1c", + shadow: "#b91c1c" + } + }, id: '00000', gradYear: 0, sgy: { diff --git a/client/src/pages/Testing.tsx b/client/src/pages/Testing.tsx index 17379d08..3ad7cf89 100644 --- a/client/src/pages/Testing.tsx +++ b/client/src/pages/Testing.tsx @@ -2,7 +2,7 @@ import {ReactNode, useContext, useEffect, useState} from 'react'; // Components import CenteredMessage from '../components/layout/CenteredMessage'; -import OutlineButton, {DangerOutlineButton, SuccessOutlineButton} from '../components/layout/OutlineButton'; +import OutlineButton, {ThemeOutlineButton, SuccessOutlineButton} from '../components/layout/OutlineButton'; import Period from '../components/schedule/Period'; import Loading from '../components/layout/Loading'; import WIP from '../components/layout/WIP'; @@ -127,7 +127,7 @@ export default function Testing() { Add to my list - Disable Schoology + Disable Schoology Looks good! diff --git a/client/src/pages/settings/Appearance.tsx b/client/src/pages/settings/Appearance.tsx index 69ebbaf1..0e9b3aaa 100644 --- a/client/src/pages/settings/Appearance.tsx +++ b/client/src/pages/settings/Appearance.tsx @@ -23,6 +23,8 @@ export default function Appearance() { const changeTheme = async (theme: string) => await updateUserData('options.theme', theme, auth, firestore); const changeTime = async (time: string) => await updateUserData('options.time', time, auth, firestore); + const changeColors = async (theme: string, accent: string, shadow: string) => + await updateUserData('colors.dark', {theme, accent, shadow}, auth, firestore); return ( @@ -40,6 +42,14 @@ export default function Appearance() { +
+

Colors

+
+ + +
+
+ 12-hour time ({currTime.toFormat('h:mm:ss a')}). diff --git a/client/tailwind.config.js b/client/tailwind.config.js index 870cd740..a81b7a7e 100644 --- a/client/tailwind.config.js +++ b/client/tailwind.config.js @@ -8,6 +8,8 @@ module.exports = { extend: { colors: { theme: 'rgb(var(--theme) / )', + 'theme-secondary': 'rgb(var(--theme-secondary) / )', + 'theme-tertiary': 'rgb(var(--theme-tertiary) / )', primary: 'rgb(var(--primary))', // NOTE: `primary`, `secondary`, and `tertiary` do *not* work with opacity modifiers. secondary: 'rgb(var(--secondary))', tertiary: 'rgb(var(--tertiary))', From 6242df16f5a6a8f4ca1afca33e01d3034c85b32d Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Wed, 14 Dec 2022 20:57:14 -0800 Subject: [PATCH 2/6] Nicer looking color cards for color preset swapping --- client/src/components/layout/HeaderPage.tsx | 2 +- client/src/contexts/UserDataContext.ts | 7 ++- client/src/pages/settings/Appearance.tsx | 50 +++++++++++++++------ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/client/src/components/layout/HeaderPage.tsx b/client/src/components/layout/HeaderPage.tsx index bc77e74a..ce16dd05 100644 --- a/client/src/components/layout/HeaderPage.tsx +++ b/client/src/components/layout/HeaderPage.tsx @@ -28,7 +28,7 @@ export default function HeaderPage(props: HeaderPageProps) { export function Header(props: {children: ReactNode}) { return ( -
+
{props.children}
) diff --git a/client/src/contexts/UserDataContext.ts b/client/src/contexts/UserDataContext.ts index cdbc28de..e4aea4d6 100644 --- a/client/src/contexts/UserDataContext.ts +++ b/client/src/contexts/UserDataContext.ts @@ -18,6 +18,8 @@ export type CustomAssignment = { export type SgyAssignmentModified = Partial & {id: string}; // or Pick export type CustomLabel = { id: string, name: string, color: string }; +export type ThemeColors = { theme: string, accent: string, shadow: string }; + export type UserData = { clubs: string[], staff: string[], @@ -31,10 +33,7 @@ export type UserData = { theme: string, time: string, period0: boolean, period8: boolean, clock: boolean, sgy: boolean }, - colors: { - dark: { theme: string, accent: string, shadow: string }, - light: { theme: string, accent: string, shadow: string } - } + colors: { dark: ThemeColors, light: ThemeColors } id: string, gradYear: number, // The year (eg. 2023) or `0` if unset sgy: { diff --git a/client/src/pages/settings/Appearance.tsx b/client/src/pages/settings/Appearance.tsx index 0e9b3aaa..ba5824e6 100644 --- a/client/src/pages/settings/Appearance.tsx +++ b/client/src/pages/settings/Appearance.tsx @@ -3,7 +3,7 @@ import {RadioGroup} from '@headlessui/react'; import {FiCheck, FiCircle} from 'react-icons/all'; // Contexts -import UserDataContext from '../../contexts/UserDataContext'; +import UserDataContext, {ThemeColors} from '../../contexts/UserDataContext'; import CurrentTimeContext from '../../contexts/CurrentTimeContext'; // Firestore @@ -23,8 +23,8 @@ export default function Appearance() { const changeTheme = async (theme: string) => await updateUserData('options.theme', theme, auth, firestore); const changeTime = async (time: string) => await updateUserData('options.time', time, auth, firestore); - const changeColors = async (theme: string, accent: string, shadow: string) => - await updateUserData('colors.dark', {theme, accent, shadow}, auth, firestore); + const changeColors = async (colors: Partial) => + await updateUserData('colors.dark', colors, auth, firestore); return ( @@ -42,13 +42,14 @@ export default function Appearance() { -
-

Colors

-
- - -
-
+ a.theme === b.theme}> + + WATT's classic, red look. + + + A golden theme for golden students. + + @@ -64,11 +65,11 @@ export default function Appearance() { } // TODO: should these be extracted as layout components? -type RadioCardsProps = { - value: string, onChange: (value: string) => void, +type RadioCardsProps = { + value: T, onChange: (value: T) => void, by?: (a: T, b: T) => boolean, label: string, children: ReactNode } -function RadioCards(props: RadioCardsProps) { +function RadioCards(props: RadioCardsProps) { const {label, children, ...radioGroupProps} = props; return ( @@ -102,3 +103,26 @@ function RadioCard(props: RadioCardProps) { ) } + +function ColorCard(props: {label: string, value: ThemeColors, children: ReactNode}) { + const {label, value, children} = props; + + return ( + + {({checked}) => (<> + +
+
+
+
+
+
+ {label} + + {children} + +
+ )} + + ) +} From ebd5c6d65cc15eb1895cf338cb8beaad835eeb08 Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Wed, 14 Dec 2022 22:09:29 -0800 Subject: [PATCH 3/6] Themes util, change logo color with theme --- client/src/components/layout/Logo.tsx | 10 +++++++-- client/src/components/layout/Sidebar.tsx | 2 +- client/src/contexts/UserDataContext.ts | 18 +++------------ client/src/pages/settings/Appearance.tsx | 21 +++++++++--------- client/src/util/themes.ts | 28 ++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 client/src/util/themes.ts diff --git a/client/src/components/layout/Logo.tsx b/client/src/components/layout/Logo.tsx index 5abbe7ea..2c82204e 100644 --- a/client/src/components/layout/Logo.tsx +++ b/client/src/components/layout/Logo.tsx @@ -1,6 +1,12 @@ +import {useContext} from 'react'; +import UserDataContext from '../../contexts/UserDataContext'; + + export default function Logo(props: {className?: string}) { - const foregroundColor = '#a51618'; - const backgroundColor = '#7f1618'; + const userData = useContext(UserDataContext); + + const foregroundColor = userData.colors.dark.theme || '#a51618'; + const backgroundColor = userData.colors.dark.accent || '#7f1618'; return ( & {id: string}; // or Pick export type CustomLabel = { id: string, name: string, color: string }; -export type ThemeColors = { theme: string, accent: string, shadow: string }; - export type UserData = { clubs: string[], staff: string[], @@ -33,7 +32,7 @@ export type UserData = { theme: string, time: string, period0: boolean, period8: boolean, clock: boolean, sgy: boolean }, - colors: { dark: ThemeColors, light: ThemeColors } + colors: ColorTheme id: string, gradYear: number, // The year (eg. 2023) or `0` if unset sgy: { @@ -74,18 +73,7 @@ export const defaultUserData: UserData = { clock: true, sgy: false }, - colors: { - dark: { - theme: "#ff594c", - accent: "#eb144c", - shadow: "#b91c1c" - }, - light: { - theme: "#a51618", - accent: "#b91c1c", - shadow: "#b91c1c" - } - }, + colors: defaultTheme, id: '00000', gradYear: 0, sgy: { diff --git a/client/src/pages/settings/Appearance.tsx b/client/src/pages/settings/Appearance.tsx index ba5824e6..4f0985db 100644 --- a/client/src/pages/settings/Appearance.tsx +++ b/client/src/pages/settings/Appearance.tsx @@ -3,12 +3,13 @@ import {RadioGroup} from '@headlessui/react'; import {FiCheck, FiCircle} from 'react-icons/all'; // Contexts -import UserDataContext, {ThemeColors} from '../../contexts/UserDataContext'; +import UserDataContext from '../../contexts/UserDataContext'; import CurrentTimeContext from '../../contexts/CurrentTimeContext'; // Firestore import {useAuth, useFirestore} from 'reactfire'; import { updateUserData } from '../../util/firestore'; +import {ColorTheme, defaultTheme, goldenRod} from '../../util/themes'; export default function Appearance() { @@ -23,8 +24,8 @@ export default function Appearance() { const changeTheme = async (theme: string) => await updateUserData('options.theme', theme, auth, firestore); const changeTime = async (time: string) => await updateUserData('options.time', time, auth, firestore); - const changeColors = async (colors: Partial) => - await updateUserData('colors.dark', colors, auth, firestore); + const changeColors = async (colors: ColorTheme) => + await updateUserData('colors', colors, auth, firestore); return ( @@ -42,11 +43,11 @@ export default function Appearance() { - a.theme === b.theme}> - + a.dark.theme === b.dark.theme}> + WATT's classic, red look. - + A golden theme for golden students. @@ -104,7 +105,7 @@ function RadioCard(props: RadioCardProps) { ) } -function ColorCard(props: {label: string, value: ThemeColors, children: ReactNode}) { +function ColorCard(props: {label: string, value: ColorTheme, children: ReactNode}) { const {label, value, children} = props; return ( @@ -112,9 +113,9 @@ function ColorCard(props: {label: string, value: ThemeColors, children: ReactNod {({checked}) => (<>
-
-
-
+
+
+
{label} diff --git a/client/src/util/themes.ts b/client/src/util/themes.ts new file mode 100644 index 00000000..f587e68d --- /dev/null +++ b/client/src/util/themes.ts @@ -0,0 +1,28 @@ +export type Colors = { theme: string, accent: string, shadow: string }; +export type ColorTheme = { dark: Colors, light: Colors } + +export const defaultTheme: ColorTheme = { + dark: { + theme: "#ff594c", + accent: "#eb144c", + shadow: "#b91c1c" + }, + light: { + theme: "#a51618", + accent: "#b91c1c", + shadow: "#b91c1c" + } +} + +export const goldenRod: ColorTheme = { + dark: { + theme: '#f59e0b', + accent: '#ea580c', + shadow: '#c2410c' + }, + light: { + theme: '#f59e0b', + accent: '#ea580c', + shadow: '#c2410c' + } +} From 87b332e32ec63467e3ae61f8b9b5d035ac0b1bfd Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Wed, 14 Dec 2022 22:16:30 -0800 Subject: [PATCH 4/6] Display correct colors on light mode --- client/src/pages/settings/Appearance.tsx | 9 ++++++--- client/src/util/themes.ts | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client/src/pages/settings/Appearance.tsx b/client/src/pages/settings/Appearance.tsx index 4f0985db..780aa157 100644 --- a/client/src/pages/settings/Appearance.tsx +++ b/client/src/pages/settings/Appearance.tsx @@ -108,14 +108,17 @@ function RadioCard(props: RadioCardProps) { function ColorCard(props: {label: string, value: ColorTheme, children: ReactNode}) { const {label, value, children} = props; + const userData = useContext(UserDataContext); + const colors = userData.options.theme === 'dark' ? value.dark : value.light; + return ( {({checked}) => (<>
-
-
-
+
+
+
{label} diff --git a/client/src/util/themes.ts b/client/src/util/themes.ts index f587e68d..b78b84a9 100644 --- a/client/src/util/themes.ts +++ b/client/src/util/themes.ts @@ -22,7 +22,7 @@ export const goldenRod: ColorTheme = { }, light: { theme: '#f59e0b', - accent: '#ea580c', + accent: '#f97316', shadow: '#c2410c' } } From 36c37dd3d80bed14bc78b69971a5aa9a0b6a5d7f Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Wed, 14 Dec 2022 22:46:01 -0800 Subject: [PATCH 5/6] Move style-tag logic to own component Plus, semi-hacky handling for default theme to accommodate special cases with wave and logo. --- client/package.json | 2 +- client/src/App.tsx | 16 +----- client/src/components/layout/Logo.tsx | 6 ++- client/src/components/layout/ThemeHandler.tsx | 54 +++++++++++++++++++ client/src/components/layout/Wave.tsx | 7 +-- client/src/contexts/UserDataContext.ts | 2 +- client/src/pages/settings/Appearance.tsx | 6 +-- client/src/util/themes.ts | 28 ---------- package-lock.json | 16 +++--- 9 files changed, 77 insertions(+), 60 deletions(-) create mode 100644 client/src/components/layout/ThemeHandler.tsx delete mode 100644 client/src/util/themes.ts diff --git a/client/package.json b/client/package.json index ee5fa176..e492d5b8 100755 --- a/client/package.json +++ b/client/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { - "@headlessui/react": "^1.7.4", + "@headlessui/react": "^1.7.5", "firebase": "^9.14.0", "he": "^1.2.0", "luxon": "^3.1.0", diff --git a/client/src/App.tsx b/client/src/App.tsx index 1d538546..4fa51a79 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -32,6 +32,7 @@ import PageNotFound from './pages/404'; import SgyAuthRedirect from './pages/SgyAuthRedirect'; // Components +import ThemeHandler from './components/layout/ThemeHandler'; import FaviconHandler from './components/schedule/FaviconHandler'; import InstallModal from './components/layout/InstallModal'; import SgyInitResults from './components/firebase/SgyInitResults'; @@ -48,7 +49,6 @@ import {getRedirectResult} from 'firebase/auth'; import {useAlternates} from './hooks/useAlternates'; import {useLocalStorageData} from './hooks/useLocalStorageData'; import {firestoreInit} from './util/firestore'; -import {hexToRgb} from "@watt/client/src/util/progressBarColor"; // Lazy-loaded pages const Testing = lazy(() => import('./pages/Testing')); @@ -122,21 +122,9 @@ export default function App() { - - navigator.serviceWorker.getRegistration().then(res => res?.update())}/> + {signInCheckResult?.signedIn && } diff --git a/client/src/components/layout/Logo.tsx b/client/src/components/layout/Logo.tsx index 2c82204e..a9de755a 100644 --- a/client/src/components/layout/Logo.tsx +++ b/client/src/components/layout/Logo.tsx @@ -5,8 +5,10 @@ import UserDataContext from '../../contexts/UserDataContext'; export default function Logo(props: {className?: string}) { const userData = useContext(UserDataContext); - const foregroundColor = userData.colors.dark.theme || '#a51618'; - const backgroundColor = userData.colors.dark.accent || '#7f1618'; + // TODO: see todo in `Wave.tsx` + const colors = userData.options.theme === 'dark' ? userData.colors.dark : userData.colors.light; + const foregroundColor = userData.colors.id !== 'default' ? colors.theme : '#a51618'; + const backgroundColor = userData.colors.id !== 'default' ? colors.accent : '#7f1618'; return ( + {`:root { + --theme: ${hexToRgb(colors.light.theme)?.join(' ')}; + --theme-secondary: ${hexToRgb(colors.light.accent)?.join(' ')}; + --theme-tertiary: ${hexToRgb(colors.light.shadow)?.join(' ')}; + } + :root.dark { + --theme: ${hexToRgb(colors.dark.theme)?.join(' ')}; + --theme-secondary: ${hexToRgb(colors.dark.accent)?.join(' ')}; + --theme-tertiary: ${hexToRgb(colors.dark.shadow)?.join(' ')}; + }`} + + ) +} + +export const defaultTheme: ColorTheme = { + id: 'default', + dark: { + theme: '#ff594c', + accent: '#eb144c', + shadow: '#b91c1c' + }, + light: { + theme: '#a51618', + accent: '#b91c1c', + shadow: '#b91c1c' + } +} + +export const goldenRod: ColorTheme = { + id: 'goldenrod', + dark: { + theme: '#f59e0b', + accent: '#ea580c', + shadow: '#c2410c' + }, + light: { + theme: '#f59e0b', + accent: '#f97316', + shadow: '#c2410c' + } +} diff --git a/client/src/components/layout/Wave.tsx b/client/src/components/layout/Wave.tsx index 8857b347..207f4b5a 100644 --- a/client/src/components/layout/Wave.tsx +++ b/client/src/components/layout/Wave.tsx @@ -5,9 +5,10 @@ import UserDataContext from '../../contexts/UserDataContext'; export default function Wave() { const userData = useContext(UserDataContext); - const colors = userData.options.theme === 'dark' ? userData.colors.dark : userData.colors.light - const leftColor = colors.theme; - const rightColor = colors.accent; + // TODO: make cleaner, extract logic? + const colors = userData.options.theme === 'dark' ? userData.colors.dark : userData.colors.light; + const leftColor = userData.colors.id !== 'default' ? colors.theme : '#ff594c'; + const rightColor = userData.colors.id !== 'default' ? colors.accent : '#eb144c'; return ( // Constrain the width between 800px and 100vw as a hack for phone aspect ratio. diff --git a/client/src/contexts/UserDataContext.ts b/client/src/contexts/UserDataContext.ts index 39821992..de0b3694 100644 --- a/client/src/contexts/UserDataContext.ts +++ b/client/src/contexts/UserDataContext.ts @@ -1,6 +1,6 @@ import {createContext} from 'react'; import {AllSgyPeriod} from './SgyDataContext'; -import {ColorTheme, defaultTheme} from '../util/themes'; +import {ColorTheme, defaultTheme} from '../components/layout/ThemeHandler'; // Represents a course on Schoology. diff --git a/client/src/pages/settings/Appearance.tsx b/client/src/pages/settings/Appearance.tsx index 780aa157..edbfc178 100644 --- a/client/src/pages/settings/Appearance.tsx +++ b/client/src/pages/settings/Appearance.tsx @@ -9,7 +9,7 @@ import CurrentTimeContext from '../../contexts/CurrentTimeContext'; // Firestore import {useAuth, useFirestore} from 'reactfire'; import { updateUserData } from '../../util/firestore'; -import {ColorTheme, defaultTheme, goldenRod} from '../../util/themes'; +import {ColorTheme, defaultTheme, goldenRod} from '../../components/layout/ThemeHandler'; export default function Appearance() { @@ -43,7 +43,7 @@ export default function Appearance() { - a.dark.theme === b.dark.theme}> + WATT's classic, red look. @@ -67,7 +67,7 @@ export default function Appearance() { // TODO: should these be extracted as layout components? type RadioCardsProps = { - value: T, onChange: (value: T) => void, by?: (a: T, b: T) => boolean, + value: T, onChange: (value: T) => void, by?: (keyof T & string) | ((a: T, b: T) => boolean), label: string, children: ReactNode } function RadioCards(props: RadioCardsProps) { diff --git a/client/src/util/themes.ts b/client/src/util/themes.ts deleted file mode 100644 index b78b84a9..00000000 --- a/client/src/util/themes.ts +++ /dev/null @@ -1,28 +0,0 @@ -export type Colors = { theme: string, accent: string, shadow: string }; -export type ColorTheme = { dark: Colors, light: Colors } - -export const defaultTheme: ColorTheme = { - dark: { - theme: "#ff594c", - accent: "#eb144c", - shadow: "#b91c1c" - }, - light: { - theme: "#a51618", - accent: "#b91c1c", - shadow: "#b91c1c" - } -} - -export const goldenRod: ColorTheme = { - dark: { - theme: '#f59e0b', - accent: '#ea580c', - shadow: '#c2410c' - }, - light: { - theme: '#f59e0b', - accent: '#f97316', - shadow: '#c2410c' - } -} diff --git a/package-lock.json b/package-lock.json index ccfb23c7..cadea92c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "name": "@watt/client", "version": "0.1.0", "dependencies": { - "@headlessui/react": "^1.7.4", + "@headlessui/react": "^1.7.5", "firebase": "^9.14.0", "he": "^1.2.0", "luxon": "^3.1.0", @@ -2705,9 +2705,9 @@ } }, "node_modules/@headlessui/react": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.4.tgz", - "integrity": "sha512-D8n5yGCF3WIkPsjEYeM8knn9jQ70bigGGb5aUvN6y4BGxcT3OcOQOKcM3zRGllRCZCFxCZyQvYJF6ZE7bQUOyQ==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.5.tgz", + "integrity": "sha512-UZSxOfA0CYKO7QDT5OGlFvesvlR1SKkawwSjwQJwt7XQItpzRKdE3ZUQxHcg4LEz3C0Wler2s9psdb872ynwrQ==", "dependencies": { "client-only": "^0.0.1" }, @@ -11084,9 +11084,9 @@ } }, "@headlessui/react": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.4.tgz", - "integrity": "sha512-D8n5yGCF3WIkPsjEYeM8knn9jQ70bigGGb5aUvN6y4BGxcT3OcOQOKcM3zRGllRCZCFxCZyQvYJF6ZE7bQUOyQ==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.5.tgz", + "integrity": "sha512-UZSxOfA0CYKO7QDT5OGlFvesvlR1SKkawwSjwQJwt7XQItpzRKdE3ZUQxHcg4LEz3C0Wler2s9psdb872ynwrQ==", "requires": { "client-only": "^0.0.1" } @@ -11630,7 +11630,7 @@ "@watt/client": { "version": "file:client", "requires": { - "@headlessui/react": "^1.7.4", + "@headlessui/react": "1.7.5", "@types/he": "^1.1.2", "@types/luxon": "^3.1.0", "@types/react": "^18.0.15", From f00d7705ec060c8d4704b6cc071d5052190f1750 Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Wed, 14 Dec 2022 23:17:00 -0800 Subject: [PATCH 6/6] Add purple theme --- client/src/components/layout/ThemeHandler.tsx | 19 +++++++++++++++++-- client/src/pages/settings/Appearance.tsx | 7 +++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/client/src/components/layout/ThemeHandler.tsx b/client/src/components/layout/ThemeHandler.tsx index 5501128f..b681edaa 100644 --- a/client/src/components/layout/ThemeHandler.tsx +++ b/client/src/components/layout/ThemeHandler.tsx @@ -4,7 +4,7 @@ import {hexToRgb} from '../../util/progressBarColor'; type Colors = { theme: string, accent: string, shadow: string }; -export type ColorTheme = { id: 'default' | 'goldenrod', dark: Colors, light: Colors } +export type ColorTheme = { id: 'default' | 'goldenrod' | 'electric-violet', dark: Colors, light: Colors } export default function ThemeHandler() { const {colors} = useContext(UserDataContext); @@ -39,7 +39,7 @@ export const defaultTheme: ColorTheme = { } } -export const goldenRod: ColorTheme = { +export const goldenrod: ColorTheme = { id: 'goldenrod', dark: { theme: '#f59e0b', @@ -52,3 +52,18 @@ export const goldenRod: ColorTheme = { shadow: '#c2410c' } } + +export const electricViolet: ColorTheme = { + id: 'electric-violet', + dark: { + theme: '#e879f9', + accent: '#9024f5', + shadow: '#6b21a8' + }, + // TODO: play around with these and make better + light: { + theme: '#913399', + accent: '#5d30a6', + shadow: '#7e22ce' + } +} diff --git a/client/src/pages/settings/Appearance.tsx b/client/src/pages/settings/Appearance.tsx index edbfc178..5caa6f5a 100644 --- a/client/src/pages/settings/Appearance.tsx +++ b/client/src/pages/settings/Appearance.tsx @@ -9,7 +9,7 @@ import CurrentTimeContext from '../../contexts/CurrentTimeContext'; // Firestore import {useAuth, useFirestore} from 'reactfire'; import { updateUserData } from '../../util/firestore'; -import {ColorTheme, defaultTheme, goldenRod} from '../../components/layout/ThemeHandler'; +import {ColorTheme, defaultTheme, goldenrod, electricViolet} from '../../components/layout/ThemeHandler'; export default function Appearance() { @@ -47,9 +47,12 @@ export default function Appearance() { WATT's classic, red look. - + A golden theme for golden students. + + High-amp action! +