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 60a87453b2.

* 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={[
{
id: "issues_closed",
color: "rgb(var(--color-accent))",
color: "rgb(var(--color-primary-100))",
data: MONTHS_LIST.map((month) => ({
x: month.label.substring(0, 3),
y:
@ -50,7 +50,7 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
</div>
)}
theme={{
background: "rgb(var(--color-bg-base))",
background: "rgb(var(--color-background-100))",
}}
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 "./modals";
export * from "./spreadsheet-view";
export * from "./theme";
export * from "./sidebar";
export * from "./issues-view";
export * from "./image-picker-popover";
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";
// icons
import { ColorPickerIcon } from "components/icons";
// types
import { ICustomTheme } from "types";
type Props = {
name: string;
name: keyof ICustomTheme;
watch: UseFormWatch<any>;
setValue: UseFormSetValue<any>;
error: FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined;
@ -31,24 +33,18 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
setValue(name, hex);
};
const getColorText = (colorName: string) => {
const getColorText = (colorName: keyof ICustomTheme) => {
switch (colorName) {
case "accent":
return "Accent";
case "bgBase":
case "background":
return "Background";
case "bgSurface1":
return "Background surface 1";
case "bgSurface2":
return "Background surface 2";
case "border":
return "Border";
case "sidebar":
return "Sidebar";
case "textBase":
return "Text primary";
case "textSecondary":
return "Text secondary";
case "text":
return "Text";
case "primary":
return "Primary(Theme)";
case "sidebarBackground":
return "Sidebar Background";
case "sidebarText":
return "Sidebar Text";
default:
return "Color";
}

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";
// ui
import { CustomSelect } from "components/ui";
// helper
import { applyTheme } from "helpers/theme.helper";
// types
import { ICustomTheme, IUser } from "types";
@ -79,19 +77,14 @@ export const ThemeSwitch: React.FC<Props> = ({
if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
} else {
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
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",
];
cssVars.forEach((cssVar) => document.documentElement.style.removeProperty(cssVar));
for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) {
document.documentElement.style.removeProperty(`--color-background-${i}`);
document.documentElement.style.removeProperty(`--color-text-${i}`);
document.documentElement.style.removeProperty(`--color-primary-${i}`);
document.documentElement.style.removeProperty(`--color-sidebar-background-${i}`);
document.documentElement.style.removeProperty(`--color-sidebar-text-${i}`);
}
}
setTheme(value);
document.documentElement.style.setProperty("color-scheme", type);

View File

@ -2,27 +2,27 @@
import { Theme } from "@nivo/core";
export const CHARTS_THEME: Theme = {
background: "rgb(var(--color-bg-surface-1))",
textColor: "rgb(var(--color-text-secondary))",
background: "rgb(var(--color-background-90))",
textColor: "rgb(var(--color-text-200))",
axis: {
domain: {
line: {
stroke: "rgb(var(--color-border))",
stroke: "rgb(var(--color-background-80))",
strokeWidth: 0.5,
},
},
},
tooltip: {
container: {
background: "rgb(var(--color-bg-surface-2))",
color: "rgb(var(--color-text-secondary))",
background: "rgb(var(--color-background-80))",
color: "rgb(var(--color-text-200))",
fontSize: "0.8rem",
border: "1px solid rgb(var(--color-border))",
border: "1px solid rgb(var(--color-background-80))",
},
},
grid: {
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) => {
hex = hex.toLowerCase();
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)].join(",")
: null;
import { TRgb, hexToRgb } from "helpers/color.helper";
type TShades = {
10: TRgb;
20: TRgb;
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) => {
const values: string[] = [];
palette.split(",").map((color: string) => {
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",
];
// palette: [bg, text, primary, sidebarBg, sidebarText]
const values: string[] = palette.split(",");
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
.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
className={`relative flex h-full w-full flex-col overflow-hidden ${
bg === "primary"
? "bg-brand-surface-1"
? "bg-brand-base"
: bg === "secondary"
? "bg-brand-sidebar"
: "bg-brand-base"
? "bg-brand-surface-1"
: "bg-brand-surface-2"
}`}
>
<AppHeader

View File

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

View File

@ -17,42 +17,199 @@
}
:root {
--color-bg-base: 255, 255, 255;
--color-bg-surface-1: 249, 250, 251;
--color-bg-surface-2: 243, 244, 246;
--color-primary-10: 236, 241, 255;
--color-primary-20: 217, 228, 255;
--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-bg-sidebar: 255, 255, 255;
--color-accent: 63, 118, 255;
--color-background-10: 250, 250, 250;
--color-background-20: 245, 245, 245;
--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-secondary: 55, 65, 81;
--color-text-10: 250, 250, 250;
--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"] {
--color-bg-base: 255, 255, 255;
--color-bg-surface-1: 249, 250, 251;
--color-bg-surface-2: 243, 244, 246;
--color-border: 229, 231, 235;
--color-bg-sidebar: 255, 255, 255;
--color-accent: 63, 118, 255;
--color-text-base: 3, 7, 18;
--color-text-secondary: 55, 65, 81;
--color-background-10: 250, 250, 250;
--color-background-20: 245, 245, 245;
--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: 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"] {
--color-bg-base: 25, 27, 27;
--color-bg-surface-1: 29, 30, 32;
--color-bg-surface-2: 39, 42, 45;
--color-background-10: 250, 250, 250;
--color-background-20: 245, 245, 245;
--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-bg-sidebar: 19, 20, 22;
--color-accent: 60, 133, 217;
--color-text-10: 250, 250, 250;
--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-text-base: 233, 244, 252;
--color-text-secondary: 142, 148, 146;
--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-contrast"] {
@ -97,7 +254,7 @@
}
body {
color: rgba(var(--color-text-base));
color: rgba(var(--color-text-100));
}
/* scrollbar style */

View File

@ -1,46 +1,155 @@
function withOpacity(variableName) {
return ({ opacityValue }) => {
if (opacityValue !== undefined) return `rgba(var(${variableName}), ${opacityValue})`;
return `rgb(var(${variableName}))`;
};
}
function convertToRGB(variableName) {
return `rgb(var(${variableName}))`;
}
const convertToRGB = (variableName) => `rgb(var(${variableName}))`;
module.exports = {
darkMode: "class",
content: ["./pages/**/*.tsx", "./components/**/*.tsx", "./layouts/**/*.tsx", "./ui/**/*.tsx"],
theme: {
extend: {
colors: {
brand: {
accent: withOpacity("--color-accent"),
base: withOpacity("--color-bg-base"),
},
},
borderColor: {
brand: {
base: withOpacity("--color-border"),
"surface-1": withOpacity("--color-bg-surface-1"),
"surface-2": withOpacity("--color-bg-surface-2"),
base: convertToRGB("--color-background-80"),
secondary: convertToRGB("--color-background-90"),
},
},
backgroundColor: {
brand: {
base: withOpacity("--color-bg-base"),
"surface-1": withOpacity("--color-bg-surface-1"),
"surface-2": withOpacity("--color-bg-surface-2"),
sidebar: withOpacity("--color-bg-sidebar"),
base: convertToRGB("--color-background-100"),
"surface-1": convertToRGB("--color-background-90"),
"surface-2": convertToRGB("--color-background-80"),
sidebar: convertToRGB("--color-sidebar-background-100"),
backdrop: "#131313",
},
},
textColor: {
brand: {
base: withOpacity("--color-text-base"),
secondary: withOpacity("--color-text-secondary"),
base: convertToRGB("--color-text-100"),
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: {
@ -60,7 +169,7 @@ module.exports = {
"--tw-prose-p": `${convertToRGB("--color-text-base")}`,
"--tw-prose-headings": `${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-counters": `${convertToRGB("--color-text-base")}`,
"--tw-prose-bullets": `${convertToRGB("--color-text-base")}`,

View File

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