/* * Vencord, a Discord client mod * Copyright (c) 2026 Vendicated and contributors * SPDX-License-Identifier: GPL-3.0-or-later */ import "../settings.css"; import { Card } from "@components/Card"; import { Heading } from "@components/Heading"; import { Paragraph } from "@components/Paragraph"; import { findComponentByCodeLazy } from "@webpack"; import { ColorPicker, Slider } from "@webpack/common"; import type { ComponentProps, ComponentType, JSX, ReactNode } from "react"; import { q } from "../utils/ui"; export function SettingsCard({ children }: { children: ReactNode; }): JSX.Element { return ( {children} ); } export function SettingsHeader({ children }: { children: ReactNode; }): JSX.Element { return ( {children} ); } export function SettingsSubheader({ children, className }: { children: ReactNode; className?: string | string[]; }): JSX.Element { return ( {children} ); } export function SettingsDescription({ children }: { children: ReactNode; }): JSX.Element { return ( {children} ); } export function SettingsParagraph({ children, className }: { children: ReactNode; className?: string | string[]; }): JSX.Element { return ( {children} ); } function withDimmedClass(className: string | string[] | undefined, dimmed: boolean): string | string[] | undefined { if (!dimmed) return className; return [ ...(Array.isArray(className) ? className : [className]), "dimmed-settings-item", ].filter(c => c !== undefined); } export function SettingsNotice({ children, className }: { children: ReactNode; className?: string | string[]; }): JSX.Element { return ( {children} ); } export interface SettingsRowProps { children: ReactNode; className?: string | string[]; } export function SettingsRow({ children, className }: SettingsRowProps): JSX.Element { return (
{children}
); } export interface SettingsRowItemProps { children: ReactNode; className?: string | string[]; width?: "fill" | "content"; } export function SettingsRowItem({ children, className, width = "fill", }: SettingsRowItemProps): JSX.Element { return (
{children}
); } export interface ManaSelectOption { id: string; value: string; label: string; disabled?: boolean; } export interface ManaSelectFormattedOption extends ManaSelectOption { description?: ReactNode; leading?: ReactNode; trailing?: ReactNode; } export interface ManaSelectProps { options: ManaSelectOption[]; value?: string | string[] | null; onSelectionChange?: (value: string | string[] | null) => void; selectionMode?: "single" | "multiple"; placeholder?: string; disabled?: boolean; readOnly?: boolean; clearable?: boolean; fullWidth?: boolean; autoFocus?: boolean; closeOnSelect?: boolean; shouldFocusWrap?: boolean; maxOptionsVisible?: number; wrapTags?: boolean; formatOption?: (option: ManaSelectOption) => ManaSelectFormattedOption; name?: string; form?: string; autoComplete?: string; label?: string; required?: boolean; } export const ManaSelect = findComponentByCodeLazy('"data-mana-component":"select"') as React.ComponentType; export interface SettingsSelectProps extends Omit { label: ReactNode; className?: string | string[]; labelClassName?: string | string[]; selectClassName?: string | string[]; tooltip?: { position: "top" | "bottom", text: string; wider?: boolean; }; } export function SettingsSelect({ label, className, labelClassName, selectClassName, tooltip, ...props }: SettingsSelectProps): JSX.Element { const selectElement = (
{label}
); if (tooltip) { return ( {selectElement} ); } return selectElement; } type ColorPickerWithOnCloseProps = ComponentProps & { onClose?: () => void; }; function ColorPickerWithOnClose(props: ColorPickerWithOnCloseProps): JSX.Element { const LiveColorPicker = ColorPicker as ComponentType; return ; } export interface SettingsColorPickerProps extends ColorPickerWithOnCloseProps { className?: string | string[]; label?: ReactNode; labelClassName?: string | string[]; } export function SettingsColorPicker({ className, label, labelClassName, ...props }: SettingsColorPickerProps): JSX.Element { return ( <> {label != null && {label}}
); } export interface SettingsSliderProps { className?: string | string[]; disabled?: boolean; label: ReactNode; labelClassName?: string | string[]; maxValue?: number; minValue?: number; onChange: (value: number) => void; sliderClassName?: string | string[]; value: number; } export function SettingsSlider({ className, disabled, label, labelClassName, maxValue = 100, minValue = 0, onChange, sliderClassName, value, }: SettingsSliderProps): JSX.Element { return (
{label}
); } interface SwitchWithLabelProps { checked: boolean; onChange?: (checked: boolean) => void; disabled?: boolean; label?: string; description?: string; } interface SettingsSwitchLayoutProps extends SwitchWithLabelProps { bottomSpacing?: "5" | "10" | "15"; topSpacing?: "5" | "10" | "15"; className?: string | string[]; tooltip?: { position: "top" | "bottom", text: string; }; } const SwitchWithLabel = findComponentByCodeLazy("switchIconsEnabled:", ".hasIcon?") as React.ComponentType; export type SettingsSubtleSwitchProps = Omit; export function SettingsSubtleSwitch(props: SettingsSubtleSwitchProps): JSX.Element { const switchElement = (
); if (props.tooltip) { return ( {switchElement} ); } return switchElement; } export const TooltipPositions = ["top", "bottom", "left", "right"] as const; export type TooltipPosition = typeof TooltipPositions[number]; export const TooltipAligns = ["start", "center", "end"] as const; export type TooltipAlign = typeof TooltipAligns[number]; export const TooltipColors = ["primary", "grey", "brand", "green", "red"] as const; export type TooltipColor = typeof TooltipColors[number]; export interface ManaTooltipProps { text: string | (() => React.ReactNode); position?: TooltipPosition; align?: TooltipAlign; color?: TooltipColor; spacing?: number; hideOnClick?: boolean; delay?: number; forceOpen?: boolean; shouldShow?: boolean; allowOverflow?: boolean; overflowOnly?: boolean; clickableOnMobile?: boolean; disableTooltipPointerEvents?: boolean; targetElementRef?: React.RefObject; tooltipClassName?: string; tooltipStyle?: React.CSSProperties; tooltipContentClassName?: string; tooltipPointerClassName?: string; positionKeyStemOverride?: string; onTooltipShow?: () => void; onTooltipHide?: () => void; onAnimationRest?: () => void; "aria-label"?: string | false; children: (props: Record) => React.ReactNode; } export const ManaTooltip = findComponentByCodeLazy("VoidTooltip cannot find DOM node") as React.ComponentType; function SettingsTooltip({ children, position, text, wider, className }: { children: ReactNode; position: "top" | "bottom"; text: string; wider?: boolean; className?: string | string[]; }): JSX.Element { return (
{tooltipProps =>
{children}
}
); } export const ManaButtonVariants = ["primary", "secondary", "critical-primary", "critical-secondary", "active", "overlay-primary", "overlay-secondary", "expressive"] as const; export type ManaButtonVariant = typeof ManaButtonVariants[number]; export const ManaButtonSizes = ["xs", "sm", "md"] as const; export type ManaButtonSize = typeof ManaButtonSizes[number]; export interface ManaButtonProps { text?: string; variant?: ManaButtonVariant; size?: ManaButtonSize; disabled?: boolean; fullWidth?: boolean; onClick?: (e: React.MouseEvent) => void; style?: React.CSSProperties; } export const ManaButton = findComponentByCodeLazy('"data-mana-component":"button"') as React.ComponentType;