diff --git a/components/Bubble.module.css b/components/Bubble.module.css index 3e0fc144..a7f3b645 100644 --- a/components/Bubble.module.css +++ b/components/Bubble.module.css @@ -3,5 +3,5 @@ } .bubble:nth-child(odd) { - background-color: var(--blue-1-20); + background-color: var(--primary-accent-light); } diff --git a/components/Button.module.css b/components/Button.module.css index a6020fbd..93ebcab1 100644 --- a/components/Button.module.css +++ b/components/Button.module.css @@ -2,8 +2,8 @@ .link { font-family: "Poppins", "sans-serif"; border-radius: calc(20rem / 16); - background-color: var(--blue-2); - color: white; + background-color: var(--primary-accent); + color: var(--primary-background); border: none; outline: none; transition-duration: 0.3s; @@ -13,7 +13,7 @@ .button:hover, .link:hover { - background-color: var(--teal-2); + background-color: var(--secondary-accent); cursor: pointer; } diff --git a/components/ConnectWithUs.module.css b/components/ConnectWithUs.module.css index a0fc921d..f2d940f5 100644 --- a/components/ConnectWithUs.module.css +++ b/components/ConnectWithUs.module.css @@ -1,5 +1,5 @@ .header { - color: var(--blue-2); + color: var(--primary-accent); font-weight: 600; font-size: calc(36rem / 16); } diff --git a/components/EmailSignup.module.css b/components/EmailSignup.module.css index 357f88b3..03dc79c1 100644 --- a/components/EmailSignup.module.css +++ b/components/EmailSignup.module.css @@ -3,7 +3,7 @@ } .header { - color: var(--blue-2); + color: var(--primary-accent); font-weight: 600; font-size: calc(36rem / 16); } diff --git a/components/EventCard.module.css b/components/EventCard.module.css index 269f51b0..27393553 100644 --- a/components/EventCard.module.css +++ b/components/EventCard.module.css @@ -41,7 +41,7 @@ } .content > h2 { - color: var(--purple-2); + color: var(--primary-heading); font-size: 1rem; margin-bottom: calc(14rem / 16); } diff --git a/components/EventDescriptionCard.module.css b/components/EventDescriptionCard.module.css index 0ddff676..baab9b78 100644 --- a/components/EventDescriptionCard.module.css +++ b/components/EventDescriptionCard.module.css @@ -4,7 +4,7 @@ max-width: calc(540rem / 16); padding: calc(24rem / 16); border-radius: calc(20rem / 16); - background-color: white; + background-color: var(--primary-background); } .poster { @@ -35,7 +35,7 @@ .setting { margin: 0; - color: var(--blue-2); + color: var(--primary-accent); font-size: calc(14rem / 16); font-weight: 600; } @@ -67,7 +67,7 @@ .poster { width: calc(95rem / 16); height: calc(95rem / 16); - border: 1px solid var(--purple-2); + border: 1px solid var(--primary-heading); box-sizing: border-box; margin-right: calc(14rem / 16); } diff --git a/components/Footer.module.css b/components/Footer.module.css index 885469ed..2f4c9d0c 100644 --- a/components/Footer.module.css +++ b/components/Footer.module.css @@ -1,6 +1,6 @@ .footer { box-sizing: border-box; - background: var(--purple-2); + background: var(--primary-heading); height: calc(66rem / 16); padding: calc(14rem / 16) 0; width: 100%; @@ -18,7 +18,7 @@ } .text { - color: var(--white); + color: var(--primary-background); font-style: normal; text-align: center; } diff --git a/components/Input.module.css b/components/Input.module.css index 7fcb4c83..44209442 100644 --- a/components/Input.module.css +++ b/components/Input.module.css @@ -8,20 +8,20 @@ border: 0; border-radius: calc(20rem / 16); - background-color: var(--grey-1-24); + background-color: var(--input-background); font-size: calc(18rem / 16); line-height: calc(30rem / 16); - color: var(--grey-3); + color: var(--input-text); } .input::placeholder { - color: var(--grey-2); + color: var(--input-placeholder-text); font-weight: 700; } .input:is(:active, :hover, :focus) { box-sizing: border-box; - border: calc(3rem / 16) solid var(--blue-1); + border: calc(3rem / 16) solid var(--primary-accent-soft); border-radius: calc(20rem / 16); outline: none; padding: calc(7rem / 16) calc(28rem / 16); diff --git a/components/Link.module.css b/components/Link.module.css index ba0d61f8..8edbfa31 100644 --- a/components/Link.module.css +++ b/components/Link.module.css @@ -1,10 +1,10 @@ .link { - color: var(--blue-2); + color: var(--primary-accent); transition-duration: 0.3s; text-decoration: none; white-space: normal; } .link:hover { - color: var(--teal-2); + color: var(--secondary-accent); } diff --git a/components/MiniEventCard.module.css b/components/MiniEventCard.module.css index ce61aa2b..c3c9e0bf 100644 --- a/components/MiniEventCard.module.css +++ b/components/MiniEventCard.module.css @@ -5,7 +5,7 @@ } .card:nth-child(odd) { - background-color: var(--teal-2-20); + background-color: var(--secondary-accent-light); } .name { @@ -19,7 +19,7 @@ } .info { - color: var(--purple-2); + color: var(--primary-heading); margin-bottom: calc(12rem / 16); } @@ -29,7 +29,7 @@ right: 0; cursor: pointer; margin: calc(20rem / 16); - color: var(--blue-2); + color: var(--primary-accent); font-size: calc(14rem / 16); } @@ -46,5 +46,5 @@ } .dropDownIcon { - fill: var(--blue-2); + fill: var(--primary-accent); } diff --git a/components/Navbar.module.css b/components/Navbar.module.css index 9dbbf03d..82e5475d 100644 --- a/components/Navbar.module.css +++ b/components/Navbar.module.css @@ -4,7 +4,7 @@ align-items: center; z-index: 10; - background-color: var(--white); + background-color: var(--primary-background); } .navContent { @@ -63,16 +63,16 @@ } .navMenu a { - color: var(--purple-2); + color: var(--primary-heading); text-decoration: none; } .navMenu a.currentPage { - color: var(--blue-2); + color: var(--primary-accent); } .navMenu > li > a:hover { - color: var(--blue-2); + color: var(--primary-accent); font-weight: 600; } @@ -116,8 +116,8 @@ padding: 0; border-radius: calc(8rem / 16); - background-color: var(--white); - box-shadow: 0 calc(8rem / 16) 1rem var(--blue-1-20); + background-color: var(--primary-background); + box-shadow: 0 calc(8rem / 16) 1rem var(--primary-accent-light); font-size: calc(14rem / 16); } @@ -134,7 +134,7 @@ .dropdown li:hover a, .dropdown li a:focus { - background-color: var(--blue-1-20); + background-color: var(--primary-accent-light); } .dropdown li:first-child a { @@ -224,7 +224,7 @@ left: 0; z-index: 20; - background-color: var(--navbar-gray); + background-color: var(--navbar-page-overlay); opacity: 0; transition: 0.5s; @@ -244,7 +244,7 @@ padding: calc(calc(64rem / 16) - 1rem); padding-left: calc(calc(78rem / 16) - 1rem); - background-color: var(--off-white); + background-color: var(--secondary-background); transform: translateX(100vw); transition: 0.5s; diff --git a/components/NewsCard.module.css b/components/NewsCard.module.css index 4114b061..b2ff0b13 100644 --- a/components/NewsCard.module.css +++ b/components/NewsCard.module.css @@ -1,7 +1,7 @@ .card { padding: calc(30rem / 16) calc(40rem / 16); max-width: calc(524rem / 16); - background-color: var(--white); + background-color: var(--primary-background); border-radius: calc(20rem / 16); } @@ -11,7 +11,7 @@ } .author { - color: var(--purple-1); + color: var(--secondary-heading); font-style: normal; } diff --git a/components/OrganizedContent.module.css b/components/OrganizedContent.module.css index 61d11ec6..8c5dc5bb 100644 --- a/components/OrganizedContent.module.css +++ b/components/OrganizedContent.module.css @@ -6,7 +6,7 @@ margin: 1rem 0; font-size: calc(24rem / 16); font-weight: 600; - color: var(--blue-2); + color: var(--primary-accent); } .content { @@ -17,7 +17,7 @@ .nav { margin: calc(8rem / 16) calc(32rem / 16) 0 0; - color: var(--purple-2); + color: var(--primary-heading); font-weight: 500; } @@ -26,7 +26,7 @@ overflow: hidden; white-space: nowrap; font-size: calc(14rem / 16); - border-bottom: calc(1rem / 16) solid var(--blue-2-25); + border-bottom: calc(1rem / 16) solid var(--primary-accent-light); align-items: center; height: calc(40rem / 16); width: calc(284rem / 16); @@ -41,8 +41,8 @@ } .selected { - background-color: var(--blue-1-05); - color: var(--blue-2); + background-color: var(--primary-accent-dim); + color: var(--primary-accent); font-weight: 700; } @@ -56,7 +56,7 @@ .selected .marker { display: inline; - background-color: var(--blue-2); + background-color: var(--primary-accent); height: calc(24rem / 16); width: calc(4rem / 16); margin-right: 1rem; @@ -73,7 +73,7 @@ flex: 1; display: flex; cursor: pointer; - color: var(--purple-2); + color: var(--primary-heading); font-size: calc(12rem / 16); } @@ -88,15 +88,15 @@ } .arrowHeading { - color: var(--blue-2); + color: var(--primary-accent); font-size: calc(14rem / 16); font-weight: 700; - border-bottom: calc(2rem / 16) solid var(--blue-2); + border-bottom: calc(2rem / 16) solid var(--primary-accent); padding-bottom: calc(4rem / 16); } .arrow { - fill: var(--blue-2); + fill: var(--primary-accent); margin-top: calc(27rem / 16); } diff --git a/components/SocialLinks.module.css b/components/SocialLinks.module.css index 200a8587..923e7dc1 100644 --- a/components/SocialLinks.module.css +++ b/components/SocialLinks.module.css @@ -18,9 +18,9 @@ } .blue { - fill: var(--blue-1); + fill: var(--primary-accent-soft); } .white { - fill: var(--white); + fill: var(--primary-background); } diff --git a/components/TeamMember.module.css b/components/TeamMember.module.css index b2f3a376..12df17b9 100644 --- a/components/TeamMember.module.css +++ b/components/TeamMember.module.css @@ -18,10 +18,10 @@ .name { font-weight: 700; - color: var(--blue-2); + color: var(--primary-accent); } .role { font-weight: 600; - color: var(--purple-2); + color: var(--primary-heading); } diff --git a/components/TeamMemberCard.module.css b/components/TeamMemberCard.module.css index 3065f92c..439cf9f0 100644 --- a/components/TeamMemberCard.module.css +++ b/components/TeamMemberCard.module.css @@ -29,7 +29,7 @@ grid-area: name; margin: 0; - color: var(--blue-2); + color: var(--primary-accent); font-size: calc(36rem / 16); font-weight: 600; } diff --git a/components/Theme.tsx b/components/Theme.tsx new file mode 100644 index 00000000..0c697b1c --- /dev/null +++ b/components/Theme.tsx @@ -0,0 +1,178 @@ +import React, { + createContext, + ReactElement, + useContext, + useEffect, + useState, +} from "react"; + +type BuiltInThemes = "light" | "dark"; + +export interface Theme { + name: BuiltInThemes | "custom"; + palette: Palette; +} + +export type SetThemeInput = BuiltInThemes | Partial; + +export const PALETTE_NAMES = [ + "--primary-background", + "--secondary-background", + + "--primary-accent", + "--primary-accent-soft", + "--primary-accent-light", + "--primary-accent-dim", + + "--secondary-accent", + "--secondary-accent-light", + + "--primary-heading", + "--secondary-heading", + + "--text", + + "--form-invalid", + + "--input-background", + "--input-placeholder-text", + "--input-text", + + "--navbar-page-overlay", +] as const; + +export const emptyPalette = PALETTE_NAMES.reduce( + (partial, varName) => ({ + ...partial, + [varName]: "#c4e0f8", + }), + {} as Palette +); + +const ThemeContext = + createContext< + | { + theme: Theme; + setTheme(input: SetThemeInput): void; + save(): void; + clearSaved(): void; + } + | undefined + >(undefined); + +export interface Props { + children?: ReactElement; +} + +export function ThemeProvider(props: Props) { + const update = useForcedUpdate(); + const [themeName, setThemeName] = + useState(undefined); + + const setTheme = (input: SetThemeInput) => { + if (typeof input === "string") { + PALETTE_NAMES.forEach((name) => + document.body.style.setProperty(name, "") + ); + + if (input === "light") { + document.body.classList.remove("dark"); + } else if (input === "dark") { + document.body.classList.add("dark"); + } + + setThemeName(input); + } else { + const properties = Object.keys(input) as PaletteNames[]; + + properties.forEach((property) => + document.body.style.setProperty( + property, + input[property]?.trim() ?? null + ) + ); + + setThemeName("custom"); + } + + update(); + }; + + useEffect(() => { + const customPalette = getSavedPalette(); + + if (customPalette == null) { + setThemeName("light"); + } else { + setTheme(customPalette); + setThemeName("custom"); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + savePalette(getCurrentPalette()), + clearSaved: clearSavedPalette, + } + } + > + {props.children} + + ); +} + +export function useThemeContext() { + return useContext(ThemeContext); +} + +export type PaletteNames = typeof PALETTE_NAMES[number]; + +export type Palette = { + [key in PaletteNames]: string; +}; + +function getCurrentPalette() { + const styles = getComputedStyle(document.body); + + return PALETTE_NAMES.reduce( + (partial, varName) => ({ + ...partial, + [varName]: styles.getPropertyValue(varName).trim(), + }), + {} as Palette + ); +} + +function useForcedUpdate() { + const [fakeState, setFakeState] = useState(true); + + return () => setFakeState(!fakeState); +} + +const STORAGE_KEY = "csc-theme-palette"; + +function getSavedPalette() { + const raw = localStorage.getItem(STORAGE_KEY); + + return raw == null ? undefined : (JSON.parse(raw) as Palette); +} + +function savePalette(palette: Palette) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(palette)); +} + +function clearSavedPalette() { + localStorage.removeItem(STORAGE_KEY); +} diff --git a/components/playground.module.css b/components/playground.module.css index b5b41d3d..c88c1f5f 100644 --- a/components/playground.module.css +++ b/components/playground.module.css @@ -1,13 +1,13 @@ .newsDemo { padding: calc(50rem / 16); - background-color: var(--off-white); + background-color: var(--secondary-background); display: inline-block; } .newsTitle { font-style: normal; font-weight: bold; - color: var(--purple-2); + color: var(--primary-heading); font-size: calc(24rem / 16); line-height: calc(36 / 24); margin-bottom: calc(14rem / 16); @@ -19,20 +19,20 @@ font-size: calc(14rem / 16); line-height: calc(21 / 14); white-space: pre-line; - color: var(--purple-2); + color: var(--primary-heading); vertical-align: baseline; } .news > hr { border: none; height: calc(1rem / 16); - background-color: var(--purple-2); + background-color: var(--primary-heading); margin: 0 0 calc(13rem / 16) 0; } .eventDescriptionCardDemo { padding: calc(50rem / 16) 0; - background-color: var(--off-white); + background-color: var(--secondary-background); display: inline-block; } @@ -54,7 +54,7 @@ .committee { margin: 0; - color: var(--purple-2); + color: var(--primary-heading); font-weight: 600; font-size: calc(24rem / 16); line-height: calc(36 / 24); @@ -63,7 +63,7 @@ .teamMemberDemo > hr { border: none; height: calc(1rem / 16); - background-color: var(--blue-2); + background-color: var(--primary-accent); width: 100%; margin-top: calc(24rem / 16); margin-bottom: calc(46rem / 16); @@ -78,24 +78,24 @@ .linkDemo { padding: calc(50rem / 16); - background-color: var(--off-white); + background-color: var(--secondary-background); } .linkTitle { font-weight: bold; - color: var(--purple-2); + color: var(--primary-heading); font-size: calc(24rem / 16); } .miniTechTalkDemo > *:nth-child(odd) { - background: var(--background-teal-2); + background: var(--secondary-accent-light); } @media only screen and (max-width: calc(768rem / 16)) { .newsDemo, .eventDescriptionCardDemo { padding: calc(20rem / 16); - background-color: var(--off-white); + background-color: var(--secondary-background); } .eventDescriptionCardDemo > * { diff --git a/components/theme.tsx b/components/theme.tsx deleted file mode 100644 index 8f972eb2..00000000 --- a/components/theme.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React, { createContext, ReactElement, useEffect, useState } from "react"; - -type Theme = "light" | "dark"; - -const ThemeContext = createContext<{ - theme: Theme; - setTheme(newTheme: Theme): void; -}>({ - theme: "light", - setTheme: () => { - throw new Error("Use ThemeProvider instead."); - }, -}); - -interface Props { - theme: Theme; - children?: ReactElement; -} - -export function ThemeProvider({ children, theme }: Props) { - const [currentTheme, setTheme] = useState(theme); - - useEffect(() => { - if (currentTheme === "light") { - document.body.classList.remove("dark"); - } else if (currentTheme === "dark") { - document.body.classList.add("dark"); - } - }, [currentTheme]); - - return ( - - {children} - - ); -} diff --git a/pages/_app.css b/pages/_app.css index 948b4449..5641a123 100644 --- a/pages/_app.css +++ b/pages/_app.css @@ -1,35 +1,31 @@ body { /* Default is light theme */ - --white: #ffffff; - --off-white: #fdf8f5; - --teal-1: #76ffdc; - --teal-2: #4ed4b2; - --teal-2-20: #4ed4b234; - --blue-1: #5caff9; - --blue-1-05: #5caff90d; - --blue-1-20: #5caff934; - --blue-2: #1482e3; - --blue-2-25: #1482e340; - --purple-1: #525284; - --purple-2: #2a2a62; - --black: #000000; - --grey-1: #c4c4c4; - --grey-1-24: #c4c4c440; - --grey-2: #bbbbbb; - --grey-3: #6b6b6b; - --red: #9f616a; - --gradient-blue-green: linear-gradient( - 99.94deg, - #1481e3 -17.95%, - #4ed4b2 172.82% - ); - --background-teal-2: rgb(78, 212, 178, 0.2); - /* used in mobile navbar background */ - --navbar-gray: #787878b2; - /* used in home page */ - --home-title-purple: #27153e; + --primary-background: #ffffff; + --secondary-background: #fdf8f5; - color: var(--black); + --primary-accent: #1482e3; + --primary-accent-soft: #5caff9; + --primary-accent-light: #c4e0f8; + --primary-accent-dim: #f7fbff; + + --secondary-accent: #4ed4b2; + --secondary-accent-light: #dcf6f0; + + --primary-heading: #2a2a62; + --secondary-heading: #525284; + + --text: #000000; + + --form-invalid: #9f616a; + + --input-background: #f0f0f0; + --input-placeholder-text: #bbbbbb; + --input-text: #6b6b6b; + + --navbar-page-overlay: #787878b2; + + background-color: var(--primary-background); + color: var(--text); font-family: "Poppins", "sans-serif"; font-size: 1rem; font-weight: 400; @@ -42,25 +38,8 @@ input { font-family: "Poppins", "sans-serif"; } -/* FIXME: Dark theme is the same as light theme right now */ .dark { - --white: #ffffff; - --off-white: #fdf8f5; - --teal-1: #76ffdc; - --teal-2: #4ed4b2; - --blue-1: #5caff9; - --blue-1-05: #5caff90d; - --blue-1-20: #5caff934; - --blue-2: #1482e3; - --purple-1: #525284; - --purple-2: #2a2a62; - --gradient-blue-green: linear-gradient( - 99.94deg, - #1481e3 -17.95%, - #4ed4b2 172.82% - ); - /* used in mobile navbar background */ - --navbar-gray: #787878b2; + /* FIXME: Implement dark theme */ } h1, @@ -71,7 +50,7 @@ h5, h6 { font-style: normal; line-height: 1.5; - color: var(--purple-2); + color: var(--primary-heading); } h1, diff --git a/pages/_app.tsx b/pages/_app.tsx index 4d14cc39..205e50dc 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -2,7 +2,7 @@ import React, { ComponentType, ReactNode } from "react"; import { NextComponentType, NextPageContext } from "next"; import { AppProps as DefaultAppProps } from "next/app"; import { MDXProvider } from "@mdx-js/react"; -import { ThemeProvider } from "../components/theme"; +import { ThemeProvider } from "../components/Theme"; import { Navbar } from "../components/Navbar"; import { Footer } from "../components/Footer"; import { Link } from "../components/Link"; @@ -16,7 +16,7 @@ export default function App({ Component, pageProps }: AppProps): JSX.Element { const Layout = Component.Layout ?? DefaultLayout; return ( - +
diff --git a/pages/about/index.module.css b/pages/about/index.module.css index cee87808..c3fc0309 100644 --- a/pages/about/index.module.css +++ b/pages/about/index.module.css @@ -9,12 +9,12 @@ } .content { - color: black; - background-color: white; + color: var(--text); + background-color: var(--primary-background); } .content span { - color: var(--blue-2); + color: var(--primary-accent); } .titleContainer { diff --git a/pages/about/our-supporters.module.css b/pages/about/our-supporters.module.css index 8cab3573..d9500dba 100644 --- a/pages/about/our-supporters.module.css +++ b/pages/about/our-supporters.module.css @@ -3,18 +3,18 @@ flex-direction: row; align-items: flex-end; padding-bottom: 1rem; - border-bottom: calc(1rem / 16) solid var(--purple-2); + border-bottom: calc(1rem / 16) solid var(--primary-heading); } .header { - color: var(--purple-2); + color: var(--primary-heading); margin: 0 1rem 0 0; text-align: center; } .content h2 { font-size: calc(24rem / 16); - color: var(--blue-2); + color: var(--primary-accent); } @media only screen and (max-width: calc(768rem / 16)) { diff --git a/pages/get-involved.module.css b/pages/get-involved.module.css index ffb0a066..8620172f 100644 --- a/pages/get-involved.module.css +++ b/pages/get-involved.module.css @@ -5,16 +5,16 @@ .page > header { display: flex; flex-direction: row; - border-bottom: calc(1rem / 16) solid var(--purple-2); + border-bottom: calc(1rem / 16) solid var(--primary-heading); } .headerText > h1 { - color: var(--purple-2); + color: var(--primary-heading); margin: 0 0 calc(8rem / 16) 0; } .headerText > p { - color: var(--black); + color: var(--text); margin: 0 0 calc(22rem / 16) 0; } @@ -27,7 +27,7 @@ } .content h2 { - color: var(--blue-2); + color: var(--primary-accent); } .content strong { @@ -60,7 +60,7 @@ } .headerText > h1 { - color: var(--purple-2); + color: var(--primary-heading); font-size: calc(24rem / 16); margin-bottom: (12rem / 16); } diff --git a/pages/index.module.css b/pages/index.module.css index ec2407d6..a68520e4 100644 --- a/pages/index.module.css +++ b/pages/index.module.css @@ -47,13 +47,13 @@ font-family: "Futura", "sans-serif"; font-size: calc(33rem / 16); text-align: center; - color: var(--home-title-purple); + color: var(--primary-heading); } .clubDescription { margin-bottom: calc(50rem / 16); text-align: center; - color: var(--purple-2); + color: var(--primary-heading); } .clubDescription br { @@ -71,7 +71,7 @@ margin: 0; width: 100%; - background-color: var(--off-white); + background-color: var(--secondary-background); } .cards { @@ -154,7 +154,7 @@ .clubDescription { margin: calc(8rem / 16) 0 calc(26rem / 16); - color: var(--purple-2); + color: var(--primary-heading); } .clubDescription br { @@ -196,6 +196,6 @@ margin: 1rem 0 calc(34rem / 16); height: calc(1rem / 16); border: none; - background-color: var(--purple-2); + background-color: var(--primary-heading); } } diff --git a/pages/themer.module.css b/pages/themer.module.css new file mode 100644 index 00000000..53ed9e6d --- /dev/null +++ b/pages/themer.module.css @@ -0,0 +1,38 @@ +.page { + margin-bottom: calc(60rem / 16); +} + +.controls { + display: flex; + justify-content: space-between; +} + +.controls > *:first-child { + margin-right: calc(20rem / 16); +} + +.palette { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(calc(150rem / 16), 1fr)); + row-gap: calc(20rem / 16); + column-gap: calc(40rem / 16); +} + +.palette > * { + display: flex; + flex-direction: column; + align-items: center; +} + +.colorSelector { + height: calc(75rem / 16); +} + +.colorReset { + margin-bottom: calc(10rem / 16); + transition-duration: unset; +} + +.colorName { + text-align: center; +} diff --git a/pages/themer.tsx b/pages/themer.tsx new file mode 100644 index 00000000..dd243d62 --- /dev/null +++ b/pages/themer.tsx @@ -0,0 +1,78 @@ +import React from "react"; +import { useThemeContext, emptyPalette } from "components/Theme"; +import { Input } from "components/Input"; +import { Button } from "components/Button"; + +import styles from "./themer.module.css"; + +export default function Themer() { + const context = useThemeContext(); + const palette = context?.theme.palette ?? emptyPalette; + + return ( +
+

Themer

+
event.preventDefault()}> +
+ + +
+
+ {Object.entries(palette).map(([key, value]) => { + const color = + value.length === 4 && value.startsWith("#") + ? `#${value[1].repeat(2)}${value[2].repeat(2)}${value[3].repeat( + 2 + )}` + : value; + + const isValidColor = color.startsWith("#") && color.length === 7; + + return ( +
+ + context?.setTheme({ [key]: event.target.value }) + } + /> + + + + +
+ ); + })} +
{" "} +
+
+ ); +}