chore: update theming structure (#1422)

* chore: store various shades of accent color

* refactor: custom theme selector

* refactor: custom theme selector

* chore: update custom theme input labels

* fix: color generator function logic

* fix: accent color preloaded data

* chore: new theming structure

* chore: update shades calculation logic

* refactor: variable names

* chore: update color scheming

* chore: new color scheming

* refactor: themes folder structure

* chore: update classnames according to new variables

* Revert "chore: update classnames according to new variables"

This reverts commit 60a87453b21768167e37889e709c12287ca07b08.

* chore: remove temp file
This commit is contained in:
Aaryan Khandelwal 2023-07-10 12:25:32 +05:30 committed by GitHub
parent d564ea8898
commit a14f8c281b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 645 additions and 337 deletions

View File

@ -22,7 +22,7 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
data={[ data={[
{ {
id: "issues_closed", id: "issues_closed",
color: "rgb(var(--color-accent))", color: "rgb(var(--color-primary-100))",
data: MONTHS_LIST.map((month) => ({ data: MONTHS_LIST.map((month) => ({
x: month.label.substring(0, 3), x: month.label.substring(0, 3),
y: y:
@ -50,7 +50,7 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
</div> </div>
)} )}
theme={{ theme={{
background: "rgb(var(--color-bg-base))", background: "rgb(var(--color-background-100))",
}} }}
enableArea enableArea
/> />

View File

@ -1,198 +0,0 @@
import React, { useEffect, useState } from "react";
import { useTheme } from "next-themes";
import { useForm } from "react-hook-form";
// hooks
import useUser from "hooks/use-user";
// ui
import { PrimaryButton } from "components/ui";
import { ColorPickerInput } from "components/core";
// services
import userService from "services/user.service";
// helper
import { applyTheme } from "helpers/theme.helper";
// types
import { ICustomTheme } from "types";
type Props = {
preLoadedData?: Partial<ICustomTheme> | null;
};
export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
const [darkPalette, setDarkPalette] = useState(false);
const defaultValues = {
accent: preLoadedData?.accent ?? "#FE5050",
bgBase: preLoadedData?.bgBase ?? "#FFF7F7",
bgSurface1: preLoadedData?.bgSurface1 ?? "#FFE0E0",
bgSurface2: preLoadedData?.bgSurface2 ?? "#FFF7F7",
border: preLoadedData?.border ?? "#FFC9C9",
darkPalette: preLoadedData?.darkPalette ?? false,
palette: preLoadedData?.palette ?? "",
sidebar: preLoadedData?.sidebar ?? "#FFFFFF",
textBase: preLoadedData?.textBase ?? "#430000",
textSecondary: preLoadedData?.textSecondary ?? "#323232",
};
const {
register,
formState: { errors, isSubmitting },
handleSubmit,
watch,
setValue,
reset,
} = useForm<any>({
defaultValues,
});
const { setTheme } = useTheme();
const { mutateUser } = useUser();
const handleFormSubmit = async (formData: any) => {
await userService
.updateUser({
theme: {
accent: formData.accent,
bgBase: formData.bgBase,
bgSurface1: formData.bgSurface1,
bgSurface2: formData.bgSurface2,
border: formData.border,
darkPalette: darkPalette,
palette: `${formData.bgBase},${formData.bgSurface1},${formData.bgSurface2},${formData.border},${formData.sidebar},${formData.accent},${formData.textBase},${formData.textSecondary}`,
sidebar: formData.sidebar,
textBase: formData.textBase,
textSecondary: formData.textSecondary,
},
})
.then((res) => {
mutateUser((prevData) => {
if (!prevData) return prevData;
return { ...prevData, user: res };
}, false);
applyTheme(formData.palette, darkPalette);
setTheme("custom");
})
.catch((err) => console.log(err));
};
const handleUpdateTheme = async (formData: any) => {
await handleFormSubmit({ ...formData, darkPalette });
reset({
...defaultValues,
});
};
useEffect(() => {
reset({
...defaultValues,
...preLoadedData,
});
}, [preLoadedData, reset]);
return (
<form onSubmit={handleSubmit(handleUpdateTheme)}>
<div className="space-y-5">
<h3 className="text-lg font-semibold text-brand-base">Customize your theme</h3>
<div className="space-y-4">
<div className="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-3">
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Background</h3>
<ColorPickerInput
name="bgBase"
error={errors.bgBase}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Background surface 1</h3>
<ColorPickerInput
name="bgSurface1"
error={errors.bgSurface1}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Background surface 2</h3>
<ColorPickerInput
name="bgSurface2"
error={errors.bgSurface2}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Border</h3>
<ColorPickerInput
name="border"
error={errors.border}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Sidebar</h3>
<ColorPickerInput
name="sidebar"
error={errors.sidebar}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Accent</h3>
<ColorPickerInput
name="accent"
error={errors.accent}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Text primary</h3>
<ColorPickerInput
name="textBase"
error={errors.textBase}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-base text-brand-secondary">Text secondary</h3>
<ColorPickerInput
name="textSecondary"
error={errors.textSecondary}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
</div>
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Creating Theme..." : "Set Theme"}
</PrimaryButton>
</div>
</form>
);
};

View File

@ -5,10 +5,8 @@ export * from "./gantt-chart-view";
export * from "./list-view"; export * from "./list-view";
export * from "./modals"; export * from "./modals";
export * from "./spreadsheet-view"; export * from "./spreadsheet-view";
export * from "./theme";
export * from "./sidebar"; export * from "./sidebar";
export * from "./issues-view"; export * from "./issues-view";
export * from "./image-picker-popover"; export * from "./image-picker-popover";
export * from "./feeds"; export * from "./feeds";
export * from "./theme-switch";
export * from "./custom-theme-selector";
export * from "./color-picker-input";

View File

@ -16,9 +16,11 @@ import { Popover, Transition } from "@headlessui/react";
import { Input } from "components/ui"; import { Input } from "components/ui";
// icons // icons
import { ColorPickerIcon } from "components/icons"; import { ColorPickerIcon } from "components/icons";
// types
import { ICustomTheme } from "types";
type Props = { type Props = {
name: string; name: keyof ICustomTheme;
watch: UseFormWatch<any>; watch: UseFormWatch<any>;
setValue: UseFormSetValue<any>; setValue: UseFormSetValue<any>;
error: FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined; error: FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined;
@ -31,31 +33,25 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
setValue(name, hex); setValue(name, hex);
}; };
const getColorText = (colorName: string) => { const getColorText = (colorName: keyof ICustomTheme) => {
switch (colorName) { switch (colorName) {
case "accent": case "background":
return "Accent";
case "bgBase":
return "Background"; return "Background";
case "bgSurface1": case "text":
return "Background surface 1"; return "Text";
case "bgSurface2": case "primary":
return "Background surface 2"; return "Primary(Theme)";
case "border": case "sidebarBackground":
return "Border"; return "Sidebar Background";
case "sidebar": case "sidebarText":
return "Sidebar"; return "Sidebar Text";
case "textBase":
return "Text primary";
case "textSecondary":
return "Text secondary";
default: default:
return "Color"; return "Color";
} }
}; };
return ( return (
<div className="relative "> <div className="relative">
<Input <Input
id={name} id={name}
name={name} name={name}

View File

@ -0,0 +1,167 @@
import React, { useEffect, useState } from "react";
import { useTheme } from "next-themes";
import { useForm } from "react-hook-form";
// hooks
import useUser from "hooks/use-user";
// ui
import { PrimaryButton } from "components/ui";
import { ColorPickerInput } from "components/core";
// services
import userService from "services/user.service";
// helper
import { applyTheme } from "helpers/theme.helper";
// types
import { ICustomTheme } from "types";
type Props = {
preLoadedData?: Partial<ICustomTheme> | null;
};
const defaultValues: ICustomTheme = {
background: "#fff7f7",
text: "#ffc9c9",
primary: "#fe5050",
sidebarBackground: "#ffffff",
sidebarText: "#000000",
darkPalette: false,
palette: "",
};
export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
const [darkPalette, setDarkPalette] = useState(false);
const {
register,
formState: { errors, isSubmitting },
handleSubmit,
watch,
setValue,
reset,
} = useForm<ICustomTheme>({
defaultValues,
});
const { setTheme } = useTheme();
const { mutateUser } = useUser();
const handleFormSubmit = async (formData: ICustomTheme) => {
const payload: ICustomTheme = {
background: formData.background,
text: formData.text,
primary: formData.primary,
sidebarBackground: formData.sidebarBackground,
sidebarText: formData.sidebarText,
darkPalette: darkPalette,
palette: `${formData.background},${formData.text},${formData.primary},${formData.sidebarBackground},${formData.sidebarText}`,
};
await userService
.updateUser({
theme: payload,
})
.then((res) => {
mutateUser((prevData) => {
if (!prevData) return prevData;
return { ...prevData, ...res };
}, false);
applyTheme(payload.palette, darkPalette);
setTheme("custom");
})
.catch((err) => console.log(err));
};
const handleUpdateTheme = async (formData: any) => {
await handleFormSubmit({ ...formData, darkPalette });
};
useEffect(() => {
reset({
...defaultValues,
...preLoadedData,
});
}, [preLoadedData, reset]);
return (
<form onSubmit={handleSubmit(handleUpdateTheme)}>
<div className="space-y-5">
<h3 className="text-lg font-semibold text-brand-base">Customize your theme</h3>
<div className="space-y-4">
<div className="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2 md:grid-cols-3">
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-brand-secondary">
Background color
</h3>
<ColorPickerInput
name="background"
error={errors.background}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-brand-secondary">Text color</h3>
<ColorPickerInput
name="text"
error={errors.text}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-brand-secondary">
Primary(Theme) color
</h3>
<ColorPickerInput
name="primary"
error={errors.primary}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-brand-secondary">
Sidebar background color
</h3>
<ColorPickerInput
name="sidebarBackground"
error={errors.sidebarBackground}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-brand-secondary">
Sidebar text color
</h3>
<ColorPickerInput
name="sidebarText"
error={errors.sidebarText}
watch={watch}
setValue={setValue}
register={register}
/>
</div>
</div>
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Creating Theme..." : "Set Theme"}
</PrimaryButton>
</div>
</form>
);
};

View File

@ -0,0 +1,3 @@
export * from "./color-picker-input";
export * from "./custom-theme-selector";
export * from "./theme-switch";

View File

@ -6,8 +6,6 @@ import { useTheme } from "next-themes";
import { THEMES_OBJ } from "constants/themes"; import { THEMES_OBJ } from "constants/themes";
// ui // ui
import { CustomSelect } from "components/ui"; import { CustomSelect } from "components/ui";
// helper
import { applyTheme } from "helpers/theme.helper";
// types // types
import { ICustomTheme, IUser } from "types"; import { ICustomTheme, IUser } from "types";
@ -79,19 +77,14 @@ export const ThemeSwitch: React.FC<Props> = ({
if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true); if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
} else { } else {
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false); if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
const cssVars = [
"--color-bg-base",
"--color-bg-surface-1",
"--color-bg-surface-2",
"--color-border", for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) {
"--color-bg-sidebar", document.documentElement.style.removeProperty(`--color-background-${i}`);
"--color-accent", document.documentElement.style.removeProperty(`--color-text-${i}`);
document.documentElement.style.removeProperty(`--color-primary-${i}`);
"--color-text-base", document.documentElement.style.removeProperty(`--color-sidebar-background-${i}`);
"--color-text-secondary", document.documentElement.style.removeProperty(`--color-sidebar-text-${i}`);
]; }
cssVars.forEach((cssVar) => document.documentElement.style.removeProperty(cssVar));
} }
setTheme(value); setTheme(value);
document.documentElement.style.setProperty("color-scheme", type); document.documentElement.style.setProperty("color-scheme", type);

View File

@ -2,27 +2,27 @@
import { Theme } from "@nivo/core"; import { Theme } from "@nivo/core";
export const CHARTS_THEME: Theme = { export const CHARTS_THEME: Theme = {
background: "rgb(var(--color-bg-surface-1))", background: "rgb(var(--color-background-90))",
textColor: "rgb(var(--color-text-secondary))", textColor: "rgb(var(--color-text-200))",
axis: { axis: {
domain: { domain: {
line: { line: {
stroke: "rgb(var(--color-border))", stroke: "rgb(var(--color-background-80))",
strokeWidth: 0.5, strokeWidth: 0.5,
}, },
}, },
}, },
tooltip: { tooltip: {
container: { container: {
background: "rgb(var(--color-bg-surface-2))", background: "rgb(var(--color-background-80))",
color: "rgb(var(--color-text-secondary))", color: "rgb(var(--color-text-200))",
fontSize: "0.8rem", fontSize: "0.8rem",
border: "1px solid rgb(var(--color-border))", border: "1px solid rgb(var(--color-background-80))",
}, },
}, },
grid: { grid: {
line: { line: {
stroke: "rgb(var(--color-border))", stroke: "rgb(var(--color-background-80))",
}, },
}, },
}; };

View File

@ -0,0 +1,19 @@
export type TRgb = { r: number; g: number; b: number };
export const hexToRgb = (hex: string): TRgb => {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return { r, g, b };
};
export const rgbToHex = (rgb: TRgb): string => {
const { r, g, b } = rgb;
const hexR = r.toString(16).padStart(2, "0");
const hexG = g.toString(16).padStart(2, "0");
const hexB = b.toString(16).padStart(2, "0");
return `#${hexR}${hexG}${hexB}`;
};

View File

@ -1,35 +1,102 @@
export const hexToRgb = (hex: string) => { import { TRgb, hexToRgb } from "helpers/color.helper";
hex = hex.toLowerCase();
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); type TShades = {
return result 10: TRgb;
? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)].join(",") 20: TRgb;
: null; 30: TRgb;
40: TRgb;
50: TRgb;
60: TRgb;
70: TRgb;
80: TRgb;
90: TRgb;
100: TRgb;
200: TRgb;
300: TRgb;
400: TRgb;
500: TRgb;
600: TRgb;
700: TRgb;
800: TRgb;
900: TRgb;
};
const calculateShades = (hexValue: string): TShades => {
const shades: Partial<TShades> = {};
const { r, g, b } = hexToRgb(hexValue);
const convertHexToSpecificShade = (shade: number): TRgb => {
if (shade <= 100) {
const decimalValue = (100 - shade) / 100;
const newR = Math.floor(r + (255 - r) * decimalValue);
const newG = Math.floor(g + (255 - g) * decimalValue);
const newB = Math.floor(b + (255 - b) * decimalValue);
return {
r: newR,
g: newG,
b: newB,
};
} else {
const decimalValue = 1 - Math.ceil((shade - 100) / 100) / 10;
const newR = Math.ceil(r * decimalValue);
const newG = Math.ceil(g * decimalValue);
const newB = Math.ceil(b * decimalValue);
return {
r: newR,
g: newG,
b: newB,
};
}
};
for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10))
shades[i as keyof TShades] = convertHexToSpecificShade(i);
return shades as TShades;
}; };
export const applyTheme = (palette: string, isDarkPalette: boolean) => { export const applyTheme = (palette: string, isDarkPalette: boolean) => {
const values: string[] = []; // palette: [bg, text, primary, sidebarBg, sidebarText]
palette.split(",").map((color: string) => { const values: string[] = palette.split(",");
const cssVarColor = hexToRgb(color);
if (cssVarColor) values.push(cssVarColor);
});
const cssVars = [
"--color-bg-base",
"--color-bg-surface-1",
"--color-bg-surface-2",
"--color-border",
"--color-bg-sidebar",
"--color-accent",
"--color-text-base",
"--color-text-secondary",
"color-scheme",
];
values.push(isDarkPalette ? "dark" : "light"); values.push(isDarkPalette ? "dark" : "light");
cssVars.forEach((cssVar, i) => const bgShades = calculateShades(values[0]);
const textShades = calculateShades(values[1]);
const primaryShades = calculateShades(values[2]);
const sidebarBackgroundShades = calculateShades(values[3]);
const sidebarTextShades = calculateShades(values[4]);
for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) {
const shade = i as keyof TShades;
const bgRgbValues = `${bgShades[shade].r}, ${bgShades[shade].g}, ${bgShades[shade].b}`;
const textRgbValues = `${textShades[shade].r}, ${textShades[shade].g}, ${textShades[shade].b}`;
const primaryRgbValues = `${primaryShades[shade].r}, ${primaryShades[shade].g}, ${primaryShades[shade].b}`;
const sidebarBackgroundRgbValues = `${sidebarBackgroundShades[shade].r}, ${sidebarBackgroundShades[shade].g}, ${sidebarBackgroundShades[shade].b}`;
const sidebarTextRgbValues = `${sidebarTextShades[shade].r}, ${sidebarTextShades[shade].g}, ${sidebarTextShades[shade].b}`;
document document
.querySelector<HTMLElement>("[data-theme='custom']") .querySelector<HTMLElement>("[data-theme='custom']")
?.style.setProperty(cssVar, values[i]) ?.style.setProperty(`--color-background-${shade}`, bgRgbValues);
); document
.querySelector<HTMLElement>("[data-theme='custom']")
?.style.setProperty(`--color-text-${shade}`, textRgbValues);
document
.querySelector<HTMLElement>("[data-theme='custom']")
?.style.setProperty(`--color-primary-${shade}`, primaryRgbValues);
document
.querySelector<HTMLElement>("[data-theme='custom']")
?.style.setProperty(`--color-sidebar-background-${shade}`, sidebarBackgroundRgbValues);
document
.querySelector<HTMLElement>("[data-theme='custom']")
?.style.setProperty(`--color-sidebar-text-${shade}`, sidebarTextRgbValues);
}
document
.querySelector<HTMLElement>("[data-theme='custom']")
?.style.setProperty("--color-scheme", values[5]);
}; };

