diff --git a/src/equicordplugins/discordColorways/components/AutoColorwaySelector.tsx b/src/equicordplugins/discordColorways/components/AutoColorwaySelector.tsx new file mode 100644 index 00000000..6ebbdace --- /dev/null +++ b/src/equicordplugins/discordColorways/components/AutoColorwaySelector.tsx @@ -0,0 +1,74 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { DataStore } from "@api/index"; +import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot } from "@utils/modal"; +import { findByProps } from "@webpack"; +import { Button, Forms, Text, useState } from "@webpack/common"; + +import { getAutoPresets } from "../css"; + +export default function ({ modalProps, onChange, autoColorwayId = "" }: { modalProps: ModalProps, onChange: (autoPresetId: string) => void, autoColorwayId: string; }) { + const [autoId, setAutoId] = useState(autoColorwayId); + const { radioBar, item: radioBarItem, itemFilled: radioBarItemFilled, radioPositionLeft } = findByProps("radioBar"); + return + + + Auto Preset Settings + + + +
+ About the Auto Colorway + The auto colorway allows you to use your system's accent color in combination with a selection of presets that will fully utilize it. +
+
+ Presets: + {Object.values(getAutoPresets()).map(autoPreset => { + return
+
{ + setAutoId(autoPreset.id); + }}> + + {autoPreset.name} +
+
; + })} +
+
+ + + + +
; +} diff --git a/src/equicordplugins/discordColorways/components/ColorwayCreatorSettingsModal.tsx b/src/equicordplugins/discordColorways/components/ColorwayCreatorSettingsModal.tsx index b1b2f4c2..c969b01c 100644 --- a/src/equicordplugins/discordColorways/components/ColorwayCreatorSettingsModal.tsx +++ b/src/equicordplugins/discordColorways/components/ColorwayCreatorSettingsModal.tsx @@ -5,6 +5,7 @@ */ import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot } from "@utils/modal"; +import { findByProps } from "@webpack"; import { Button, Forms, ScrollerThin, Switch, Text, useState } from "@webpack/common"; import { getPreset } from "../css"; @@ -13,27 +14,31 @@ export default function ({ modalProps, onSettings, presetId, hasTintedText, hasD const [tintedText, setTintedText] = useState(hasTintedText); const [discordSaturation, setDiscordSaturation] = useState(hasDiscordSaturation); const [preset, setPreset] = useState(presetId); + const { radioBar, item: radioBarItem, itemFilled: radioBarItemFilled, radioPositionLeft } = findByProps("radioBar"); return Creator Settings -
- - Presets: - - - {Object.values(getPreset()).map(pre => { - return
{ - setPreset(pre.id); - }}> + + Presets: + + + {Object.values(getPreset()).map(pre => { + return
+
{ + setPreset(pre.id); + }}> {pre.name} -
; - })} - -
+
+
; + })} + Use colored text Use Discord's saturation
diff --git a/src/equicordplugins/discordColorways/components/ColorwaysButton.tsx b/src/equicordplugins/discordColorways/components/ColorwaysButton.tsx index f63b0039..cc8923f8 100644 --- a/src/equicordplugins/discordColorways/components/ColorwaysButton.tsx +++ b/src/equicordplugins/discordColorways/components/ColorwaysButton.tsx @@ -9,33 +9,22 @@ import { openModal } from "@utils/modal"; import { FluxDispatcher, Text, Tooltip, useEffect, useState } from "@webpack/common"; import { FluxEvents } from "@webpack/types"; +import { getAutoPresets } from "../css"; +import { ColorwayObject } from "../types"; import { PalleteIcon } from "./Icons"; import Selector from "./Selector"; -export default function ({ - listItemClass = "ColorwaySelectorBtnContainer", - listItemWrapperClass = "", - listItemTooltipClass = "colorwaysBtn-tooltipContent" -}: { - listItemClass?: string; - listItemWrapperClass?: string; - listItemTooltipClass?: string; -}) { +export default function () { const [activeColorway, setActiveColorway] = useState("None"); const [visibility, setVisibility] = useState(true); const [isThin, setIsThin] = useState(false); - async function setButtonVisibility() { - const [showColorwaysButton, useThinMenuButton] = await DataStore.getMany([ - "showColorwaysButton", - "useThinMenuButton" - ]); - - setVisibility(showColorwaysButton); - setIsThin(useThinMenuButton); - } - + const [autoPreset, setAutoPreset] = useState("hueRotation"); useEffect(() => { - setButtonVisibility(); + (async function () { + setVisibility(await DataStore.get("showColorwaysButton") as boolean); + setIsThin(await DataStore.get("useThinMenuButton") as boolean); + setAutoPreset(await DataStore.get("activeAutoPreset") as string); + })(); }); FluxDispatcher.subscribe("COLORWAYS_UPDATE_BUTTON_HEIGHT" as FluxEvents, ({ isTall }) => { @@ -47,7 +36,13 @@ export default function ({ }); return Colorways{"Active Colorway: " + activeColorway} : {"Active Colorway: " + activeColorway} + <> + {!isThin ? <> + Colorways + {"Active Colorway: " + activeColorway} + : {"Active Colorway: " + activeColorway}} + {activeColorway === "Auto" ? {"Auto Preset: " + (getAutoPresets()[autoPreset].name || "None")} : <>} + } position="right" tooltipContentClassName="colorwaysBtn-tooltipContent" > {({ onMouseEnter, onMouseLeave, onClick }) => visibility ?
@@ -55,7 +50,8 @@ export default function ({ className={"ColorwaySelectorBtn" + (isThin ? " ColorwaySelectorBtn_thin" : "")} onMouseEnter={async () => { onMouseEnter(); - setActiveColorway(await DataStore.get("actveColorwayID") || "None"); + setActiveColorway((await DataStore.get("activeColorwayObject") as ColorwayObject).id || "None"); + setAutoPreset(await DataStore.get("activeAutoPreset") as string); }} onMouseLeave={onMouseLeave} onClick={() => { diff --git a/src/equicordplugins/discordColorways/components/CreatorModal.tsx b/src/equicordplugins/discordColorways/components/CreatorModal.tsx index aec1bebf..8da939b2 100644 --- a/src/equicordplugins/discordColorways/components/CreatorModal.tsx +++ b/src/equicordplugins/discordColorways/components/CreatorModal.tsx @@ -4,7 +4,6 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -import * as DataStore from "@api/DataStore"; import { ModalContent, ModalFooter, @@ -16,6 +15,7 @@ import { import { Button, Forms, + Slider, Text, TextInput, useEffect, @@ -25,12 +25,13 @@ import { import { ColorPicker } from ".."; import { knownThemeVars } from "../constants"; -import { generateCss, getPreset, gradientPresetIds, pureGradientBase } from "../css"; +import { generateCss, getPreset, gradientPresetIds, PrimarySatDiffs, pureGradientBase } from "../css"; import { Colorway } from "../types"; -import { colorToHex, getHex, hexToString } from "../utils"; +import { colorToHex, getHex, HexToHSL, hexToString } from "../utils"; import ColorwayCreatorSettingsModal from "./ColorwayCreatorSettingsModal"; import ConflictingColorsModal from "./ConflictingColorsModal"; import InputColorwayIdModal from "./InputColorwayIdModal"; +import SaveColorwayModal from "./SaveColorwayModal"; import ThemePreviewCategory from "./ThemePreview"; export default function ({ modalProps, @@ -48,10 +49,9 @@ export default function ({ const [colorwayName, setColorwayName] = useState(""); const [tintedText, setTintedText] = useState(true); const [discordSaturation, setDiscordSaturation] = useState(true); - const [collapsedSettings, setCollapsedSettings] = useState(true); - const [collapsedPresets, setCollapsedPresets] = useState(true); const [preset, setPreset] = useState("default"); - const [presetColorArray, setPresetColorArray] = useState(["primary", "secondary", "tertiary", "accent"]); + const [presetColorArray, setPresetColorArray] = useState(["accent", "primary", "secondary", "tertiary"]); + const [mutedTextBrightness, setMutedTextBrightness] = useState(Math.min(HexToHSL("#" + primaryColor)[2] + (3.6 * 3), 100)); const colorProps = { accent: { @@ -77,11 +77,8 @@ export default function ({ }; useEffect(() => { - const parsedID = colorwayID?.split("colorway:")[1]; - if (parsedID) { - if (!parsedID) { - throw new Error("Please enter a Colorway ID"); - } else if (!hexToString(parsedID).includes(",")) { + if (colorwayID) { + if (!colorwayID.includes(",")) { throw new Error("Invalid Colorway ID"); } else { const setColor = [ @@ -90,7 +87,20 @@ export default function ({ setSecondaryColor, setTertiaryColor ]; - hexToString(parsedID).split(/,#/).forEach((color: string, i: number) => setColor[i](colorToHex(color))); + colorwayID.split("|").forEach((prop: string) => { + if (prop.includes(",#")) { + prop.split(/,#/).forEach((color: string, i: number) => setColor[i](colorToHex(color))); + } + if (prop.includes("n:")) { + setColorwayName(prop.split("n:")[1]); + } + if (prop.includes("p:")) { + if (Object.values(getPreset()).map(preset => preset.id).includes(prop.split("p:")[1])) { + setPreset(prop.split("p:")[1]); + setPresetColorArray(getPreset()[prop.split("p:")[1]].colors); + } + } + }); } } }); @@ -122,7 +132,7 @@ export default function ({ />
- Colors: + Colors & Values:
{presetColorArray.map(presetColor => { @@ -140,6 +150,14 @@ export default function ({ />; })}
+ + Muted Text Brightness: +
@@ -179,7 +199,7 @@ export default function ({ color={Button.Colors.BRAND} size={Button.Sizes.MEDIUM} look={Button.Looks.FILLED} - onClick={e => { + onClick={async () => { var customColorwayCSS: string = ""; if (preset === "default") { customColorwayCSS = generateCss( @@ -188,24 +208,26 @@ export default function ({ tertiaryColor, accentColor, tintedText, - discordSaturation + discordSaturation, + mutedTextBrightness, + (colorwayName || "Colorway") ); } else { gradientPresetIds.includes(getPreset()[preset].id) ? - customColorwayCSS = getPreset( + customColorwayCSS = (getPreset( primaryColor, secondaryColor, tertiaryColor, accentColor - )[preset].preset(discordSaturation).full : customColorwayCSS = getPreset( + )[preset].preset(discordSaturation) as { full: string; }).full : customColorwayCSS = (getPreset( primaryColor, secondaryColor, tertiaryColor, accentColor - )[preset].preset(discordSaturation); + )[preset].preset(discordSaturation) as string); } const customColorway: Colorway = { - name: (colorwayName || "Colorway") + (preset === "default" ? "" : ": Made for " + getPreset()[preset].name), + name: (colorwayName || "Colorway"), "dc-import": customColorwayCSS, accent: "#" + accentColor, primary: "#" + primaryColor, @@ -215,30 +237,22 @@ export default function ({ author: UserStore.getCurrentUser().username, authorID: UserStore.getCurrentUser().id, isGradient: gradientPresetIds.includes(getPreset()[preset].id), - linearGradient: gradientPresetIds.includes(getPreset()[preset].id) ? getPreset( + linearGradient: gradientPresetIds.includes(getPreset()[preset].id) ? (getPreset( primaryColor, secondaryColor, tertiaryColor, accentColor - )[preset].preset(discordSaturation).base : null + )[preset].preset(discordSaturation) as { base: string; }).base : "", + preset: getPreset()[preset].id }; - const customColorwaysArray: Colorway[] = [customColorway]; - DataStore.get("customColorways").then( - customColorways => { - customColorways.forEach( - (color: Colorway, i: number) => { - if (color.name !== customColorway.name) { - customColorwaysArray.push(color); - } - } - ); - DataStore.set("customColorways", customColorwaysArray); - } - ); - modalProps.onClose(); - loadUIProps!(); + openModal(props => { + modalProps.onClose(); + loadUIProps!(); + }} />); }} - >Finish + > + Finish + + + + ; +} export default function ({ modalProps, - colorwayProps, - discrimProps = false, + colorway, loadUIProps }: { modalProps: ModalProps; - colorwayProps: Colorway; - discrimProps?: boolean; + colorway: Colorway; loadUIProps: () => Promise; }) { - const colors: string[] = colorwayProps.colors || [ + const colors: string[] = colorway.colors || [ "accent", "primary", "secondary", "tertiary", ]; - const [collapsedCSS, setCollapsedCSS] = useState(true); - return - + const profile = useStateFromStores([UserStore], () => UserStore.getUser(colorway.authorID)); + return + - Colorway Details: {colorwayProps.name} + Colorway: {colorway.name} modalProps.onClose()} /> -
-
- {colors.map(color =>
+ Creator: + + + {colorway.author} + + Colors: + + {colors.map(color =>
)} + + Actions: + +
-
- - Properties: - - - {discrimProps && } - -
-
- - CSS: - - - {discrimProps ? : } - - - {colorwayProps["dc-import"]} - -
- -
+ Copy Colorway ID + + + + {colorway.sourceType === "offline" && } + + + {colorway.sourceType === "offline" && } + +
; diff --git a/src/equicordplugins/discordColorways/components/SaveColorwayModal.tsx b/src/equicordplugins/discordColorways/components/SaveColorwayModal.tsx new file mode 100644 index 00000000..8a034edb --- /dev/null +++ b/src/equicordplugins/discordColorways/components/SaveColorwayModal.tsx @@ -0,0 +1,207 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { DataStore } from "@api/index"; +import { PlusIcon } from "@components/Icons"; +import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal"; +import { findByProps } from "@webpack"; +import { Button, Text, TextInput, useEffect, useState } from "@webpack/common"; + +import { Colorway } from "../types"; +import { StoreNameModal } from "./SettingsTabs/SourceManager"; + +export default function ({ modalProps, colorways, onFinish }: { modalProps: ModalProps, colorways: Colorway[], onFinish: () => void; }) { + const [offlineColorwayStores, setOfflineColorwayStores] = useState<{ name: string, colorways: Colorway[], id?: string; }[]>([]); + const [storename, setStorename] = useState(); + const [noStoreError, setNoStoreError] = useState(false); + const { radioBar, item: radioBarItem, itemFilled: radioBarItemFilled, radioPositionLeft } = findByProps("radioBar"); + useEffect(() => { + (async () => { + setOfflineColorwayStores(await DataStore.get("customColorways") as { name: string, colorways: Colorway[], id?: string; }[]); + })(); + }); + return + + Select Offline Colorway Source + + + {noStoreError ? Error: No store selected : <>} + {offlineColorwayStores.map(store => { + return
+
{ + setStorename(store.name); + }}> + + {store.name} +
+
; + })} +
+
{ + openModal(props => { + await DataStore.set("customColorways", [...await DataStore.get("customColorways"), { name: e, colorways: [] }]); + setOfflineColorwayStores(await DataStore.get("customColorways") as { name: string, colorways: Colorway[]; }[]); + }} />); + }}> + + Create new store... +
+
+
+ + + + + +
; + } + openModal(propss => { + const newStore = { name: storeToModify.name, colorways: [...storeToModify.colorways, { ...colorway, name: e }] }; + DataStore.set("customColorways", [...oldStores!.filter(source => source.name !== storename), newStore]); + props.onClose(); + if (i + 1 === colorways.length) { + modalProps.onClose(); + onFinish!(); + } + }} />); + }} + > + Rename + + + + ); + } else { + const newStore = { name: storeToModify.name, colorways: [...storeToModify.colorways, colorway] }; + DataStore.set("customColorways", [...oldStores!.filter(source => source.name !== storename), newStore]); + if (i + 1 === colorways.length) { + modalProps.onClose(); + onFinish(); + } + } + }); + } + }} + > + Finish + + + + ; +} diff --git a/src/equicordplugins/discordColorways/components/Selector.tsx b/src/equicordplugins/discordColorways/components/Selector.tsx index 66df1138..74446dd5 100644 --- a/src/equicordplugins/discordColorways/components/Selector.tsx +++ b/src/equicordplugins/discordColorways/components/Selector.tsx @@ -8,33 +8,37 @@ import * as DataStore from "@api/DataStore"; import { Flex } from "@components/Flex"; +import { DeleteIcon, PlusIcon } from "@components/Icons"; import { SettingsTab } from "@components/VencordSettings/shared"; -import { ModalContent, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal"; -import { findByPropsLazy } from "@webpack"; +import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal"; +import { findByProps, findByPropsLazy } from "@webpack"; import { Button, + ButtonLooks, + Clipboard, Forms, Menu, Popout, ScrollerThin, Select, SettingsRouter, + Text, TextInput, + Toasts, Tooltip, - useCallback, useEffect, - useState, + useState } from "@webpack/common"; import { ReactNode } from "react"; import { ColorwayCSS } from ".."; -import { defaultColorwaySource, fallbackColorways } from "../constants"; -import { generateCss, gradientBase } from "../css"; -import { Colorway } from "../types"; -import { colorToHex } from "../utils"; +import { generateCss, getAutoPresets, gradientBase } from "../css"; +import { Colorway, ColorwayObject, SortOptions, SourceObject } from "../types"; +import { colorToHex, getHex, stringToHex } from "../utils"; +import AutoColorwaySelector from "./AutoColorwaySelector"; import ColorPickerModal from "./ColorPicker"; import CreatorModal from "./CreatorModal"; -import { CloseIcon } from "./Icons"; +import { CodeIcon, IDIcon, MoreIcon, PalleteIcon } from "./Icons"; import ColorwayInfoModal from "./InfoModal"; const { SelectionCircle } = findByPropsLazy("SelectionCircle"); @@ -55,7 +59,7 @@ function SelectorContainer({ children, isSettings, modalProps }: { children: Rea function SelectorHeader({ children, isSettings }: { children: ReactNode, isSettings?: boolean; }) { if (!isSettings) { - return + return {children} ; } else { @@ -75,106 +79,73 @@ function SelectorContent({ children, isSettings }: { children: ReactNode, isSett export default function ({ modalProps, - isSettings + isSettings, + onSelected }: { modalProps: ModalProps, - isSettings?: boolean; + isSettings?: boolean, + onSelected?: (colorways: Colorway[]) => void; }): JSX.Element | any { - const [currentColorway, setCurrentColorway] = useState(""); - const [colorways, setColorways] = useState([]); - const [thirdPartyColorways, setThirdPartyColorways] = useState([]); - const [customColorways, setCustomColorways] = useState([]); - const [searchString, setSearchString] = useState(""); - const [loaderHeight, setLoaderHeight] = useState("2px"); - const [visibility, setVisibility] = useState("all"); - const [showReloadMenu, setShowReloadMenu] = useState(false); - let visibleColorwayArray: Colorway[]; + const [colorwayData, setColorwayData] = useState([]); + const [searchValue, setSearchValue] = useState(""); + const [sortBy, setSortBy] = useState(SortOptions.NAME_AZ); + const [activeColorwayObject, setActiveColorwayObject] = useState({ id: null, css: null, sourceType: null, source: null }); + const [customColorwayData, setCustomColorwayData] = useState([]); + const [loaderHeight, setLoaderHeight] = useState<"2px" | "0px">("2px"); + const [visibleSources, setVisibleSources] = useState("all"); + const [showReloadMenu, setShowReloadMenu] = useState(false); + const [viewMode, setViewMode] = useState<"list" | "grid">("grid"); + const [showLabelsInSelectorGridView, setShowLabelsInSelectorGridView] = useState(false); + const [showSortingMenu, setShowSotringMenu] = useState(false); - 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; - } + const { item: radioBarItem, itemFilled: radioBarItemFilled } = findByProps("radioBar"); + + const filters = [ + { + name: "All", + id: "all", + sources: [...colorwayData, ...customColorwayData] + }, + ...colorwayData.map((source) => ({ + name: source.source, + id: source.source.toLowerCase().replaceAll(" ", "-"), + sources: [source] + })), + ...customColorwayData.map((source) => ({ + name: source.source, + id: source.source.toLowerCase().replaceAll(" ", "-"), + sources: [source] + })) + ]; + + async function loadUI(force?: boolean) { + setActiveColorwayObject(await DataStore.get("activeColorwayObject") as ColorwayObject); + setViewMode(await DataStore.get("selectorViewMode") as "list" | "grid"); + setShowLabelsInSelectorGridView(await DataStore.get("showLabelsInSelectorGridView") as boolean); + setLoaderHeight("0px"); + setCustomColorwayData((await DataStore.get("customColorways") as { name: string, colorways: Colorway[], id?: string; }[]).map((colorSrc: { name: string, colorways: Colorway[], id?: string; }) => ({ type: "offline", source: colorSrc.name, colorways: colorSrc.colorways }))); + + const onlineSources: { name: string, url: string; }[] = await DataStore.get("colorwaySourceFiles") as { name: string, url: string; }[]; - async function loadUI() { - const colorwaySourceFiles = await DataStore.get( - "colorwaySourceFiles" - ); const responses: Response[] = await Promise.all( - colorwaySourceFiles.map((url: string) => - fetch(url) + onlineSources.map((source) => + fetch(source.url, force ? { cache: "no-store" } : {}) ) ); - 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); + setColorwayData(await Promise.all( + responses + .map((res, i) => ({ response: res, name: onlineSources[i].name })) + .map((res: { response: Response, name: string; }) => + res.response.json().then(dt => ({ colorways: dt.colorways as Colorway[], source: res.name, type: "online" })).catch(() => ({ colorways: [] as Colorway[], source: res.name, type: "online" })) + )) as { type: "online" | "offline" | "temporary", source: string, colorways: Colorway[]; }[]); } useEffect(() => { - if (!searchString) { - cached_loadUI(); + if (!searchValue) { + loadUI(); } - setLoaderHeight("0px"); - }, [searchString]); + }, []); function ReloadPopout(onClose: () => void) { return ( @@ -185,143 +156,133 @@ export default function ({ { - 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]); - }} + action={() => loadUI(true)} /> ); } + function SortingPopout(onClose: () => void) { + return ( + + + { + setViewMode("grid"); + DataStore.set("selectorViewMode", "grid"); + }} + /> + { + setViewMode("list"); + DataStore.set("selectorViewMode", "list"); + }} + /> + + + setSortBy(SortOptions.NAME_AZ)} + /> + setSortBy(SortOptions.NAME_ZA)} + /> + setSortBy(SortOptions.SOURCE_AZ)} + /> + setSortBy(SortOptions.SOURCE_ZA)} + /> + + + ); + } + return ( - ({ label: filter.name, value: (filter.id as string) }))} + select={value => setVisibleSources(value)} + isSelected={value => visibleSources === value} + serialize={String} + popoutPosition="bottom" /> : <>}
- - {visibleColorwayArray.length === 0 && - + {activeColorwayObject.sourceType === "temporary" && + {({ onMouseEnter, onMouseLeave }) =>
{ }} + onMouseLeave={viewMode === "grid" ? onMouseLeave : () => { }} + onClick={async () => { + DataStore.set("activeColorwayObject", { id: null, css: null, sourceType: null, source: null }); + setActiveColorwayObject({ id: null, css: null, sourceType: null, source: null }); + ColorwayCSS.remove(); }} > - No colorways... - - } - {["all", "official", "3rdparty", "custom"].includes(visibility) && ( - visibleColorwayArray.map((color, ind) => { - var colors: Array = color.colors || [ - "accent", - "primary", - "secondary", - "tertiary", - ]; - return ( - - {({ onMouseEnter, onMouseLeave }) => { - return ( -
{ - 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 = !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 { - DataStore.set("actveColorway", color["dc-import"]); - ColorwayCSS.set(color["dc-import"]); - } - } - setCurrentColorway(await DataStore.get("actveColorwayID") as string); - }} - > + {viewMode === "list" && } +
+
+
+
+
+
+
+ {(activeColorwayObject.id === "Temporary Colorway" && activeColorwayObject.sourceType === "temporary" && viewMode === "grid") && } +
+ {(showLabelsInSelectorGridView || viewMode === "list") && Temporary Colorway} + {viewMode === "list" && <> + + {({ onMouseEnter, onMouseLeave }) => } + + } +
} + } + {getComputedStyle(document.body).getPropertyValue("--os-accent-color") && ["all", "official"].includes(visibleSources) && "auto".includes(searchValue.toLowerCase()) ? + {({ onMouseEnter, onMouseLeave }) =>
{ }} + onMouseLeave={viewMode === "grid" ? onMouseLeave : () => { }} + onClick={async () => { + const activeAutoPreset = await DataStore.get("activeAutoPreset"); + if (activeColorwayObject.id === "Auto") { + DataStore.set("activeColorwayObject", { id: null, css: null, sourceType: null, source: null }); + setActiveColorwayObject({ id: null, css: null, sourceType: null, source: null }); + ColorwayCSS.remove(); + } else { + if (!activeAutoPreset) { + openModal((props: ModalProps) => { + const demandedColorway = getAutoPresets(colorToHex(getComputedStyle(document.body).getPropertyValue("--os-accent-color")).slice(0, 6))[autoPresetId].preset(); + ColorwayCSS.set(demandedColorway); + DataStore.set("activeColorwayObject", { id: "Auto", css: demandedColorway, sourceType: "online", source: null }); + setActiveColorwayObject({ id: "Auto", css: demandedColorway, sourceType: "online", source: null }); + }} />); + } else { + const autoColorway = getAutoPresets(colorToHex(getComputedStyle(document.body).getPropertyValue("--os-accent-color")).slice(0, 6))[activeAutoPreset].preset(); + DataStore.set("activeColorwayObject", { id: "Auto", css: autoColorway, sourceType: "online", source: null }); + setActiveColorwayObject({ id: "Auto", css: autoColorway, sourceType: "online", source: null }); + ColorwayCSS.set(autoColorway); + } + } + }} + > + {viewMode === "list" && } +
+
+ {(activeColorwayObject.id === "Auto" && activeColorwayObject.source === null && viewMode === "grid") && } +
+ {(showLabelsInSelectorGridView || viewMode === "list") && Auto} +
{ + e.stopPropagation(); + const activeAutoPreset = await DataStore.get("activeAutoPreset"); + openModal((props: ModalProps) => { + if (activeColorwayObject.id === "Auto") { + const demandedColorway = getAutoPresets(colorToHex(getComputedStyle(document.body).getPropertyValue("--os-accent-color")).slice(0, 6))[autoPresetId].preset(); + DataStore.set("activeColorwayObject", { id: "Auto", css: demandedColorway, sourceType: "online", source: null }); + setActiveColorwayObject({ id: "Auto", css: demandedColorway, sourceType: "online", source: null }); + ColorwayCSS.set(demandedColorway); + } + }} />); + }} + > + + + +
+
} + : <>} + {(!getComputedStyle(document.body).getPropertyValue("--os-accent-color") || !["all", "official"].includes(visibleSources)) && !filters.filter(filter => filter.id === visibleSources)[0].sources.map(source => source.colorways).flat().length ? + No colorways... + : <>} + {filters.map(filter => filter.id).includes(visibleSources) && ( + filters + .filter(filter => filter.id === visibleSources)[0].sources + .map(({ colorways, source, type }) => colorways.map((colorway: Colorway) => ({ ...colorway, sourceType: type, source: source, preset: colorway.preset || (colorway.isGradient ? "Gradient" : "Default") }))) + .flat() + .sort((a, b) => { + switch (sortBy) { + case SortOptions.NAME_AZ: + return a.name.localeCompare(b.name); + case SortOptions.NAME_ZA: + return b.name.localeCompare(a.name); + case SortOptions.SOURCE_AZ: + return a.source.localeCompare(b.source); + case SortOptions.SOURCE_ZA: + return b.source.localeCompare(a.source); + default: + return a.name.localeCompare(b.name); + } + }) + .map((color: Colorway) => { + var colors: Array = color.colors || [ + "accent", + "primary", + "secondary", + "tertiary", + ]; + return (color.name.toLowerCase().includes(searchValue.toLowerCase()) ? + + {({ onMouseEnter, onMouseLeave }) => { + return (
{ - e.stopPropagation(); - openModal((props) => ( - - )); + className={viewMode === "grid" ? "discordColorway" : `${radioBarItem} ${radioBarItemFilled} discordColorway-listItem`} + id={"colorway-" + color.name} + onMouseEnter={viewMode === "grid" ? onMouseEnter : () => { }} + onMouseLeave={viewMode === "grid" ? onMouseLeave : () => { }} + aria-checked={activeColorwayObject.id === color.name && activeColorwayObject.source === color.source} + onClick={async () => { + const [ + onDemandWays, + onDemandWaysTintedText, + onDemandWaysDiscordSaturation, + onDemandWaysOsAccentColor + ] = await DataStore.getMany([ + "onDemandWays", + "onDemandWaysTintedText", + "onDemandWaysDiscordSaturation", + "onDemandWaysOsAccentColor" + ]); + if (activeColorwayObject.id === color.name && activeColorwayObject.source === color.source) { + DataStore.set("activeColorwayObject", { id: null, css: null, sourceType: null, source: null }); + setActiveColorwayObject({ id: null, css: null, sourceType: null, source: null }); + ColorwayCSS.remove(); + } else { + if (onDemandWays) { + const demandedColorway = !color.isGradient ? generateCss( + colorToHex(color.primary), + colorToHex(color.secondary), + colorToHex(color.tertiary), + colorToHex(onDemandWaysOsAccentColor ? getComputedStyle(document.body).getPropertyValue("--os-accent-color") : color.accent).slice(0, 6), + onDemandWaysTintedText, + onDemandWaysDiscordSaturation, + undefined, + color.name + ) : gradientBase(colorToHex(onDemandWaysOsAccentColor ? getComputedStyle(document.body).getPropertyValue("--os-accent-color") : color.accent), onDemandWaysDiscordSaturation) + `:root:root {--custom-theme-background: linear-gradient(${color.linearGradient})}`; + ColorwayCSS.set(demandedColorway); + setActiveColorwayObject({ id: color.name, css: demandedColorway, sourceType: color.type, source: color.source }); + DataStore.set("activeColorwayObject", { id: color.name, css: demandedColorway, sourceType: color.type, source: color.source }); + } else { + ColorwayCSS.set(color["dc-import"]); + setActiveColorwayObject({ id: color.name, css: color["dc-import"], sourceType: color.type, source: color.source }); + DataStore.set("activeColorwayObject", { id: color.name, css: color["dc-import"], sourceType: color.type, source: color.source }); + } + } }} > - } +
+ {!color.isGradient ? colors.map((colorItm) =>
) :
} +
+
+ {(activeColorwayObject.id === color.name && activeColorwayObject.source === color.source && viewMode === "grid") && } +
+ {(showLabelsInSelectorGridView || viewMode === "list") && {color.name}} +
{ + e.stopPropagation(); + openModal((props) => ); + }} > - - + + + +
+ {viewMode === "list" && <> + + {({ onMouseEnter, onMouseLeave }) => } + + {({ onMouseEnter, onMouseLeave }) => } + + {color.sourceType === "offline" && + {({ onMouseEnter, onMouseLeave }) => } + } + }
-
- {!color.isGradient ? colors.map((colorItm) =>
) :
} -
- {currentColorway === color.name && } -
- ); - }} - - ); - }) + ); + }} + : <> + ); + }) )} + {!isSettings ? + + +