/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import { Settings, useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { Flex } from "@components/Flex";
import { Link } from "@components/Link";
import { Margins } from "@utils/margins";
import { classes, identity } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
import { showItemInFolder } from "@utils/native";
import { LazyComponent, useAwaiter } from "@utils/react";
import type { ThemeHeader } from "@utils/themes";
import { getThemeInfo, stripBOM, type UserThemeHeader } from "@utils/themes/bd";
import { usercssParse } from "@utils/themes/usercss";
import { find, findByCodeLazy, findByPropsLazy, findLazy } from "@webpack";
import { Button, Card, ComponentTypes, FluxDispatcher, Forms, Popout, React, Select, showToast, Slider, Switch, TabBar, Text, TextArea, TextInput, useEffect, useRef, useState } from "@webpack/common";
import type { ComponentType, ReactNode, Ref, SyntheticEvent } from "react";
import type { UserstyleHeader } from "usercss-meta";
import { AddonCard } from "./AddonCard";
import { SettingsTab, wrapTab } from "./shared";
type FileInput = ComponentType<{
ref: Ref;
onChange: (e: SyntheticEvent) => void;
multiple?: boolean;
filters?: { name?: string; extensions: string[]; }[];
}>;
interface ColorPickerProps {
value: number | null;
showEyeDropper?: boolean;
onChange(value: number | null): void;
onClose?(): void;
}
const ColorPickerModal = LazyComponent(() => find(m => m?.type?.toString?.().includes(".showEyeDropper")));
const InviteActions = findByPropsLazy("resolveInvite");
const TrashIcon = findByCodeLazy("M5 6.99902V18.999C5 20.101 5.897 20.999");
const CogWheel = findByCodeLazy("18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069");
const FileInput: FileInput = findByCodeLazy("activateUploadDialogue=");
// TinyColor is completely unmangled and it's duplicated in two modules! Fun!
const TinyColor: tinycolor.Constructor = findByCodeLazy("this._gradientType=");
const TextAreaProps = findLazy(m => typeof m.textarea === "string");
const cl = classNameFactory("vc-settings-theme-");
function Validator({ link }: { link: string; }) {
const [res, err, pending] = useAwaiter(() => fetch(link).then(res => {
if (res.status > 300) throw `${res.status} ${res.statusText}`;
const contentType = res.headers.get("Content-Type");
if (!contentType?.startsWith("text/css") && !contentType?.startsWith("text/plain"))
throw "Not a CSS file. Remember to use the raw link!";
return "Okay!";
}));
const text = pending
? "Checking..."
: err
? `Error: ${err instanceof Error ? err.message : String(err)}`
: "Valid!";
return {text};
}
function Validators({ themeLinks }: { themeLinks: string[]; }) {
if (!themeLinks.length) return null;
return (
<>
ValidatorThis section will tell you whether your themes can successfully be loaded