/* * Vencord, a Discord client mod * Copyright (c) 2023 Vendicated and contributors * SPDX-License-Identifier: GPL-3.0-or-later */ import { Settings, useSettings } from "@api/Settings"; import { Flex } from "@components/Flex"; import { CopyIcon, PasteIcon, ResetIcon } from "@components/Icons"; import { copyWithToast } from "@utils/misc"; import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot } from "@utils/modal"; import { showToast, Text, Toasts, Tooltip } from "@webpack/common"; import { type ReactNode } from "react"; import { UserstyleHeader } from "usercss-meta"; import { SettingBooleanComponent, SettingColorComponent, SettingNumberComponent, SettingRangeComponent, SettingSelectComponent, SettingTextComponent } from "./components"; interface UserCSSSettingsModalProps { modalProps: ModalProps; theme: UserstyleHeader; onSettingsReset: () => void; } function ExportButton({ themeSettings }: { themeSettings: Settings["userCssVars"][""]; }) { return {({ onMouseLeave, onMouseEnter }) => (
{ copyWithToast(JSON.stringify(themeSettings), "Copied theme settings to clipboard."); }}>
)}
; } function ImportButton({ themeSettings }: { themeSettings: Settings["userCssVars"][""]; }) { return {({ onMouseLeave, onMouseEnter }) => (
{ const clip = (await navigator.clipboard.read())[0]; if (!clip) return showToast("Your clipboard is empty.", Toasts.Type.FAILURE); if (!clip.types.includes("text/plain")) return showToast("Your clipboard doesn't have valid settings data.", Toasts.Type.FAILURE); try { var potentialSettings: Record = JSON.parse(await clip.getType("text/plain").then(b => b.text())); } catch (e) { return showToast("Your clipboard doesn't have valid settings data.", Toasts.Type.FAILURE); } for (const [key, value] of Object.entries(potentialSettings)) { if (Object.prototype.hasOwnProperty.call(themeSettings, key)) themeSettings[key] = value; } showToast("Pasted theme settings from clipboard.", Toasts.Type.SUCCESS); }}>
)}
; } interface ResetButtonProps { themeSettings: Settings["userCssVars"]; themeId: string; close: () => void; onReset: () => void; } function ResetButton({ themeSettings, themeId, close, onReset }: ResetButtonProps) { return {({ onMouseLeave, onMouseEnter }) => (
{ await close(); // close the modal first to stop rendering delete themeSettings[themeId]; onReset(); }}>
)}
; } export function UserCSSSettingsModal({ modalProps, theme, onSettingsReset }: UserCSSSettingsModalProps) { // @ts-expect-error UseSettings<> can't determine this is a valid key const { userCssVars } = useSettings(["userCssVars"], false); const themeVars = userCssVars[theme.id]; const controls: ReactNode[] = []; for (const [name, varInfo] of Object.entries(theme.vars)) { switch (varInfo.type) { case "text": { controls.push( ); break; } case "checkbox": { controls.push( ); break; } case "color": { controls.push( ); break; } case "number": { controls.push( ); break; } case "select": { controls.push( ); break; } case "range": { controls.push( ); break; } } } return ( Settings for {theme.name} {controls} ); }