feat: @vc-requiredPlugins

This commit is contained in:
Lewis Crichton 2023-10-16 22:53:37 +01:00
parent b7cdb96e09
commit b6547b463b
No known key found for this signature in database
4 changed files with 68 additions and 6 deletions

View file

@ -255,3 +255,21 @@ export function DeleteIcon(props: IconProps) {
</Icon> </Icon>
); );
} }
/**
* A plugin icon, created by CorellanStoma. https://github.com/CreArts-Community/Settings-Icons
*/
export function PluginIcon(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-plugin-icon")}
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7s2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"
/>
</Icon>
);
}

View file

@ -21,7 +21,7 @@ import "./themesStyles.css";
import { Settings, useSettings } from "@api/Settings"; import { Settings, useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles"; import { classNameFactory } from "@api/Styles";
import { Flex } from "@components/Flex"; import { Flex } from "@components/Flex";
import { CogWheel, DeleteIcon } from "@components/Icons"; import { CogWheel, DeleteIcon, PluginIcon } from "@components/Icons";
import { Link } from "@components/Link"; import { Link } from "@components/Link";
import { AddonCard } from "@components/VencordSettings/AddonCard"; import { AddonCard } from "@components/VencordSettings/AddonCard";
import { SettingsTab, wrapTab } from "@components/VencordSettings/shared"; import { SettingsTab, wrapTab } from "@components/VencordSettings/shared";
@ -34,10 +34,11 @@ import type { ThemeHeader } from "@utils/themes";
import { getThemeInfo, stripBOM, type UserThemeHeader } from "@utils/themes/bd"; import { getThemeInfo, stripBOM, type UserThemeHeader } from "@utils/themes/bd";
import { usercssParse } from "@utils/themes/usercss"; import { usercssParse } from "@utils/themes/usercss";
import { findByCodeLazy, findByPropsLazy, findLazy } from "@webpack"; import { findByCodeLazy, findByPropsLazy, findLazy } from "@webpack";
import { Button, Card, FluxDispatcher, Forms, React, showToast, TabBar, TextArea, useEffect, useRef, useState } from "@webpack/common"; import { Button, Card, FluxDispatcher, Forms, React, showToast, TabBar, TextArea, Tooltip, useEffect, useMemo, useRef, useState } from "@webpack/common";
import type { ComponentType, Ref, SyntheticEvent } from "react"; import { type ComponentType, type Ref, type SyntheticEvent } from "react";
import type { UserstyleHeader } from "usercss-meta"; import type { UserstyleHeader } from "usercss-meta";
import { isPluginEnabled } from "../../plugins";
import { UserCSSSettingsModal } from "./UserCSSModal"; import { UserCSSSettingsModal } from "./UserCSSModal";
type FileInput = ComponentType<{ type FileInput = ComponentType<{
@ -118,6 +119,9 @@ interface UserCSSCardProps {
} }
function UserCSSThemeCard({ theme, enabled, onChange, onDelete }: UserCSSCardProps) { function UserCSSThemeCard({ theme, enabled, onChange, onDelete }: UserCSSCardProps) {
const missingPlugins = useMemo(() =>
theme.requiredPlugins?.filter(p => !isPluginEnabled(p)), [theme]);
return ( return (
<AddonCard <AddonCard
name={theme.name ?? "Unknown"} name={theme.name ?? "Unknown"}
@ -127,6 +131,19 @@ function UserCSSThemeCard({ theme, enabled, onChange, onDelete }: UserCSSCardPro
setEnabled={onChange} setEnabled={onChange}
infoButton={ infoButton={
<> <>
{missingPlugins && missingPlugins.length > 0 && (
<Tooltip text={"The following plugins are required, but aren't enabled: " + missingPlugins.join(", ")}>
{({ onMouseLeave, onMouseEnter }) => (
<div
style={{ color: "var(--status-warning" }}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<PluginIcon />
</div>
)}
</Tooltip>
)}
{theme.vars && ( {theme.vars && (
<div style={{ cursor: "pointer" }} onClick={ <div style={{ cursor: "pointer" }} onClick={
() => openModal(modalProps => () => openModal(modalProps =>

View file

@ -10,16 +10,22 @@ import { parse as originalParse, UserstyleHeader } from "usercss-meta";
const UserCSSLogger = new Logger("UserCSS", "#d2acf5"); const UserCSSLogger = new Logger("UserCSS", "#d2acf5");
export async function usercssParse(text: string, fileName: string): Promise<UserstyleHeader> { export async function usercssParse(text: string, fileName: string): Promise<UserstyleHeader> {
var { metadata, errors } = originalParse(text.replace(/\r/g, ""), { allowErrors: true }); const { metadata, errors } = originalParse(text.replace(/\r/g, ""), {
allowErrors: true,
unknownKey: "assign"
});
if (errors.length) { if (errors.length) {
UserCSSLogger.warn("Parsed", fileName, "with errors:", errors); UserCSSLogger.warn("Parsed", fileName, "with errors:", errors);
} }
const requiredPlugins = metadata["vc-requiredPlugins"]?.split(",").map(p => p.trim());
return { return {
...metadata, ...metadata,
fileName, fileName,
id: await getUserCssId(metadata) id: await getUserCssId(metadata),
requiredPlugins
}; };
} }

View file

@ -55,6 +55,14 @@ declare module "usercss-meta" {
*/ */
fileName: string; fileName: string;
/**
* The required plugins for this style.
*
* @vencord Specific to Vencord, not part of the original module.
* @see {@link vc-requiredPlugins}
*/
requiredPlugins?: string[];
/** /**
* The name of your style. * The name of your style.
* *
@ -107,7 +115,20 @@ declare module "usercss-meta" {
* A list of variables the style defines. * A list of variables the style defines.
*/ */
vars: Record<string, UserCSSVariable>; vars: Record<string, UserCSSVariable>;
/**
* Required plugins for this style to work. Comma-separated list of plugin names.
*
* @vencord This is a Vencord-specific extension, however we wish for this to become a standard for client mods
* to implement, hence the more generic namespaced name.
*/
"vc-requiredPlugins"?: string;
} }
export function parse(text: string, options: { allowErrors: boolean; }): { metadata: UserstyleHeader; errors: { code: string; args: any; }[]; }; type UserCSSParseOptions = {
allowErrors: boolean;
unknownKey: "assign";
};
export function parse(text: string, options: UserCSSParseOptions): { metadata: UserstyleHeader; errors: { code: string; args: any; }[]; };
} }