added QuickReactFrequents and DiscordColorways
This commit is contained in:
parent
fa99ee4093
commit
523dae7fa6
21 changed files with 5759 additions and 0 deletions
220
src/userplugins/DiscordColorways/components/ColorPicker.tsx
Normal file
220
src/userplugins/DiscordColorways/components/ColorPicker.tsx
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { CopyIcon } from "@components/Icons";
|
||||
import {
|
||||
ModalProps,
|
||||
ModalRoot,
|
||||
} from "@utils/modal";
|
||||
import {
|
||||
Button,
|
||||
Clipboard,
|
||||
ScrollerThin,
|
||||
TextInput,
|
||||
Toasts,
|
||||
useState,
|
||||
} from "@webpack/common";
|
||||
|
||||
import { colorVariables } from "../css";
|
||||
|
||||
interface ToolboxItem {
|
||||
title: string;
|
||||
onClick: () => void;
|
||||
id?: string;
|
||||
iconClassName?: string;
|
||||
}
|
||||
|
||||
const ColorVarItems: ToolboxItem[] = colorVariables.map((colorVariable: string) => {
|
||||
return {
|
||||
title: "Copy " + colorVariable,
|
||||
onClick: () => {
|
||||
function getHex(str: string): string { return Object.assign(document.createElement("canvas").getContext("2d") as {}, { fillStyle: str }).fillStyle; }
|
||||
Clipboard.copy(getHex(getComputedStyle(document.body).getPropertyValue("--" + colorVariable)));
|
||||
Toasts.show({ message: "Color " + colorVariable + " copied to clipboard", id: "toolbox-color-var-copied", type: 1 });
|
||||
},
|
||||
id: colorVariable
|
||||
};
|
||||
});
|
||||
|
||||
const ToolboxItems: ToolboxItem[] = [
|
||||
{
|
||||
title: "Copy Accent Color",
|
||||
onClick: () => {
|
||||
function getHex(str: string): string {
|
||||
return Object.assign(
|
||||
document.createElement("canvas").getContext("2d") as {},
|
||||
{ fillStyle: str }
|
||||
).fillStyle;
|
||||
}
|
||||
Clipboard.copy(
|
||||
getHex(
|
||||
getComputedStyle(document.body).getPropertyValue(
|
||||
"--brand-experiment"
|
||||
)
|
||||
)
|
||||
);
|
||||
Toasts.show({
|
||||
message: "Accent color copied to clipboard",
|
||||
id: "toolbox-accent-color-copied",
|
||||
type: 1,
|
||||
});
|
||||
},
|
||||
id: "colorways-toolbox_copy-accent",
|
||||
iconClassName: "copy",
|
||||
},
|
||||
{
|
||||
title: "Copy Primary Color",
|
||||
onClick: () => {
|
||||
function getHex(str: string): string {
|
||||
return Object.assign(
|
||||
document.createElement("canvas").getContext("2d") as {},
|
||||
{ fillStyle: str }
|
||||
).fillStyle;
|
||||
}
|
||||
Clipboard.copy(
|
||||
getHex(
|
||||
getComputedStyle(document.body).getPropertyValue(
|
||||
"--background-primary"
|
||||
)
|
||||
)
|
||||
);
|
||||
Toasts.show({
|
||||
message: "Primary color copied to clipboard",
|
||||
id: "toolbox-primary-color-copied",
|
||||
type: 1,
|
||||
});
|
||||
},
|
||||
id: "colorways-toolbox_copy-primary",
|
||||
iconClassName: "copy",
|
||||
},
|
||||
{
|
||||
title: "Copy Secondary Color",
|
||||
onClick: () => {
|
||||
function getHex(str: string): string {
|
||||
return Object.assign(
|
||||
document.createElement("canvas").getContext("2d") as {},
|
||||
{ fillStyle: str }
|
||||
).fillStyle;
|
||||
}
|
||||
Clipboard.copy(
|
||||
getHex(
|
||||
getComputedStyle(document.body).getPropertyValue(
|
||||
"--background-secondary"
|
||||
)
|
||||
)
|
||||
);
|
||||
Toasts.show({
|
||||
message: "Secondary color copied to clipboard",
|
||||
id: "toolbox-secondary-color-copied",
|
||||
type: 1,
|
||||
});
|
||||
},
|
||||
id: "colorways-toolbox_copy-secondary",
|
||||
iconClassName: "copy",
|
||||
},
|
||||
{
|
||||
title: "Copy Tertiary Color",
|
||||
onClick: () => {
|
||||
function getHex(str: string): string {
|
||||
return Object.assign(
|
||||
document.createElement("canvas").getContext("2d") as {},
|
||||
{ fillStyle: str }
|
||||
).fillStyle;
|
||||
}
|
||||
Clipboard.copy(
|
||||
getHex(
|
||||
getComputedStyle(document.body).getPropertyValue(
|
||||
"--background-tertiary"
|
||||
)
|
||||
)
|
||||
);
|
||||
Toasts.show({
|
||||
message: "Tertiary color copied to clipboard",
|
||||
id: "toolbox-tertiary-color-copied",
|
||||
type: 1,
|
||||
});
|
||||
},
|
||||
id: "colorways-toolbox_copy-tertiary",
|
||||
iconClassName: "copy",
|
||||
}
|
||||
];
|
||||
|
||||
export default function ({ modalProps }: { modalProps: ModalProps; }) {
|
||||
const [colorVarItems, setColorVarItems] = useState<ToolboxItem[]>(ColorVarItems);
|
||||
const [collapsedSettings, setCollapsedSettings] = useState<boolean>(true);
|
||||
let results: ToolboxItem[];
|
||||
function searchToolboxItems(e: string) {
|
||||
results = [];
|
||||
ColorVarItems.find((ToolboxItem: ToolboxItem) => {
|
||||
if (ToolboxItem.title.toLowerCase().includes(e.toLowerCase())) {
|
||||
results.push(ToolboxItem);
|
||||
}
|
||||
});
|
||||
setColorVarItems(results);
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalRoot {...modalProps} className="colorwayColorpicker">
|
||||
<Flex style={{ gap: "8px", marginBottom: "8px" }}>
|
||||
<TextInput
|
||||
className="colorwaysColorpicker-search"
|
||||
placeholder="Search for a color:"
|
||||
onChange={e => {
|
||||
searchToolboxItems(e);
|
||||
if (e) {
|
||||
setCollapsedSettings(false);
|
||||
} else {
|
||||
setCollapsedSettings(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
onClick={() => setCollapsedSettings(!collapsedSettings)}
|
||||
>
|
||||
<svg width="32" height="24" viewBox="0 0 24 24" aria-hidden="true" role="img">
|
||||
<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M7 10L12 15 17 10" aria-hidden="true" />
|
||||
</svg>
|
||||
</Button>
|
||||
</Flex>
|
||||
<ScrollerThin style={{ color: "var(--text-normal)" }} orientation="vertical" className={collapsedSettings ? " colorwaysColorpicker-collapsed" : ""} paddingFix>
|
||||
{colorVarItems.map((toolboxItem: ToolboxItem) => {
|
||||
return (
|
||||
<div
|
||||
id={
|
||||
"colorways-colorstealer-item_" +
|
||||
toolboxItem.id
|
||||
}
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-toolboxItm"
|
||||
onClick={toolboxItem.onClick}
|
||||
style={
|
||||
{
|
||||
"--brand-experiment":
|
||||
"var(--" + toolboxItem.id + ")",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
{toolboxItem.title}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</ScrollerThin>
|
||||
<Flex style={{ justifyContent: "space-between", marginTop: "8px" }} wrap="wrap" className={collapsedSettings ? "" : " colorwaysColorpicker-collapsed"}>
|
||||
{ToolboxItems.map((toolboxItem: ToolboxItem, i: number) => <div
|
||||
id={toolboxItem.id || `colorways-toolbox_item-${i}`}
|
||||
className="colorwayToolbox-listItem"
|
||||
>
|
||||
<CopyIcon onClick={toolboxItem.onClick} width={20} height={20} className="colorwayToolbox-listItemSVG" />
|
||||
<span className="colorwaysToolbox-label">{toolboxItem.title}</span>
|
||||
</div>
|
||||
)}
|
||||
</Flex>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
108
src/userplugins/DiscordColorways/components/ColorwaysButton.tsx
Normal file
108
src/userplugins/DiscordColorways/components/ColorwaysButton.tsx
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { FluxDispatcher, Text, Tooltip, useCallback, useEffect, useState } from "@webpack/common";
|
||||
import { FluxEvents } from "@webpack/types";
|
||||
|
||||
import { PalleteIcon } from "./Icons";
|
||||
import SelectorModal from "./SelectorModal";
|
||||
|
||||
export default function ({
|
||||
listItemClass = "ColorwaySelectorBtnContainer",
|
||||
listItemWrapperClass = "",
|
||||
listItemTooltipClass = "colorwaysBtn-tooltipContent"
|
||||
}: {
|
||||
listItemClass?: string;
|
||||
listItemWrapperClass?: string;
|
||||
listItemTooltipClass?: string;
|
||||
}) {
|
||||
const [activeColorway, setActiveColorway] = useState<string>("None");
|
||||
const [visibility, setVisibility] = useState<boolean>(true);
|
||||
const [isThin, setIsThin] = useState<boolean>(false);
|
||||
async function setButtonVisibility() {
|
||||
const [showColorwaysButton, useThinMenuButton] = await DataStore.getMany([
|
||||
"showColorwaysButton",
|
||||
"useThinMenuButton"
|
||||
]);
|
||||
|
||||
setVisibility(showColorwaysButton);
|
||||
setIsThin(useThinMenuButton);
|
||||
}
|
||||
|
||||
const cached_setButtonVisibility = useCallback(setButtonVisibility, []);
|
||||
|
||||
useEffect(() => {
|
||||
cached_setButtonVisibility();
|
||||
});
|
||||
|
||||
FluxDispatcher.subscribe("COLORWAYS_UPDATE_BUTTON_HEIGHT" as FluxEvents, ({ isTall }) => {
|
||||
setIsThin(isTall);
|
||||
});
|
||||
|
||||
FluxDispatcher.subscribe("COLORWAYS_UPDATE_BUTTON_VISIBILITY" as FluxEvents, ({ isVisible }) => {
|
||||
setVisibility(isVisible);
|
||||
});
|
||||
|
||||
if (!isThin) {
|
||||
return (<Tooltip text={<>
|
||||
<span>Colorways</span>
|
||||
<Text variant="text-xs/normal" style={{ color: "var(--text-muted)", fontWeight: 500 }}>{"Active Colorway: " + activeColorway}</Text>
|
||||
</>} position="right" tooltipContentClassName={listItemTooltipClass}
|
||||
>
|
||||
{({ onMouseEnter, onMouseLeave, onClick }) => {
|
||||
return (
|
||||
<>
|
||||
{visibility && <div className={listItemClass}>
|
||||
<div
|
||||
className={listItemWrapperClass + " ColorwaySelectorBtn"}
|
||||
onMouseEnter={async () => {
|
||||
onMouseEnter();
|
||||
setActiveColorway(await DataStore.get("actveColorwayID") || "None");
|
||||
}}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => {
|
||||
onClick();
|
||||
openModal(props => <SelectorModal modalProps={props} />);
|
||||
}}
|
||||
><PalleteIcon /></div>
|
||||
</div>}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Tooltip>
|
||||
);
|
||||
} else {
|
||||
return (<Tooltip text={<>
|
||||
<span>Colorways</span>
|
||||
<Text variant="text-xs/normal" style={{ color: "var(--text-muted)", fontWeight: 500 }}>{"Active Colorway: " + activeColorway}</Text>
|
||||
</>} position="right" tooltipContentClassName={listItemTooltipClass}
|
||||
>
|
||||
{({ onMouseEnter, onMouseLeave, onClick }) => {
|
||||
return (
|
||||
<>
|
||||
{visibility && <div className={listItemClass}>
|
||||
<div
|
||||
className={listItemWrapperClass + " ColorwaySelectorBtn ColorwaySelectorBtn_thin"}
|
||||
onMouseEnter={async () => {
|
||||
onMouseEnter();
|
||||
setActiveColorway(await DataStore.get("actveColorwayID") || "None");
|
||||
}}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => {
|
||||
onClick();
|
||||
openModal(props => <SelectorModal modalProps={props} />);
|
||||
}}
|
||||
><Text variant="text-xs/normal" style={{ color: "var(--header-primary)", fontWeight: 700, fontSize: 9 }}>Colorways</Text></div>
|
||||
</div>}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
||||
import { Button, Forms, ScrollerThin, Text, useState } from "@webpack/common";
|
||||
|
||||
import { knownThemeVars } from "../constants";
|
||||
import { getFontOnBg, getHex } from "../utils";
|
||||
|
||||
export default function ({
|
||||
modalProps,
|
||||
onFinished
|
||||
}: {
|
||||
modalProps: ModalProps;
|
||||
onFinished: ({ accent, primary, secondary, tertiary }: { accent: string, primary: string, secondary: string, tertiary: string; }) => void;
|
||||
}) {
|
||||
const [accentColor, setAccentColor] = useState<string>(getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--brand-experiment")
|
||||
));
|
||||
const [primaryColor, setPrimaryColor] = useState<string>(getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-primary")
|
||||
));
|
||||
const [secondaryColor, setSecondaryColor] = useState<string>(getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-secondary")
|
||||
));
|
||||
const [tertiaryColor, setTertiaryColor] = useState<string>(getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-tertiary")
|
||||
));
|
||||
return <ModalRoot {...modalProps} className="colorwayCreator-modal">
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/semibold" tag="h1">
|
||||
Conflicting Colors Found
|
||||
</Text>
|
||||
</ModalHeader>
|
||||
<ModalContent className="colorwayCreator-menuWrapper">
|
||||
<Text className="colorwaysConflictingColors-warning">Multiple known themes have been found, select the colors you want to copy from below:</Text>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>Colors to copy:</Forms.FormTitle>
|
||||
<div className="colorwayCreator-colorPreviews">
|
||||
<div className="colorwayCreator-colorPreview" style={{ backgroundColor: primaryColor, color: getFontOnBg(primaryColor) }} >Primary</div>
|
||||
<div className="colorwayCreator-colorPreview" style={{ backgroundColor: secondaryColor, color: getFontOnBg(secondaryColor) }} >Secondary</div>
|
||||
<div className="colorwayCreator-colorPreview" style={{ backgroundColor: tertiaryColor, color: getFontOnBg(tertiaryColor) }} >Tertiary</div>
|
||||
<div className="colorwayCreator-colorPreview" style={{ backgroundColor: accentColor, color: getFontOnBg(accentColor) }} >Accent</div>
|
||||
</div>
|
||||
<div className="colorwaysCreator-settingCat">
|
||||
<ScrollerThin orientation="vertical" className="colorwaysCreator-settingsList" paddingFix>
|
||||
<div
|
||||
id="colorways-colorstealer-item_Default"
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-colorPreviewItm"
|
||||
>
|
||||
<Forms.FormTitle>Discord</Forms.FormTitle>
|
||||
<div className="colorwayCreator-colorPreviews">
|
||||
<div
|
||||
className="colorwayCreator-colorPreview" style={{
|
||||
backgroundColor: getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-primary")
|
||||
),
|
||||
color: getFontOnBg(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-primary")
|
||||
)
|
||||
)
|
||||
}}
|
||||
onClick={() => setPrimaryColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-primary")
|
||||
)
|
||||
)}
|
||||
>Primary</div>
|
||||
<div
|
||||
className="colorwayCreator-colorPreview" style={{
|
||||
backgroundColor: getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-secondary")
|
||||
),
|
||||
color: getFontOnBg(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-secondary")
|
||||
)
|
||||
)
|
||||
}}
|
||||
onClick={() => setSecondaryColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-secondary")
|
||||
)
|
||||
)}
|
||||
>Secondary</div>
|
||||
<div
|
||||
className="colorwayCreator-colorPreview" style={{
|
||||
backgroundColor: getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-tertiary")
|
||||
),
|
||||
color: getFontOnBg(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-tertiary")
|
||||
)
|
||||
)
|
||||
}}
|
||||
onClick={() => setTertiaryColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-tertiary")
|
||||
)
|
||||
)}
|
||||
>Tertiary</div>
|
||||
<div
|
||||
className="colorwayCreator-colorPreview" style={{
|
||||
backgroundColor: getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--brand-experiment")
|
||||
),
|
||||
color: getFontOnBg(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--brand-experiment")
|
||||
)
|
||||
)
|
||||
}}
|
||||
onClick={() => setAccentColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--brand-experiment")
|
||||
)
|
||||
)}
|
||||
>Accent</div>
|
||||
</div>
|
||||
</div>
|
||||
{Object.values(knownThemeVars).map((theme: any, i) => {
|
||||
if (getComputedStyle(document.body).getPropertyValue(theme.variable)) {
|
||||
return (
|
||||
<div
|
||||
id={
|
||||
"colorways-colorstealer-item_" +
|
||||
Object.keys(knownThemeVars)[i]
|
||||
}
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-colorPreviewItm"
|
||||
>
|
||||
<Forms.FormTitle>{Object.keys(knownThemeVars)[i] + (theme.alt ? " (Main)" : "")}</Forms.FormTitle>
|
||||
<div className="colorwayCreator-colorPreviews">
|
||||
{theme.primary && getComputedStyle(document.body).getPropertyValue(theme.primary).match(/^\d.*%$/)
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_primary"
|
||||
style={{
|
||||
backgroundColor: getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.primary)})`),
|
||||
color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.primary)})`))
|
||||
}}
|
||||
onClick={() => {
|
||||
setPrimaryColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.primary)})`));
|
||||
}}
|
||||
>Primary</div>
|
||||
: (
|
||||
theme.primary
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_primary"
|
||||
style={{
|
||||
backgroundColor: getHex(getComputedStyle(document.body).getPropertyValue(theme.primary)),
|
||||
color: getFontOnBg(getHex(getComputedStyle(document.body).getPropertyValue(theme.primary)))
|
||||
}}
|
||||
onClick={() => {
|
||||
setPrimaryColor(getHex(getComputedStyle(document.body).getPropertyValue(theme.primary)));
|
||||
}}
|
||||
>Primary</div>
|
||||
: (theme.primaryVariables
|
||||
&& <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_primary"
|
||||
style={{ backgroundColor: `hsl(${getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l)})`, color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l)})`)) }}
|
||||
onClick={() => {
|
||||
setPrimaryColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.primaryVariables.l)})`));
|
||||
}}
|
||||
>Primary</div>))
|
||||
}
|
||||
{theme.secondary && getComputedStyle(document.body).getPropertyValue(theme.secondary).match(/^\d.*%$/)
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_secondary"
|
||||
style={{
|
||||
backgroundColor: getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.secondary)})`),
|
||||
color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.secondary)})`))
|
||||
}}
|
||||
onClick={() => {
|
||||
setSecondaryColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.secondary)})`));
|
||||
}}
|
||||
>Secondary</div>
|
||||
: (theme.secondary
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_secondary"
|
||||
style={{
|
||||
backgroundColor: getHex(getComputedStyle(document.body).getPropertyValue(theme.secondary)),
|
||||
color: getFontOnBg(getHex(getComputedStyle(document.body).getPropertyValue(theme.secondary)))
|
||||
}}
|
||||
onClick={() => {
|
||||
setSecondaryColor(getHex(getComputedStyle(document.body).getPropertyValue(theme.secondary)));
|
||||
}}
|
||||
>Secondary</div>
|
||||
: (theme.secondaryVariables
|
||||
&& <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_secondary"
|
||||
style={{ backgroundColor: `hsl(${getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l)})`, color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l)})`)) }}
|
||||
onClick={() => {
|
||||
setSecondaryColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.secondaryVariables.l)})`));
|
||||
}}
|
||||
>Secondary</div>))
|
||||
}
|
||||
{theme.tertiary && getComputedStyle(document.body).getPropertyValue(theme.tertiary).match(/^\d.*%$/)
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_tertiary"
|
||||
style={{
|
||||
backgroundColor: getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.tertiary)})`),
|
||||
color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.tertiary)})`))
|
||||
}}
|
||||
onClick={() => {
|
||||
setTertiaryColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.tertiary)})`));
|
||||
}}
|
||||
>Tertiary</div>
|
||||
: (theme.tertiary
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_tertiary"
|
||||
style={{
|
||||
backgroundColor: getHex(getComputedStyle(document.body).getPropertyValue(theme.tertiary)),
|
||||
color: getFontOnBg(getHex(getComputedStyle(document.body).getPropertyValue(theme.tertiary)))
|
||||
}}
|
||||
onClick={() => {
|
||||
setTertiaryColor(getHex(getComputedStyle(document.body).getPropertyValue(theme.tertiary)));
|
||||
}}
|
||||
>Tertiary</div>
|
||||
: (theme.tertiaryVariables
|
||||
&& <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_tertiary"
|
||||
style={{ backgroundColor: `hsl(${getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l)})`, color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l)})`)) }}
|
||||
onClick={() => {
|
||||
setTertiaryColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.tertiaryVariables.l)})`));
|
||||
}}
|
||||
>Tertiary</div>))}
|
||||
{theme.accent && getComputedStyle(document.body).getPropertyValue(theme.accent).match(/^\d.*%$/)
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_accent"
|
||||
style={{
|
||||
backgroundColor: getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.accent)})`),
|
||||
color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.accent)})`))
|
||||
}}
|
||||
onClick={() => {
|
||||
setAccentColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.accent)})`));
|
||||
}}
|
||||
>Accent</div>
|
||||
: (theme.accent
|
||||
? <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_accent"
|
||||
style={{
|
||||
backgroundColor: getHex(getComputedStyle(document.body).getPropertyValue(theme.accent)),
|
||||
color: getFontOnBg(getHex(getComputedStyle(document.body).getPropertyValue(theme.accent)))
|
||||
}}
|
||||
onClick={() => {
|
||||
setAccentColor(getHex(getComputedStyle(document.body).getPropertyValue(theme.accent)));
|
||||
}}
|
||||
>Accent</div>
|
||||
: (theme.accentVariables
|
||||
&& <div
|
||||
className="colorwayCreator-colorPreview colorwayCreator-colorPreview_accent"
|
||||
style={{ backgroundColor: `hsl(${getComputedStyle(document.body).getPropertyValue(theme.accentVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l)})`, color: getFontOnBg(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.accentVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l)})`)) }}
|
||||
onClick={() => {
|
||||
setAccentColor(getHex(`hsl(${getComputedStyle(document.body).getPropertyValue(theme.accentVariables.h)} ${!getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s) + "%") : getComputedStyle(document.body).getPropertyValue(theme.accentVariables.s)} ${!getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l).includes("%") ? (getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l) + "%") : getComputedStyle(document.body).getPropertyValue(theme.accentVariables.l)})`));
|
||||
}}
|
||||
>Accent</div>))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</ScrollerThin>
|
||||
</div>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.BRAND}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
onFinished({
|
||||
accent: accentColor,
|
||||
primary: primaryColor,
|
||||
secondary: secondaryColor,
|
||||
tertiary: tertiaryColor
|
||||
});
|
||||
modalProps.onClose();
|
||||
}}
|
||||
>Finish</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot >;
|
||||
}
|
413
src/userplugins/DiscordColorways/components/CreatorModal.tsx
Normal file
413
src/userplugins/DiscordColorways/components/CreatorModal.tsx
Normal file
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import {
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalProps,
|
||||
ModalRoot,
|
||||
openModal,
|
||||
} from "@utils/modal";
|
||||
import {
|
||||
Button,
|
||||
Forms,
|
||||
ScrollerThin,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
useEffect,
|
||||
UserStore,
|
||||
useState,
|
||||
} from "@webpack/common";
|
||||
|
||||
import { ColorPicker } from "..";
|
||||
import { knownThemeVars } from "../constants";
|
||||
import { generateCss, getPreset } from "../css";
|
||||
import { Colorway } from "../types";
|
||||
import { getHex, hexToString, hslToHex, rgbToHex } from "../utils";
|
||||
import ConflictingColorsModal from "./ConflictingColorsModal";
|
||||
import ThemePreviewCategory from "./ThemePreview";
|
||||
export default function ({
|
||||
modalProps,
|
||||
loadUIProps,
|
||||
colorwayID
|
||||
}: {
|
||||
modalProps: ModalProps;
|
||||
loadUIProps?: () => Promise<void>;
|
||||
colorwayID?: string;
|
||||
}) {
|
||||
const [accentColor, setAccentColor] = useState<string>("5865f2");
|
||||
const [primaryColor, setPrimaryColor] = useState<string>("313338");
|
||||
const [secondaryColor, setSecondaryColor] = useState<string>("2b2d31");
|
||||
const [tertiaryColor, setTertiaryColor] = useState<string>("1e1f22");
|
||||
const [colorwayName, setColorwayName] = useState<string>("");
|
||||
const [tintedText, setTintedText] = useState<boolean>(true);
|
||||
const [discordSaturation, setDiscordSaturation] = useState<boolean>(true);
|
||||
const [collapsedSettings, setCollapsedSettings] = useState<boolean>(true);
|
||||
const [collapsedPresets, setCollapsedPresets] = useState<boolean>(true);
|
||||
const [preset, setPreset] = useState<string>("default");
|
||||
const [presetColorArray, setPresetColorArray] = useState<string[]>(["accent", "primary", "secondary", "tertiary"]);
|
||||
|
||||
useEffect(() => {
|
||||
const parsedID = colorwayID?.split("colorway:")[1];
|
||||
if (parsedID) {
|
||||
const allEqual = (arr: any[]) => arr.every(v => v === arr[0]);
|
||||
if (!parsedID) {
|
||||
throw new Error("Please enter a Colorway ID");
|
||||
} else if (parsedID.length < 62) {
|
||||
throw new Error("Invalid Colorway ID");
|
||||
} else if (!hexToString(parsedID).includes(",")) {
|
||||
throw new Error("Invalid Colorway ID");
|
||||
} else if (!allEqual(hexToString(parsedID).split(",").map((e: string) => e.match("#")!.length)) && hexToString(parsedID).split(",").map((e: string) => e.match("#")!.length)[0] !== 1) {
|
||||
throw new Error("Invalid Colorway ID");
|
||||
} else {
|
||||
const colorArray: string[] = hexToString(parsedID).split(",");
|
||||
setAccentColor(colorArray[0].split("#")[1]);
|
||||
setPrimaryColor(colorArray[1].split("#")[1]);
|
||||
setSecondaryColor(colorArray[2].split("#")[1]);
|
||||
setTertiaryColor(colorArray[3].split("#")[1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
const colorPickerProps = {
|
||||
suggestedColors: [
|
||||
"#313338",
|
||||
"#2b2d31",
|
||||
"#1e1f22",
|
||||
"#5865f2",
|
||||
],
|
||||
showEyeDropper: true
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalRoot {...modalProps} className="colorwayCreator-modal">
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/semibold" tag="h1">
|
||||
Create Colorway
|
||||
</Text>
|
||||
</ModalHeader>
|
||||
<ModalContent className="colorwayCreator-menuWrapper">
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
Name:
|
||||
</Forms.FormTitle>
|
||||
<TextInput
|
||||
placeholder="Give your Colorway a name"
|
||||
value={colorwayName}
|
||||
onChange={setColorwayName}
|
||||
/>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
Colors:
|
||||
</Forms.FormTitle>
|
||||
<div className="colorwayCreator-colorPreviews">
|
||||
{presetColorArray.includes("primary") &&
|
||||
<ColorPicker
|
||||
label={<Text className="colorwaysPicker-colorLabel">Primary</Text>}
|
||||
color={parseInt(primaryColor, 16)}
|
||||
onChange={(color: number) => {
|
||||
let hexColor = color.toString(16);
|
||||
while (hexColor.length < 6) {
|
||||
hexColor = "0" + hexColor;
|
||||
}
|
||||
setPrimaryColor(hexColor);
|
||||
}}
|
||||
{...colorPickerProps}
|
||||
/>}
|
||||
{presetColorArray.includes("secondary") &&
|
||||
<ColorPicker
|
||||
label={<Text className="colorwaysPicker-colorLabel">Secondary</Text>}
|
||||
color={parseInt(secondaryColor, 16)}
|
||||
onChange={(color: number) => {
|
||||
let hexColor = color.toString(16);
|
||||
while (hexColor.length < 6) {
|
||||
hexColor = "0" + hexColor;
|
||||
}
|
||||
setSecondaryColor(hexColor);
|
||||
}}
|
||||
{...colorPickerProps}
|
||||
/>}
|
||||
{presetColorArray.includes("tertiary") &&
|
||||
<ColorPicker
|
||||
label={<Text className="colorwaysPicker-colorLabel">Tertiary</Text>}
|
||||
color={parseInt(tertiaryColor, 16)}
|
||||
onChange={(color: number) => {
|
||||
let hexColor = color.toString(16);
|
||||
while (hexColor.length < 6) {
|
||||
hexColor = "0" + hexColor;
|
||||
}
|
||||
setTertiaryColor(hexColor);
|
||||
}}
|
||||
{...colorPickerProps}
|
||||
/>}
|
||||
{presetColorArray.includes("accent") &&
|
||||
<ColorPicker
|
||||
label={<Text className="colorwaysPicker-colorLabel">Accent</Text>}
|
||||
color={parseInt(accentColor, 16)}
|
||||
onChange={(color: number) => {
|
||||
let hexColor = color.toString(16);
|
||||
while (hexColor.length < 6) {
|
||||
hexColor = "0" + hexColor;
|
||||
}
|
||||
setAccentColor(hexColor);
|
||||
}}
|
||||
{...colorPickerProps}
|
||||
/>}
|
||||
</div>
|
||||
<div className={`colorwaysCreator-settingCat${collapsedSettings ? " colorwaysCreator-settingCat-collapsed" : ""}`}>
|
||||
<div
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-settingHeader"
|
||||
onClick={() => setCollapsedSettings(!collapsedSettings)}>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>Settings</Forms.FormTitle>
|
||||
<svg className="expand-3Nh1P5 transition-30IQBn directionDown-2w0MZz" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" role="img">
|
||||
<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M7 10L12 15 17 10" aria-hidden="true" />
|
||||
</svg>
|
||||
</div>
|
||||
<ScrollerThin orientation="vertical" className="colorwaysCreator-settingsList" paddingFix>
|
||||
<div className="colorwaysCreator-settingItm" onClick={() => setTintedText(!tintedText)}>
|
||||
<Text variant="eyebrow" tag="h5">Use colored text</Text>
|
||||
<Switch value={tintedText} onChange={setTintedText} hideBorder={true} style={{ marginBottom: 0 }} />
|
||||
</div>
|
||||
<div className="colorwaysCreator-settingItm" onClick={() => setDiscordSaturation(!discordSaturation)}>
|
||||
<Text variant="eyebrow" tag="h5">Use Discord's saturation</Text>
|
||||
<Switch value={discordSaturation} onChange={setDiscordSaturation} hideBorder={true} style={{ marginBottom: 0 }} />
|
||||
</div>
|
||||
</ScrollerThin>
|
||||
</div>
|
||||
<div className={`colorwaysCreator-settingCat${collapsedPresets ? " colorwaysCreator-settingCat-collapsed" : ""}`}>
|
||||
<div
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-settingHeader"
|
||||
onClick={() => setCollapsedPresets(!collapsedPresets)}>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>Presets</Forms.FormTitle>
|
||||
<svg className="expand-3Nh1P5 transition-30IQBn directionDown-2w0MZz" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" role="img">
|
||||
<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M7 10L12 15 17 10" aria-hidden="true" />
|
||||
</svg>
|
||||
</div>
|
||||
<ScrollerThin orientation="vertical" className="colorwaysCreator-settingsList">
|
||||
<div className="colorwaysCreator-settingItm colorwaysCreator-preset" onClick={() => {
|
||||
setPreset("default");
|
||||
setPresetColorArray(["primary", "secondary", "tertiary", "accent"]);
|
||||
}}>
|
||||
<svg aria-hidden="true" role="img" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" fill="currentColor" />
|
||||
{preset === "default" && <circle cx="12" cy="12" r="5" className="radioIconForeground-3wH3aU" fill="currentColor" />}
|
||||
</svg>
|
||||
<Text variant="eyebrow" tag="h5">Default</Text>
|
||||
</div>
|
||||
{Object.values(getPreset()).map(pre => {
|
||||
return <div className="colorwaysCreator-settingItm colorwaysCreator-preset" onClick={() => {
|
||||
setPreset(pre.id);
|
||||
setPresetColorArray(pre.colors);
|
||||
}}>
|
||||
<svg aria-hidden="true" role="img" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" fill="currentColor" />
|
||||
{preset === pre.id && <circle cx="12" cy="12" r="5" className="radioIconForeground-3wH3aU" fill="currentColor" />}
|
||||
</svg>
|
||||
<Text variant="eyebrow" tag="h5">{pre.name}</Text>
|
||||
</div>;
|
||||
})}
|
||||
</ScrollerThin>
|
||||
</div>
|
||||
<ThemePreviewCategory isCollapsed={false} accent={"#" + accentColor} primary={"#" + primaryColor} secondary={"#" + secondaryColor} tertiary={"#" + tertiaryColor} />
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.BRAND}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={e => {
|
||||
var customColorwayCSS: string = "";
|
||||
if (preset === "default") {
|
||||
customColorwayCSS = generateCss(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
tertiaryColor,
|
||||
accentColor,
|
||||
tintedText,
|
||||
discordSaturation
|
||||
);
|
||||
} else {
|
||||
customColorwayCSS = getPreset(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
tertiaryColor,
|
||||
accentColor
|
||||
)[preset].preset(discordSaturation);
|
||||
}
|
||||
const customColorway: Colorway = {
|
||||
name: (colorwayName || "Colorway") + (preset === "default" ? "" : ": Made for " + getPreset()[preset].name),
|
||||
"dc-import": customColorwayCSS,
|
||||
accent: "#" + accentColor,
|
||||
primary: "#" + primaryColor,
|
||||
secondary: "#" + secondaryColor,
|
||||
tertiary: "#" + tertiaryColor,
|
||||
colors: presetColorArray,
|
||||
author: UserStore.getCurrentUser().username,
|
||||
authorID: UserStore.getCurrentUser().id,
|
||||
};
|
||||
const customColorwaysArray: Colorway[] = [customColorway];
|
||||
DataStore.get("customColorways").then(
|
||||
customColorways => {
|
||||
customColorways.forEach(
|
||||
(color: Colorway, i: number) => {
|
||||
if (color.name !== customColorway.name) {
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
}
|
||||
);
|
||||
DataStore.set("customColorways", customColorwaysArray);
|
||||
}
|
||||
);
|
||||
modalProps.onClose();
|
||||
loadUIProps!();
|
||||
}}
|
||||
>Finish</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
function setAllColors({ accent, primary, secondary, tertiary }: { accent: string, primary: string, secondary: string, tertiary: string; }) {
|
||||
setAccentColor(accent.split("#")[1]);
|
||||
setPrimaryColor(primary.split("#")[1]);
|
||||
setSecondaryColor(secondary.split("#")[1]);
|
||||
setTertiaryColor(tertiary.split("#")[1]);
|
||||
}
|
||||
var copiedThemes = ["Discord"];
|
||||
Object.values(knownThemeVars).map((theme: { variable: string; variableType?: string; }, i: number) => {
|
||||
if (getComputedStyle(document.body).getPropertyValue(theme.variable)) {
|
||||
copiedThemes.push(Object.keys(knownThemeVars)[i]);
|
||||
}
|
||||
});
|
||||
if (copiedThemes.length > 1) {
|
||||
openModal(props => <ConflictingColorsModal modalProps={props} onFinished={setAllColors} />);
|
||||
} else {
|
||||
setPrimaryColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-primary")
|
||||
).split("#")[1]
|
||||
);
|
||||
setSecondaryColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-secondary")
|
||||
).split("#")[1]
|
||||
);
|
||||
setTertiaryColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--background-tertiary")
|
||||
).split("#")[1]
|
||||
);
|
||||
setAccentColor(
|
||||
getHex(
|
||||
getComputedStyle(
|
||||
document.body
|
||||
).getPropertyValue("--brand-experiment")
|
||||
).split("#")[1]
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Copy Current Colors
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
let colorwayID: string;
|
||||
function setColorwayID(e: string) {
|
||||
colorwayID = e;
|
||||
}
|
||||
openModal(props => {
|
||||
return (
|
||||
<ModalRoot {...props} className="colorwaysCreator-noMinHeight">
|
||||
<ModalContent className="colorwaysCreator-noHeader colorwaysCreator-noMinHeight">
|
||||
<Forms.FormTitle>Colorway ID:</Forms.FormTitle>
|
||||
<TextInput placeholder="Enter Colorway ID" onInput={e => setColorwayID(e.currentTarget.value)} />
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.BRAND}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
if (!colorwayID) {
|
||||
throw new Error("Please enter a Colorway ID");
|
||||
} else if (!hexToString(colorwayID).includes(",")) {
|
||||
throw new Error("Invalid Colorway ID");
|
||||
} else {
|
||||
const setColor = [
|
||||
setAccentColor,
|
||||
setPrimaryColor,
|
||||
setSecondaryColor,
|
||||
setTertiaryColor
|
||||
];
|
||||
hexToString(colorwayID).split(/,#/).forEach((color: string, i: number) => {
|
||||
var colorType = "hex";
|
||||
if (color.includes("hsl")) {
|
||||
colorType = "hsl";
|
||||
} else if (color.includes("rgb")) {
|
||||
colorType = "rgb";
|
||||
}
|
||||
color = color.replaceAll(",", "").replace(/.+?\(/, "").replace(")", "").replaceAll(/[ \t]+\/[ \t]+/g, " ").replaceAll("%", "");
|
||||
if (colorType === "hsl") {
|
||||
color = hslToHex(Number(color.split(" ")[0]), Number(color.split(" ")[1]), Number(color.split(" ")[2]));
|
||||
}
|
||||
if (colorType === "rgb") {
|
||||
color = rgbToHex(Number(color.split(" ")[0]), Number(color.split(" ")[1]), Number(color.split(" ")[2]));
|
||||
}
|
||||
setColor[i](color.replace("#", ""));
|
||||
});
|
||||
props.onClose();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
});
|
||||
}}
|
||||
>
|
||||
Enter Colorway ID
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
modalProps.onClose();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
15
src/userplugins/DiscordColorways/components/Divider.tsx
Normal file
15
src/userplugins/DiscordColorways/components/Divider.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export default () => {
|
||||
return <div style={{
|
||||
width: "100%",
|
||||
height: 1,
|
||||
borderTop: "thin solid var(--background-modifier-accent)",
|
||||
marginTop: "var(--custom-margin-margin-medium)",
|
||||
marginBottom: 20
|
||||
}} />;
|
||||
};
|
62
src/userplugins/DiscordColorways/components/Icons.tsx
Normal file
62
src/userplugins/DiscordColorways/components/Icons.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { classes } from "@utils/misc";
|
||||
import type { PropsWithChildren, SVGProps } from "react";
|
||||
|
||||
interface BaseIconProps extends IconProps {
|
||||
viewBox: string;
|
||||
}
|
||||
|
||||
interface IconProps extends SVGProps<SVGSVGElement> {
|
||||
className?: string;
|
||||
height?: string | number;
|
||||
width?: string | number;
|
||||
}
|
||||
|
||||
function Icon({ height = 24, width = 24, className, children, viewBox, ...svgProps }: PropsWithChildren<BaseIconProps>) {
|
||||
return (
|
||||
<svg
|
||||
className={classes(className, "vc-icon")}
|
||||
role="img"
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
{...svgProps}
|
||||
>
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function PalleteIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
className={classes(props.className, "vc-pallete-icon")}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M 12 7.5 C 13.242188 7.5 14.25 6.492188 14.25 5.25 C 14.25 4.007812 13.242188 3 12 3 C 10.757812 3 9.75 4.007812 9.75 5.25 C 9.75 6.492188 10.757812 7.5 12 7.5 Z M 18 12 C 19.242188 12 20.25 10.992188 20.25 9.75 C 20.25 8.507812 19.242188 7.5 18 7.5 C 16.757812 7.5 15.75 8.507812 15.75 9.75 C 15.75 10.992188 16.757812 12 18 12 Z M 8.25 10.5 C 8.25 11.742188 7.242188 12.75 6 12.75 C 4.757812 12.75 3.75 11.742188 3.75 10.5 C 3.75 9.257812 4.757812 8.25 6 8.25 C 7.242188 8.25 8.25 9.257812 8.25 10.5 Z M 9 19.5 C 10.242188 19.5 11.25 18.492188 11.25 17.25 C 11.25 16.007812 10.242188 15 9 15 C 7.757812 15 6.75 16.007812 6.75 17.25 C 6.75 18.492188 7.757812 19.5 9 19.5 Z M 9 19.5 M 24 12 C 24 16.726562 21.199219 15.878906 18.648438 15.105469 C 17.128906 14.644531 15.699219 14.210938 15 15 C 14.09375 16.023438 14.289062 17.726562 14.472656 19.378906 C 14.738281 21.742188 14.992188 24 12 24 C 5.371094 24 0 18.628906 0 12 C 0 5.371094 5.371094 0 12 0 C 18.628906 0 24 5.371094 24 12 Z M 12 22.5 C 12.917969 22.5 12.980469 22.242188 12.984375 22.234375 C 13.097656 22.015625 13.167969 21.539062 13.085938 20.558594 C 13.066406 20.304688 13.03125 20.003906 12.996094 19.671875 C 12.917969 18.976562 12.828125 18.164062 12.820312 17.476562 C 12.804688 16.417969 12.945312 15.0625 13.875 14.007812 C 14.429688 13.382812 15.140625 13.140625 15.78125 13.078125 C 16.390625 13.023438 17 13.117188 17.523438 13.234375 C 18.039062 13.351562 18.574219 13.515625 19.058594 13.660156 L 19.101562 13.675781 C 19.621094 13.832031 20.089844 13.972656 20.53125 14.074219 C 21.511719 14.296875 21.886719 14.199219 22.019531 14.109375 C 22.074219 14.070312 22.5 13.742188 22.5 12 C 22.5 6.199219 17.800781 1.5 12 1.5 C 6.199219 1.5 1.5 6.199219 1.5 12 C 1.5 17.800781 6.199219 22.5 12 22.5 Z M 12 22.5"
|
||||
/></Icon>
|
||||
);
|
||||
}
|
||||
|
||||
export function CloseIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
className={classes(props.className, "vc-close-icon")}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M18.4 4L12 10.4L5.6 4L4 5.6L10.4 12L4 18.4L5.6 20L12 13.6L18.4 20L20 18.4L13.6 12L20 5.6L18.4 4Z"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
275
src/userplugins/DiscordColorways/components/InfoModal.tsx
Normal file
275
src/userplugins/DiscordColorways/components/InfoModal.tsx
Normal file
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { openUserProfile } from "@utils/discord";
|
||||
import {
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalProps,
|
||||
ModalRoot,
|
||||
} from "@utils/modal";
|
||||
import { Button, Clipboard, Forms, Text, Toasts } from "@webpack/common";
|
||||
|
||||
import { ColorwayCSS } from "..";
|
||||
import { generateCss } from "../css";
|
||||
import { Colorway } from "../types";
|
||||
import ThemePreviewCategory from "./ThemePreview";
|
||||
|
||||
export default function ({
|
||||
modalProps,
|
||||
colorwayProps,
|
||||
discrimProps = false,
|
||||
loadUIProps
|
||||
}: {
|
||||
modalProps: ModalProps;
|
||||
colorwayProps: Colorway;
|
||||
discrimProps?: boolean;
|
||||
loadUIProps: () => Promise<void>;
|
||||
}) {
|
||||
const colors: string[] = colorwayProps.colors || [
|
||||
"accent",
|
||||
"primary",
|
||||
"secondary",
|
||||
"tertiary",
|
||||
];
|
||||
return (
|
||||
<ModalRoot {...modalProps} className="colorwayCreator-modal">
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/semibold" tag="h1">
|
||||
Colorway Details: {colorwayProps.name}
|
||||
</Text>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<div className="colorwayInfo-wrapper">
|
||||
<div className="colorwayInfo-colorSwatches">
|
||||
{colors.map(color => {
|
||||
return (
|
||||
<div
|
||||
className="colorwayInfo-colorSwatch"
|
||||
style={{
|
||||
backgroundColor: colorwayProps[color],
|
||||
}}
|
||||
onClick={() => {
|
||||
Clipboard.copy(colorwayProps[color]);
|
||||
Toasts.show({
|
||||
message:
|
||||
"Copied color successfully",
|
||||
type: 1,
|
||||
id: "copy-colorway-color-notify",
|
||||
});
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="colorwayInfo-row colorwayInfo-author">
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
Author:
|
||||
</Forms.FormTitle>
|
||||
<Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
openUserProfile(colorwayProps.authorID);
|
||||
}}
|
||||
>
|
||||
{colorwayProps.author}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="colorwayInfo-row colorwayInfo-css">
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
CSS:
|
||||
</Forms.FormTitle>
|
||||
<Text
|
||||
variant="code"
|
||||
selectable={true}
|
||||
className="colorwayInfo-cssCodeblock"
|
||||
>
|
||||
{colorwayProps["dc-import"]}
|
||||
</Text>
|
||||
</div>
|
||||
<ThemePreviewCategory
|
||||
isCollapsed={true}
|
||||
className="colorwayInfo-lastCat"
|
||||
accent={colorwayProps.accent}
|
||||
primary={colorwayProps.primary}
|
||||
secondary={colorwayProps.secondary}
|
||||
tertiary={colorwayProps.tertiary}
|
||||
></ThemePreviewCategory>
|
||||
</div>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
{discrimProps && <Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.RED}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={async () => {
|
||||
const customColorways = await DataStore.get("customColorways");
|
||||
const actveColorwayID = await DataStore.get("actveColorwayID");
|
||||
const customColorwaysArray: Colorway[] = [];
|
||||
customColorways.map((color: Colorway, i: number) => {
|
||||
if (customColorways.length > 0) {
|
||||
if (color.name !== colorwayProps.name) {
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
if (++i === customColorways.length) {
|
||||
DataStore.set("customColorways", customColorwaysArray);
|
||||
}
|
||||
if (actveColorwayID === colorwayProps.name) {
|
||||
DataStore.set("actveColorway", null);
|
||||
DataStore.set("actveColorwayID", null);
|
||||
ColorwayCSS.set("");
|
||||
}
|
||||
modalProps.onClose();
|
||||
loadUIProps();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Delete...
|
||||
</Button>}
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
const stringToHex = (str: string) => {
|
||||
let hex = "";
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const charCode = str.charCodeAt(i);
|
||||
const hexValue = charCode.toString(16);
|
||||
|
||||
// Pad with zeros to ensure two-digit representation
|
||||
hex += hexValue.padStart(2, "0");
|
||||
}
|
||||
return hex;
|
||||
};
|
||||
const colorwayIDArray = `${colorwayProps.accent},${colorwayProps.primary},${colorwayProps.secondary},${colorwayProps.tertiary}`;
|
||||
const colorwayID = stringToHex(colorwayIDArray);
|
||||
Clipboard.copy(colorwayID);
|
||||
Toasts.show({
|
||||
message: "Copied Colorway ID Successfully",
|
||||
type: 1,
|
||||
id: "copy-colorway-id-notify",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Copy Colorway ID
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
Clipboard.copy(colorwayProps["dc-import"]);
|
||||
Toasts.show({
|
||||
message: "Copied CSS to Clipboard",
|
||||
type: 1,
|
||||
id: "copy-colorway-css-notify",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Copy CSS
|
||||
</Button>
|
||||
{discrimProps ? <Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={async () => {
|
||||
const customColorways = await DataStore.get("customColorways");
|
||||
const actveColorwayID = await DataStore.get("actveColorwayID");
|
||||
const customColorwaysArray: Colorway[] = [];
|
||||
customColorways.map((color: Colorway, i: number) => {
|
||||
if (customColorways.length > 0) {
|
||||
if (color.name === colorwayProps.name) {
|
||||
color["dc-import"] = generateCss(color.primary.split("#")[1] || "313338", color.secondary.split("#")[1] || "2b2d31", color.tertiary.split("#")[1] || "1e1f22", color.accent.split("#")[1] || "5865f2", true, true);
|
||||
customColorwaysArray.push(color);
|
||||
} else {
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
if (++i === customColorways.length) {
|
||||
DataStore.set("customColorways", customColorwaysArray);
|
||||
}
|
||||
if (actveColorwayID === colorwayProps.name) {
|
||||
DataStore.set("actveColorway", color["dc-import"]);
|
||||
DataStore.set("actveColorwayID", color.name);
|
||||
ColorwayCSS.set(color["dc-import"]);
|
||||
}
|
||||
modalProps.onClose();
|
||||
loadUIProps();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Update CSS
|
||||
</Button> : <Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={async () => {
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url)
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) =>
|
||||
res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; })
|
||||
));
|
||||
const colorways = data.flatMap(json => json.colorways);
|
||||
|
||||
const customColorways = await DataStore.get("customColorways");
|
||||
const actveColorwayID = await DataStore.get("actveColorwayID");
|
||||
const customColorwaysArray: Colorway[] = [];
|
||||
colorways.map((color: Colorway, i: number) => {
|
||||
if (colorways.length > 0) {
|
||||
if (color.name === colorwayProps.name) {
|
||||
color.name += " (Custom)";
|
||||
color["dc-import"] = generateCss(color.primary.split("#")[1] || "313338", color.secondary.split("#")[1] || "2b2d31", color.tertiary.split("#")[1] || "1e1f22", color.accent.split("#")[1] || "5865f2", true, true);
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
if (++i === colorways.length) {
|
||||
DataStore.set("customColorways", [...customColorways, ...customColorwaysArray]);
|
||||
}
|
||||
if (actveColorwayID === colorwayProps.name) {
|
||||
DataStore.set("actveColorway", color["dc-import"]);
|
||||
DataStore.set("actveColorwayID", color.name);
|
||||
ColorwayCSS.set(color["dc-import"]);
|
||||
}
|
||||
modalProps.onClose();
|
||||
loadUIProps();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Update CSS (Local)
|
||||
</Button>}
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => {
|
||||
modalProps.onClose();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
460
src/userplugins/DiscordColorways/components/SelectorModal.tsx
Normal file
460
src/userplugins/DiscordColorways/components/SelectorModal.tsx
Normal file
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/* eslint-disable arrow-parens */
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { ModalContent, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||
import {
|
||||
Button,
|
||||
Forms,
|
||||
Menu,
|
||||
Popout,
|
||||
ScrollerThin,
|
||||
Select,
|
||||
SettingsRouter,
|
||||
TextInput,
|
||||
Tooltip,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "@webpack/common";
|
||||
|
||||
import { ColorwayCSS } from "..";
|
||||
import { defaultColorwaySource, fallbackColorways } from "../constants";
|
||||
import { generateCss } from "../css";
|
||||
import { Colorway } from "../types";
|
||||
import { getHex } from "../utils";
|
||||
import ColorPickerModal from "./ColorPicker";
|
||||
import CreatorModal from "./CreatorModal";
|
||||
import { CloseIcon } from "./Icons";
|
||||
import ColorwayInfoModal from "./InfoModal";
|
||||
|
||||
export default function ({
|
||||
modalProps,
|
||||
}: {
|
||||
modalProps: ModalProps;
|
||||
}): JSX.Element | any {
|
||||
const [currentColorway, setCurrentColorway] = useState<string>("");
|
||||
const [colorways, setColorways] = useState<Colorway[]>([]);
|
||||
const [thirdPartyColorways, setThirdPartyColorways] = useState<Colorway[]>([]);
|
||||
const [customColorways, setCustomColorways] = useState<Colorway[]>([]);
|
||||
const [searchString, setSearchString] = useState<string>("");
|
||||
const [loaderHeight, setLoaderHeight] = useState<string>("2px");
|
||||
const [visibility, setVisibility] = useState<string>("all");
|
||||
const [showReloadMenu, setShowReloadMenu] = useState(false);
|
||||
let visibleColorwayArray: Colorway[];
|
||||
|
||||
switch (visibility) {
|
||||
case "all":
|
||||
visibleColorwayArray = [...colorways, ...thirdPartyColorways, ...customColorways];
|
||||
break;
|
||||
case "official":
|
||||
visibleColorwayArray = [...colorways];
|
||||
break;
|
||||
case "3rdparty":
|
||||
visibleColorwayArray = [...thirdPartyColorways];
|
||||
break;
|
||||
case "custom":
|
||||
visibleColorwayArray = [...customColorways];
|
||||
break;
|
||||
default:
|
||||
visibleColorwayArray = [...colorways, ...thirdPartyColorways, ...customColorways];
|
||||
break;
|
||||
}
|
||||
|
||||
async function loadUI() {
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url)
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) =>
|
||||
res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; })
|
||||
));
|
||||
const colorways = data.flatMap((json) => json.url === defaultColorwaySource ? json.colorways : []);
|
||||
const thirdPartyColorwaysArr = data.flatMap((json) => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const baseData = await DataStore.getMany([
|
||||
"customColorways",
|
||||
"actveColorwayID",
|
||||
]);
|
||||
setColorways(colorways || fallbackColorways);
|
||||
setThirdPartyColorways(thirdPartyColorwaysArr);
|
||||
setCustomColorways(baseData[0]);
|
||||
setCurrentColorway(baseData[1]);
|
||||
}
|
||||
|
||||
const cached_loadUI = useCallback(loadUI, [setColorways, setCustomColorways, setCurrentColorway]);
|
||||
|
||||
async function searchColorways(e: string) {
|
||||
if (!e) {
|
||||
cached_loadUI();
|
||||
return;
|
||||
}
|
||||
const colorwaySourceFiles = await DataStore.get("colorwaySourceFiles");
|
||||
const data = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url).then((res) => res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; }))
|
||||
)
|
||||
);
|
||||
const colorways = data.flatMap((json) => json.url === defaultColorwaySource ? json.colorways : []);
|
||||
const thirdPartyColorwaysArr = data.flatMap((json) => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const baseData = await DataStore.get("customColorways");
|
||||
var results: Colorway[] = [];
|
||||
(colorways || fallbackColorways).find((Colorway: Colorway) => {
|
||||
if (Colorway.name.toLowerCase().includes(e.toLowerCase()))
|
||||
results.push(Colorway);
|
||||
});
|
||||
var thirdPartyResults: Colorway[] = [];
|
||||
(thirdPartyColorwaysArr).find((Colorway: Colorway) => {
|
||||
if (Colorway.name.toLowerCase().includes(e.toLowerCase()))
|
||||
thirdPartyResults.push(Colorway);
|
||||
});
|
||||
var customResults: Colorway[] = [];
|
||||
baseData.find((Colorway: Colorway) => {
|
||||
if (Colorway.name.toLowerCase().includes(e.toLowerCase()))
|
||||
customResults.push(Colorway);
|
||||
});
|
||||
setColorways(results);
|
||||
setThirdPartyColorways(thirdPartyResults);
|
||||
setCustomColorways(customResults);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchString) {
|
||||
cached_loadUI();
|
||||
}
|
||||
setLoaderHeight("0px");
|
||||
}, [searchString]);
|
||||
|
||||
function ReloadPopout(onClose: () => void) {
|
||||
return (
|
||||
<Menu.Menu
|
||||
navId="dc-reload-menu"
|
||||
onClose={onClose}
|
||||
>
|
||||
<Menu.MenuItem
|
||||
id="dc-force-reload"
|
||||
label="Force Reload"
|
||||
action={async () => {
|
||||
setLoaderHeight("2px");
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url, { cache: "no-store" })
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) => {
|
||||
setLoaderHeight("0px");
|
||||
return res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; });
|
||||
}
|
||||
));
|
||||
const colorways = data.flatMap((json) => json.url === defaultColorwaySource ? json.colorways : []);
|
||||
const thirdPartyColorwaysArr = data.flatMap((json) => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const baseData = await DataStore.getMany([
|
||||
"customColorways",
|
||||
"actveColorwayID",
|
||||
]);
|
||||
setColorways(colorways || fallbackColorways);
|
||||
setThirdPartyColorways(thirdPartyColorwaysArr);
|
||||
setCustomColorways(baseData[0]);
|
||||
setCurrentColorway(baseData[1]);
|
||||
}}
|
||||
/>
|
||||
</Menu.Menu>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalRoot {...modalProps} className="colorwaySelectorModal">
|
||||
<ModalHeader>
|
||||
<Select className="colorwaySelector-pill colorwaySelector-pill_select" options={[{
|
||||
value: "all",
|
||||
label: "All"
|
||||
},
|
||||
{
|
||||
value: "official",
|
||||
label: "Official"
|
||||
},
|
||||
{
|
||||
value: "3rdparty",
|
||||
label: "3rd-Party"
|
||||
},
|
||||
{
|
||||
value: "custom",
|
||||
label: "Custom"
|
||||
}]} select={value => {
|
||||
setVisibility(value);
|
||||
}} isSelected={value => visibility === value} serialize={String} />
|
||||
<TextInput
|
||||
inputClassName="colorwaySelector-searchInput"
|
||||
className="colorwaySelector-search"
|
||||
placeholder="Search for Colorways..."
|
||||
value={searchString}
|
||||
onChange={(e: string) => [searchColorways, setSearchString].forEach(t => t(e))}
|
||||
/>
|
||||
<Tooltip text="Refresh Colorways...">
|
||||
{({ onMouseEnter, onMouseLeave }) => {
|
||||
return <Popout
|
||||
position="bottom"
|
||||
align="right"
|
||||
animation={Popout.Animation.NONE}
|
||||
shouldShow={showReloadMenu}
|
||||
onRequestClose={() => setShowReloadMenu(false)}
|
||||
renderPopout={() => ReloadPopout(() => setShowReloadMenu(false))}
|
||||
>
|
||||
{(_, { isShown }) => (
|
||||
<Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
style={{ marginLeft: "8px" }}
|
||||
id="colorway-refreshcolorway"
|
||||
onMouseEnter={isShown ? () => { } : onMouseEnter}
|
||||
onMouseLeave={isShown ? () => { } : onMouseLeave}
|
||||
onClick={() => {
|
||||
setLoaderHeight("2px");
|
||||
cached_loadUI().then(() => setLoaderHeight("0px"));
|
||||
}}
|
||||
onContextMenu={() => { onMouseLeave(); setShowReloadMenu(v => !v); }}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px" }}
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<rect
|
||||
y="0"
|
||||
fill="none"
|
||||
width="24"
|
||||
height="24"
|
||||
/>
|
||||
<path d="M6.351,6.351C7.824,4.871,9.828,4,12,4c4.411,0,8,3.589,8,8h2c0-5.515-4.486-10-10-10 C9.285,2,6.779,3.089,4.938,4.938L3,3v6h6L6.351,6.351z" />
|
||||
<path d="M17.649,17.649C16.176,19.129,14.173,20,12,20c-4.411,0-8-3.589-8-8H2c0,5.515,4.486,10,10,10 c2.716,0,5.221-1.089,7.062-2.938L21,21v-6h-6L17.649,17.649z" />
|
||||
</svg>
|
||||
</Button>
|
||||
)}
|
||||
</Popout>;
|
||||
}}
|
||||
</Tooltip>
|
||||
<Tooltip text="Open Settings">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
style={{ marginLeft: "8px" }}
|
||||
id="colorway-opensettings"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => {
|
||||
SettingsRouter.open("ColorwaysSettings");
|
||||
modalProps.onClose();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px" }}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M19.738 10H22V14H19.739C19.498 14.931 19.1 15.798 18.565 16.564L20 18L18 20L16.565 18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069 19.498 8.203 19.099 7.436 18.564L6 20L4 18L5.436 16.564C4.901 15.799 4.502 14.932 4.262 14H2V10H4.262C4.502 9.068 4.9 8.202 5.436 7.436L4 6L6 4L7.436 5.436C8.202 4.9 9.068 4.502 10 4.262V2H14V4.261C14.932 4.502 15.797 4.9 16.565 5.435L18 3.999L20 5.999L18.564 7.436C19.099 8.202 19.498 9.069 19.738 10ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z" />
|
||||
</svg>
|
||||
</Button>}
|
||||
</Tooltip>
|
||||
<Tooltip text="Create Colorway...">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
style={{ marginLeft: "8px" }}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => openModal((props) => <CreatorModal
|
||||
modalProps={props}
|
||||
loadUIProps={cached_loadUI}
|
||||
/>)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px" }}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M20 11.1111H12.8889V4H11.1111V11.1111H4V12.8889H11.1111V20H12.8889V12.8889H20V11.1111Z"
|
||||
/>
|
||||
</svg>
|
||||
</Button>}
|
||||
</Tooltip>
|
||||
<Tooltip text="Open Color Stealer">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
style={{ marginLeft: "8px" }}
|
||||
id="colorway-opencolorstealer"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => openModal((props) => <ColorPickerModal modalProps={props} />)}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" style={{ padding: "6px" }} fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.433 10.07C14.133 10.585 16 11.15 16 8a8 8 0 1 0-8 8c1.996 0 1.826-1.504 1.649-3.08-.124-1.101-.252-2.237.351-2.92.465-.527 1.42-.237 2.433.07zM8 5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4.5 3a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM5 6.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm.5 6.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z" />
|
||||
</svg>
|
||||
</Button>}
|
||||
</Tooltip>
|
||||
<Tooltip text="Close">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
id="colorwaySelector-pill_closeSelector"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => modalProps.onClose()}
|
||||
>
|
||||
<CloseIcon style={{ padding: "6px" }} width={20} height={20} />
|
||||
</Button>}
|
||||
</Tooltip>
|
||||
</ModalHeader>
|
||||
<ModalContent className="colorwaySelectorModalContent">
|
||||
<div className="colorwaysLoader-barContainer"><div className="colorwaysLoader-bar" style={{ height: loaderHeight }} /></div>
|
||||
<ScrollerThin style={{ maxHeight: "450px" }} className="ColorwaySelectorWrapper">
|
||||
{visibleColorwayArray.length === 0 &&
|
||||
<Forms.FormTitle
|
||||
style={{
|
||||
marginBottom: 0,
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
No colorways...
|
||||
</Forms.FormTitle>
|
||||
}
|
||||
{["all", "official", "3rdparty", "custom"].includes(visibility) && (
|
||||
visibleColorwayArray.map((color, ind) => {
|
||||
var colors: Array<string> = color.colors || [
|
||||
"accent",
|
||||
"primary",
|
||||
"secondary",
|
||||
"tertiary",
|
||||
];
|
||||
return (
|
||||
<Tooltip text={color.name}>
|
||||
{({ onMouseEnter, onMouseLeave }) => <div
|
||||
className={"discordColorway" + (currentColorway === color.name ? " active" : "")}
|
||||
id={"colorway-" + color.name}
|
||||
data-last-official={ind + 1 === colorways.length}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<div
|
||||
className="colorwayInfoIconContainer"
|
||||
onClick={() => openModal((props) => <ColorwayInfoModal
|
||||
modalProps={props}
|
||||
colorwayProps={color}
|
||||
discrimProps={customColorways.includes(color)}
|
||||
loadUIProps={cached_loadUI}
|
||||
/>)}
|
||||
>
|
||||
<div className="colorwayInfoIcon">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div className="colorwayCheckIconContainer">
|
||||
<div className="colorwayCheckIcon">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle r="8" cx="12" cy="12" fill="var(--white-500)" />
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="var(--brand-500)" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="discordColorwayPreviewColorContainer"
|
||||
onClick={async () => {
|
||||
const [
|
||||
onDemandWays,
|
||||
onDemandWaysTintedText,
|
||||
onDemandWaysDiscordSaturation
|
||||
] = await DataStore.getMany([
|
||||
"onDemandWays",
|
||||
"onDemandWaysTintedText",
|
||||
"onDemandWaysDiscordSaturation"
|
||||
]);
|
||||
if (currentColorway === color.name) {
|
||||
DataStore.set("actveColorwayID", null);
|
||||
DataStore.set("actveColorway", null);
|
||||
ColorwayCSS.remove();
|
||||
} else {
|
||||
DataStore.set("activeColorwayColors", color.colors);
|
||||
DataStore.set("actveColorwayID", color.name);
|
||||
if (onDemandWays) {
|
||||
const demandedColorway = generateCss(
|
||||
getHex(color.primary).split("#")[1],
|
||||
getHex(color.secondary).split("#")[1],
|
||||
getHex(color.tertiary).split("#")[1],
|
||||
getHex(color.accent).split("#")[1],
|
||||
onDemandWaysTintedText,
|
||||
onDemandWaysDiscordSaturation
|
||||
);
|
||||
DataStore.set("actveColorway", demandedColorway);
|
||||
ColorwayCSS.set(demandedColorway);
|
||||
} else {
|
||||
DataStore.set("actveColorway", color["dc-import"]);
|
||||
ColorwayCSS.set(color["dc-import"]);
|
||||
}
|
||||
}
|
||||
setCurrentColorway(await DataStore.get("actveColorwayID") as string);
|
||||
}}
|
||||
>
|
||||
{colors.map((colorItm) => <div
|
||||
className="discordColorwayPreviewColor"
|
||||
style={{ backgroundColor: color[colorItm] }}
|
||||
/>)}
|
||||
</div>
|
||||
</div>}
|
||||
</Tooltip>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</ScrollerThin>
|
||||
</ModalContent >
|
||||
</ModalRoot >
|
||||
);
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { SettingsTab } from "@components/VencordSettings/shared";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes } from "@utils/misc";
|
||||
import { chooseFile, saveFile } from "@utils/web";
|
||||
import { Button, Card, Forms, Text } from "@webpack/common";
|
||||
|
||||
import { defaultColorwaySource } from "../../constants";
|
||||
import { generateCss } from "../../css";
|
||||
import { Colorway } from "../../types";
|
||||
|
||||
export default function () {
|
||||
return <SettingsTab title="Manage Colorways">
|
||||
<Forms.FormSection title="Import/Export">
|
||||
<Card className={classes("vc-settings-card", "vc-backup-restore-card")}>
|
||||
<Flex flexDirection="column">
|
||||
<strong>Warning</strong>
|
||||
<span>Importing a colorways file will overwrite your current custom colorways.</span>
|
||||
</Flex>
|
||||
</Card>
|
||||
<Text variant="text-md/normal" className={Margins.bottom8}>
|
||||
You can import and export your custom colorways as a JSON file.
|
||||
This allows you to easily transfer them to another device/installation.
|
||||
</Text>
|
||||
<Flex>
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
onClick={async () => {
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
const [file] = await DiscordNative.fileManager.openFiles({
|
||||
filters: [
|
||||
{ name: "Discord Colorways List", extensions: ["json"] },
|
||||
{ name: "all", extensions: ["*"] }
|
||||
]
|
||||
});
|
||||
if (file) {
|
||||
try {
|
||||
await DataStore.set("customColorways", JSON.parse(new TextDecoder().decode(file.data)));
|
||||
} catch (err) {
|
||||
new Logger("DiscordColorways").error(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const file = await chooseFile("application/json");
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
try {
|
||||
await DataStore.set("customColorways", JSON.parse(reader.result as string));
|
||||
} catch (err) {
|
||||
new Logger("DiscordColorways").error(err);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}}>
|
||||
Import Colorways
|
||||
</Button>
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
onClick={async () => {
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
DiscordNative.fileManager.saveWithDialog(JSON.stringify(await DataStore.get("customColorways") as string), "colorways.json");
|
||||
} else {
|
||||
saveFile(new File([JSON.stringify(await DataStore.get("customColorways") as string)], "colorways.json", { type: "application/json" }));
|
||||
}
|
||||
}}>
|
||||
Export Colorways
|
||||
</Button>
|
||||
</Flex>
|
||||
</Forms.FormSection>
|
||||
<Forms.FormDivider className={Margins.top8 + " " + Margins.bottom8} />
|
||||
<Forms.FormSection title="Transfer 3rd Party Colorways to local index (3rd-Party > Custom):">
|
||||
<Flex>
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
onClick={async () => {
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url)
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) =>
|
||||
res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; })
|
||||
));
|
||||
const thirdPartyColorwaysArr: Colorway[] = data.flatMap(json => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const customColorways: Colorway[] = await DataStore.get("customColorways") as Colorway[];
|
||||
DataStore.set("customColorways", [...customColorways, ...thirdPartyColorwaysArr.map(({ name: nameOld, ...rest }) => ({ name: (nameOld + " (Custom)"), ...rest }))]);
|
||||
}}>
|
||||
As-Is
|
||||
</Button>
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
onClick={async () => {
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url)
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) =>
|
||||
res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; })
|
||||
));
|
||||
const thirdPartyColorwaysArr: Colorway[] = data.flatMap(json => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const customColorways: Colorway[] = await DataStore.get("customColorways") as Colorway[];
|
||||
DataStore.set("customColorways", [...customColorways, ...thirdPartyColorwaysArr.map(({ name: nameOld, "dc-import": oldImport, ...rest }: Colorway) => ({ name: (nameOld + " (Custom)"), "dc-import": generateCss(rest.primary.split("#")[1] || "313338", rest.secondary.split("#")[1] || "2b2d31", rest.tertiary.split("#")[1] || "1e1f22", rest.accent.split("#")[1] || "5865f2", true, true), ...rest }))]);
|
||||
}}>
|
||||
With Updated CSS
|
||||
</Button>
|
||||
</Flex>
|
||||
</Forms.FormSection>
|
||||
</SettingsTab>;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import { SettingsTab } from "@components/VencordSettings/shared";
|
||||
import { Switch, useCallback, useEffect, useState } from "@webpack/common";
|
||||
|
||||
export default function () {
|
||||
const [onDemand, setOnDemand] = useState<boolean>(false);
|
||||
const [onDemandTinted, setOnDemandTinted] = useState<boolean>(false);
|
||||
const [onDemandDiscordSat, setOnDemandDiscordSat] = useState<boolean>(false);
|
||||
async function loadUI() {
|
||||
const [
|
||||
onDemandWays,
|
||||
onDemandWaysTintedText,
|
||||
onDemandWaysDiscordSaturation
|
||||
] = await DataStore.getMany([
|
||||
"onDemandWays",
|
||||
"onDemandWaysTintedText",
|
||||
"onDemandWaysDiscordSaturation"
|
||||
]);
|
||||
setOnDemand(onDemandWays);
|
||||
setOnDemandTinted(onDemandWaysTintedText);
|
||||
setOnDemandDiscordSat(onDemandWaysDiscordSaturation);
|
||||
}
|
||||
|
||||
const cached_loadUI = useCallback(loadUI, []);
|
||||
|
||||
useEffect(() => {
|
||||
cached_loadUI();
|
||||
}, []);
|
||||
return <SettingsTab title="On-Demand">
|
||||
<Switch
|
||||
value={onDemand}
|
||||
onChange={(v: boolean) => {
|
||||
setOnDemand(v);
|
||||
DataStore.set("onDemandWays", v);
|
||||
}}
|
||||
note="Always utilise the latest of what DiscordColorways has to offer. CSS is being directly generated on the device and gets applied in the place of the normal import/CSS given by the colorway."
|
||||
>
|
||||
Enable Colorways On Demand
|
||||
</Switch>
|
||||
<Switch
|
||||
value={onDemandTinted}
|
||||
onChange={(v: boolean) => {
|
||||
setOnDemandTinted(v);
|
||||
DataStore.set("onDemandWaysTintedText", v);
|
||||
}}
|
||||
disabled={!onDemand}
|
||||
>
|
||||
Use tinted text
|
||||
</Switch>
|
||||
<Switch
|
||||
hideBorder
|
||||
value={onDemandDiscordSat}
|
||||
onChange={(v: boolean) => {
|
||||
setOnDemandDiscordSat(v);
|
||||
DataStore.set("onDemandWaysDiscordSaturation", v);
|
||||
}}
|
||||
disabled={!onDemand}
|
||||
>
|
||||
Use Discord's saturation
|
||||
</Switch>
|
||||
</SettingsTab>;
|
||||
}
|
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/* eslint-disable arrow-parens */
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { SettingsTab } from "@components/VencordSettings/shared";
|
||||
import { openModal } from "@utils/modal";
|
||||
import {
|
||||
Button,
|
||||
Forms,
|
||||
Menu,
|
||||
Popout,
|
||||
Select,
|
||||
TextInput,
|
||||
Tooltip,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "@webpack/common";
|
||||
|
||||
import { ColorwayCSS } from "../..";
|
||||
import { defaultColorwaySource, fallbackColorways } from "../../constants";
|
||||
import { Colorway } from "../../types";
|
||||
import ColorPickerModal from "../ColorPicker";
|
||||
import CreatorModal from "../CreatorModal";
|
||||
import ColorwayInfoModal from "../InfoModal";
|
||||
|
||||
export default function ({
|
||||
visibleTabProps = "all",
|
||||
}: {
|
||||
visibleTabProps?: string;
|
||||
}): JSX.Element | any {
|
||||
const [currentColorway, setCurrentColorway] = useState<string>("");
|
||||
const [colorways, setColorways] = useState<Colorway[]>([]);
|
||||
const [thirdPartyColorways, setThirdPartyColorways] = useState<Colorway[]>([]);
|
||||
const [customColorways, setCustomColorways] = useState<Colorway[]>([]);
|
||||
const [searchString, setSearchString] = useState<string>("");
|
||||
const [loaderHeight, setLoaderHeight] = useState<string>("2px");
|
||||
const [visibility, setVisibility] = useState<string>(visibleTabProps);
|
||||
const [showReloadMenu, setShowReloadMenu] = useState(false);
|
||||
let visibleColorwayArray: Colorway[];
|
||||
|
||||
switch (visibility) {
|
||||
case "all":
|
||||
visibleColorwayArray = [...colorways, ...thirdPartyColorways, ...customColorways];
|
||||
break;
|
||||
case "official":
|
||||
visibleColorwayArray = [...colorways];
|
||||
break;
|
||||
case "3rdparty":
|
||||
visibleColorwayArray = [...thirdPartyColorways];
|
||||
break;
|
||||
case "custom":
|
||||
visibleColorwayArray = [...customColorways];
|
||||
break;
|
||||
default:
|
||||
visibleColorwayArray = [...colorways, ...thirdPartyColorways, ...customColorways];
|
||||
break;
|
||||
}
|
||||
|
||||
async function loadUI() {
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url)
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) =>
|
||||
res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; })
|
||||
));
|
||||
const colorways = data.flatMap((json) => json.url === defaultColorwaySource ? json.colorways : []);
|
||||
const thirdPartyColorwaysArr = data.flatMap((json) => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const baseData = await DataStore.getMany([
|
||||
"customColorways",
|
||||
"actveColorwayID",
|
||||
]);
|
||||
setColorways(colorways || fallbackColorways);
|
||||
setThirdPartyColorways(thirdPartyColorwaysArr);
|
||||
setCustomColorways(baseData[0]);
|
||||
setCurrentColorway(baseData[1]);
|
||||
}
|
||||
|
||||
const cached_loadUI = useCallback(loadUI, [setColorways, setCustomColorways, setCurrentColorway]);
|
||||
|
||||
async function searchColorways(e: string) {
|
||||
if (!e) {
|
||||
cached_loadUI();
|
||||
return;
|
||||
}
|
||||
const colorwaySourceFiles = await DataStore.get("colorwaySourceFiles");
|
||||
const data = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url).then((res) => res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; }))
|
||||
)
|
||||
);
|
||||
const colorways = data.flatMap((json) => json.url === defaultColorwaySource ? json.colorways : []);
|
||||
const thirdPartyColorwaysArr = data.flatMap((json) => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const baseData = await DataStore.get("customColorways");
|
||||
var results: Colorway[] = [];
|
||||
(colorways || fallbackColorways).find((Colorway: Colorway) => {
|
||||
if (Colorway.name.toLowerCase().includes(e.toLowerCase()))
|
||||
results.push(Colorway);
|
||||
});
|
||||
var thirdPartyResults: Colorway[] = [];
|
||||
(thirdPartyColorwaysArr).find((Colorway: Colorway) => {
|
||||
if (Colorway.name.toLowerCase().includes(e.toLowerCase()))
|
||||
thirdPartyResults.push(Colorway);
|
||||
});
|
||||
var customResults: Colorway[] = [];
|
||||
baseData.find((Colorway: Colorway) => {
|
||||
if (Colorway.name.toLowerCase().includes(e.toLowerCase()))
|
||||
customResults.push(Colorway);
|
||||
});
|
||||
setColorways(results);
|
||||
setThirdPartyColorways(thirdPartyResults);
|
||||
setCustomColorways(customResults);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchString) {
|
||||
cached_loadUI();
|
||||
}
|
||||
setLoaderHeight("0px");
|
||||
}, [searchString]);
|
||||
|
||||
function ReloadPopout(onClose: () => void) {
|
||||
return (
|
||||
<Menu.Menu
|
||||
navId="dc-reload-menu"
|
||||
onClose={onClose}
|
||||
>
|
||||
<Menu.MenuItem
|
||||
id="dc-force-reload"
|
||||
label="Force Reload"
|
||||
action={async () => {
|
||||
setLoaderHeight("2px");
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url, { cache: "no-store" })
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) => {
|
||||
setLoaderHeight("0px");
|
||||
return res.json().then(dt => { return { colorways: dt.colorways, url: res.url }; }).catch(() => { return { colorways: [], url: res.url }; });
|
||||
}
|
||||
));
|
||||
const colorways = data.flatMap((json) => json.url === defaultColorwaySource ? json.colorways : []);
|
||||
const thirdPartyColorwaysArr = data.flatMap((json) => json.url !== defaultColorwaySource ? json.colorways : []);
|
||||
const baseData = await DataStore.getMany([
|
||||
"customColorways",
|
||||
"actveColorwayID",
|
||||
]);
|
||||
setColorways(colorways || fallbackColorways);
|
||||
setThirdPartyColorways(thirdPartyColorwaysArr);
|
||||
setCustomColorways(baseData[0]);
|
||||
setCurrentColorway(baseData[1]);
|
||||
}}
|
||||
/>
|
||||
</Menu.Menu>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsTab title="Colors">
|
||||
<div className="colorwaysSettingsSelector-wrapper">
|
||||
<Flex style={{ gap: "0" }}>
|
||||
<Select className="colorwaySelector-pill colorwaySelector-pill_select" options={[{
|
||||
value: "all",
|
||||
label: "All"
|
||||
},
|
||||
{
|
||||
value: "official",
|
||||
label: "Official"
|
||||
},
|
||||
{
|
||||
value: "3rdparty",
|
||||
label: "3rd-Party"
|
||||
},
|
||||
{
|
||||
value: "custom",
|
||||
label: "Custom"
|
||||
}]} select={value => {
|
||||
setVisibility(value);
|
||||
}} isSelected={value => visibility === value} serialize={String} />
|
||||
<TextInput
|
||||
inputClassName="colorwaySelector-searchInput"
|
||||
className="colorwaySelector-search"
|
||||
placeholder="Search for Colorways..."
|
||||
value={searchString}
|
||||
onChange={(e: string) => [searchColorways, setSearchString].forEach(t => t(e))}
|
||||
/>
|
||||
<Tooltip text="Refresh Colorways...">
|
||||
{({ onMouseEnter, onMouseLeave }) => {
|
||||
return <Popout
|
||||
position="bottom"
|
||||
align="right"
|
||||
animation={Popout.Animation.NONE}
|
||||
shouldShow={showReloadMenu}
|
||||
onRequestClose={() => setShowReloadMenu(false)}
|
||||
renderPopout={() => ReloadPopout(() => setShowReloadMenu(false))}
|
||||
>
|
||||
{(_, { isShown }) => (
|
||||
<Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
style={{ marginLeft: "8px" }}
|
||||
id="colorway-refreshcolorway"
|
||||
onMouseEnter={isShown ? () => { } : onMouseEnter}
|
||||
onMouseLeave={isShown ? () => { } : onMouseLeave}
|
||||
onClick={() => {
|
||||
setLoaderHeight("2px");
|
||||
cached_loadUI().then(() => setLoaderHeight("0px"));
|
||||
}}
|
||||
onContextMenu={() => { onMouseLeave(); setShowReloadMenu(v => !v); }}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px", boxSizing: "content-box" }}
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<rect
|
||||
y="0"
|
||||
fill="none"
|
||||
width="24"
|
||||
height="24"
|
||||
/>
|
||||
<path d="M6.351,6.351C7.824,4.871,9.828,4,12,4c4.411,0,8,3.589,8,8h2c0-5.515-4.486-10-10-10 C9.285,2,6.779,3.089,4.938,4.938L3,3v6h6L6.351,6.351z" />
|
||||
<path d="M17.649,17.649C16.176,19.129,14.173,20,12,20c-4.411,0-8-3.589-8-8H2c0,5.515,4.486,10,10,10 c2.716,0,5.221-1.089,7.062-2.938L21,21v-6h-6L17.649,17.649z" />
|
||||
</svg>
|
||||
</Button>
|
||||
)}
|
||||
</Popout>;
|
||||
}}
|
||||
</Tooltip>
|
||||
<Tooltip text="Create Colorway...">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
style={{ marginLeft: "8px" }}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => openModal((props) => <CreatorModal
|
||||
modalProps={props}
|
||||
loadUIProps={cached_loadUI}
|
||||
/>)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px", boxSizing: "content-box" }}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M20 11.1111H12.8889V4H11.1111V11.1111H4V12.8889H11.1111V20H12.8889V12.8889H20V11.1111Z"
|
||||
/>
|
||||
</svg>
|
||||
</Button>}
|
||||
</Tooltip>
|
||||
<Tooltip text="Open Color Stealer">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.PRIMARY}
|
||||
style={{ marginLeft: "8px" }}
|
||||
id="colorway-opencolorstealer"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => openModal((props) => <ColorPickerModal modalProps={props} />)}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" style={{ padding: "6px", boxSizing: "content-box" }} fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.433 10.07C14.133 10.585 16 11.15 16 8a8 8 0 1 0-8 8c1.996 0 1.826-1.504 1.649-3.08-.124-1.101-.252-2.237.351-2.92.465-.527 1.42-.237 2.433.07zM8 5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4.5 3a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM5 6.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm.5 6.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z" />
|
||||
</svg>
|
||||
</Button>}
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<div className="colorwaysLoader-barContainer"><div className="colorwaysLoader-bar" style={{ height: loaderHeight }} /></div>
|
||||
<div className="ColorwaySelectorWrapper">
|
||||
{visibleColorwayArray.length === 0 &&
|
||||
<Forms.FormTitle
|
||||
style={{
|
||||
marginBottom: 0,
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
No colorways...
|
||||
</Forms.FormTitle>
|
||||
}
|
||||
{visibleColorwayArray.map((color, ind) => {
|
||||
var colors: Array<string> = color.colors || [
|
||||
"accent",
|
||||
"primary",
|
||||
"secondary",
|
||||
"tertiary",
|
||||
];
|
||||
return (
|
||||
<Tooltip text={color.name}>
|
||||
{({ onMouseEnter, onMouseLeave }) => {
|
||||
return (
|
||||
<div
|
||||
className={"discordColorway" + (currentColorway === color.name ? " active" : "")}
|
||||
id={"colorway-" + color.name}
|
||||
data-last-official={
|
||||
ind + 1 === colorways.length
|
||||
}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<div
|
||||
className="colorwayInfoIconContainer"
|
||||
onClick={() => {
|
||||
openModal((props) => (
|
||||
<ColorwayInfoModal
|
||||
modalProps={
|
||||
props
|
||||
}
|
||||
colorwayProps={
|
||||
color
|
||||
}
|
||||
discrimProps={customColorways.includes(
|
||||
color
|
||||
)}
|
||||
loadUIProps={cached_loadUI}
|
||||
/>
|
||||
));
|
||||
}}
|
||||
>
|
||||
<div className="colorwayInfoIcon">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div className="colorwayCheckIconContainer">
|
||||
<div className="colorwayCheckIcon">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle r="8" cx="12" cy="12" fill="var(--white-500)" />
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="var(--brand-500)" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="discordColorwayPreviewColorContainer"
|
||||
onClick={() => {
|
||||
if (
|
||||
currentColorway ===
|
||||
color.name
|
||||
) {
|
||||
DataStore.set(
|
||||
"actveColorwayID",
|
||||
null
|
||||
);
|
||||
DataStore.set(
|
||||
"actveColorway",
|
||||
null
|
||||
);
|
||||
ColorwayCSS.remove();
|
||||
} else {
|
||||
DataStore.set(
|
||||
"actveColorwayID",
|
||||
color.name
|
||||
);
|
||||
DataStore.set(
|
||||
"actveColorway",
|
||||
color["dc-import"]
|
||||
);
|
||||
ColorwayCSS.set(
|
||||
color["dc-import"]
|
||||
);
|
||||
}
|
||||
DataStore.get(
|
||||
"actveColorwayID"
|
||||
).then(
|
||||
(
|
||||
actveColorwayID: string
|
||||
) =>
|
||||
setCurrentColorway(
|
||||
actveColorwayID
|
||||
)
|
||||
);
|
||||
}}
|
||||
>
|
||||
{colors.map((colorItm) => {
|
||||
return (
|
||||
<div
|
||||
className="discordColorwayPreviewColor"
|
||||
style={{
|
||||
// prettier-ignore
|
||||
backgroundColor: color[colorItm],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</SettingsTab>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { CopyIcon } from "@components/Icons";
|
||||
import { Link } from "@components/Link";
|
||||
import { SettingsTab } from "@components/VencordSettings/shared";
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||
import {
|
||||
Button,
|
||||
Clipboard,
|
||||
FluxDispatcher,
|
||||
Forms,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState
|
||||
} from "@webpack/common";
|
||||
import { FluxEvents } from "@webpack/types";
|
||||
import { versionData } from "userplugins/discordColorways";
|
||||
|
||||
import { defaultColorwaySource, fallbackColorways, knownColorwaySources } from "../../constants";
|
||||
import { Colorway } from "../../types";
|
||||
import Divider from "../Divider";
|
||||
import { CloseIcon } from "../Icons";
|
||||
|
||||
export default function () {
|
||||
const [colorways, setColorways] = useState<Colorway[]>([]);
|
||||
const [customColorways, setCustomColorways] = useState<Colorway[]>([]);
|
||||
const [colorwaySourceFiles, setColorwaySourceFiles] = useState<string[]>();
|
||||
const [colorsButtonVisibility, setColorsButtonVisibility] = useState<boolean>(false);
|
||||
const [isButtonThin, setIsButtonThin] = useState<boolean>(false);
|
||||
|
||||
async function loadUI() {
|
||||
const colorwaySourceFiles = await DataStore.get(
|
||||
"colorwaySourceFiles"
|
||||
);
|
||||
const responses: Response[] = await Promise.all(
|
||||
colorwaySourceFiles.map((url: string) =>
|
||||
fetch(url)
|
||||
)
|
||||
);
|
||||
const data = await Promise.all(
|
||||
responses.map((res: Response) =>
|
||||
res.json().catch(() => { return { colorways: [] }; })
|
||||
));
|
||||
const colorways = data.flatMap(json => json.colorways);
|
||||
const [
|
||||
customColorways,
|
||||
colorwaySourceFiless,
|
||||
showColorwaysButton,
|
||||
useThinMenuButton
|
||||
] = await DataStore.getMany([
|
||||
"customColorways",
|
||||
"colorwaySourceFiles",
|
||||
"showColorwaysButton",
|
||||
"useThinMenuButton"
|
||||
]);
|
||||
setColorways(colorways || fallbackColorways);
|
||||
setCustomColorways(customColorways);
|
||||
setColorwaySourceFiles(colorwaySourceFiless);
|
||||
setColorsButtonVisibility(showColorwaysButton);
|
||||
setIsButtonThin(useThinMenuButton);
|
||||
}
|
||||
|
||||
const cached_loadUI = useCallback(loadUI, []);
|
||||
|
||||
useEffect(() => {
|
||||
cached_loadUI();
|
||||
}, []);
|
||||
|
||||
return <SettingsTab title="Settings">
|
||||
<div className="colorwaysSettingsPage-wrapper">
|
||||
<Flex style={{ gap: "0", marginBottom: "8px" }}>
|
||||
<Forms.FormTitle tag="h5" style={{ width: "100%", marginBottom: "0", lineHeight: "32px" }}>Sources</Forms.FormTitle>
|
||||
<Button
|
||||
className="colorwaysSettings-colorwaySourceAction"
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
style={{ flexShrink: "0" }}
|
||||
size={Button.Sizes.SMALL}
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
onClick={() => {
|
||||
openModal(props => {
|
||||
var colorwaySource = "";
|
||||
return <ModalRoot {...props}>
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/semibold" tag="h1">
|
||||
Add a source:
|
||||
</Text>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<TextInput
|
||||
placeholder="Enter a valid URL..."
|
||||
onChange={e => colorwaySource = e}
|
||||
/>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.BRAND}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={async () => {
|
||||
var sourcesArr: string[] = [];
|
||||
const colorwaySourceFilesArr = await DataStore.get("colorwaySourceFiles");
|
||||
colorwaySourceFilesArr.map((source: string) => sourcesArr.push(source));
|
||||
if (colorwaySource !== defaultColorwaySource) {
|
||||
sourcesArr.push(colorwaySource);
|
||||
}
|
||||
DataStore.set("colorwaySourceFiles", sourcesArr);
|
||||
setColorwaySourceFiles(sourcesArr);
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
onClick={() => props.onClose()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>;
|
||||
});
|
||||
}}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M20 11.1111H12.8889V4H11.1111V11.1111H4V12.8889H11.1111V20H12.8889V12.8889H20V11.1111Z"
|
||||
/>
|
||||
</svg>
|
||||
Add a source...
|
||||
</Button>
|
||||
</Flex>
|
||||
<Flex flexDirection="column">
|
||||
{colorwaySourceFiles?.map((colorwaySourceFile: string) => <div className="colorwaysSettings-colorwaySource">
|
||||
{knownColorwaySources.find(o => o.url === colorwaySourceFile) ? <div className="hoverRoll">
|
||||
<Text className="colorwaysSettings-colorwaySourceLabel hoverRoll_normal">
|
||||
{knownColorwaySources.find(o => o.url === colorwaySourceFile)!.name} {colorwaySourceFile === defaultColorwaySource && <div className="colorways-badge">DEFAULT</div>}
|
||||
</Text>
|
||||
<Text className="colorwaysSettings-colorwaySourceLabel hoverRoll_hovered">
|
||||
{colorwaySourceFile}
|
||||
</Text>
|
||||
</div>
|
||||
: <Text className="colorwaysSettings-colorwaySourceLabel">
|
||||
{colorwaySourceFile}
|
||||
</Text>}
|
||||
{colorwaySourceFile !== defaultColorwaySource
|
||||
&& <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
onClick={async () => {
|
||||
var sourcesArr: string[] = [];
|
||||
const colorwaySourceFilesArr = await DataStore.get("colorwaySourceFiles");
|
||||
colorwaySourceFilesArr.map((source: string) => {
|
||||
if (source !== colorwaySourceFile) {
|
||||
sourcesArr.push(source);
|
||||
}
|
||||
});
|
||||
DataStore.set("colorwaySourceFiles", sourcesArr);
|
||||
setColorwaySourceFiles(sourcesArr);
|
||||
}}
|
||||
>
|
||||
<CloseIcon width={20} height={20} />
|
||||
</Button>}
|
||||
<Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
onClick={() => { Clipboard.copy(colorwaySourceFile); }}
|
||||
>
|
||||
<CopyIcon width={20} height={20} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Flex>
|
||||
<Divider />
|
||||
<Forms.FormTitle tag="h5">Quick Switch</Forms.FormTitle>
|
||||
<Switch
|
||||
value={colorsButtonVisibility}
|
||||
onChange={(v: boolean) => {
|
||||
setColorsButtonVisibility(v);
|
||||
DataStore.set("showColorwaysButton", v);
|
||||
FluxDispatcher.dispatch({
|
||||
type: "COLORWAYS_UPDATE_BUTTON_VISIBILITY" as FluxEvents,
|
||||
isVisible: v
|
||||
});
|
||||
}}
|
||||
note="Shows a button on the top of the servers list that opens a colorway selector modal."
|
||||
>
|
||||
Enable Quick Switch
|
||||
</Switch>
|
||||
<Switch
|
||||
value={isButtonThin}
|
||||
onChange={(v: boolean) => {
|
||||
setIsButtonThin(v);
|
||||
DataStore.set("useThinMenuButton", v);
|
||||
FluxDispatcher.dispatch({
|
||||
type: "COLORWAYS_UPDATE_BUTTON_HEIGHT" as FluxEvents,
|
||||
isTall: v
|
||||
});
|
||||
}}
|
||||
note="Replaces the icon on the colorways launcher button with text, making it more compact."
|
||||
>
|
||||
Use thin Quick Switch button
|
||||
</Switch>
|
||||
<Flex flexDirection="column" style={{ gap: 0 }}>
|
||||
<h1 style={{
|
||||
fontFamily: "var(--font-headline)",
|
||||
fontSize: "24px",
|
||||
color: "var(--header-primary)",
|
||||
lineHeight: "31px",
|
||||
marginBottom: "0"
|
||||
}}>
|
||||
Discord <span style={{
|
||||
fontFamily: "var(--font-display)",
|
||||
fontSize: "24px",
|
||||
backgroundColor: "var(--brand-500)",
|
||||
padding: "0 4px",
|
||||
borderRadius: "4px"
|
||||
}}>Colorways</span>
|
||||
</h1>
|
||||
<Text
|
||||
variant="text-xs/normal"
|
||||
style={{
|
||||
color: "var(--text-normal)",
|
||||
fontWeight: 500,
|
||||
fontSize: "14px",
|
||||
marginBottom: "12px"
|
||||
}}
|
||||
>by Project Colorway</Text>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
Plugin Version:
|
||||
</Forms.FormTitle>
|
||||
<Text
|
||||
variant="text-xs/normal"
|
||||
style={{
|
||||
color: "var(--text-muted)",
|
||||
fontWeight: 500,
|
||||
fontSize: "14px",
|
||||
marginBottom: "8px"
|
||||
}}
|
||||
>
|
||||
{versionData.pluginVersion}
|
||||
</Text>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
Creator Version:
|
||||
</Forms.FormTitle>
|
||||
<Text
|
||||
variant="text-xs/normal"
|
||||
style={{
|
||||
color: "var(--text-muted)",
|
||||
fontWeight: 500,
|
||||
fontSize: "14px",
|
||||
marginBottom: "8px"
|
||||
}}
|
||||
>
|
||||
{versionData.creatorVersion}{" "}
|
||||
(Stable)
|
||||
</Text>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
Loaded Colorways:
|
||||
</Forms.FormTitle>
|
||||
<Text
|
||||
variant="text-xs/normal"
|
||||
style={{
|
||||
color: "var(--text-muted)",
|
||||
fontWeight: 500,
|
||||
fontSize: "14px",
|
||||
marginBottom: "8px"
|
||||
}}
|
||||
>
|
||||
{[...colorways, ...customColorways].length}
|
||||
</Text>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
Project Repositories:
|
||||
</Forms.FormTitle>
|
||||
<Forms.FormText style={{ marginBottom: "8px" }}>
|
||||
<Link href="https://github.com/DaBluLite/DiscordColorways">DiscordColorways</Link>
|
||||
<br />
|
||||
<Link href="https://github.com/DaBluLite/ProjectColorway">Project Colorway</Link>
|
||||
</Forms.FormText>
|
||||
</Flex>
|
||||
</div>
|
||||
</SettingsTab>;
|
||||
}
|
17
src/userplugins/DiscordColorways/components/Spinner.tsx
Normal file
17
src/userplugins/DiscordColorways/components/Spinner.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export default function ({ className }: { className?: string; }) {
|
||||
return <div className={"colorwaysBtn-spinner" + (className ? " " + className : "")} role="img" aria-label="Loading">
|
||||
<div className="colorwaysBtn-spinnerInner">
|
||||
<svg className="colorwaysBtn-spinnerCircular" viewBox="25 25 50 50" fill="currentColor">
|
||||
<circle className="colorwaysBtn-spinnerBeam colorwaysBtn-spinnerBeam3" cx="50" cy="50" r="20" />
|
||||
<circle className="colorwaysBtn-spinnerBeam colorwaysBtn-spinnerBeam2" cx="50" cy="50" r="20" />
|
||||
<circle className="colorwaysBtn-spinnerBeam" cx="50" cy="50" r="20" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
222
src/userplugins/DiscordColorways/components/ThemePreview.tsx
Normal file
222
src/userplugins/DiscordColorways/components/ThemePreview.tsx
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import {
|
||||
Forms,
|
||||
Text,
|
||||
useState
|
||||
} from "@webpack/common";
|
||||
|
||||
import { HexToHSL } from "../utils";
|
||||
import { CloseIcon } from "./Icons";
|
||||
|
||||
export default function ({
|
||||
accent,
|
||||
primary,
|
||||
secondary,
|
||||
tertiary,
|
||||
className,
|
||||
isCollapsed,
|
||||
previewCSS
|
||||
}: {
|
||||
accent: string,
|
||||
primary: string,
|
||||
secondary: string,
|
||||
tertiary: string,
|
||||
className?: string,
|
||||
isCollapsed: boolean,
|
||||
previewCSS?: string;
|
||||
}) {
|
||||
const [collapsed, setCollapsed] = useState<boolean>(isCollapsed);
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
`${collapsed === true
|
||||
? "colorwaysPreview colorwaysPreview-collapsed"
|
||||
: "colorwaysPreview"
|
||||
} ${className}`
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-settingHeader"
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
>
|
||||
<Forms.FormTitle
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
Preview
|
||||
</Forms.FormTitle>
|
||||
<svg
|
||||
className="expand-3Nh1P5 transition-30IQBn directionDown-2w0MZz"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M7 10L12 15 17 10"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<style>
|
||||
{previewCSS}
|
||||
</style>
|
||||
<ThemePreview
|
||||
accent={accent}
|
||||
primary={primary}
|
||||
secondary={secondary}
|
||||
tertiary={tertiary}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ThemePreview({
|
||||
accent,
|
||||
primary,
|
||||
secondary,
|
||||
tertiary,
|
||||
previewCSS
|
||||
}: {
|
||||
accent: string,
|
||||
primary: string,
|
||||
secondary: string,
|
||||
tertiary: string,
|
||||
previewCSS?: string;
|
||||
}) {
|
||||
const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
|
||||
return (
|
||||
<div
|
||||
className="colorwaysPreview-container"
|
||||
>
|
||||
<style>
|
||||
{previewCSS}
|
||||
</style>
|
||||
<div
|
||||
className="colorwaysPreview-wrapper"
|
||||
style={{ backgroundColor: tertiary }}
|
||||
>
|
||||
<div className="colorwaysPreview-titlebar" />
|
||||
<div className="colorwaysPreview-body">
|
||||
<div className="colorwayPreview-guilds">
|
||||
<div className="colorwayPreview-guild">
|
||||
<div
|
||||
className="colorwayPreview-guildItem"
|
||||
style={{ backgroundColor: primary }}
|
||||
onMouseEnter={e => e.currentTarget.style.backgroundColor = accent}
|
||||
onMouseLeave={e => e.currentTarget.style.backgroundColor = primary}
|
||||
onClick={e => {
|
||||
if (!document.fullscreenElement) {
|
||||
e.currentTarget
|
||||
.parentElement
|
||||
?.parentElement
|
||||
?.parentElement
|
||||
?.parentElement
|
||||
?.requestFullscreen();
|
||||
} else {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
setIsFullscreen(!isFullscreen);
|
||||
}}
|
||||
>
|
||||
{isFullscreen ? <CloseIcon /> : <svg
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19,3H14V5h5v5h2V5A2,2,0,0,0,19,3Z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19,19H14v2h5a2,2,0,0,0,2-2V14H19Z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M3,5v5H5V5h5V3H5A2,2,0,0,0,3,5Z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5,14H3v5a2,2,0,0,0,2,2h5V19H5Z"
|
||||
/>
|
||||
</svg>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="colorwayPreview-guild">
|
||||
<div className="colorwayPreview-guildSeparator" style={{ backgroundColor: primary }} />
|
||||
</div>
|
||||
<div className="colorwayPreview-guild">
|
||||
<div
|
||||
className="colorwayPreview-guildItem"
|
||||
style={{ backgroundColor: primary }}
|
||||
onMouseEnter={e => { e.currentTarget.style.backgroundColor = accent; }}
|
||||
onMouseLeave={e => { e.currentTarget.style.backgroundColor = primary; }}
|
||||
/>
|
||||
</div>
|
||||
<div className="colorwayPreview-guild">
|
||||
<div
|
||||
className="colorwayPreview-guildItem"
|
||||
style={{ backgroundColor: primary }}
|
||||
onMouseEnter={e => { e.currentTarget.style.backgroundColor = accent; }}
|
||||
onMouseLeave={e => { e.currentTarget.style.backgroundColor = primary; }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="colorwayPreview-channels" style={{ backgroundColor: secondary }}>
|
||||
<div
|
||||
className="colorwayPreview-userArea"
|
||||
style={{
|
||||
backgroundColor: "hsl(" + HexToHSL(secondary)[0] + " " + HexToHSL(secondary)[1] + "% " + Math.max(HexToHSL(secondary)[2] - 3.6, 0) + "%)"
|
||||
}}
|
||||
/>
|
||||
<div className="colorwayPreview-filler" />
|
||||
<div
|
||||
className="colorwayPreview-topShadow"
|
||||
style={{
|
||||
"--primary-900-hsl": `${HexToHSL(tertiary)[0]} ${HexToHSL(tertiary)[1]}% ${Math.max(HexToHSL(tertiary)[2] - (3.6 * 6), 0)}%`,
|
||||
"--primary-500-hsl": `${HexToHSL(primary)[0]} ${HexToHSL(primary)[1]}% ${Math.min(HexToHSL(primary)[2] + (3.6 * 3), 100)}%`
|
||||
} as React.CSSProperties}
|
||||
>
|
||||
<Text
|
||||
tag="div"
|
||||
variant="text-md/semibold"
|
||||
lineClamp={1}
|
||||
selectable={false}
|
||||
>
|
||||
Preview
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className="colorwayPreview-chat" style={{ backgroundColor: primary }}>
|
||||
<div
|
||||
className="colorwayPreview-chatBox"
|
||||
style={{
|
||||
backgroundColor: "hsl(" + HexToHSL(primary)[0] + " " + HexToHSL(primary)[1] + "% " + Math.min(HexToHSL(primary)[2] + 3.6, 100) + "%)"
|
||||
}}
|
||||
/>
|
||||
<div className="colorwayPreview-filler" />
|
||||
<div
|
||||
className="colorwayPreview-topShadow"
|
||||
style={{
|
||||
"--primary-900-hsl": `${HexToHSL(tertiary)[0]} ${HexToHSL(tertiary)[1]}% ${Math.max(HexToHSL(tertiary)[2] - (3.6 * 6), 0)}%`
|
||||
} as React.CSSProperties}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
317
src/userplugins/DiscordColorways/constants.ts
Normal file
317
src/userplugins/DiscordColorways/constants.ts
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export const defaultColorwaySource = "https://raw.githubusercontent.com/DaBluLite/ProjectColorway/master/index.json";
|
||||
|
||||
export const knownColorwaySources = [
|
||||
{
|
||||
name: "Project Colorway",
|
||||
url: "https://raw.githubusercontent.com/DaBluLite/ProjectColorway/master/index.json"
|
||||
},
|
||||
{
|
||||
name: "DaBluLite's Personal Colorways",
|
||||
url: "https://raw.githubusercontent.com/DaBluLite/dablulite.github.io/master/colorways/index.json"
|
||||
}
|
||||
];
|
||||
|
||||
export const fallbackColorways = [
|
||||
{
|
||||
name: "Keyboard Purple",
|
||||
original: false,
|
||||
accent: "hsl(235 85.6% 64.7%)",
|
||||
primary: "#222456",
|
||||
secondary: "#1c1f48",
|
||||
tertiary: "#080d1d",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/KeyboardPurple/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Eclipse",
|
||||
original: false,
|
||||
accent: "hsl(87 85.6% 64.7%)",
|
||||
primary: "#000000",
|
||||
secondary: "#181818",
|
||||
tertiary: "#0a0a0a",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Eclipse/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Cyan",
|
||||
original: false,
|
||||
accent: "#009f88",
|
||||
primary: "#202226",
|
||||
secondary: "#1c1e21",
|
||||
tertiary: "#141517",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Cyan/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Spotify",
|
||||
original: false,
|
||||
accent: "hsl(141 76% 48%)",
|
||||
primary: "#121212",
|
||||
secondary: "#090909",
|
||||
tertiary: "#090909",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Spotify/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Bright n' Blue",
|
||||
original: true,
|
||||
accent: "hsl(234, 68%, 33%)",
|
||||
primary: "#394aae",
|
||||
secondary: "#29379d",
|
||||
tertiary: "#1b278d",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/BrightBlue/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Still Young",
|
||||
original: true,
|
||||
accent: "hsl(58 85.6% 89%)",
|
||||
primary: "#443a31",
|
||||
secondary: "#7c3d3e",
|
||||
tertiary: "#207578",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/StillYoung/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Sea",
|
||||
original: true,
|
||||
accent: "hsl(184, 100%, 50%)",
|
||||
primary: "#07353b",
|
||||
secondary: "#0b5e60",
|
||||
tertiary: "#08201d",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Sea/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Lava",
|
||||
original: true,
|
||||
accent: "hsl(4, 80.4%, 32%)",
|
||||
primary: "#401b17",
|
||||
secondary: "#351917",
|
||||
tertiary: "#230b0b",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Lava/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Solid Pink",
|
||||
original: true,
|
||||
accent: "hsl(340, 55.2%, 56.3%)",
|
||||
primary: "#1e151c",
|
||||
secondary: "#21181f",
|
||||
tertiary: "#291e27",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/SolidPink/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Sand",
|
||||
original: true,
|
||||
accent: "hsl(41, 31%, 45%)",
|
||||
primary: "#7f6c43",
|
||||
secondary: "#665b33",
|
||||
tertiary: "#5c5733",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Sand/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "AMOLED",
|
||||
original: true,
|
||||
accent: "hsl(235 85.6% 64.7%)",
|
||||
primary: "#000000",
|
||||
secondary: "#000000",
|
||||
tertiary: "#000000",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Amoled/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Zorin",
|
||||
original: false,
|
||||
accent: "hsl(200, 89%, 86%)",
|
||||
primary: "#171d20",
|
||||
secondary: "#171d20",
|
||||
tertiary: "#1e2529",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Zorin/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Desaturated",
|
||||
original: false,
|
||||
accent: "hsl(227, 58%, 65%)",
|
||||
primary: "#35383d",
|
||||
secondary: "#2c2f34",
|
||||
tertiary: "#1e1f24",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Desaturated/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Crimson",
|
||||
original: false,
|
||||
accent: "hsl(0, 100%, 50%)",
|
||||
primary: "#050000",
|
||||
secondary: "#0a0000",
|
||||
tertiary: "#0f0000",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Crimson/import.css);",
|
||||
author: "Riddim_GLiTCH",
|
||||
authorID: "801089753038061669",
|
||||
},
|
||||
{
|
||||
name: "Jupiter",
|
||||
original: true,
|
||||
accent: "#ffd89b",
|
||||
primary: "#ffd89b",
|
||||
secondary: "#19547b",
|
||||
tertiary: "#1e1f22",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Jupiter/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
isGradient: true,
|
||||
colors: ["accent", "primary", "secondary"],
|
||||
},
|
||||
{
|
||||
name: "Neon Candy",
|
||||
original: true,
|
||||
accent: "#FC00FF",
|
||||
primary: "#00DBDE",
|
||||
secondary: "#00DBDE",
|
||||
tertiary: "#00DBDE",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/NeonCandy/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
isGradient: true,
|
||||
colors: ["accent", "primary"],
|
||||
},
|
||||
{
|
||||
name: "Wildberry",
|
||||
original: false,
|
||||
accent: "#f40172",
|
||||
primary: "#180029",
|
||||
secondary: "#340057",
|
||||
tertiary: "#4b007a",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Wildberry/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Facebook",
|
||||
original: false,
|
||||
accent: "#2375e1",
|
||||
primary: "#18191a",
|
||||
secondary: "#242526",
|
||||
tertiary: "#3a3b3c",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Facebook/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Material You",
|
||||
original: false,
|
||||
accent: "#004977",
|
||||
primary: "#1f1f1f",
|
||||
secondary: "#28292a",
|
||||
tertiary: "#2d2f31",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/MaterialYou/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "Discord Teal",
|
||||
original: false,
|
||||
accent: "#175f6d",
|
||||
primary: "#313338",
|
||||
secondary: "#2b2d31",
|
||||
tertiary: "#1e1f22",
|
||||
"dc-import": "@import url(//dablulite.github.io/css-snippets/DiscordTeal/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
colors: ["accent"],
|
||||
},
|
||||
{
|
||||
name: "黄昏の花 (Twilight Blossom)",
|
||||
original: true,
|
||||
accent: "#e100ff",
|
||||
primary: "#04000a",
|
||||
secondary: "#0b0024",
|
||||
tertiary: "#210042",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/TwilightBlossom/import.css);",
|
||||
author: "Riddim_GLiTCH",
|
||||
authorID: "801089753038061669",
|
||||
},
|
||||
{
|
||||
name: "Chai",
|
||||
original: true,
|
||||
accent: "#59cd51",
|
||||
primary: "#1c1e15",
|
||||
secondary: "#1e2118",
|
||||
tertiary: "#24291e",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/Chai/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
{
|
||||
name: "CS1.6",
|
||||
original: false,
|
||||
accent: "#929a8d",
|
||||
primary: "#3f4738",
|
||||
secondary: "#5b6c51",
|
||||
tertiary: "#4d5945",
|
||||
"dc-import": "@import url(//dablulite.github.io/DiscordColorways/CS16/import.css);",
|
||||
author: "DaBluLite",
|
||||
authorID: "582170007505731594",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const knownThemeVars = {
|
||||
"Cyan": {
|
||||
variable: "--cyan-accent-color",
|
||||
accent: "--cyan-accent-color",
|
||||
primary: "--cyan-background-primary",
|
||||
secondary: "--cyan-background-secondary"
|
||||
},
|
||||
"Virtual Boy": {
|
||||
variable: "--VBaccent",
|
||||
tertiary: "--VBaccent-muted",
|
||||
alt: {
|
||||
tertiary: "--VBaccent-dimmest"
|
||||
}
|
||||
},
|
||||
"Modular": {
|
||||
variable: "--modular-hue",
|
||||
accentVariables: {
|
||||
h: "--modular-hue",
|
||||
s: "--modular-saturation",
|
||||
l: "--modular-lightness"
|
||||
}
|
||||
},
|
||||
"Solana": {
|
||||
variable: "--accent-hue",
|
||||
accentVariables: {
|
||||
h: "--accent-hue",
|
||||
s: "--accent-saturation",
|
||||
l: "--accent-brightness"
|
||||
},
|
||||
primaryVariables: {
|
||||
h: "--background-accent-hue",
|
||||
s: "--background-accent-saturation",
|
||||
l: "--background-accent-brightness"
|
||||
}
|
||||
}
|
||||
};
|
767
src/userplugins/DiscordColorways/css.ts
Normal file
767
src/userplugins/DiscordColorways/css.ts
Normal file
|
@ -0,0 +1,767 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Plugins } from "Vencord";
|
||||
|
||||
import { HexToHSL } from "./utils";
|
||||
|
||||
export const colorVariables: string[] = [
|
||||
"brand-100",
|
||||
"brand-130",
|
||||
"brand-160",
|
||||
"brand-200",
|
||||
"brand-230",
|
||||
"brand-260",
|
||||
"brand-300",
|
||||
"brand-330",
|
||||
"brand-345",
|
||||
"brand-360",
|
||||
"brand-400",
|
||||
"brand-430",
|
||||
"brand-460",
|
||||
"brand-500",
|
||||
"brand-530",
|
||||
"brand-560",
|
||||
"brand-600",
|
||||
"brand-630",
|
||||
"brand-660",
|
||||
"brand-700",
|
||||
"brand-730",
|
||||
"brand-760",
|
||||
"brand-800",
|
||||
"brand-830",
|
||||
"brand-860",
|
||||
"brand-900",
|
||||
"primary-900",
|
||||
"primary-860",
|
||||
"primary-830",
|
||||
"primary-800",
|
||||
"primary-760",
|
||||
"primary-730",
|
||||
"primary-700",
|
||||
"primary-660",
|
||||
"primary-645",
|
||||
"primary-630",
|
||||
"primary-600",
|
||||
"primary-560",
|
||||
"primary-530",
|
||||
"primary-500",
|
||||
"primary-460",
|
||||
"primary-430",
|
||||
"primary-400",
|
||||
"primary-360",
|
||||
"primary-330",
|
||||
"primary-300",
|
||||
"primary-260",
|
||||
"primary-230",
|
||||
"primary-200",
|
||||
"primary-160",
|
||||
"primary-130",
|
||||
"primary-100",
|
||||
"white-900",
|
||||
"white-860",
|
||||
"white-830",
|
||||
"white-800",
|
||||
"white-760",
|
||||
"white-730",
|
||||
"white-700",
|
||||
"white-660",
|
||||
"white-630",
|
||||
"white-600",
|
||||
"white-560",
|
||||
"white-530",
|
||||
"white-500",
|
||||
"white-460",
|
||||
"white-430",
|
||||
"white-400",
|
||||
"white-360",
|
||||
"white-330",
|
||||
"white-300",
|
||||
"white-260",
|
||||
"white-230",
|
||||
"white-200",
|
||||
"white-160",
|
||||
"white-130",
|
||||
"white-100",
|
||||
"teal-900",
|
||||
"teal-860",
|
||||
"teal-830",
|
||||
"teal-800",
|
||||
"teal-760",
|
||||
"teal-730",
|
||||
"teal-700",
|
||||
"teal-660",
|
||||
"teal-630",
|
||||
"teal-600",
|
||||
"teal-560",
|
||||
"teal-530",
|
||||
"teal-500",
|
||||
"teal-460",
|
||||
"teal-430",
|
||||
"teal-400",
|
||||
"teal-360",
|
||||
"teal-330",
|
||||
"teal-300",
|
||||
"teal-260",
|
||||
"teal-230",
|
||||
"teal-200",
|
||||
"teal-160",
|
||||
"teal-130",
|
||||
"teal-100",
|
||||
"black-900",
|
||||
"black-860",
|
||||
"black-830",
|
||||
"black-800",
|
||||
"black-760",
|
||||
"black-730",
|
||||
"black-700",
|
||||
"black-660",
|
||||
"black-630",
|
||||
"black-600",
|
||||
"black-560",
|
||||
"black-530",
|
||||
"black-500",
|
||||
"black-460",
|
||||
"black-430",
|
||||
"black-400",
|
||||
"black-360",
|
||||
"black-330",
|
||||
"black-300",
|
||||
"black-260",
|
||||
"black-230",
|
||||
"black-200",
|
||||
"black-160",
|
||||
"black-130",
|
||||
"black-100",
|
||||
"red-900",
|
||||
"red-860",
|
||||
"red-830",
|
||||
"red-800",
|
||||
"red-760",
|
||||
"red-730",
|
||||
"red-700",
|
||||
"red-660",
|
||||
"red-630",
|
||||
"red-600",
|
||||
"red-560",
|
||||
"red-530",
|
||||
"red-500",
|
||||
"red-460",
|
||||
"red-430",
|
||||
"red-400",
|
||||
"red-360",
|
||||
"red-330",
|
||||
"red-300",
|
||||
"red-260",
|
||||
"red-230",
|
||||
"red-200",
|
||||
"red-160",
|
||||
"red-130",
|
||||
"red-100",
|
||||
"yellow-900",
|
||||
"yellow-860",
|
||||
"yellow-830",
|
||||
"yellow-800",
|
||||
"yellow-760",
|
||||
"yellow-730",
|
||||
"yellow-700",
|
||||
"yellow-660",
|
||||
"yellow-630",
|
||||
"yellow-600",
|
||||
"yellow-560",
|
||||
"yellow-530",
|
||||
"yellow-500",
|
||||
"yellow-460",
|
||||
"yellow-430",
|
||||
"yellow-400",
|
||||
"yellow-360",
|
||||
"yellow-330",
|
||||
"yellow-300",
|
||||
"yellow-260",
|
||||
"yellow-230",
|
||||
"yellow-200",
|
||||
"yellow-160",
|
||||
"yellow-130",
|
||||
"yellow-100",
|
||||
"green-900",
|
||||
"green-860",
|
||||
"green-830",
|
||||
"green-800",
|
||||
"green-760",
|
||||
"green-730",
|
||||
"green-700",
|
||||
"green-660",
|
||||
"green-630",
|
||||
"green-600",
|
||||
"green-560",
|
||||
"green-530",
|
||||
"green-500",
|
||||
"green-460",
|
||||
"green-430",
|
||||
"green-400",
|
||||
"green-360",
|
||||
"green-330",
|
||||
"green-300",
|
||||
"green-260",
|
||||
"green-230",
|
||||
"green-200",
|
||||
"green-160",
|
||||
"green-130",
|
||||
"green-100",
|
||||
];
|
||||
|
||||
const PrimarySatDiffs = {
|
||||
130: 63.9594,
|
||||
160: 49.4382,
|
||||
200: 37.5758,
|
||||
230: 30.3797,
|
||||
260: 22.5166,
|
||||
300: 32.5,
|
||||
330: 27.0968,
|
||||
345: 22.5166,
|
||||
360: 18.9189,
|
||||
400: -14.4,
|
||||
430: -33.0435,
|
||||
460: 25.2101,
|
||||
500: -11.0236,
|
||||
530: -3.0303,
|
||||
645: 7.40741,
|
||||
660: 3.0303,
|
||||
730: 11.9403,
|
||||
800: 25,
|
||||
};
|
||||
|
||||
const BrandSatDiffs = {
|
||||
100: -9.54712,
|
||||
130: 2.19526,
|
||||
160: -1.17509,
|
||||
200: -2.72351,
|
||||
230: 1.62225,
|
||||
260: 0.698487,
|
||||
300: 0.582411,
|
||||
330: -0.585823,
|
||||
345: -0.468384,
|
||||
360: 0.582411,
|
||||
400: 0.582411,
|
||||
430: 0.116754,
|
||||
460: -0.116891,
|
||||
530: -24.8194,
|
||||
560: -49.927,
|
||||
600: -58.8057,
|
||||
630: -58.8057,
|
||||
660: -58.0256,
|
||||
700: -58.2202,
|
||||
730: -58.6103,
|
||||
760: -58.4151,
|
||||
800: -57.2502,
|
||||
830: -57.4436,
|
||||
860: -58.4151,
|
||||
900: -52.5074
|
||||
};
|
||||
|
||||
const BrandLightDiffs = {
|
||||
100: 33.5,
|
||||
130: 32.2,
|
||||
160: 30.2,
|
||||
200: 28.2,
|
||||
230: 26.2999,
|
||||
260: 23.8999,
|
||||
300: 21.2,
|
||||
330: 16.8999,
|
||||
345: 14.0999,
|
||||
360: 12.7999,
|
||||
400: 7.0999,
|
||||
430: 5.0999,
|
||||
460: 2.7999,
|
||||
530: -5.9,
|
||||
560: -12.3,
|
||||
600: -20.6,
|
||||
630: -26.5,
|
||||
660: -31.4,
|
||||
700: -38.8,
|
||||
730: -40.4,
|
||||
760: -42.5,
|
||||
800: -45.3,
|
||||
830: -49.8,
|
||||
860: -55.1,
|
||||
900: -61.6
|
||||
};
|
||||
|
||||
function gradientBase(accentColor?: string, discordSaturation = false) {
|
||||
return `@import url(//dablulite.github.io/css-snippets/NoLightInDark/import.css);
|
||||
@import url(//dablulite.github.io/css-snippets/NitroThemesFix/import.css);
|
||||
.theme-dark {
|
||||
--bg-overlay-color: 0 0 0;
|
||||
--bg-overlay-color-inverse: 255 255 255;
|
||||
--bg-overlay-opacity-1: 0.85;
|
||||
--bg-overlay-opacity-2: 0.8;
|
||||
--bg-overlay-opacity-3: 0.7;
|
||||
--bg-overlay-opacity-4: 0.5;
|
||||
--bg-overlay-opacity-5: 0.4;
|
||||
--bg-overlay-opacity-6: 0.1;
|
||||
--bg-overlay-opacity-hover: 0.5;
|
||||
--bg-overlay-opacity-hover-inverse: 0.08;
|
||||
--bg-overlay-opacity-active: 0.45;
|
||||
--bg-overlay-opacity-active-inverse: 0.1;
|
||||
--bg-overlay-opacity-selected: 0.4;
|
||||
--bg-overlay-opacity-selected-inverse: 0.15;
|
||||
--bg-overlay-opacity-chat: 0.8;
|
||||
--bg-overlay-opacity-home: 0.85;
|
||||
--bg-overlay-opacity-home-card: 0.8;
|
||||
--bg-overlay-opacity-app-frame: var(--bg-overlay-opacity-4);
|
||||
}
|
||||
.theme-light {
|
||||
--bg-overlay-color: 255 255 255;
|
||||
--bg-overlay-color-inverse: 0 0 0;
|
||||
--bg-overlay-opacity-1: 0.9;
|
||||
--bg-overlay-opacity-2: 0.8;
|
||||
--bg-overlay-opacity-3: 0.7;
|
||||
--bg-overlay-opacity-4: 0.6;
|
||||
--bg-overlay-opacity-5: 0.3;
|
||||
--bg-overlay-opacity-6: 0.15;
|
||||
--bg-overlay-opacity-hover: 0.7;
|
||||
--bg-overlay-opacity-hover-inverse: 0.02;
|
||||
--bg-overlay-opacity-active: 0.65;
|
||||
--bg-overlay-opacity-active-inverse: 0.03;
|
||||
--bg-overlay-opacity-selected: 0.6;
|
||||
--bg-overlay-opacity-selected-inverse: 0.04;
|
||||
--bg-overlay-opacity-chat: 0.9;
|
||||
--bg-overlay-opacity-home: 0.7;
|
||||
--bg-overlay-opacity-home-card: 0.9;
|
||||
--bg-overlay-opacity-app-frame: var(--bg-overlay-opacity-5);
|
||||
}
|
||||
.children_cde9af:after, .form_d8a4a1:before {
|
||||
content: none;
|
||||
}
|
||||
.scroller_de945b {
|
||||
background: var(--bg-overlay-app-frame,var(--background-tertiary));
|
||||
}
|
||||
.expandedFolderBackground_b1385f {
|
||||
background: rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-6));
|
||||
}
|
||||
.wrapper__8436d:not(:hover):not(.selected_ae80f7) .childWrapper_a6ce15 {
|
||||
background: rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-6));
|
||||
}
|
||||
.folder__17546:has(.expandedFolderIconWrapper__324c1) {
|
||||
background: var(--bg-overlay-6,var(--background-secondary));
|
||||
}
|
||||
.circleIconButton__05cf2:not(.selected_aded59) {
|
||||
background: rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-6));
|
||||
}
|
||||
.auto_a3c0bd::-webkit-scrollbar-thumb,
|
||||
.thin_b1c063::-webkit-scrollbar-thumb {
|
||||
background-size: 200vh;
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,from(rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-4))),to(rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-4)))),var(--custom-theme-background);
|
||||
background-image: linear-gradient(rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-4)),rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-4))),var(--custom-theme-background);
|
||||
}
|
||||
.auto_a3c0bd::-webkit-scrollbar-track {
|
||||
background-size: 200vh;
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,from(rgb(var(--bg-overlay-color)/.4)),to(rgb(var(--bg-overlay-color)/.4))),var(--custom-theme-background);
|
||||
background-image: linear-gradient(rgb(var(--bg-overlay-color)/.4),rgb(var(--bg-overlay-color)/.4)),var(--custom-theme-background);
|
||||
}
|
||||
:root:root {
|
||||
--brand-100-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[100])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[100]) * 10) / 10, 0)};
|
||||
--brand-130-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[130])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[130]) * 10) / 10, 0)}%;
|
||||
--brand-160-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[160])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[160]) * 10) / 10, 0)}%;
|
||||
--brand-200-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[200])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[200]) * 10) / 10, 0)}%;
|
||||
--brand-230-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[230])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[230]) * 10) / 10, 0)}%;
|
||||
--brand-260-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[260])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[260]) * 10) / 10, 0)}%;
|
||||
--brand-300-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[300])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[300]) * 10) / 10, 0)}%;
|
||||
--brand-330-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[330])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[330]) * 10) / 10, 0)}%;
|
||||
--brand-345-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[345])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[345]) * 10) / 10, 0)}%;
|
||||
--brand-360-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[360])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[360]) * 10) / 10, 0)}%;
|
||||
--brand-400-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[400])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[400]) * 10) / 10, 0)}%;
|
||||
--brand-430-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[430])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[430]) * 10) / 10, 0)}%;
|
||||
--brand-460-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[460])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[460]) * 10) / 10, 0)}%;
|
||||
--brand-500-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + accentColor)[1]}%) ${HexToHSL("#" + accentColor)[2]}%;
|
||||
--brand-530-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[530])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[530]) * 10) / 10, 100)}%;
|
||||
--brand-560-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[560])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[560]) * 10) / 10, 100)}%;
|
||||
--brand-600-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[600])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[600]) * 10) / 10, 100)}%;
|
||||
--brand-630-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[630])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[630]) * 10) / 10, 100)}%;
|
||||
--brand-660-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[660])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[660]) * 10) / 10, 100)}%;
|
||||
--brand-700-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[700])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[700]) * 10) / 10, 100)}%;
|
||||
--brand-730-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[730])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[730]) * 10) / 10, 100)}%;
|
||||
--brand-760-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[760])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[760]) * 10) / 10, 100)}%;
|
||||
--brand-800-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[800])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[800]) * 10) / 10, 100)}%;
|
||||
--brand-830-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[830])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[830]) * 10) / 10, 100)}%;
|
||||
--brand-860-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[860])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[860]) * 10) / 10, 100)}%;
|
||||
--brand-900-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[900])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[900]) * 10) / 10, 100)}%;
|
||||
--bg-overlay-1: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-1)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-1))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-2: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-2)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-2))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-3: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-3)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-3))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-4: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-4)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-4))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-5: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-5)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-5))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-6: linear-gradient(rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-6)),rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-6))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-hover: linear-gradient(rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-hover-inverse)),rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-hover-inverse))) fixed 0 0/cover,linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-hover)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-hover))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-active: linear-gradient(rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-active-inverse)),rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-active-inverse))) fixed 0 0/cover,linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-active)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-active))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-selected: linear-gradient(rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-selected-inverse)),rgb(var(--bg-overlay-color-inverse)/var(--bg-overlay-opacity-selected-inverse))) fixed 0 0/cover,linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-selected)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-selected))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-chat: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-chat)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-chat))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-home: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-home)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-home))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-home-card: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-home-card)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-home-card))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;
|
||||
--bg-overlay-app-frame: linear-gradient(rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-app-frame)),rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-app-frame))) fixed 0 0/cover,var(--custom-theme-background) fixed 0 0/cover;`;
|
||||
}
|
||||
|
||||
export function generateCss(primaryColor: string, secondaryColor: string, tertiaryColor: string, accentColor: string, tintedText: boolean, discordSaturation: boolean) {
|
||||
const colorwayCss = `/*Automatically Generated - Colorway Creator V${(Plugins.plugins.DiscordColorways as any).creatorVersion}*/
|
||||
:root:root {
|
||||
--brand-100-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[100])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[100]) * 10) / 10, 0)};
|
||||
--brand-130-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[130])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[130]) * 10) / 10, 0)}%;
|
||||
--brand-160-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[160])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[160]) * 10) / 10, 0)}%;
|
||||
--brand-200-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[200])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[200]) * 10) / 10, 0)}%;
|
||||
--brand-230-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[230])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[230]) * 10) / 10, 0)}%;
|
||||
--brand-260-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[260])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[260]) * 10) / 10, 0)}%;
|
||||
--brand-300-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[300])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[300]) * 10) / 10, 0)}%;
|
||||
--brand-330-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[330])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[330]) * 10) / 10, 0)}%;
|
||||
--brand-345-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[345])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[345]) * 10) / 10, 0)}%;
|
||||
--brand-360-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[360])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[360]) * 10) / 10, 0)}%;
|
||||
--brand-400-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[400])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[400]) * 10) / 10, 0)}%;
|
||||
--brand-430-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[430])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[430]) * 10) / 10, 0)}%;
|
||||
--brand-460-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[460])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[460]) * 10) / 10, 0)}%;
|
||||
--brand-500-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + accentColor)[1]}%) ${HexToHSL("#" + accentColor)[2]}%;
|
||||
--brand-530-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[530])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[530]) * 10) / 10, 100)}%;
|
||||
--brand-560-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[560])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[560]) * 10) / 10, 100)}%;
|
||||
--brand-600-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[600])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[600]) * 10) / 10, 100)}%;
|
||||
--brand-630-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[630])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[630]) * 10) / 10, 100)}%;
|
||||
--brand-660-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[660])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[660]) * 10) / 10, 100)}%;
|
||||
--brand-700-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[700])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[700]) * 10) / 10, 100)}%;
|
||||
--brand-730-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[730])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[730]) * 10) / 10, 100)}%;
|
||||
--brand-760-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[760])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[760]) * 10) / 10, 100)}%;
|
||||
--brand-800-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[800])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[800]) * 10) / 10, 100)}%;
|
||||
--brand-830-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[830])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[830]) * 10) / 10, 100)}%;
|
||||
--brand-860-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[860])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[860]) * 10) / 10, 100)}%;
|
||||
--brand-900-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[900])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[900]) * 10) / 10, 100)}%;
|
||||
--primary-800-hsl: ${HexToHSL("#" + tertiaryColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + tertiaryColor)[1] / 100) * (100 + PrimarySatDiffs[800])) * 10) / 10 : HexToHSL("#" + tertiaryColor)[1]}%) ${Math.max(HexToHSL("#" + tertiaryColor)[2] - (3.6 * 2), 0)}%;
|
||||
--primary-730-hsl: ${HexToHSL("#" + tertiaryColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + tertiaryColor)[1] / 100) * (100 + PrimarySatDiffs[730])) * 10) / 10 : HexToHSL("#" + tertiaryColor)[1]}%) ${Math.max(HexToHSL("#" + tertiaryColor)[2] - 3.6, 0)}%;
|
||||
--primary-700-hsl: ${HexToHSL("#" + tertiaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + tertiaryColor)[1]}%) ${HexToHSL("#" + tertiaryColor)[2]}%;
|
||||
--primary-660-hsl: ${HexToHSL("#" + secondaryColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + secondaryColor)[1] / 100) * (100 + PrimarySatDiffs[660])) * 10) / 10 : HexToHSL("#" + secondaryColor)[1]}%) ${Math.max(HexToHSL("#" + secondaryColor)[2] - 3.6, 0)}%;
|
||||
--primary-645-hsl: ${HexToHSL("#" + secondaryColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + secondaryColor)[1] / 100) * (100 + PrimarySatDiffs[645])) * 10) / 10 : HexToHSL("#" + secondaryColor)[1]}%) ${Math.max(HexToHSL("#" + secondaryColor)[2] - 1.1, 0)}%;
|
||||
--primary-630-hsl: ${HexToHSL("#" + secondaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + secondaryColor)[1]}%) ${HexToHSL("#" + secondaryColor)[2]}%;
|
||||
--primary-600-hsl: ${HexToHSL("#" + primaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + primaryColor)[1]}%) ${HexToHSL("#" + primaryColor)[2]}%;
|
||||
--primary-560-hsl: ${HexToHSL("#" + primaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + primaryColor)[1]}%) ${Math.min(HexToHSL("#" + primaryColor)[2] + 3.6, 100)}%;
|
||||
--primary-530-hsl: ${HexToHSL("#" + primaryColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + primaryColor)[1] / 100) * (100 + PrimarySatDiffs[530])) * 10) / 10 : HexToHSL("#" + primaryColor)[1]}%) ${Math.min(HexToHSL("#" + primaryColor)[2] + (3.6 * 2), 100)}%;
|
||||
--primary-500-hsl: ${HexToHSL("#" + primaryColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + primaryColor)[1] / 100) * (100 + PrimarySatDiffs[500])) * 10) / 10 : HexToHSL("#" + primaryColor)[1]}%) ${Math.min(HexToHSL("#" + primaryColor)[2] + (3.6 * 3), 100)}%;${tintedText ? `\n --primary-460-hsl: 0 calc(var(--saturation-factor, 1)*0%) 50%;
|
||||
--primary-430: ${HexToHSL("#" + secondaryColor)[0] === 0 ? "gray" : ((HexToHSL("#" + secondaryColor)[2] < 80) ? "hsl(" + HexToHSL("#" + secondaryColor)[0] + `, calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + primaryColor)[1] / 100) * (100 + PrimarySatDiffs[430])) * 10) / 10 : HexToHSL("#" + primaryColor)[1]}%), 90%)` : "hsl(" + HexToHSL("#" + secondaryColor)[0] + ", calc(var(--saturation-factor, 1)*100%), 20%)")};
|
||||
--primary-400: ${HexToHSL("#" + secondaryColor)[0] === 0 ? "gray" : ((HexToHSL("#" + secondaryColor)[2] < 80) ? "hsl(" + HexToHSL("#" + secondaryColor)[0] + `, calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + primaryColor)[1] / 100) * (100 + PrimarySatDiffs[400])) * 10) / 10 : HexToHSL("#" + primaryColor)[1]}%), 90%)` : "hsl(" + HexToHSL("#" + secondaryColor)[0] + ", calc(var(--saturation-factor, 1)*100%), 20%)")};
|
||||
--primary-360: ${HexToHSL("#" + secondaryColor)[0] === 0 ? "gray" : ((HexToHSL("#" + secondaryColor)[2] < 80) ? "hsl(" + HexToHSL("#" + secondaryColor)[0] + `, calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + primaryColor)[1] / 100) * (100 + PrimarySatDiffs[360])) * 10) / 10 : HexToHSL("#" + primaryColor)[1]}%), 90%)` : "hsl(" + HexToHSL("#" + secondaryColor)[0] + ", calc(var(--saturation-factor, 1)*100%), 20%)")};` : ""}
|
||||
}
|
||||
.emptyPage_feb902,
|
||||
.scrollerContainer_dda72c,
|
||||
.container__03ec9,
|
||||
.header__71942 {
|
||||
background-color: unset !important;
|
||||
}${(Math.round(HexToHSL("#" + primaryColor)[2]) > 80) ? `\n\n/*Primary*/
|
||||
.theme-dark .container_bd15da,
|
||||
.theme-dark .body__616e6,
|
||||
.theme-dark .toolbar__62fb5,
|
||||
.theme-dark .container_e1387b,
|
||||
.theme-dark .messageContent_abea64,
|
||||
.theme-dark .attachButtonPlus_fd0021,
|
||||
.theme-dark .username__0b0e7:not([style]),
|
||||
.theme-dark .children_cde9af,
|
||||
.theme-dark .buttonContainer__6de7e,
|
||||
.theme-dark .listItem__48528,
|
||||
.theme-dark .body__616e6 .caret__33d19,
|
||||
.theme-dark .body__616e6 .titleWrapper_d6133e > h1,
|
||||
.theme-dark .body__616e6 .icon_ae0b42 {
|
||||
--white-500: black !important;
|
||||
--interactive-normal: black !important;
|
||||
--text-normal: black !important;
|
||||
--text-muted: black !important;
|
||||
--header-primary: black !important;
|
||||
--header-secondary: black !important;
|
||||
}
|
||||
|
||||
.theme-dark .contentRegionScroller__9ae20 :not(.mtk1,.mtk2,.mtk3,.mtk4,.mtk5,.mtk6,.mtk7,.mtk8,.mtk9,.monaco-editor .line-numbers) {
|
||||
--white-500: black !important;
|
||||
}
|
||||
|
||||
.theme-dark .container__6b2e5,
|
||||
.theme-dark .container__03ec9,
|
||||
.theme-dark .header__71942 {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.theme-dark .container__26baa {
|
||||
--channel-icon: black;
|
||||
}
|
||||
|
||||
.theme-dark .callContainer__1477d {
|
||||
--white-500: ${(HexToHSL("#" + tertiaryColor)[2] > 80) ? "black" : "white"} !important;
|
||||
}
|
||||
|
||||
.theme-dark .channelTextArea_c2094b {
|
||||
--text-normal: ${(HexToHSL("#" + primaryColor)[2] + 3.6 > 80) ? "black" : "white"};
|
||||
}
|
||||
|
||||
.theme-dark .placeholder_dec8c7 {
|
||||
--channel-text-area-placeholder: ${(HexToHSL("#" + primaryColor)[2] + 3.6 > 80) ? "black" : "white"};
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.theme-dark .colorwaySelectorIcon {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.theme-dark .root_a28985 > .header__5e5a6 > h1 {
|
||||
color: black;
|
||||
}
|
||||
/*End Primary*/`: ""}${(HexToHSL("#" + secondaryColor)[2] > 80) ? `\n\n/*Secondary*/
|
||||
.theme-dark .wrapper__3c6d5 *,
|
||||
.theme-dark .sidebar_e031be *:not(.hasBanner__04337 *),
|
||||
.theme-dark .members__573eb *:not([style]),
|
||||
.theme-dark .sidebarRegionScroller__8113e *,
|
||||
.theme-dark .header__8e271,
|
||||
.theme-dark .lookFilled__950dd.colorPrimary_ebe632 {
|
||||
--white-500: black !important;
|
||||
--channels-default: black !important;
|
||||
--channel-icon: black !important;
|
||||
--interactive-normal: var(--white-500);
|
||||
--interactive-hover: var(--white-500);
|
||||
--interactive-active: var(--white-500);
|
||||
}
|
||||
|
||||
.theme-dark .channelRow__538ef {
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.theme-dark .channelRow__538ef * {
|
||||
--channel-icon: black;
|
||||
}
|
||||
|
||||
.theme-dark #app-mount .activity_bafb94 {
|
||||
--channels-default: var(--white-500) !important;
|
||||
}
|
||||
|
||||
.theme-dark .nameTag__77ab2 {
|
||||
--header-primary: black !important;
|
||||
--header-secondary: ${HexToHSL("#" + secondaryColor)[0] === 0 ? "gray" : ((HexToHSL("#" + secondaryColor)[2] < 80) ? "hsl(" + HexToHSL("#" + secondaryColor)[0] + ", calc(var(--saturation-factor, 1)*100%), 90%)" : "hsl(" + HexToHSL("#" + secondaryColor)[0] + ", calc(var(--saturation-factor, 1)*100%), 20%)")} !important;
|
||||
}
|
||||
|
||||
.theme-dark .bannerVisible_ef30fe .headerContent__6fcc7 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.theme-dark .embedFull__14919 {
|
||||
--text-normal: black;
|
||||
}
|
||||
/*End Secondary*/`: ""}${HexToHSL("#" + tertiaryColor)[2] > 80 ? `\n\n/*Tertiary*/
|
||||
.theme-dark .winButton_f17fb6,
|
||||
.theme-dark .searchBar__310d8 *,
|
||||
.theme-dark .wordmarkWindows_ffbc5e,
|
||||
.theme-dark .searchBar__5a20a *,
|
||||
.theme-dark .searchBarComponent__8f95f {
|
||||
--white-500: black !important;
|
||||
}
|
||||
|
||||
.theme-dark [style="background-color: var(--background-secondary);"] {
|
||||
color: ${HexToHSL("#" + secondaryColor)[2] > 80 ? "black" : "white"};
|
||||
}
|
||||
|
||||
.theme-dark .popout__24e32 > * {
|
||||
--interactive-normal: black !important;
|
||||
--header-secondary: black !important;
|
||||
}
|
||||
|
||||
.theme-dark .tooltip__7b090 {
|
||||
--text-normal: black !important;
|
||||
}
|
||||
.theme-dark .children_cde9af .icon_ae0b42 {
|
||||
color: var(--interactive-active) !important;
|
||||
}
|
||||
/*End Tertiary*/`: ""}${HexToHSL("#" + accentColor)[2] > 80 ? `\n\n/*Accent*/
|
||||
.selected_aded59 *,
|
||||
.selected_ae80f7 *,
|
||||
#app-mount .lookFilled__950dd.colorBrand__27d57:not(.buttonColor__7bad9),
|
||||
.colorDefault_e361cf.focused_dcafb9,
|
||||
.row__9e25f:hover,
|
||||
.colorwayInfoIcon,
|
||||
.checkmarkCircle_b1b1cc > circle {
|
||||
--white-500: black !important;
|
||||
}
|
||||
|
||||
.ColorwaySelectorBtn:hover .vc-pallete-icon {
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
:root:root {
|
||||
--mention-foreground: black !important;
|
||||
}
|
||||
/*End Accent*/`: ""}`;
|
||||
return colorwayCss;
|
||||
}
|
||||
|
||||
export function getPreset(primaryColor?: string, secondaryColor?: string, tertiaryColor?: string, accentColor?: string) {
|
||||
function cyan(discordSaturation = false) {
|
||||
return `:root:root {
|
||||
--cyan-accent-color: ${"#" + accentColor};
|
||||
--cyan-background-primary: hsl(${HexToHSL("#" + primaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + primaryColor)[1]}%) ${HexToHSL("#" + primaryColor)[2]}%/40%);
|
||||
--cyan-background-secondary: hsl(${HexToHSL("#" + tertiaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + tertiaryColor)[1]}%) ${Math.min(HexToHSL("#" + tertiaryColor)[2] + (3.6 * 2), 100)}%);
|
||||
}`;
|
||||
}
|
||||
|
||||
function virtualBoy(discordSaturation = false) {
|
||||
return `:root:root {
|
||||
--VBaccent: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + accentColor)[1]}%) ${HexToHSL("#" + accentColor)[2]}%;
|
||||
--VBaccent-muted: ${HexToHSL("#" + tertiaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + tertiaryColor)[1]}%) ${Math.max(((HexToHSL("#" + tertiaryColor)[2]) - 10), 0)}%;
|
||||
--VBaccent-dimmest: ${HexToHSL("#" + tertiaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + tertiaryColor)[1]}%) ${Math.min((HexToHSL("#" + tertiaryColor)[2] + (3.6 * 5) - 3), 100)}%;
|
||||
}`;
|
||||
}
|
||||
|
||||
function modular(discordSaturation = false) {
|
||||
return `:root:root {
|
||||
--modular-hue: ${HexToHSL("#" + accentColor)[0]};
|
||||
--modular-saturation: calc(var(--saturation-factor, 1)${HexToHSL("#" + accentColor)[1]}%);
|
||||
--modular-lightness: ${HexToHSL("#" + accentColor)[2]}%;
|
||||
}`;
|
||||
}
|
||||
|
||||
function solana(discordSaturation = false) {
|
||||
return `:root:root {
|
||||
--accent-hue: ${HexToHSL("#" + accentColor)[0]};
|
||||
--accent-saturation: calc(var(--saturation-factor, 1)${HexToHSL("#" + accentColor)[1]}%);
|
||||
--accent-brightness: ${HexToHSL("#" + accentColor)[2]}%;
|
||||
--background-accent-hue: ${HexToHSL("#" + primaryColor)[0]};
|
||||
--background-accent-saturation: calc(var(--saturation-factor, 1)${HexToHSL("#" + primaryColor)[1]}%);
|
||||
--background-accent-brightness: ${HexToHSL("#" + primaryColor)[2]}%;
|
||||
--background-overlay-opacity: 0%;
|
||||
}`;
|
||||
}
|
||||
|
||||
function gradientType1(discordSaturation = false) {
|
||||
return `${gradientBase(accentColor, discordSaturation)}
|
||||
--custom-theme-background: linear-gradient(239.16deg, #${primaryColor} 10.39%, #${secondaryColor} 26.87%, #${tertiaryColor} 48.31%, hsl(${HexToHSL("#" + secondaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + secondaryColor)[1]}%) ${Math.min(HexToHSL("#" + secondaryColor)[2] + 3.6, 100)}%) 64.98%, #${primaryColor} 92.5%);
|
||||
}`;
|
||||
}
|
||||
|
||||
function gradientType2(discordSaturation = false) {
|
||||
return `${gradientBase(accentColor, discordSaturation)}
|
||||
--custom-theme-background: linear-gradient(48.17deg, #${primaryColor} 11.21%, #${secondaryColor} 61.92%);
|
||||
}`;
|
||||
}
|
||||
|
||||
function hueRotation(discordSaturation = false) {
|
||||
return `:root:root {
|
||||
--brand-100-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[100])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[100]) * 10) / 10, 0)};
|
||||
--brand-130-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[130])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[130]) * 10) / 10, 0)}%;
|
||||
--brand-160-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[160])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[160]) * 10) / 10, 0)}%;
|
||||
--brand-200-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[200])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[200]) * 10) / 10, 0)}%;
|
||||
--brand-230-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[230])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[230]) * 10) / 10, 0)}%;
|
||||
--brand-260-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[260])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[260]) * 10) / 10, 0)}%;
|
||||
--brand-300-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[300])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[300]) * 10) / 10, 0)}%;
|
||||
--brand-330-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[330])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[330]) * 10) / 10, 0)}%;
|
||||
--brand-345-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[345])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[345]) * 10) / 10, 0)}%;
|
||||
--brand-360-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[360])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[360]) * 10) / 10, 0)}%;
|
||||
--brand-400-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[400])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[400]) * 10) / 10, 0)}%;
|
||||
--brand-430-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[430])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[430]) * 10) / 10, 0)}%;
|
||||
--brand-460-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[460])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[460]) * 10) / 10, 0)}%;
|
||||
--brand-500-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + accentColor)[1]}%) ${HexToHSL("#" + accentColor)[2]}%;
|
||||
--brand-530-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[530])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[530]) * 10) / 10, 100)}%;
|
||||
--brand-560-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[560])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[560]) * 10) / 10, 100)}%;
|
||||
--brand-600-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[600])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[600]) * 10) / 10, 100)}%;
|
||||
--brand-630-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[630])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[630]) * 10) / 10, 100)}%;
|
||||
--brand-660-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[660])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[660]) * 10) / 10, 100)}%;
|
||||
--brand-700-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[700])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[700]) * 10) / 10, 100)}%;
|
||||
--brand-730-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[730])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[730]) * 10) / 10, 100)}%;
|
||||
--brand-760-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[760])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[760]) * 10) / 10, 100)}%;
|
||||
--brand-800-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[800])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[800]) * 10) / 10, 100)}%;
|
||||
--brand-830-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[830])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[830]) * 10) / 10, 100)}%;
|
||||
--brand-860-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[860])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[860]) * 10) / 10, 100)}%;
|
||||
--brand-900-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[900])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[900]) * 10) / 10, 100)}%;
|
||||
--primary-800-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*12%) 7%;
|
||||
--primary-730-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*10%) 13%;
|
||||
--primary-700-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*10%) 13%;
|
||||
--primary-660-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*11%) 15%;
|
||||
--primary-645-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*11%) 16%;
|
||||
--primary-630-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*11%) 18%;
|
||||
--primary-600-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*11%) 21%;
|
||||
--primary-560-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*11%) 24%;
|
||||
--primary-530-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*11%) 24%;
|
||||
--primary-500-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*11%) 24%;
|
||||
}`;
|
||||
}
|
||||
|
||||
function accentSwap(discordSaturation = false) {
|
||||
return `:root:root {
|
||||
--brand-100-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[100])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[100]) * 10) / 10, 0)};
|
||||
--brand-130-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[130])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[130]) * 10) / 10, 0)}%;
|
||||
--brand-160-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[160])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[160]) * 10) / 10, 0)}%;
|
||||
--brand-200-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[200])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[200]) * 10) / 10, 0)}%;
|
||||
--brand-230-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[230])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[230]) * 10) / 10, 0)}%;
|
||||
--brand-260-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[260])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[260]) * 10) / 10, 0)}%;
|
||||
--brand-300-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[300])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[300]) * 10) / 10, 0)}%;
|
||||
--brand-330-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[330])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[330]) * 10) / 10, 0)}%;
|
||||
--brand-345-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[345])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[345]) * 10) / 10, 0)}%;
|
||||
--brand-360-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[360])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[360]) * 10) / 10, 0)}%;
|
||||
--brand-400-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[400])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[400]) * 10) / 10, 0)}%;
|
||||
--brand-430-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[430])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[430]) * 10) / 10, 0)}%;
|
||||
--brand-460-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[460])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.max(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[460]) * 10) / 10, 0)}%;
|
||||
--brand-500-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + accentColor)[1]}%) ${HexToHSL("#" + accentColor)[2]}%;
|
||||
--brand-530-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[530])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[530]) * 10) / 10, 100)}%;
|
||||
--brand-560-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[560])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[560]) * 10) / 10, 100)}%;
|
||||
--brand-600-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[600])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[600]) * 10) / 10, 100)}%;
|
||||
--brand-630-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[630])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[630]) * 10) / 10, 100)}%;
|
||||
--brand-660-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[660])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[660]) * 10) / 10, 100)}%;
|
||||
--brand-700-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[700])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[700]) * 10) / 10, 100)}%;
|
||||
--brand-730-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[730])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[730]) * 10) / 10, 100)}%;
|
||||
--brand-760-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[760])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[760]) * 10) / 10, 100)}%;
|
||||
--brand-800-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[800])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[800]) * 10) / 10, 100)}%;
|
||||
--brand-830-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[830])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[830]) * 10) / 10, 100)}%;
|
||||
--brand-860-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[860])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[860]) * 10) / 10, 100)}%;
|
||||
--brand-900-hsl: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${discordSaturation ? Math.round(((HexToHSL("#" + accentColor)[1] / 100) * (100 + BrandSatDiffs[900])) * 10) / 10 : HexToHSL("#" + accentColor)[1]}%) ${Math.min(Math.round((HexToHSL("#" + accentColor)[2] + BrandLightDiffs[900]) * 10) / 10, 100)}%;
|
||||
}`;
|
||||
}
|
||||
|
||||
return {
|
||||
cyan: {
|
||||
name: "Cyan",
|
||||
preset: cyan,
|
||||
id: "cyan",
|
||||
colors: ["primary", "secondary", "accent"]
|
||||
},
|
||||
virtualBoy: {
|
||||
name: "Virtual Boy",
|
||||
preset: virtualBoy,
|
||||
id: "virtualBoy",
|
||||
colors: ["tertiary", "accent"]
|
||||
},
|
||||
modular: {
|
||||
name: "Modular",
|
||||
preset: modular,
|
||||
id: "modular",
|
||||
colors: ["accent"]
|
||||
},
|
||||
solana: {
|
||||
name: "Solana",
|
||||
preset: solana,
|
||||
id: "solana",
|
||||
colors: ["primary", "accent"]
|
||||
},
|
||||
gradientType1: {
|
||||
name: "Gradient Type 1",
|
||||
preset: gradientType1,
|
||||
id: "gradientType1",
|
||||
colors: ["primary", "secondary", "tertiary", "accent"]
|
||||
},
|
||||
gradientType2: {
|
||||
name: "Gradient Type 2",
|
||||
preset: gradientType2,
|
||||
id: "gradientType2",
|
||||
colors: ["primary", "secondary", "accent"]
|
||||
},
|
||||
hueRotation: {
|
||||
name: "Hue Rotation",
|
||||
preset: hueRotation,
|
||||
id: "hueRotation",
|
||||
colors: ["accent"]
|
||||
},
|
||||
accentSwap: {
|
||||
name: "Accent Swap",
|
||||
preset: accentSwap,
|
||||
id: "accentSwap",
|
||||
colors: ["accent"]
|
||||
}
|
||||
};
|
||||
}
|
225
src/userplugins/DiscordColorways/index.tsx
Normal file
225
src/userplugins/DiscordColorways/index.tsx
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
|
||||
import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "@api/ServerList";
|
||||
import { disableStyle, enableStyle } from "@api/Styles";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { openModal } from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
import {
|
||||
Button,
|
||||
SettingsRouter,
|
||||
} from "@webpack/common";
|
||||
|
||||
import ColorPickerModal from "./components/ColorPicker";
|
||||
import ColorwaysButton from "./components/ColorwaysButton";
|
||||
import CreatorModal from "./components/CreatorModal";
|
||||
import SelectorModal from "./components/SelectorModal";
|
||||
import ManageColorwaysPage from "./components/SettingsTabs/ManageColorwaysPage";
|
||||
import OnDemandWaysPage from "./components/SettingsTabs/OnDemandPage";
|
||||
import SelectorPage from "./components/SettingsTabs/SelectorPage";
|
||||
import SettingsPage from "./components/SettingsTabs/SettingsPage";
|
||||
import Spinner from "./components/Spinner";
|
||||
import { defaultColorwaySource } from "./constants";
|
||||
import style from "./style.css?managed";
|
||||
import { ColorPickerProps } from "./types";
|
||||
|
||||
export let ColorPicker: React.FunctionComponent<ColorPickerProps> = () => {
|
||||
return <Spinner className="colorways-creator-module-warning" />;
|
||||
};
|
||||
|
||||
(async function () {
|
||||
const [
|
||||
customColorways,
|
||||
colorwaySourcesFiles,
|
||||
showColorwaysButton,
|
||||
onDemandWays,
|
||||
onDemandWaysTintedText,
|
||||
useThinMenuButton,
|
||||
onDemandWaysDiscordSaturation,
|
||||
onDemandWaysColorArray
|
||||
] = await DataStore.getMany([
|
||||
"customColorways",
|
||||
"colorwaySourceFiles",
|
||||
"showColorwaysButton",
|
||||
"onDemandWays",
|
||||
"onDemandWaysTintedText",
|
||||
"useThinMenuButton",
|
||||
"onDemandWaysDiscordSaturation",
|
||||
"onDemandWaysColorArray"
|
||||
]);
|
||||
|
||||
if (!customColorways)
|
||||
DataStore.set("customColorways", []);
|
||||
|
||||
if (!colorwaySourcesFiles)
|
||||
DataStore.set("colorwaySourceFiles", [defaultColorwaySource]);
|
||||
|
||||
if (!showColorwaysButton)
|
||||
DataStore.set("showColorwaysButton", false);
|
||||
|
||||
if (!onDemandWays)
|
||||
DataStore.set("onDemandWays", false);
|
||||
|
||||
if (!onDemandWaysTintedText)
|
||||
DataStore.set("onDemandWaysTintedText", true);
|
||||
|
||||
if (!useThinMenuButton)
|
||||
DataStore.set("useThinMenuButton", false);
|
||||
|
||||
if (!onDemandWaysDiscordSaturation)
|
||||
DataStore.set("onDemandWaysDiscordSaturation", false);
|
||||
|
||||
if (!onDemandWaysColorArray)
|
||||
DataStore.set("onDemandWaysColorArray", ["313338", "2b2d31", "1e1f22", "5865f2"]);
|
||||
|
||||
})();
|
||||
|
||||
export const ColorwayCSS = {
|
||||
get: () => document.getElementById("activeColorwayCSS")?.textContent || "",
|
||||
set: (e: string) => {
|
||||
if (!document.getElementById("activeColorwayCSS")) {
|
||||
var activeColorwayCSS: HTMLStyleElement =
|
||||
document.createElement("style");
|
||||
activeColorwayCSS.id = "activeColorwayCSS";
|
||||
activeColorwayCSS.textContent = e;
|
||||
document.head.append(activeColorwayCSS);
|
||||
} else document.getElementById("activeColorwayCSS")!.textContent = e;
|
||||
},
|
||||
remove: () => document.getElementById("activeColorwayCSS")!.remove(),
|
||||
};
|
||||
|
||||
export const versionData = {
|
||||
pluginVersion: "5.6.1",
|
||||
creatorVersion: "1.18",
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "DiscordColorways",
|
||||
description:
|
||||
"A plugin that offers easy access to simple color schemes/themes for Discord, also known as Colorways",
|
||||
authors: [{
|
||||
name: "DaBluLite",
|
||||
id: 582170007505731594n
|
||||
}, Devs.ImLvna],
|
||||
dependencies: ["ServerListAPI", "MessageAccessoriesAPI"],
|
||||
pluginVersion: versionData.pluginVersion,
|
||||
creatorVersion: versionData.creatorVersion,
|
||||
toolboxActions: {
|
||||
"Change Colorway": () => openModal(props => <SelectorModal modalProps={props} />),
|
||||
"Open Colorway Creator": () => openModal(props => <CreatorModal modalProps={props} />),
|
||||
"Open Color Stealer": () => openModal(props => <ColorPickerModal modalProps={props} />),
|
||||
"Open Settings": () => SettingsRouter.open("ColorwaysSettings"),
|
||||
"Open On-Demand Settings": () => SettingsRouter.open("ColorwaysOnDemand"),
|
||||
"Manage Colorways...": () => SettingsRouter.open("ColorwaysManagement"),
|
||||
},
|
||||
patches: [
|
||||
// Credits to Kyuuhachi for the BetterSettings plugin patches
|
||||
{
|
||||
find: "this.renderArtisanalHack()",
|
||||
replacement: {
|
||||
match: /createPromise:\(\)=>([^:}]*?),webpackId:"\d+",name:(?!="CollectiblesShop")"[^"]+"/g,
|
||||
replace: "$&,_:$1",
|
||||
predicate: () => true
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
find: "Messages.USER_SETTINGS_WITH_BUILD_OVERRIDE.format",
|
||||
replacement: {
|
||||
match: /(?<=(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?openContextMenuLazy.{0,100}?(await Promise\.all[^};]*?\)\)).*?,)(?=\1\(this)/,
|
||||
replace: "(async ()=>$2)(),"
|
||||
},
|
||||
predicate: () => true
|
||||
},
|
||||
{
|
||||
find: "colorPickerFooter:",
|
||||
replacement: {
|
||||
match: /function (\i).{0,200}colorPickerFooter:/,
|
||||
replace: "$self.ColorPicker=$1;$&",
|
||||
},
|
||||
},
|
||||
{
|
||||
find: "Messages.ACTIVITY_SETTINGS",
|
||||
replacement: {
|
||||
match: /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.APP_SETTINGS\}/,
|
||||
replace: "...$self.makeSettingsCategories($1),$&"
|
||||
}
|
||||
}
|
||||
],
|
||||
set ColorPicker(e) {
|
||||
ColorPicker = e;
|
||||
},
|
||||
|
||||
makeSettingsCategories(SectionTypes: Record<string, unknown>) {
|
||||
console.log(SectionTypes);
|
||||
return [
|
||||
{
|
||||
section: SectionTypes.HEADER,
|
||||
label: "DiscordColorways",
|
||||
className: "vc-settings-header"
|
||||
},
|
||||
{
|
||||
section: "ColorwaysSelector",
|
||||
label: "Colorways",
|
||||
element: SelectorPage,
|
||||
className: "dc-colorway-selector"
|
||||
},
|
||||
{
|
||||
section: "ColorwaysSettings",
|
||||
label: "Settings",
|
||||
element: SettingsPage,
|
||||
className: "dc-colorway-settings"
|
||||
},
|
||||
{
|
||||
section: "ColorwaysOnDemand",
|
||||
label: "On-Demand",
|
||||
element: OnDemandWaysPage,
|
||||
className: "dc-colorway-ondemand"
|
||||
},
|
||||
{
|
||||
section: "ColorwaysManagement",
|
||||
label: "Manage...",
|
||||
element: ManageColorwaysPage,
|
||||
className: "dc-colorway-management"
|
||||
},
|
||||
{
|
||||
section: SectionTypes.DIVIDER
|
||||
}
|
||||
].filter(Boolean);
|
||||
},
|
||||
|
||||
ColorwaysButton: () => <ColorwaysButton />,
|
||||
|
||||
async start() {
|
||||
addServerListElement(ServerListRenderPosition.In, this.ColorwaysButton);
|
||||
|
||||
enableStyle(style);
|
||||
ColorwayCSS.set((await DataStore.get("actveColorway")) || "");
|
||||
|
||||
addAccessory("colorways-btn", props => {
|
||||
if (String(props.message.content).match(/colorway:[0-9a-f]{0,71}/))
|
||||
return <Button onClick={() => {
|
||||
openModal(propss => (
|
||||
<CreatorModal
|
||||
modalProps={propss}
|
||||
colorwayID={String(props.message.content).match(/colorway:[0-9a-f]{0,71}/)![0]}
|
||||
/>
|
||||
));
|
||||
}} size={Button.Sizes.SMALL} color={Button.Colors.PRIMARY}>Add this Colorway...</Button>;
|
||||
return null;
|
||||
});
|
||||
},
|
||||
stop() {
|
||||
removeServerListElement(ServerListRenderPosition.In, this.ColorwaysButton);
|
||||
|
||||
disableStyle(style);
|
||||
ColorwayCSS.remove();
|
||||
removeAccessory("colorways-btn");
|
||||
},
|
||||
});
|
1214
src/userplugins/DiscordColorways/style.css
Normal file
1214
src/userplugins/DiscordColorways/style.css
Normal file
File diff suppressed because it is too large
Load diff
29
src/userplugins/DiscordColorways/types.ts
Normal file
29
src/userplugins/DiscordColorways/types.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export interface Colorway {
|
||||
name: string,
|
||||
"dc-import": string,
|
||||
accent: string,
|
||||
primary: string,
|
||||
secondary: string,
|
||||
tertiary: string,
|
||||
original?: boolean,
|
||||
author: string,
|
||||
authorID: string,
|
||||
colors?: string[],
|
||||
isGradient?: boolean,
|
||||
sourceUrl?: string,
|
||||
sourceName?: string;
|
||||
}
|
||||
|
||||
export interface ColorPickerProps {
|
||||
color: number;
|
||||
showEyeDropper: boolean;
|
||||
suggestedColors: string[];
|
||||
label: any;
|
||||
onChange(color: number): void;
|
||||
}
|
133
src/userplugins/DiscordColorways/utils.ts
Normal file
133
src/userplugins/DiscordColorways/utils.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export function HexToHSL(H: string) {
|
||||
let r: any = 0, g: any = 0, b: any = 0;
|
||||
if (H.length === 4) r = "0x" + H[1] + H[1], g = "0x" + H[2] + H[2], b = "0x" + H[3] + H[3];
|
||||
else if (H.length === 7) {
|
||||
r = "0x" + H[1] + H[2];
|
||||
g = "0x" + H[3] + H[4];
|
||||
b = "0x" + H[5] + H[6];
|
||||
}
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
var cmin = Math.min(r, g, b),
|
||||
cmax = Math.max(r, g, b),
|
||||
delta = cmax - cmin,
|
||||
h = 0,
|
||||
s = 0,
|
||||
l = 0;
|
||||
if (delta === 0) h = 0;
|
||||
else if (cmax === r) h = ((g - b) / delta) % 6;
|
||||
else if (cmax === g) h = (b - r) / delta + 2;
|
||||
else h = (r - g) / delta + 4;
|
||||
h = Math.round(h * 60);
|
||||
if (h < 0) h += 360;
|
||||
l = (cmax + cmin) / 2;
|
||||
s = delta === 0
|
||||
? 0
|
||||
: delta / (1 - Math.abs(2 * l - 1));
|
||||
s = +(s * 100).toFixed(1);
|
||||
l = +(l * 100).toFixed(1);
|
||||
|
||||
return [Math.round(h), Math.round(s), Math.round(l)];
|
||||
}
|
||||
|
||||
export const canonicalizeHex = (hex: string) => {
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
|
||||
ctx.fillStyle = hex;
|
||||
hex = ctx.fillStyle;
|
||||
canvas.remove();
|
||||
|
||||
return hex;
|
||||
};
|
||||
|
||||
export const stringToHex = (str: string) => {
|
||||
let hex = "";
|
||||
for (
|
||||
let i = 0;
|
||||
i < str.length;
|
||||
i++
|
||||
) {
|
||||
const charCode = str.charCodeAt(i);
|
||||
const hexValue = charCode.toString(16);
|
||||
hex += hexValue.padStart(2, "0");
|
||||
}
|
||||
return hex;
|
||||
};
|
||||
|
||||
export const hexToString = (hex: string) => {
|
||||
let str = "";
|
||||
for (let i = 0; i < hex.length; i += 2) {
|
||||
const hexValue = hex.substr(i, 2);
|
||||
const decimalValue = parseInt(hexValue, 16);
|
||||
str += String.fromCharCode(decimalValue);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
export function getHex(str: string): string {
|
||||
const color = Object.assign(
|
||||
document.createElement("canvas").getContext("2d") as {},
|
||||
{ fillStyle: str }
|
||||
).fillStyle;
|
||||
if (color.includes("rgba(")) {
|
||||
return getHex(String([...color.split(",").slice(0, 3), ")"]).replace(",)", ")").replace("a", ""));
|
||||
} else {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
export function getFontOnBg(bgColor: string) {
|
||||
var color = (bgColor.charAt(0) === "#") ? bgColor.substring(1, 7) : bgColor;
|
||||
var r = parseInt(color.substring(0, 2), 16);
|
||||
var g = parseInt(color.substring(2, 4), 16);
|
||||
var b = parseInt(color.substring(4, 6), 16);
|
||||
return (((r * 0.299) + (g * 0.587) + (b * 0.114)) > 186) ?
|
||||
"#000000" : "#ffffff";
|
||||
}
|
||||
|
||||
export function $e(funcArray: Array<(...vars: any) => void>, ...vars: any[]) {
|
||||
funcArray.forEach(e => e(vars));
|
||||
}
|
||||
|
||||
export function hslToHex(h: number, s: number, l: number) {
|
||||
h /= 360;
|
||||
s /= 100;
|
||||
l /= 100;
|
||||
let r: any, g: any, b: any;
|
||||
if (s === 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
const hue2rgb = (p: number, q: number, t: number) => {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
const p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1 / 3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1 / 3);
|
||||
}
|
||||
const toHex = (x: number) => {
|
||||
const hex = Math.round(x * 255).toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
};
|
||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||
}
|
||||
|
||||
export function rgbToHex(r: number, g: number, b: number) {
|
||||
const toHex = (x: number) => {
|
||||
const hex = Math.round(x * 255).toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
};
|
||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||
}
|
22
src/userplugins/QuickReactFrequents/index.ts
Normal file
22
src/userplugins/QuickReactFrequents/index.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "QuickReactFrequents",
|
||||
description: "Make quick react use top frecency emojis instead of favourites",
|
||||
authors: [Devs.Ven],
|
||||
|
||||
patches: [{
|
||||
find: "this.favoriteEmojisWithoutFetchingLatest.concat",
|
||||
replacement: {
|
||||
match: "this.favoriteEmojisWithoutFetchingLatest.concat",
|
||||
replace: "[].concat"
|
||||
}
|
||||
}]
|
||||
});
|
Loading…
Reference in a new issue