View File

@ -94,10 +94,10 @@ const ProjectAuthorizationWrapped: React.FC<Props> = ({
<main <main
className={`relative flex h-full w-full flex-col overflow-hidden ${ className={`relative flex h-full w-full flex-col overflow-hidden ${
bg === "primary" bg === "primary"
? "bg-brand-surface-1" ? "bg-brand-base"
: bg === "secondary" : bg === "secondary"
? "bg-brand-sidebar" ? "bg-brand-surface-1"
: "bg-brand-base" : "bg-brand-surface-2"
}`} }`}
> >
<AppHeader <AppHeader

View File

@ -101,10 +101,10 @@ export const WorkspaceAuthorizationLayout: React.FC<Props> = ({
<main <main
className={`relative flex h-full w-full flex-col overflow-hidden ${ className={`relative flex h-full w-full flex-col overflow-hidden ${
bg === "primary" bg === "primary"
? "bg-brand-surface-1" ? "bg-brand-base"
: bg === "secondary" : bg === "secondary"
? "bg-brand-sidebar" ? "bg-brand-surface-1"
: "bg-brand-base" : "bg-brand-surface-2"
}`} }`}
> >
<AppHeader <AppHeader

View File

@ -17,42 +17,199 @@
} }
:root { :root {
--color-bg-base: 255, 255, 255; --color-primary-10: 236, 241, 255;
--color-bg-surface-1: 249, 250, 251; --color-primary-20: 217, 228, 255;
--color-bg-surface-2: 243, 244, 246; --color-primary-30: 197, 214, 255;
--color-primary-40: 178, 200, 255;
--color-primary-50: 159, 187, 255;
--color-primary-60: 140, 173, 255;
--color-primary-70: 121, 159, 255;
--color-primary-80: 101, 145, 255;
--color-primary-90: 82, 132, 255;
--color-primary-100: 63, 118, 255;
--color-primary-200: 57, 106, 230;
--color-primary-300: 50, 94, 204;
--color-primary-400: 44, 83, 179;
--color-primary-500: 38, 71, 153;
--color-primary-600: 32, 59, 128;
--color-primary-700: 25, 47, 102;
--color-primary-800: 19, 35, 76;
--color-primary-900: 13, 24, 51;
--color-border: 229, 231, 235; --color-background-10: 250, 250, 250;
--color-bg-sidebar: 255, 255, 255; --color-background-20: 245, 245, 245;
--color-accent: 63, 118, 255; --color-background-30: 241, 241, 241;
--color-background-40: 229, 229, 229;
--color-background-50: 212, 212, 212;
--color-background-60: 185, 185, 185;
--color-background-70: 163, 163, 163;
--color-background-80: 157, 157, 157;
--color-background-90: 129, 129, 129;
--color-background-100: 115, 115, 115;
--color-background-200: 104, 104, 104;
--color-background-300: 82, 82, 82;
--color-background-400: 64, 64, 64;
--color-background-500: 58, 58, 58;
--color-background-600: 46, 46, 46;
--color-background-700: 38, 38, 38;
--color-background-800: 34, 34, 34;
--color-background-900: 23, 23, 23;
--color-text-base: 3, 7, 18; --color-text-10: 250, 250, 250;
--color-text-secondary: 55, 65, 81; --color-text-20: 245, 245, 245;
--color-text-30: 241, 241, 241;
--color-text-40: 229, 229, 229;
--color-text-50: 212, 212, 212;
--color-text-60: 185, 185, 185;
--color-text-70: 163, 163, 163;
--color-text-80: 157, 157, 157;
--color-text-90: 129, 129, 129;
--color-text-100: 115, 115, 115;
--color-text-200: 104, 104, 104;
--color-text-300: 82, 82, 82;
--color-text-400: 64, 64, 64;
--color-text-500: 58, 58, 58;
--color-text-600: 46, 46, 46;
--color-text-700: 38, 38, 38;
--color-text-800: 34, 34, 34;
--color-text-900: 23, 23, 23;
--color-sidebar-background-10: 250, 250, 250;
--color-sidebar-background-20: 245, 245, 245;
--color-sidebar-background-30: 241, 241, 241;
--color-sidebar-background-40: 229, 229, 229;
--color-sidebar-background-50: 212, 212, 212;
--color-sidebar-background-60: 185, 185, 185;
--color-sidebar-background-70: 163, 163, 163;
--color-sidebar-background-80: 157, 157, 157;
--color-sidebar-background-90: 129, 129, 129;
--color-sidebar-background-100: 115, 115, 115;
--color-sidebar-background-200: 104, 104, 104;
--color-sidebar-background-300: 82, 82, 82;
--color-sidebar-background-400: 64, 64, 64;
--color-sidebar-background-500: 58, 58, 58;
--color-sidebar-background-600: 46, 46, 46;
--color-sidebar-background-700: 38, 38, 38;
--color-sidebar-background-800: 34, 34, 34;
--color-sidebar-background-900: 23, 23, 23;
--color-sidebar-text-10: 250, 250, 250;
--color-sidebar-text-20: 245, 245, 245;
--color-sidebar-text-30: 241, 241, 241;
--color-sidebar-text-40: 229, 229, 229;
--color-sidebar-text-50: 212, 212, 212;
--color-sidebar-text-60: 185, 185, 185;
--color-sidebar-text-70: 163, 163, 163;
--color-sidebar-text-80: 157, 157, 157;
--color-sidebar-text-90: 129, 129, 129;
--color-sidebar-text-100: 115, 115, 115;
--color-sidebar-text-200: 104, 104, 104;
--color-sidebar-text-300: 82, 82, 82;
--color-sidebar-text-400: 64, 64, 64;
--color-sidebar-text-500: 58, 58, 58;
--color-sidebar-text-600: 46, 46, 46;
--color-sidebar-text-700: 38, 38, 38;
--color-sidebar-text-800: 34, 34, 34;
--color-sidebar-text-900: 23, 23, 23;
} }
[data-theme="light"] { [data-theme="light"] {
--color-bg-base: 255, 255, 255; --color-background-10: 250, 250, 250;
--color-bg-surface-1: 249, 250, 251; --color-background-20: 245, 245, 245;
--color-bg-surface-2: 243, 244, 246; --color-background-30: 241, 241, 241;
--color-background-40: 229, 229, 229;
--color-border: 229, 231, 235; --color-background-50: 212, 212, 212;
--color-bg-sidebar: 255, 255, 255; --color-background-60: 185, 185, 185;
--color-accent: 63, 118, 255; --color-background-70: 163, 163, 163;
--color-background-80: 157, 157, 157;
--color-text-base: 3, 7, 18; --color-background-90: 129, 129, 129;
--color-text-secondary: 55, 65, 81; --color-background-100: 255, 255, 255;
--color-background-200: 104, 104, 104;
--color-background-300: 82, 82, 82;
--color-background-400: 64, 64, 64;
--color-background-500: 58, 58, 58;
--color-background-600: 46, 46, 46;
--color-background-700: 38, 38, 38;
--color-background-800: 34, 34, 34;
--color-background-900: 23, 23, 23;
} }
[data-theme="dark"] { [data-theme="dark"] {
--color-bg-base: 25, 27, 27; --color-background-10: 250, 250, 250;
--color-bg-surface-1: 29, 30, 32; --color-background-20: 245, 245, 245;
--color-bg-surface-2: 39, 42, 45; --color-background-30: 241, 241, 241;
--color-background-40: 229, 229, 229;
--color-background-50: 212, 212, 212;
--color-background-60: 185, 185, 185;
--color-background-70: 163, 163, 163;
--color-background-80: 157, 157, 157;
--color-background-90: 129, 129, 129;
--color-background-100: 115, 115, 115;
--color-background-200: 104, 104, 104;
--color-background-300: 82, 82, 82;
--color-background-400: 64, 64, 64;
--color-background-500: 58, 58, 58;
--color-background-600: 46, 46, 46;
--color-background-700: 38, 38, 38;
--color-background-800: 34, 34, 34;
--color-background-900: 23, 23, 23;
--color-border: 46, 50, 52; --color-text-10: 250, 250, 250;
--color-bg-sidebar: 19, 20, 22; --color-text-20: 245, 245, 245;
--color-accent: 60, 133, 217; --color-text-30: 241, 241, 241;
--color-text-40: 229, 229, 229;
--color-text-50: 212, 212, 212;
--color-text-60: 185, 185, 185;
--color-text-70: 163, 163, 163;
--color-text-80: 157, 157, 157;
--color-text-90: 129, 129, 129;
--color-text-100: 115, 115, 115;
--color-text-200: 104, 104, 104;
--color-text-300: 82, 82, 82;
--color-text-400: 64, 64, 64;
--color-text-500: 58, 58, 58;
--color-text-600: 46, 46, 46;
--color-text-700: 38, 38, 38;
--color-text-800: 34, 34, 34;
--color-text-900: 23, 23, 23;
--color-text-base: 233, 244, 252; --color-sidebar-background-10: 250, 250, 250;
--color-text-secondary: 142, 148, 146; --color-sidebar-background-20: 245, 245, 245;
--color-sidebar-background-30: 241, 241, 241;
--color-sidebar-background-40: 229, 229, 229;
--color-sidebar-background-50: 212, 212, 212;
--color-sidebar-background-60: 185, 185, 185;
--color-sidebar-background-70: 163, 163, 163;
--color-sidebar-background-80: 157, 157, 157;
--color-sidebar-background-90: 129, 129, 129;
--color-sidebar-background-100: 115, 115, 115;
--color-sidebar-background-200: 104, 104, 104;
--color-sidebar-background-300: 82, 82, 82;
--color-sidebar-background-400: 64, 64, 64;
--color-sidebar-background-500: 58, 58, 58;
--color-sidebar-background-600: 46, 46, 46;
--color-sidebar-background-700: 38, 38, 38;
--color-sidebar-background-800: 34, 34, 34;
--color-sidebar-background-900: 23, 23, 23;
--color-sidebar-text-10: 250, 250, 250;
--color-sidebar-text-20: 245, 245, 245;
--color-sidebar-text-30: 241, 241, 241;
--color-sidebar-text-40: 229, 229, 229;
--color-sidebar-text-50: 212, 212, 212;
--color-sidebar-text-60: 185, 185, 185;
--color-sidebar-text-70: 163, 163, 163;
--color-sidebar-text-80: 157, 157, 157;
--color-sidebar-text-90: 129, 129, 129;
--color-sidebar-text-100: 115, 115, 115;
--color-sidebar-text-200: 104, 104, 104;
--color-sidebar-text-300: 82, 82, 82;
--color-sidebar-text-400: 64, 64, 64;
--color-sidebar-text-500: 58, 58, 58;
--color-sidebar-text-600: 46, 46, 46;
--color-sidebar-text-700: 38, 38, 38;
--color-sidebar-text-800: 34, 34, 34;
--color-sidebar-text-900: 23, 23, 23;
} }
[data-theme="light-contrast"] { [data-theme="light-contrast"] {
@ -97,7 +254,7 @@
} }
body { body {
color: rgba(var(--color-text-base)); color: rgba(var(--color-text-100));
} }
/* scrollbar style */ /* scrollbar style */

View File

@ -1,46 +1,155 @@
function withOpacity(variableName) { const convertToRGB = (variableName) => `rgb(var(${variableName}))`;
return ({ opacityValue }) => {
if (opacityValue !== undefined) return `rgba(var(${variableName}), ${opacityValue})`;
return `rgb(var(${variableName}))`;
};
}
function convertToRGB(variableName) {
return `rgb(var(${variableName}))`;
}
module.exports = { module.exports = {
darkMode: "class", darkMode: "class",
content: ["./pages/**/*.tsx", "./components/**/*.tsx", "./layouts/**/*.tsx", "./ui/**/*.tsx"], content: ["./pages/**/*.tsx", "./components/**/*.tsx", "./layouts/**/*.tsx", "./ui/**/*.tsx"],
theme: { theme: {
extend: { extend: {
colors: {
brand: {
accent: withOpacity("--color-accent"),
base: withOpacity("--color-bg-base"),
},
},
borderColor: { borderColor: {
brand: { brand: {
base: withOpacity("--color-border"), base: convertToRGB("--color-background-80"),
"surface-1": withOpacity("--color-bg-surface-1"), secondary: convertToRGB("--color-background-90"),
"surface-2": withOpacity("--color-bg-surface-2"),
}, },
}, },
backgroundColor: { backgroundColor: {
brand: { brand: {
base: withOpacity("--color-bg-base"), base: convertToRGB("--color-background-100"),
"surface-1": withOpacity("--color-bg-surface-1"), "surface-1": convertToRGB("--color-background-90"),
"surface-2": withOpacity("--color-bg-surface-2"), "surface-2": convertToRGB("--color-background-80"),
sidebar: withOpacity("--color-bg-sidebar"), sidebar: convertToRGB("--color-sidebar-background-100"),
backdrop: "#131313", backdrop: "#131313",
}, },
}, },
textColor: { textColor: {
brand: { brand: {
base: withOpacity("--color-text-base"), base: convertToRGB("--color-text-100"),
secondary: withOpacity("--color-text-secondary"), secondary: convertToRGB("--color-text-200"),
},
},
colors: {
brand: {
base: convertToRGB("--color-background-100"),
accent: convertToRGB("--color-primary-100"),
backdrop: "#131313",
},
custom: {
primary: {
0: "rgb(255, 255, 255)",
10: convertToRGB("--color-primary-10"),
20: convertToRGB("--color-primary-20"),
30: convertToRGB("--color-primary-30"),
40: convertToRGB("--color-primary-40"),
50: convertToRGB("--color-primary-50"),
60: convertToRGB("--color-primary-60"),
70: convertToRGB("--color-primary-70"),
80: convertToRGB("--color-primary-80"),
90: convertToRGB("--color-primary-90"),
100: convertToRGB("--color-primary-100"),
200: convertToRGB("--color-primary-200"),
300: convertToRGB("--color-primary-300"),
400: convertToRGB("--color-primary-400"),
500: convertToRGB("--color-primary-500"),
600: convertToRGB("--color-primary-600"),
700: convertToRGB("--color-primary-700"),
800: convertToRGB("--color-primary-800"),
900: convertToRGB("--color-primary-900"),
1000: "rgb(0, 0, 0)",
DEFAULT: convertToRGB("--color-primary-100"),
},
background: {
0: "rgb(255, 255, 255)",
10: convertToRGB("--color-background-10"),
20: convertToRGB("--color-background-20"),
30: convertToRGB("--color-background-30"),
40: convertToRGB("--color-background-40"),
50: convertToRGB("--color-background-50"),
60: convertToRGB("--color-background-60"),
70: convertToRGB("--color-background-70"),
80: convertToRGB("--color-background-80"),
90: convertToRGB("--color-background-90"),
100: convertToRGB("--color-background-100"),
200: convertToRGB("--color-background-200"),
300: convertToRGB("--color-background-300"),
400: convertToRGB("--color-background-400"),
500: convertToRGB("--color-background-500"),
600: convertToRGB("--color-background-600"),
700: convertToRGB("--color-background-700"),
800: convertToRGB("--color-background-800"),
900: convertToRGB("--color-background-900"),
1000: "rgb(0, 0, 0)",
DEFAULT: convertToRGB("--color-background-100"),
},
text: {
0: "rgb(255, 255, 255)",
10: convertToRGB("--color-text-10"),
20: convertToRGB("--color-text-20"),
30: convertToRGB("--color-text-30"),
40: convertToRGB("--color-text-40"),
50: convertToRGB("--color-text-50"),
60: convertToRGB("--color-text-60"),
70: convertToRGB("--color-text-70"),
80: convertToRGB("--color-text-80"),
90: convertToRGB("--color-text-90"),
100: convertToRGB("--color-text-100"),
200: convertToRGB("--color-text-200"),
300: convertToRGB("--color-text-300"),
400: convertToRGB("--color-text-400"),
500: convertToRGB("--color-text-500"),
600: convertToRGB("--color-text-600"),
700: convertToRGB("--color-text-700"),
800: convertToRGB("--color-text-800"),
900: convertToRGB("--color-text-900"),
1000: "rgb(0, 0, 0)",
DEFAULT: convertToRGB("--color-text-100"),
},
sidebar: {
background: {
0: "rgb(255, 255, 255)",
10: convertToRGB("--color-sidebar-background-10"),
20: convertToRGB("--color-sidebar-background-20"),
30: convertToRGB("--color-sidebar-background-30"),
40: convertToRGB("--color-sidebar-background-40"),
50: convertToRGB("--color-sidebar-background-50"),
60: convertToRGB("--color-sidebar-background-60"),
70: convertToRGB("--color-sidebar-background-70"),
80: convertToRGB("--color-sidebar-background-80"),
90: convertToRGB("--color-sidebar-background-90"),
100: convertToRGB("--color-sidebar-background-100"),
200: convertToRGB("--color-sidebar-background-200"),
300: convertToRGB("--color-sidebar-background-300"),
400: convertToRGB("--color-sidebar-background-400"),
500: convertToRGB("--color-sidebar-background-500"),
600: convertToRGB("--color-sidebar-background-600"),
700: convertToRGB("--color-sidebar-background-700"),
800: convertToRGB("--color-sidebar-background-800"),
900: convertToRGB("--color-sidebar-background-900"),
1000: "rgb(0, 0, 0)",
DEFAULT: convertToRGB("--color-sidebar-background-100"),
},
text: {
0: "rgb(255, 255, 255)",
10: convertToRGB("--color-sidebar-text-10"),
20: convertToRGB("--color-sidebar-text-20"),
30: convertToRGB("--color-sidebar-text-30"),
40: convertToRGB("--color-sidebar-text-40"),
50: convertToRGB("--color-sidebar-text-50"),
60: convertToRGB("--color-sidebar-text-60"),
70: convertToRGB("--color-sidebar-text-70"),
80: convertToRGB("--color-sidebar-text-80"),
90: convertToRGB("--color-sidebar-text-90"),
100: convertToRGB("--color-sidebar-text-100"),
200: convertToRGB("--color-sidebar-text-200"),
300: convertToRGB("--color-sidebar-text-300"),
400: convertToRGB("--color-sidebar-text-400"),
500: convertToRGB("--color-sidebar-text-500"),
600: convertToRGB("--color-sidebar-text-600"),
700: convertToRGB("--color-sidebar-text-700"),
800: convertToRGB("--color-sidebar-text-800"),
900: convertToRGB("--color-sidebar-text-900"),
1000: "rgb(0, 0, 0)",
DEFAULT: convertToRGB("--color-sidebar-text-100"),
},
},
}, },
}, },
keyframes: { keyframes: {
@ -60,7 +169,7 @@ module.exports = {
"--tw-prose-p": `${convertToRGB("--color-text-base")}`, "--tw-prose-p": `${convertToRGB("--color-text-base")}`,
"--tw-prose-headings": `${convertToRGB("--color-text-base")}`, "--tw-prose-headings": `${convertToRGB("--color-text-base")}`,
"--tw-prose-lead": `${convertToRGB("--color-text-base")}`, "--tw-prose-lead": `${convertToRGB("--color-text-base")}`,
"--tw-prose-links": `${convertToRGB("--color-accent")}`, "--tw-prose-links": `${convertToRGB("--color-primary-100")}`,
"--tw-prose-bold": `${convertToRGB("--color-text-base")}`, "--tw-prose-bold": `${convertToRGB("--color-text-base")}`,
"--tw-prose-counters": `${convertToRGB("--color-text-base")}`, "--tw-prose-counters": `${convertToRGB("--color-text-base")}`,
"--tw-prose-bullets": `${convertToRGB("--color-text-base")}`, "--tw-prose-bullets": `${convertToRGB("--color-text-base")}`,

View File

@ -29,16 +29,13 @@ export interface IUser {
} }
export interface ICustomTheme { export interface ICustomTheme {
accent: string; background: string;
bgBase: string; text: string;
bgSurface1: string; primary: string;
bgSurface2: string; sidebarBackground: string;
border: string; sidebarText: string;
darkPalette: boolean; darkPalette: boolean;
palette: string; palette: string;
sidebar: string;
textBase: string;
textSecondary: string;
} }
export interface ICurrentUserResponse extends IUser { export interface ICurrentUserResponse extends IUser {