mirror of
https://github.com/Equicord/Equicord.git
synced 2025-02-20 15:18:50 -05:00
Updates
This commit is contained in:
parent
6d0658c60d
commit
093ec3b30b
20 changed files with 953 additions and 1125 deletions
136
src/equicordplugins/betterQuests/index.tsx
Normal file
136
src/equicordplugins/betterQuests/index.tsx
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { extractAndLoadChunksLazy, findByPropsLazy, findComponentByCodeLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
|
||||
import { useEffect, useState } from "@webpack/common";
|
||||
|
||||
|
||||
const LinkButton = findExportedComponentLazy("LinkButton"); // let {route: e, selected: t, icon: n, iconClassName: a, interactiveClassName: s, text: r, children: o, locationState: d, onClick: f, className: p, role: m, "aria-posinset": C, "aria-setsize": g, ...E} = this.props;
|
||||
const NumberBadge = findExportedComponentLazy("NumberBadge"); // let { count: l } = this.props
|
||||
const QuestsComponent = findComponentByCodeLazy(".questsContainer"); // No nessessary props to include
|
||||
|
||||
const questsStore = findStoreLazy("QuestsStore");
|
||||
|
||||
const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}Promise\.all\((\[\i\.\i\(".+?"\).+?\])\).then\(\i\.bind\(\i,"(.+?)"\)\).{0,50}"UserSettings"/);
|
||||
const nav: NavigationSettings = findByPropsLazy("transitionTo", "transitionToGuild", "getHistory");
|
||||
|
||||
|
||||
// Routes used in this plugin (in case someone wants to add new ones)
|
||||
const routes = new Map<string, RouteData>();
|
||||
|
||||
routes.set("/questsMenu", {
|
||||
path: "/questsMenu",
|
||||
render: (...props) => <QuestPage {...props} />,
|
||||
disableTrack: 1,
|
||||
redirectTo: "/channels/@me"
|
||||
});
|
||||
|
||||
|
||||
// Credits to https://www.svgrepo.com/svg/507254/crown
|
||||
const CrownIcon = () => {
|
||||
return (
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 19C5 18.4477 5.44772 18 6 18L18 18C18.5523 18 19 18.4477 19 19C19 19.5523 18.5523 20 18 20L6 20C5.44772 20 5 19.5523 5 19Z" fill="currentColor" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.87867 4.70711C11.0502 3.53554 12.9497 3.53554 14.1213 4.70711L16.6878 7.27359C16.9922 7.57795 17.4571 7.6534 17.8421 7.46091L18.5528 7.10558C20.0877 6.33813 21.7842 7.80954 21.2416 9.43755L19.4045 14.9487C18.9962 16.1737 17.8498 17 16.5585 17H7.44151C6.15022 17 5.0038 16.1737 4.59546 14.9487L2.75842 9.43755C2.21575 7.80955 3.91231 6.33813 5.44721 7.10558L6.15787 7.46091C6.54286 7.6534 7.00783 7.57795 7.31219 7.27359L9.87867 4.70711Z" fill="currentColor" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const QuestPage = (props?: any) => {
|
||||
const [loadedQuests, setLoaded] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const loadQuests = async () => {
|
||||
await requireSettingsMenu();
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
loadQuests();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main className="quests-container">
|
||||
{loadedQuests && <QuestsComponent />}
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const QuestButtonComponent = () => {
|
||||
const activeQuests = Array.from(questsStore.quests.values()).filter((q: any) => new Date(q.config.expiresAt).getTime() > Date.now() && q.claimedAt);
|
||||
return (
|
||||
<ErrorBoundary noop>
|
||||
<LinkButton
|
||||
text="Quests"
|
||||
icon={CrownIcon}
|
||||
route={"/questsMenu"}
|
||||
>
|
||||
{activeQuests.length > 0 && <NumberBadge count={activeQuests.length} />}
|
||||
</LinkButton>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
const redirectRoute = (ev: BeforeUnloadEvent) => {
|
||||
const paths = Array.from(routes.keys());
|
||||
const path = nav.getHistory().location.pathname;
|
||||
|
||||
if (paths.includes(path)) {
|
||||
const data = routes.get(path);
|
||||
ev.preventDefault();
|
||||
nav.transitionTo(data?.redirectTo ?? "/channels/@me");
|
||||
setTimeout(() => window.location.reload(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "BetterQuests",
|
||||
description: "Puts the quest button in more accessibile place.",
|
||||
authors: [EquicordDevs.kvba],
|
||||
|
||||
start: () => window.addEventListener("beforeunload", redirectRoute),
|
||||
stop: () => window.removeEventListener("beforeunload", redirectRoute),
|
||||
|
||||
get paths() {
|
||||
return Array.from(routes.keys());
|
||||
},
|
||||
|
||||
get routes() {
|
||||
return Array.from(routes.values());
|
||||
},
|
||||
|
||||
patches: [
|
||||
{ // Add new quest button
|
||||
find: "\"discord-shop\"",
|
||||
replacement: {
|
||||
match: /"discord-shop"\),/,
|
||||
replace: "$&,$self.QuestButtonComponent(),"
|
||||
}
|
||||
},
|
||||
{ // Add new route
|
||||
find: "Routes.MESSAGE_REQUESTS,render:",
|
||||
replacement: {
|
||||
match: /\((0,.{0,10}\.jsx\)\(.{0,10}\.default,){path:.{0,10}\.Routes\.MESSAGE_REQUESTS,.{0,100}?\),/,
|
||||
replace: "$&...$self.routes.map(r => (($1r))),"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: 'on("LAUNCH_APPLICATION"',
|
||||
replacement: {
|
||||
match: /path:\[.{0,500}Routes\.MESSAGE_REQUESTS,/,
|
||||
replace: "$&...$self.paths,"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
QuestButtonComponent
|
||||
});
|
9
src/equicordplugins/betterQuests/style.css
Normal file
9
src/equicordplugins/betterQuests/style.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
.quests-container {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-overlay-chat,var(--background-primary));
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
}
|
23
src/equicordplugins/betterQuests/types.ts
Normal file
23
src/equicordplugins/betterQuests/types.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
type RouteData = {
|
||||
path: string,
|
||||
render: (props?: any) => JSX.Element,
|
||||
disableTrack: 1 | 0;
|
||||
redirectTo?: string;
|
||||
};
|
||||
|
||||
type NavigationSettings = {
|
||||
/** Transition to a route */
|
||||
transitionTo: (path: string) => unknown,
|
||||
getHistory: () => {
|
||||
location: {
|
||||
/** The current route */
|
||||
pathname: string;
|
||||
};
|
||||
},
|
||||
};
|
|
@ -19,202 +19,73 @@ import {
|
|||
useState,
|
||||
} from "@webpack/common";
|
||||
|
||||
import { mainColors } from "../constants";
|
||||
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",
|
||||
}
|
||||
];
|
||||
import { getHex } from "../utils";
|
||||
|
||||
export default function ({ modalProps }: { modalProps: ModalProps; }) {
|
||||
const [colorVarItems, setColorVarItems] = useState<ToolboxItem[]>(ColorVarItems);
|
||||
const [ColorVars, setColorVars] = useState<string[]>(colorVariables);
|
||||
const [collapsedSettings, setCollapsedSettings] = useState<boolean>(true);
|
||||
let results: ToolboxItem[];
|
||||
let results: string[];
|
||||
function searchToolboxItems(e: string) {
|
||||
results = [];
|
||||
ColorVarItems.find((ToolboxItem: ToolboxItem) => {
|
||||
if (ToolboxItem.title.toLowerCase().includes(e.toLowerCase())) {
|
||||
results.push(ToolboxItem);
|
||||
colorVariables.find((colorVariable: string) => {
|
||||
if (colorVariable.toLowerCase().includes(e.toLowerCase())) {
|
||||
results.push(colorVariable);
|
||||
}
|
||||
});
|
||||
setColorVarItems(results);
|
||||
setColorVars(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>
|
||||
);
|
||||
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.PRIMARY}
|
||||
look={Button.Looks.OUTLINED}
|
||||
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>
|
||||
{ColorVars.map((colorVariable: string) => <div
|
||||
id={`colorways-colorstealer-item_${colorVariable}`}
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-toolboxItm"
|
||||
onClick={() => {
|
||||
Clipboard.copy(getHex(getComputedStyle(document.body).getPropertyValue("--" + colorVariable)));
|
||||
Toasts.show({ message: "Color " + colorVariable + " copied to clipboard", id: "toolbox-color-var-copied", type: 1 });
|
||||
}} style={{ "--brand-experiment": `var(--${colorVariable})` } as React.CSSProperties}>
|
||||
{`Copy ${colorVariable}`}
|
||||
</div>)}
|
||||
</ScrollerThin>
|
||||
<Flex style={{ justifyContent: "space-between", marginTop: "8px" }} wrap="wrap" className={collapsedSettings ? "" : " colorwaysColorpicker-collapsed"}>
|
||||
{mainColors.map(mainColor => <div
|
||||
id={`colorways-toolbox_copy-${mainColor.name}`}
|
||||
className="colorwayToolbox-listItem"
|
||||
>
|
||||
<CopyIcon onClick={() => {
|
||||
Clipboard.copy(getHex(getComputedStyle(document.body).getPropertyValue(mainColor.var)));
|
||||
Toasts.show({ message: `${mainColor.title} color copied to clipboard`, id: `toolbox-${mainColor.name}-color-copied`, type: 1 });
|
||||
}} width={20} height={20} className="colorwayToolbox-listItemSVG" />
|
||||
<span className="colorwaysToolbox-label">{`Copy ${mainColor.title} Color`}</span>
|
||||
</div>
|
||||
)}
|
||||
</Flex>
|
||||
</ModalRoot>;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
||||
import { Button, Forms, ScrollerThin, Switch, Text, useState } from "@webpack/common";
|
||||
|
||||
import { getPreset } from "../css";
|
||||
|
||||
export default function ({ modalProps, onSettings, presetId, hasTintedText, hasDiscordSaturation }: { modalProps: ModalProps, presetId: string, hasTintedText: boolean, hasDiscordSaturation: boolean, onSettings: ({ presetId, tintedText, discordSaturation }: { presetId: string, tintedText: boolean, discordSaturation: boolean; }) => void; }) {
|
||||
const [tintedText, setTintedText] = useState<boolean>(hasTintedText);
|
||||
const [discordSaturation, setDiscordSaturation] = useState<boolean>(hasDiscordSaturation);
|
||||
const [preset, setPreset] = useState<string>(presetId);
|
||||
return <ModalRoot {...modalProps} className="colorwaysPresetPicker">
|
||||
<ModalHeader><Text variant="heading-lg/semibold" tag="h1">Creator Settings</Text></ModalHeader>
|
||||
<ModalContent className="colorwaysPresetPicker-content">
|
||||
<div className="colorwaysCreator-settingCat" style={{ marginBottom: "20px" }}>
|
||||
<Forms.FormTitle style={{ marginBottom: "0" }}>
|
||||
Presets:
|
||||
</Forms.FormTitle>
|
||||
<ScrollerThin orientation="vertical" className="colorwaysCreator-settingsList" paddingFix style={{ paddingRight: "2px" }}>
|
||||
{Object.values(getPreset()).map(pre => {
|
||||
return <div className="colorwaysCreator-settingItm colorwaysCreator-preset" onClick={() => {
|
||||
setPreset(pre.id);
|
||||
}}>
|
||||
<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>
|
||||
<Switch value={tintedText} onChange={setTintedText}>Use colored text</Switch>
|
||||
<Switch value={discordSaturation} onChange={setDiscordSaturation} hideBorder style={{ marginBottom: "0" }}>Use Discord's saturation</Switch>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.BRAND_NEW}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
onClick={() => {
|
||||
onSettings({ presetId: preset, discordSaturation: discordSaturation, tintedText: tintedText });
|
||||
modalProps.onClose();
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
onClick={() => {
|
||||
modalProps.onClose();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>;
|
||||
}
|
|
@ -10,7 +10,7 @@ import { FluxDispatcher, Text, Tooltip, useEffect, useState } from "@webpack/com
|
|||
import { FluxEvents } from "@webpack/types";
|
||||
|
||||
import { PalleteIcon } from "./Icons";
|
||||
import SelectorModal from "./SelectorModal";
|
||||
import Selector from "./Selector";
|
||||
|
||||
export default function ({
|
||||
listItemClass = "ColorwaySelectorBtnContainer",
|
||||
|
@ -46,49 +46,23 @@ export default function ({
|
|||
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 }) => 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 }) => 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>
|
||||
);
|
||||
}
|
||||
return <Tooltip text={
|
||||
!isThin ? <><span>Colorways</span><Text variant="text-xs/normal" style={{ color: "var(--text-muted)", fontWeight: 500 }}>{"Active Colorway: " + activeColorway}</Text></> : <span>{"Active Colorway: " + activeColorway}</span>
|
||||
} position="right" tooltipContentClassName="colorwaysBtn-tooltipContent"
|
||||
>
|
||||
{({ onMouseEnter, onMouseLeave, onClick }) => visibility ? <div className="ColorwaySelectorBtnContainer">
|
||||
<div
|
||||
className={"ColorwaySelectorBtn" + (isThin ? " ColorwaySelectorBtn_thin" : "")}
|
||||
onMouseEnter={async () => {
|
||||
onMouseEnter();
|
||||
setActiveColorway(await DataStore.get("actveColorwayID") || "None");
|
||||
}}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => {
|
||||
onClick();
|
||||
openModal((props: any) => <Selector modalProps={props} />);
|
||||
}}
|
||||
>{isThin ? <Text variant="text-xs/normal" style={{ color: "var(--header-primary)", fontWeight: 700, fontSize: 9 }}>Colorways</Text> : <PalleteIcon />}</div>
|
||||
</div> : <></>}
|
||||
</Tooltip>;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@ import {
|
|||
import {
|
||||
Button,
|
||||
Forms,
|
||||
ScrollerThin,
|
||||
Switch,
|
||||
Text,
|
||||
TextInput,
|
||||
useEffect,
|
||||
|
@ -27,9 +25,10 @@ import {
|
|||
|
||||
import { ColorPicker } from "..";
|
||||
import { knownThemeVars } from "../constants";
|
||||
import { generateCss, getPreset } from "../css";
|
||||
import { generateCss, getPreset, gradientPresetIds, pureGradientBase } from "../css";
|
||||
import { Colorway } from "../types";
|
||||
import { colorToHex, getHex, hexToString } from "../utils";
|
||||
import ColorwayCreatorSettingsModal from "./ColorwayCreatorSettingsModal";
|
||||
import ConflictingColorsModal from "./ConflictingColorsModal";
|
||||
import InputColorwayIdModal from "./InputColorwayIdModal";
|
||||
import ThemePreviewCategory from "./ThemePreview";
|
||||
|
@ -52,7 +51,7 @@ export default function ({
|
|||
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"]);
|
||||
const [presetColorArray, setPresetColorArray] = useState<string[]>(["primary", "secondary", "tertiary", "accent"]);
|
||||
|
||||
const colorProps = {
|
||||
accent: {
|
||||
|
@ -80,21 +79,18 @@ export default function ({
|
|||
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 setColor = [
|
||||
setAccentColor,
|
||||
setPrimaryColor,
|
||||
setSecondaryColor,
|
||||
setTertiaryColor
|
||||
];
|
||||
hexToString(parsedID).split(/,#/).forEach((color: string, i: number) => setColor[i](colorToHex(color)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -125,7 +121,7 @@ export default function ({
|
|||
onChange={setColorwayName}
|
||||
/>
|
||||
<div className="colorwaysCreator-settingCat">
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>
|
||||
<Forms.FormTitle style={{ marginBottom: "0" }}>
|
||||
Colors:
|
||||
</Forms.FormTitle>
|
||||
<div className="colorwayCreator-colorPreviews">
|
||||
|
@ -145,61 +141,37 @@ export default function ({
|
|||
})}
|
||||
</div>
|
||||
</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
|
||||
className="colorwaysCreator-setting"
|
||||
onClick={() => openModal((props: ModalProps) => <ColorwayCreatorSettingsModal
|
||||
modalProps={props}
|
||||
hasDiscordSaturation={discordSaturation}
|
||||
hasTintedText={tintedText}
|
||||
presetId={preset}
|
||||
onSettings={({ presetId, tintedText, discordSaturation }) => {
|
||||
setPreset(presetId);
|
||||
setPresetColorArray(getPreset()[presetId].colors);
|
||||
setDiscordSaturation(discordSaturation);
|
||||
setTintedText(tintedText);
|
||||
}} />)}>
|
||||
<Forms.FormTitle style={{ marginBottom: 0 }}>Settings & Presets</Forms.FormTitle>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" role="img" style={{ rotate: "-90deg" }}>
|
||||
<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>
|
||||
<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} />
|
||||
<ThemePreviewCategory
|
||||
isCollapsed={false}
|
||||
accent={"#" + accentColor}
|
||||
primary={"#" + primaryColor}
|
||||
secondary={"#" + secondaryColor}
|
||||
tertiary={"#" + tertiaryColor}
|
||||
previewCSS={gradientPresetIds.includes(getPreset()[preset].id) ? pureGradientBase + `.colorwaysPreview-modal,.colorwaysPreview-wrapper {--gradient-theme-bg: linear-gradient(${(getPreset(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
tertiaryColor,
|
||||
accentColor
|
||||
)[preset].preset(discordSaturation) as { full: string, base: string; }).base})}` : ""}
|
||||
/>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
|
@ -219,12 +191,18 @@ export default function ({
|
|||
discordSaturation
|
||||
);
|
||||
} else {
|
||||
customColorwayCSS = getPreset(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
tertiaryColor,
|
||||
accentColor
|
||||
)[preset].preset(discordSaturation);
|
||||
gradientPresetIds.includes(getPreset()[preset].id) ?
|
||||
customColorwayCSS = getPreset(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
tertiaryColor,
|
||||
accentColor
|
||||
)[preset].preset(discordSaturation).full : customColorwayCSS = getPreset(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
tertiaryColor,
|
||||
accentColor
|
||||
)[preset].preset(discordSaturation);
|
||||
}
|
||||
const customColorway: Colorway = {
|
||||
name: (colorwayName || "Colorway") + (preset === "default" ? "" : ": Made for " + getPreset()[preset].name),
|
||||
|
@ -236,6 +214,13 @@ export default function ({
|
|||
colors: presetColorArray,
|
||||
author: UserStore.getCurrentUser().username,
|
||||
authorID: UserStore.getCurrentUser().id,
|
||||
isGradient: gradientPresetIds.includes(getPreset()[preset].id),
|
||||
linearGradient: gradientPresetIds.includes(getPreset()[preset].id) ? getPreset(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
tertiaryColor,
|
||||
accentColor
|
||||
)[preset].preset(discordSaturation).base : null
|
||||
};
|
||||
const customColorwaysArray: Colorway[] = [customColorway];
|
||||
DataStore.get("customColorways").then(
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
}} />;
|
||||
};
|
|
@ -5,20 +5,21 @@
|
|||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { openUserProfile } from "@utils/discord";
|
||||
import {
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalProps,
|
||||
ModalRoot,
|
||||
} from "@utils/modal";
|
||||
import { Button, Clipboard, Forms, Text, Toasts } from "@webpack/common";
|
||||
import { Button, Clipboard, Forms, Text, Toasts, useState } from "@webpack/common";
|
||||
|
||||
import { ColorwayCSS } from "..";
|
||||
import { generateCss } from "../css";
|
||||
import { generateCss, pureGradientBase } from "../css";
|
||||
import { Colorway } from "../types";
|
||||
import { colorToHex } from "../utils";
|
||||
import { colorToHex, stringToHex } from "../utils";
|
||||
import ThemePreviewCategory from "./ThemePreview";
|
||||
|
||||
export default function ({
|
||||
|
@ -38,227 +39,208 @@ export default function ({
|
|||
"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>
|
||||
const [collapsedCSS, setCollapsedCSS] = useState(true);
|
||||
return <ModalRoot {...modalProps} className="colorwayCreator-modal">
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/semibold" tag="h1" style={{ marginRight: "auto" }}>
|
||||
Colorway Details: {colorwayProps.name}
|
||||
</Text>
|
||||
<ModalCloseButton onClick={() => modalProps.onClose()} />
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<div className="colorwayInfo-wrapper">
|
||||
<div className="colorwayInfo-colorSwatches">
|
||||
{colors.map(color => <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 className="colorwayInfo-row colorwayInfo-author">
|
||||
<Flex style={{ gap: "10px", width: "100%", alignItems: "center" }}>
|
||||
<Forms.FormTitle style={{ marginBottom: 0, width: "100%" }}>Properties:</Forms.FormTitle>
|
||||
<Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
look={Button.Looks.OUTLINED}
|
||||
style={{ flex: "0 0 auto", maxWidth: "236px" }}
|
||||
onClick={() => {
|
||||
openUserProfile(colorwayProps.authorID);
|
||||
}}
|
||||
>
|
||||
{colorwayProps.author}
|
||||
Author: {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"
|
||||
<Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
style={{ flex: "0 0 auto" }}
|
||||
onClick={() => {
|
||||
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",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{colorwayProps["dc-import"]}
|
||||
</Text>
|
||||
</div>
|
||||
<ThemePreviewCategory
|
||||
isCollapsed={true}
|
||||
className="colorwayInfo-lastCat"
|
||||
accent={colorwayProps.accent}
|
||||
primary={colorwayProps.primary}
|
||||
secondary={colorwayProps.secondary}
|
||||
tertiary={colorwayProps.tertiary}
|
||||
></ThemePreviewCategory>
|
||||
Copy Colorway ID
|
||||
</Button>
|
||||
{discrimProps && <Button
|
||||
color={Button.Colors.RED}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.FILLED}
|
||||
style={{ flex: "0 0 auto" }}
|
||||
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>}
|
||||
</Flex>
|
||||
</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.OUTLINED}
|
||||
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);
|
||||
<div className={"colorwayInfo-row colorwayInfo-css" + (collapsedCSS ? " colorwaysCreator-settingCat-collapsed" : "")}>
|
||||
<Flex style={{ gap: "10px", width: "100%", alignItems: "center" }}>
|
||||
<Forms.FormTitle style={{ marginBottom: 0, width: "100%" }}>CSS:</Forms.FormTitle>
|
||||
<Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
style={{ flex: "0 0 auto" }}
|
||||
onClick={() => setCollapsedCSS(!collapsedCSS)}
|
||||
>
|
||||
{collapsedCSS ? "Show" : "Hide"}
|
||||
</Button>
|
||||
<Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
style={{ flex: "0 0 auto" }}
|
||||
onClick={() => {
|
||||
Clipboard.copy(colorwayProps["dc-import"]);
|
||||
Toasts.show({
|
||||
message: "Copied CSS to Clipboard",
|
||||
type: 1,
|
||||
id: "copy-colorway-css-notify",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Copy
|
||||
</Button>
|
||||
{discrimProps ? <Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
style={{ flex: "0 0 auto" }}
|
||||
onClick={async () => {
|
||||
const customColorways = await DataStore.get("customColorways");
|
||||
const customColorwaysArray: Colorway[] = [];
|
||||
customColorways.map((color: Colorway, i: number) => {
|
||||
if (customColorways.length > 0) {
|
||||
if (color.name === colorwayProps.name) {
|
||||
color["dc-import"] = generateCss(colorToHex(color.primary) || "313338", colorToHex(color.secondary) || "2b2d31", colorToHex(color.tertiary) || "1e1f22", colorToHex(color.accent) || "5865f2", true, true);
|
||||
customColorwaysArray.push(color);
|
||||
} else {
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
if (++i === customColorways.length) {
|
||||
DataStore.set("customColorways", customColorwaysArray);
|
||||
}
|
||||
modalProps.onClose();
|
||||
loadUIProps();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Update
|
||||
</Button> : <Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
style={{ flex: "0 0 auto" }}
|
||||
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);
|
||||
|
||||
// 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.OUTLINED}
|
||||
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.OUTLINED}
|
||||
onClick={async () => {
|
||||
const customColorways = await DataStore.get("customColorways");
|
||||
const customColorwaysArray: Colorway[] = [];
|
||||
customColorways.map((color: Colorway, i: number) => {
|
||||
if (customColorways.length > 0) {
|
||||
if (color.name === colorwayProps.name) {
|
||||
color["dc-import"] = generateCss(colorToHex(color.primary) || "313338", colorToHex(color.secondary) || "2b2d31", colorToHex(color.tertiary) || "1e1f22", colorToHex(color.accent) || "5865f2", true, true);
|
||||
customColorwaysArray.push(color);
|
||||
} else {
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
if (++i === customColorways.length) {
|
||||
DataStore.set("customColorways", customColorwaysArray);
|
||||
}
|
||||
modalProps.onClose();
|
||||
loadUIProps();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Update CSS
|
||||
</Button> : <Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
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 customColorwaysArray: Colorway[] = [];
|
||||
colorways.map((color: Colorway, i: number) => {
|
||||
if (colorways.length > 0) {
|
||||
if (color.name === colorwayProps.name) {
|
||||
color.name += " (Custom)";
|
||||
color["dc-import"] = generateCss(colorToHex(color.primary) || "313338", colorToHex(color.secondary) || "2b2d31", colorToHex(color.tertiary) || "1e1f22", colorToHex(color.accent) || "5865f2", true, true);
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
if (++i === colorways.length) {
|
||||
DataStore.set("customColorways", [...customColorways, ...customColorwaysArray]);
|
||||
}
|
||||
modalProps.onClose();
|
||||
loadUIProps();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Update CSS (Local)
|
||||
</Button>}
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
look={Button.Looks.OUTLINED}
|
||||
onClick={() => {
|
||||
modalProps.onClose();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
const customColorways = await DataStore.get("customColorways");
|
||||
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(colorToHex(color.primary) || "313338", colorToHex(color.secondary) || "2b2d31", colorToHex(color.tertiary) || "1e1f22", colorToHex(color.accent) || "5865f2", true, true);
|
||||
customColorwaysArray.push(color);
|
||||
}
|
||||
if (++i === colorways.length) {
|
||||
DataStore.set("customColorways", [...customColorways, ...customColorwaysArray]);
|
||||
}
|
||||
modalProps.onClose();
|
||||
loadUIProps();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Update
|
||||
</Button>}
|
||||
</Flex>
|
||||
<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}
|
||||
previewCSS={colorwayProps.isGradient ? pureGradientBase + `.colorwaysPreview-modal,.colorwaysPreview-wrapper {--gradient-theme-bg: linear-gradient(${colorwayProps.linearGradient})}` : ""}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ width: "100%", height: "20px" }} />
|
||||
</ModalContent>
|
||||
</ModalRoot>;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
/* eslint-disable arrow-parens */
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { SettingsTab } from "@components/VencordSettings/shared";
|
||||
import { ModalContent, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import {
|
||||
|
@ -23,10 +25,11 @@ import {
|
|||
useEffect,
|
||||
useState,
|
||||
} from "@webpack/common";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import { ColorwayCSS } from "..";
|
||||
import { defaultColorwaySource, fallbackColorways } from "../constants";
|
||||
import { generateCss } from "../css";
|
||||
import { generateCss, gradientBase } from "../css";
|
||||
import { Colorway } from "../types";
|
||||
import { colorToHex } from "../utils";
|
||||
import ColorPickerModal from "./ColorPicker";
|
||||
|
@ -36,10 +39,46 @@ import ColorwayInfoModal from "./InfoModal";
|
|||
|
||||
const { SelectionCircle } = findByPropsLazy("SelectionCircle");
|
||||
|
||||
function SelectorContainer({ children, isSettings, modalProps }: { children: ReactNode, isSettings?: boolean, modalProps: ModalProps; }) {
|
||||
if (!isSettings) {
|
||||
return <ModalRoot {...modalProps} className="colorwaySelectorModal">
|
||||
{children}
|
||||
</ModalRoot>;
|
||||
} else {
|
||||
return <SettingsTab title="Colors">
|
||||
<div className="colorwaysSettingsSelector-wrapper">
|
||||
{children}
|
||||
</div>
|
||||
</SettingsTab>;
|
||||
}
|
||||
}
|
||||
|
||||
function SelectorHeader({ children, isSettings }: { children: ReactNode, isSettings?: boolean; }) {
|
||||
if (!isSettings) {
|
||||
return <ModalHeader>
|
||||
{children}
|
||||
</ModalHeader>;
|
||||
} else {
|
||||
return <Flex style={{ gap: "0" }}>
|
||||
{children}
|
||||
</Flex>;
|
||||
}
|
||||
}
|
||||
|
||||
function SelectorContent({ children, isSettings }: { children: ReactNode, isSettings?: boolean; }) {
|
||||
if (!isSettings) {
|
||||
return <ModalContent className="colorwaySelectorModalContent">{children}</ModalContent>;
|
||||
} else {
|
||||
return <>{children}</>;
|
||||
}
|
||||
}
|
||||
|
||||
export default function ({
|
||||
modalProps,
|
||||
isSettings
|
||||
}: {
|
||||
modalProps: ModalProps;
|
||||
modalProps: ModalProps,
|
||||
isSettings?: boolean;
|
||||
}): JSX.Element | any {
|
||||
const [currentColorway, setCurrentColorway] = useState<string>("");
|
||||
const [colorways, setColorways] = useState<Colorway[]>([]);
|
||||
|
@ -179,8 +218,8 @@ export default function ({
|
|||
}
|
||||
|
||||
return (
|
||||
<ModalRoot {...modalProps} className="colorwaySelectorModal">
|
||||
<ModalHeader>
|
||||
<SelectorContainer modalProps={modalProps} isSettings={isSettings}>
|
||||
<SelectorHeader isSettings={isSettings}>
|
||||
<Select className="colorwaySelector-pill colorwaySelector-pill_select" options={[{
|
||||
value: "all",
|
||||
label: "All"
|
||||
|
@ -238,7 +277,7 @@ export default function ({
|
|||
y="0px"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px" }}
|
||||
style={{ padding: "6px", boxSizing: "content-box" }}
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
|
@ -256,7 +295,7 @@ export default function ({
|
|||
</Popout>;
|
||||
}}
|
||||
</Tooltip>
|
||||
<Tooltip text="Open Settings">
|
||||
{!isSettings ? <Tooltip text="Open Settings">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
|
@ -276,13 +315,13 @@ export default function ({
|
|||
role="img"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px" }}
|
||||
style={{ padding: "6px", boxSizing: "content-box" }}
|
||||
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> : <></>}
|
||||
<Tooltip text="Create Colorway...">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
|
@ -303,7 +342,7 @@ export default function ({
|
|||
role="img"
|
||||
width="20"
|
||||
height="20"
|
||||
style={{ padding: "6px" }}
|
||||
style={{ padding: "6px", boxSizing: "content-box" }}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
|
@ -325,12 +364,12 @@ export default function ({
|
|||
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">
|
||||
<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>
|
||||
<Tooltip text="Close">
|
||||
{!isSettings ? <Tooltip text="Close">
|
||||
{({ onMouseEnter, onMouseLeave }) => <Button
|
||||
innerClassName="colorwaysSettings-iconButtonInner"
|
||||
size={Button.Sizes.ICON}
|
||||
|
@ -341,11 +380,11 @@ export default function ({
|
|||
onMouseLeave={onMouseLeave}
|
||||
onClick={() => modalProps.onClose()}
|
||||
>
|
||||
<CloseIcon style={{ padding: "6px" }} width={20} height={20} />
|
||||
<CloseIcon style={{ padding: "6px", boxSizing: "content-box" }} width={20} height={20} />
|
||||
</Button>}
|
||||
</Tooltip>
|
||||
</ModalHeader>
|
||||
<ModalContent className="colorwaySelectorModalContent">
|
||||
</Tooltip> : <></>}
|
||||
</SelectorHeader>
|
||||
<SelectorContent isSettings={isSettings}>
|
||||
<div className="colorwaysLoader-barContainer"><div className="colorwaysLoader-bar" style={{ height: loaderHeight }} /></div>
|
||||
<ScrollerThin style={{ maxHeight: "450px" }} className="ColorwaySelectorWrapper">
|
||||
{visibleColorwayArray.length === 0 &&
|
||||
|
@ -397,14 +436,14 @@ export default function ({
|
|||
DataStore.set("activeColorwayColors", color.colors);
|
||||
DataStore.set("actveColorwayID", color.name);
|
||||
if (onDemandWays) {
|
||||
const demandedColorway = generateCss(
|
||||
const demandedColorway = !color.isGradient ? generateCss(
|
||||
colorToHex(color.primary),
|
||||
colorToHex(color.secondary),
|
||||
colorToHex(color.tertiary),
|
||||
colorToHex(color.accent),
|
||||
onDemandWaysTintedText,
|
||||
onDemandWaysDiscordSaturation
|
||||
);
|
||||
) : gradientBase(colorToHex(color.accent), onDemandWaysDiscordSaturation) + `:root:root {--custom-theme-background: linear-gradient(${color.linearGradient})}`;
|
||||
DataStore.set("actveColorway", demandedColorway);
|
||||
ColorwayCSS.set(demandedColorway);
|
||||
} else {
|
||||
|
@ -446,13 +485,17 @@ export default function ({
|
|||
</svg>
|
||||
</div>
|
||||
<div className="discordColorwayPreviewColorContainer">
|
||||
{colors.map((colorItm) => <div
|
||||
{!color.isGradient ? colors.map((colorItm) => <div
|
||||
className="discordColorwayPreviewColor"
|
||||
style={{
|
||||
backgroundColor: color[colorItm],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>) : <div
|
||||
className="discordColorwayPreviewColor"
|
||||
style={{
|
||||
background: `linear-gradient(${color.linearGradient})`,
|
||||
}}
|
||||
/>}
|
||||
</div>
|
||||
{currentColorway === color.name && <SelectionCircle />}
|
||||
</div>
|
||||
|
@ -463,7 +506,7 @@ export default function ({
|
|||
})
|
||||
)}
|
||||
</ScrollerThin>
|
||||
</ModalContent >
|
||||
</ModalRoot >
|
||||
</SelectorContent>
|
||||
</SelectorContainer >
|
||||
);
|
||||
}
|
|
@ -1,421 +0,0 @@
|
|||
/*
|
||||
* 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 { findByPropsLazy } from "@webpack";
|
||||
import {
|
||||
Button,
|
||||
Forms,
|
||||
Menu,
|
||||
Popout,
|
||||
Select,
|
||||
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 { colorToHex } from "../../utils";
|
||||
import ColorPickerModal from "../ColorPicker";
|
||||
import CreatorModal from "../CreatorModal";
|
||||
import ColorwayInfoModal from "../InfoModal";
|
||||
|
||||
const { SelectionCircle } = findByPropsLazy("SelectionCircle");
|
||||
|
||||
export default function (): 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 (
|
||||
<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}
|
||||
look={Button.Looks.OUTLINED}
|
||||
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}
|
||||
look={Button.Looks.OUTLINED}
|
||||
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}
|
||||
look={Button.Looks.OUTLINED}
|
||||
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"
|
||||
id={"colorway-" + color.name}
|
||||
data-last-official={
|
||||
ind + 1 === colorways.length
|
||||
}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
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(
|
||||
colorToHex(color.primary),
|
||||
colorToHex(color.secondary),
|
||||
colorToHex(color.tertiary),
|
||||
colorToHex(color.accent),
|
||||
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);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="colorwayInfoIconContainer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
openModal((props) => (
|
||||
<ColorwayInfoModal
|
||||
modalProps={
|
||||
props
|
||||
}
|
||||
colorwayProps={
|
||||
color
|
||||
}
|
||||
discrimProps={customColorways.includes(
|
||||
color
|
||||
)}
|
||||
loadUIProps={cached_loadUI}
|
||||
/>
|
||||
));
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
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 className="discordColorwayPreviewColorContainer">
|
||||
{colors.map((colorItm) => <div
|
||||
className="discordColorwayPreviewColor"
|
||||
style={{
|
||||
backgroundColor: color[colorItm],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{currentColorway === color.name && <SelectionCircle />}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</SettingsTab>
|
||||
);
|
||||
}
|
|
@ -9,7 +9,7 @@ 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 { ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||
import {
|
||||
Button,
|
||||
Clipboard,
|
||||
|
@ -24,10 +24,9 @@ import {
|
|||
} from "@webpack/common";
|
||||
import { FluxEvents } from "@webpack/types";
|
||||
|
||||
import { versionData } from "../..";
|
||||
import { versionData } from "../../../discordColorways";
|
||||
import { defaultColorwaySource, fallbackColorways, knownColorwaySources } from "../../constants";
|
||||
import { Colorway } from "../../types";
|
||||
import Divider from "../Divider";
|
||||
import { CloseIcon } from "../Icons";
|
||||
|
||||
export default function () {
|
||||
|
@ -88,18 +87,17 @@ export default function () {
|
|||
onClick={() => {
|
||||
openModal(props => {
|
||||
var colorwaySource = "";
|
||||
return <ModalRoot {...props}>
|
||||
return <ModalRoot {...props} className="colorwaySourceModal">
|
||||
<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>
|
||||
<TextInput
|
||||
placeholder="Enter a valid URL..."
|
||||
onChange={e => colorwaySource = e}
|
||||
style={{ margin: "8px", width: "calc(100% - 16px)" }}
|
||||
/>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
|
@ -193,7 +191,7 @@ export default function () {
|
|||
</div>
|
||||
)}
|
||||
</Flex>
|
||||
<Divider />
|
||||
<Forms.FormDivider style={{ margin: "20px 0" }} />
|
||||
<Forms.FormTitle tag="h5">Quick Switch</Forms.FormTitle>
|
||||
<Switch
|
||||
value={colorsButtonVisibility}
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
import { ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||
import {
|
||||
Forms,
|
||||
Text,
|
||||
useState
|
||||
Text
|
||||
} from "@webpack/common";
|
||||
|
||||
import { HexToHSL } from "../utils";
|
||||
|
@ -21,7 +20,8 @@ export default function ({
|
|||
tertiary,
|
||||
className,
|
||||
isCollapsed,
|
||||
previewCSS
|
||||
previewCSS,
|
||||
noContainer
|
||||
}: {
|
||||
accent: string,
|
||||
primary: string,
|
||||
|
@ -29,9 +29,9 @@ export default function ({
|
|||
tertiary: string,
|
||||
className?: string,
|
||||
isCollapsed: boolean,
|
||||
previewCSS?: string;
|
||||
previewCSS?: string,
|
||||
noContainer?: boolean;
|
||||
}) {
|
||||
const [collapsed, setCollapsed] = useState<boolean>(isCollapsed);
|
||||
function ThemePreview({
|
||||
accent,
|
||||
primary,
|
||||
|
@ -50,7 +50,7 @@ export default function ({
|
|||
return (
|
||||
<div
|
||||
className="colorwaysPreview-wrapper"
|
||||
style={{ backgroundColor: tertiary }}
|
||||
style={{ background: `var(--dc-overlay-app-frame, ${tertiary})` }}
|
||||
>
|
||||
<div className="colorwaysPreview-titlebar" />
|
||||
<div className="colorwaysPreview-body">
|
||||
|
@ -58,9 +58,9 @@ export default function ({
|
|||
<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}
|
||||
style={{ background: `var(--dc-guild-button, ${primary})` }}
|
||||
onMouseEnter={e => e.currentTarget.style.background = accent}
|
||||
onMouseLeave={e => e.currentTarget.style.background = `var(--dc-guild-button, ${primary})`}
|
||||
onClick={() => {
|
||||
if (isModal) {
|
||||
modalProps?.onClose();
|
||||
|
@ -106,25 +106,25 @@ export default function ({
|
|||
<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; }}
|
||||
style={{ background: `var(--dc-guild-button, ${primary})` }}
|
||||
onMouseEnter={e => e.currentTarget.style.background = accent}
|
||||
onMouseLeave={e => e.currentTarget.style.background = `var(--dc-guild-button, ${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; }}
|
||||
style={{ background: `var(--dc-guild-button, ${primary})` }}
|
||||
onMouseEnter={e => e.currentTarget.style.background = accent}
|
||||
onMouseLeave={e => e.currentTarget.style.background = `var(--dc-guild-button, ${primary})`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="colorwayPreview-channels" style={{ backgroundColor: secondary }}>
|
||||
<div className="colorwayPreview-channels" style={{ background: `var(--dc-overlay-3, ${secondary})` }}>
|
||||
<div
|
||||
className="colorwayPreview-userArea"
|
||||
style={{
|
||||
backgroundColor: "hsl(" + HexToHSL(secondary)[0] + " " + HexToHSL(secondary)[1] + "% " + Math.max(HexToHSL(secondary)[2] - 3.6, 0) + "%)"
|
||||
background: `var(--dc-secondary-alt, hsl(${HexToHSL(secondary)[0]} ${HexToHSL(secondary)[1]}% ${Math.max(HexToHSL(secondary)[2] - 3.6, 0)}%))`
|
||||
}}
|
||||
/>
|
||||
<div className="colorwayPreview-filler" />
|
||||
|
@ -145,19 +145,16 @@ export default function ({
|
|||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className="colorwayPreview-chat" style={{ backgroundColor: primary }}>
|
||||
<div className="colorwayPreview-chat" style={{ background: `var(--dc-overlay-chat, ${primary})` }}>
|
||||
<div
|
||||
className="colorwayPreview-chatBox"
|
||||
style={{
|
||||
backgroundColor: "hsl(" + HexToHSL(primary)[0] + " " + HexToHSL(primary)[1] + "% " + Math.min(HexToHSL(primary)[2] + 3.6, 100) + "%)"
|
||||
background: `var(--dc-overlay-3, 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>
|
||||
|
@ -165,35 +162,12 @@ export default function ({
|
|||
);
|
||||
}
|
||||
return (
|
||||
<div className={`${collapsed ? "colorwaysPreview colorwaysPreview-collapsed" : "colorwaysPreview"} ${className || ""}`}>
|
||||
<div
|
||||
className="colorwaysCreator-settingItm colorwaysCreator-settingHeader"
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
!noContainer ? <div className="colorwaysPreview">
|
||||
<Forms.FormTitle
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<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>
|
||||
Preview
|
||||
</Forms.FormTitle>
|
||||
<style>
|
||||
{previewCSS}
|
||||
</style>
|
||||
|
@ -203,7 +177,16 @@ export default function ({
|
|||
secondary={secondary}
|
||||
tertiary={tertiary}
|
||||
/>
|
||||
</div>
|
||||
</div> : <>
|
||||
<style>
|
||||
{".colorwaysPreview-wrapper {color: var(--header-secondary); box-shadow: var(--legacy-elevation-border);}" + previewCSS}
|
||||
</style>
|
||||
<ThemePreview
|
||||
accent={accent}
|
||||
primary={primary}
|
||||
secondary={secondary}
|
||||
tertiary={tertiary}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -315,3 +315,10 @@ export const knownThemeVars = {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const mainColors = [
|
||||
{ name: "accent", title: "Accent", var: "--brand-experiment" },
|
||||
{ name: "primary", title: "Primary", var: "--background-primary" },
|
||||
{ name: "secondary", title: "Secondary", var: "--background-secondary" },
|
||||
{ name: "tertiary", title: "Tertiary", var: "--background-tertiary" }
|
||||
];
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { Plugins } from "Vencord";
|
||||
|
||||
import { colorToHex, HexToHSL } from "./utils";
|
||||
import { HexToHSL } from "./utils";
|
||||
|
||||
export const colorVariables: string[] = [
|
||||
"brand-100",
|
||||
|
@ -290,9 +290,73 @@ const BrandLightDiffs = {
|
|||
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);
|
||||
export const pureGradientBase = `
|
||||
.theme-dark :is(.colorwaysPreview-modal, .colorwaysPreview-wrapper) {
|
||||
--dc-overlay-color: 0 0 0;
|
||||
--dc-overlay-color-inverse: 255 255 255;
|
||||
--dc-overlay-opacity-1: 0.85;
|
||||
--dc-overlay-opacity-2: 0.8;
|
||||
--dc-overlay-opacity-3: 0.7;
|
||||
--dc-overlay-opacity-4: 0.5;
|
||||
--dc-overlay-opacity-5: 0.4;
|
||||
--dc-overlay-opacity-6: 0.1;
|
||||
--dc-overlay-opacity-hover: 0.5;
|
||||
--dc-overlay-opacity-hover-inverse: 0.08;
|
||||
--dc-overlay-opacity-active: 0.45;
|
||||
--dc-overlay-opacity-active-inverse: 0.1;
|
||||
--dc-overlay-opacity-selected: 0.4;
|
||||
--dc-overlay-opacity-selected-inverse: 0.15;
|
||||
--dc-overlay-opacity-chat: 0.8;
|
||||
--dc-overlay-opacity-home: 0.85;
|
||||
--dc-overlay-opacity-home-card: 0.8;
|
||||
--dc-overlay-opacity-app-frame: var(--dc-overlay-opacity-4);
|
||||
--dc-guild-button: rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-6));
|
||||
--dc-secondary-alt: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-3)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-3))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-chat-header: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-2)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-2))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
}
|
||||
.theme-light :is(.colorwaysPreview-modal, .colorwaysPreview-wrapper) {
|
||||
--dc-overlay-color: 255 255 255;
|
||||
--dc-overlay-color-inverse: 0 0 0;
|
||||
--dc-overlay-opacity-1: 0.9;
|
||||
--dc-overlay-opacity-2: 0.8;
|
||||
--dc-overlay-opacity-3: 0.7;
|
||||
--dc-overlay-opacity-4: 0.6;
|
||||
--dc-overlay-opacity-5: 0.3;
|
||||
--dc-overlay-opacity-6: 0.15;
|
||||
--dc-overlay-opacity-hover: 0.7;
|
||||
--dc-overlay-opacity-hover-inverse: 0.02;
|
||||
--dc-overlay-opacity-active: 0.65;
|
||||
--dc-overlay-opacity-active-inverse: 0.03;
|
||||
--dc-overlay-opacity-selected: 0.6;
|
||||
--dc-overlay-opacity-selected-inverse: 0.04;
|
||||
--dc-overlay-opacity-chat: 0.9;
|
||||
--dc-overlay-opacity-home: 0.7;
|
||||
--dc-overlay-opacity-home-card: 0.9;
|
||||
--dc-overlay-opacity-app-frame: var(--dc-overlay-opacity-5);
|
||||
--dc-guild-button: rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-3));
|
||||
--dc-secondary-alt: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-1)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-1))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-chat-header: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-1)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-1))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
}
|
||||
.colorwaysPreview-modal,
|
||||
.colorwaysPreview-wrapper {
|
||||
--dc-overlay-1: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-1)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-1))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-2: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-2)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-2))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-3: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-3)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-3))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-4: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-4)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-4))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-5: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-5)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-5))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-6: linear-gradient(rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-6)),rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-6))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-hover: linear-gradient(rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-hover-inverse)),rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-hover-inverse))) fixed 0 0/cover,linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-hover)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-hover))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-active: linear-gradient(rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-active-inverse)),rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-active-inverse))) fixed 0 0/cover,linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-active)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-active))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-selected: linear-gradient(rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-selected-inverse)),rgb(var(--dc-overlay-color-inverse)/var(--dc-overlay-opacity-selected-inverse))) fixed 0 0/cover,linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-selected)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-selected))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-chat: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-chat)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-chat))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-home: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-home)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-home))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-home-card: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-home-card)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-home-card))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
--dc-overlay-app-frame: linear-gradient(rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-app-frame)),rgb(var(--dc-overlay-color)/var(--dc-overlay-opacity-app-frame))) fixed 0 0/cover,var(--gradient-theme-bg) fixed 0 0/cover;
|
||||
}`;
|
||||
|
||||
|
||||
export function gradientBase(accentColor?: string, discordSaturation = false) {
|
||||
return `@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;
|
||||
|
@ -401,14 +465,11 @@ function gradientBase(accentColor?: string, discordSaturation = false) {
|
|||
--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;`;
|
||||
--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) {
|
||||
primaryColor = colorToHex(primaryColor);
|
||||
secondaryColor = colorToHex(secondaryColor);
|
||||
tertiaryColor = colorToHex(tertiaryColor);
|
||||
accentColor = colorToHex(accentColor);
|
||||
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)};
|
||||
|
@ -446,7 +507,9 @@ export function generateCss(primaryColor: string, secondaryColor: string, tertia
|
|||
--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-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)}%;
|
||||
--interactive-muted: hsl(${HexToHSL("#" + primaryColor)[0]} 0% ${Math.min(HexToHSL("#" + primaryColor)[2] + (3.6 * 3), 100)}%);
|
||||
${tintedText ? `--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%)")};` : ""}
|
||||
|
@ -606,6 +669,14 @@ export function getPreset(primaryColor?: string, secondaryColor?: string, tertia
|
|||
}`;
|
||||
}
|
||||
|
||||
function cyan2(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]}%/60%);
|
||||
--cyan-second-layer: hsl(${HexToHSL("#" + tertiaryColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + tertiaryColor)[1]}%) ${Math.min(HexToHSL("#" + tertiaryColor)[2] + (3.6 * 2), 100)}%/60%);
|
||||
}`;
|
||||
}
|
||||
|
||||
function virtualBoy(discordSaturation = false) {
|
||||
return `:root:root {
|
||||
--VBaccent: ${HexToHSL("#" + accentColor)[0]} calc(var(--saturation-factor, 1)*${HexToHSL("#" + accentColor)[1]}%) ${HexToHSL("#" + accentColor)[2]}%;
|
||||
|
@ -635,15 +706,22 @@ export function getPreset(primaryColor?: string, secondaryColor?: string, tertia
|
|||
}
|
||||
|
||||
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%);
|
||||
}`;
|
||||
return {
|
||||
full: `${gradientBase(accentColor, discordSaturation)}
|
||||
:root:root {
|
||||
--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%);
|
||||
}`,
|
||||
base: `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%);
|
||||
}`;
|
||||
return {
|
||||
full: `${gradientBase(accentColor, discordSaturation)}
|
||||
:root:root {
|
||||
--custom-theme-background: linear-gradient(48.17deg, #${primaryColor} 11.21%, #${secondaryColor} 61.92%);
|
||||
}`, base: `48.17deg, #${primaryColor} 11.21%, #${secondaryColor} 61.92%`
|
||||
};
|
||||
}
|
||||
|
||||
function hueRotation(discordSaturation = false) {
|
||||
|
@ -719,17 +797,29 @@ export function getPreset(primaryColor?: string, secondaryColor?: string, tertia
|
|||
}
|
||||
|
||||
return {
|
||||
default: {
|
||||
name: "Default",
|
||||
preset: generateCss,
|
||||
id: "default",
|
||||
colors: ["accent", "primary", "secondary", "tertiary"]
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan",
|
||||
preset: cyan,
|
||||
id: "cyan",
|
||||
colors: ["primary", "secondary", "accent"]
|
||||
colors: ["accent", "primary", "secondary"]
|
||||
},
|
||||
cyan2: {
|
||||
name: "Cyan 2",
|
||||
preset: cyan2,
|
||||
id: "cyan2",
|
||||
colors: ["accent", "primary", "secondary"]
|
||||
},
|
||||
virtualBoy: {
|
||||
name: "Virtual Boy",
|
||||
preset: virtualBoy,
|
||||
id: "virtualBoy",
|
||||
colors: ["tertiary", "accent"]
|
||||
colors: ["accent", "tertiary"]
|
||||
},
|
||||
modular: {
|
||||
name: "Modular",
|
||||
|
@ -741,19 +831,19 @@ export function getPreset(primaryColor?: string, secondaryColor?: string, tertia
|
|||
name: "Solana",
|
||||
preset: solana,
|
||||
id: "solana",
|
||||
colors: ["primary", "accent"]
|
||||
colors: ["accent", "primary"]
|
||||
},
|
||||
gradientType1: {
|
||||
name: "Gradient Type 1",
|
||||
preset: gradientType1,
|
||||
id: "gradientType1",
|
||||
colors: ["primary", "secondary", "tertiary", "accent"]
|
||||
colors: ["accent", "primary", "secondary", "tertiary"]
|
||||
},
|
||||
gradientType2: {
|
||||
name: "Gradient Type 2",
|
||||
preset: gradientType2,
|
||||
id: "gradientType2",
|
||||
colors: ["primary", "secondary", "accent"]
|
||||
colors: ["accent", "primary", "secondary"]
|
||||
},
|
||||
hueRotation: {
|
||||
name: "Hue Rotation",
|
||||
|
@ -769,3 +859,8 @@ export function getPreset(primaryColor?: string, secondaryColor?: string, tertia
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const gradientPresetIds = [
|
||||
"gradientType1",
|
||||
"gradientType2"
|
||||
];
|
||||
|
|
|
@ -8,7 +8,7 @@ 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, EquicordDevs } from "@utils/constants";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { openModal } from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
import {
|
||||
|
@ -19,10 +19,9 @@ import {
|
|||
import ColorPickerModal from "./components/ColorPicker";
|
||||
import ColorwaysButton from "./components/ColorwaysButton";
|
||||
import CreatorModal from "./components/CreatorModal";
|
||||
import SelectorModal from "./components/SelectorModal";
|
||||
import Selector from "./components/Selector";
|
||||
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";
|
||||
|
@ -36,7 +35,7 @@ export let ColorPicker: React.FunctionComponent<ColorPickerProps> = () => {
|
|||
(async function () {
|
||||
const [
|
||||
customColorways,
|
||||
colorwaySourcesFiles,
|
||||
colorwaySourceFiles,
|
||||
showColorwaysButton,
|
||||
onDemandWays,
|
||||
onDemandWaysTintedText,
|
||||
|
@ -54,29 +53,20 @@ export let ColorPicker: React.FunctionComponent<ColorPickerProps> = () => {
|
|||
"onDemandWaysColorArray"
|
||||
]);
|
||||
|
||||
if (!customColorways)
|
||||
DataStore.set("customColorways", []);
|
||||
const defaults = [
|
||||
{ name: "customColorways", checkedValue: customColorways, defaults: [] },
|
||||
{ name: "colorwaySourceFiles", checkedValue: colorwaySourceFiles, defaults: [defaultColorwaySource] },
|
||||
{ name: "showColorwaysButton", checkedValue: showColorwaysButton, defaults: false },
|
||||
{ name: "onDemandWays", checkedValue: onDemandWays, defaults: false },
|
||||
{ name: "onDemandWaysTintedText", checkedValue: onDemandWaysTintedText, defaults: true },
|
||||
{ name: "useThinMenuButton", checkedValue: useThinMenuButton, defaults: false },
|
||||
{ name: "onDemandWaysDiscordSaturation", checkedValue: onDemandWaysDiscordSaturation, defaults: false },
|
||||
{ name: "onDemandWaysColorArray", checkedValue: onDemandWaysColorArray, defaults: ["313338", "2b2d31", "1e1f22", "5865f2"] }
|
||||
];
|
||||
|
||||
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"]);
|
||||
defaults.forEach(({ name, checkedValue, defaults }) => {
|
||||
if (!checkedValue) DataStore.set(name, defaults);
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
|
@ -95,20 +85,22 @@ export const ColorwayCSS = {
|
|||
};
|
||||
|
||||
export const versionData = {
|
||||
pluginVersion: "5.6.3",
|
||||
creatorVersion: "1.18.1",
|
||||
pluginVersion: "5.6.5.1",
|
||||
creatorVersion: "1.19",
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "DiscordColorways",
|
||||
description:
|
||||
"A plugin that offers easy access to simple color schemes/themes for Discord, also known as Colorways",
|
||||
authors: [EquicordDevs.DaBluLite, Devs.ImLvna],
|
||||
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} />),
|
||||
"Change Colorway": () => openModal(props => <Selector modalProps={props} />),
|
||||
"Open Colorway Creator": () => openModal(props => <CreatorModal modalProps={props} />),
|
||||
"Open Color Stealer": () => openModal(props => <ColorPickerModal modalProps={props} />),
|
||||
"Open Settings": () => SettingsRouter.open("ColorwaysSettings"),
|
||||
|
@ -149,22 +141,22 @@ export default definePlugin({
|
|||
}
|
||||
}
|
||||
],
|
||||
|
||||
set ColorPicker(e) {
|
||||
ColorPicker = e;
|
||||
},
|
||||
|
||||
makeSettingsCategories(SectionTypes: Record<string, unknown>) {
|
||||
console.log(SectionTypes);
|
||||
return [
|
||||
{
|
||||
section: SectionTypes.HEADER,
|
||||
label: "DiscordColorways",
|
||||
label: "Discord Colorways",
|
||||
className: "vc-settings-header"
|
||||
},
|
||||
{
|
||||
section: "ColorwaysSelector",
|
||||
label: "Colorways",
|
||||
element: SelectorPage,
|
||||
element: () => <Selector isSettings modalProps={{ onClose: () => new Promise(() => true), transitionState: 1 }} />,
|
||||
className: "dc-colorway-selector"
|
||||
},
|
||||
{
|
||||
|
@ -199,22 +191,20 @@ export default definePlugin({
|
|||
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;
|
||||
});
|
||||
addAccessory("colorways-btn", props => String(props.message.content).match(/colorway:[0-9a-f]{0,100}/) ? <Button
|
||||
onClick={() => openModal(modalProps => <CreatorModal
|
||||
modalProps={modalProps}
|
||||
colorwayID={String(props.message.content).match(/colorway:[0-9a-f]{0,100}/)![0]}
|
||||
/>)}
|
||||
size={Button.Sizes.SMALL}
|
||||
color={Button.Colors.PRIMARY}
|
||||
look={Button.Looks.OUTLINED}
|
||||
>
|
||||
Add this Colorway...
|
||||
</Button> : null);
|
||||
},
|
||||
stop() {
|
||||
removeServerListElement(ServerListRenderPosition.In, this.ColorwaysButton);
|
||||
|
||||
disableStyle(style);
|
||||
ColorwayCSS.remove();
|
||||
removeAccessory("colorways-btn");
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
export interface Colorway {
|
||||
[key: string]: any,
|
||||
name: string,
|
||||
"dc-import": string,
|
||||
accent: string,
|
||||
|
@ -17,7 +18,8 @@ export interface Colorway {
|
|||
colors?: string[],
|
||||
isGradient?: boolean,
|
||||
sourceUrl?: string,
|
||||
sourceName?: string;
|
||||
sourceName?: string,
|
||||
linearGradient?: string;
|
||||
}
|
||||
|
||||
export interface ColorPickerProps {
|
||||
|
|
32
src/equicordplugins/noAppsAllowed/index.tsx
Normal file
32
src/equicordplugins/noAppsAllowed/index.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "noAppsAllowed",
|
||||
description: "returns the bot's tag :skulk:",
|
||||
authors: [EquicordDevs.kvba],
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "\"APP_TAG\"",
|
||||
replacement: {
|
||||
match: /"APP_TAG":".*?"/,
|
||||
replace: "\"APP_TAG\":\"BOT\""
|
||||
}
|
||||
},
|
||||
{
|
||||
find: ",APP_TAG:\"",
|
||||
replacement: {
|
||||
match: /APP_TAG:".*?"/,
|
||||
replace: "APP_TAG:\"BOT\""
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
});
|
|
@ -591,6 +591,10 @@ export const EquicordDevs = Object.freeze({
|
|||
name: "DaBluLite",
|
||||
id: 582170007505731594n,
|
||||
},
|
||||
kvba: {
|
||||
name: "kvba",
|
||||
id: 105170831130234880n,
|
||||
},
|
||||
} satisfies Record<string, Dev>);
|
||||
|
||||
// iife so #__PURE__ works correctly
|
||||
|
|
Loading…
Add table
Reference in a new issue