parent
019c04c332
commit
83357c5dfa
5 changed files with 41 additions and 215 deletions
|
|
@ -17,9 +17,8 @@ import { useIntersection } from "@utils/react";
|
|||
import { Icon } from "@vencord/discord-types";
|
||||
import { Clickable, TextInput, useCallback, useEffect, useMemo, useState } from "@webpack/common";
|
||||
|
||||
import { getNameByIcon, IconsFinds } from "../names";
|
||||
import { IconsDef } from "../types";
|
||||
import { findAllIcons } from "../utils";
|
||||
import { getIconsModule } from "../utils";
|
||||
import { openIconModal } from "./Modals";
|
||||
|
||||
let cachedIcons: IconsDef | null = null;
|
||||
|
|
@ -27,10 +26,13 @@ let cachedIcons: IconsDef | null = null;
|
|||
function getIcons(): IconsDef {
|
||||
if (cachedIcons) return cachedIcons;
|
||||
|
||||
const allIcons = Array.from(new Set(findAllIcons()));
|
||||
const iconsModule = getIconsModule();
|
||||
cachedIcons = Object.fromEntries(
|
||||
allIcons.map((icon, idx) => [getNameByIcon(icon, String(idx)), icon])
|
||||
Object.entries(iconsModule).filter(([name, fn]) =>
|
||||
typeof fn === "function" && name.endsWith("Icon")
|
||||
)
|
||||
);
|
||||
|
||||
return cachedIcons;
|
||||
}
|
||||
|
||||
|
|
@ -47,11 +49,11 @@ function searchMatch(search: string, name: string, Icon: Icon, searchByFunction:
|
|||
}
|
||||
|
||||
function IconItem({ iconName, Icon }: { iconName: string; Icon: Icon; }) {
|
||||
const fill = iconName === "CircleShield" ? "var(--background-base-low)" : "var(--interactive-icon-default)";
|
||||
const fill = iconName === "CircleShieldIcon" ? "var(--background-base-low)" : "var(--interactive-icon-default)";
|
||||
|
||||
return (
|
||||
<div className="vc-icon-box">
|
||||
<Clickable onClick={() => openIconModal(iconName, Icon, IconsFinds[iconName])}>
|
||||
<Clickable onClick={() => openIconModal(iconName, Icon)}>
|
||||
<div className="vc-icon-container">
|
||||
<Icon className="vc-icon-icon" size="lg" width={32} height={32} color="var(--interactive-icon-default)" fill={fill} />
|
||||
</div>
|
||||
|
|
@ -107,7 +109,7 @@ function IconsTab() {
|
|||
return (
|
||||
<SettingsTab>
|
||||
<div className={classes(Margins.top16, "vc-icon-tab-search-bar-grid")}>
|
||||
<TextInput autoFocus value={searchInput} placeholder="Search for an icon..." onChange={onSearch} />
|
||||
<TextInput autoFocus value={searchInput} placeholder={`Search ${Object.keys(icons).length} icons...`} onChange={onSearch} />
|
||||
<TooltipContainer text="Search by function context">
|
||||
<Button
|
||||
size="small"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import { BaseText } from "@components/BaseText";
|
||||
import { Button } from "@components/Button";
|
||||
import { CodeBlock } from "@components/CodeBlock";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { HeadingSecondary } from "@components/Heading";
|
||||
import { Paragraph } from "@components/Paragraph";
|
||||
|
|
@ -25,6 +26,7 @@ import { saveFile } from "@utils/web";
|
|||
import { Icon } from "@vencord/discord-types";
|
||||
import { findComponentByCodeLazy } from "@webpack";
|
||||
import {
|
||||
Clickable,
|
||||
ContextMenuApi,
|
||||
createRoot,
|
||||
FluxDispatcher,
|
||||
|
|
@ -164,7 +166,7 @@ function saveIcon(iconName: string, icon: Element | string, color: number, size:
|
|||
img.src = `data:image/svg+xml;base64,${btoa(icon.outerHTML)}`;
|
||||
}
|
||||
|
||||
function OtherContextMenu({ iconName, Icon, color, findCode }: { iconName: string; Icon: Icon; color: number; findCode: string | null; }) {
|
||||
function OtherContextMenu({ iconName, Icon, color }: { iconName: string; Icon: Icon; color: number; }) {
|
||||
const colorData = cssColors[color];
|
||||
|
||||
const handleSave = (type: string) => {
|
||||
|
|
@ -224,15 +226,13 @@ function OtherContextMenu({ iconName, Icon, color, findCode }: { iconName: strin
|
|||
);
|
||||
}
|
||||
|
||||
function IconModal({ iconName, Icon, findPattern, onClose, transitionState }: { iconName: string; Icon: Icon; findPattern?: string; } & ModalProps) {
|
||||
function IconModal({ iconName, Icon, onClose, transitionState }: { iconName: string; Icon: Icon; } & ModalProps) {
|
||||
const [color, setColor] = useColorNavigation(209);
|
||||
const colorData = cssColors[color];
|
||||
const colorKeys = useMemo(() => getCssColorKeys(), []);
|
||||
|
||||
const fill = iconName === "CircleShield" ? "var(--background-base-low)" : colorData?.css;
|
||||
const findCode = findPattern
|
||||
? `const ${iconName}Icon = findComponentByCode(${JSON.stringify(findPattern)})`
|
||||
: null;
|
||||
const fill = iconName === "CircleShieldIcon" ? "var(--background-base-low)" : colorData?.css;
|
||||
const findCode = `const ${iconName} = findExportedComponentLazy("${iconName}")`;
|
||||
|
||||
const openColorMenu = (e: React.MouseEvent) => {
|
||||
ContextMenuApi.openContextMenu(e, () => <ColorContextMenu colorKeys={colorKeys} />);
|
||||
|
|
@ -249,7 +249,7 @@ function IconModal({ iconName, Icon, findPattern, onClose, transitionState }: {
|
|||
|
||||
const openOtherMenu = (e: React.MouseEvent) => {
|
||||
ContextMenuApi.openContextMenu(e, () => (
|
||||
<OtherContextMenu iconName={iconName} Icon={Icon} color={color} findCode={findCode} />
|
||||
<OtherContextMenu iconName={iconName} Icon={Icon} color={color} />
|
||||
));
|
||||
};
|
||||
|
||||
|
|
@ -288,12 +288,17 @@ function IconModal({ iconName, Icon, findPattern, onClose, transitionState }: {
|
|||
</TooltipContainer>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<div className="vc-ic-use-as">
|
||||
<BaseText size="md" weight="semibold">Usage</BaseText>
|
||||
<BaseText size="sm" color="text-muted">Click to copy</BaseText>
|
||||
</div>
|
||||
{/* for some reason i cant make this shit codeblock full width, FF 15 */}
|
||||
<Clickable className="vc-ic-codeblock-wrapper" onClick={() => copyWithToast(findCode, "Copied!")}>
|
||||
<CodeBlock content={findCode} lang="ts" />
|
||||
</Clickable>
|
||||
</ModalContent>
|
||||
<ModalFooter className="vc-ic-modal-footer">
|
||||
<Button variant="primary" onClick={() => copyWithToast(findCode ?? String(Icon), findCode ? "Find code copied!" : "Raw function copied!")}>
|
||||
{findCode ? "Copy" : "Copy Raw"}
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={openOtherMenu}>
|
||||
<Button variant="primary" onClick={openOtherMenu}>
|
||||
Actions
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
|
|
@ -301,8 +306,8 @@ function IconModal({ iconName, Icon, findPattern, onClose, transitionState }: {
|
|||
);
|
||||
}
|
||||
|
||||
export function openIconModal(iconName: string, Icon: Icon, findPattern?: string) {
|
||||
openModal(props => <IconModal iconName={iconName} Icon={Icon} findPattern={findPattern} {...props} />);
|
||||
export function openIconModal(iconName: string, Icon: Icon) {
|
||||
openModal(props => <IconModal iconName={iconName} Icon={Icon} {...props} />);
|
||||
}
|
||||
|
||||
export function SettingsAbout() {
|
||||
|
|
|
|||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Icon } from "@vencord/discord-types";
|
||||
|
||||
// name: pattern
|
||||
export const IconsFinds: Record<string, string> = {
|
||||
Discord: "1.6 5.64-2.87",
|
||||
XboxNeutral: "8.68-.62c.89-.81 1.5",
|
||||
PlaystationNeutral: "2.04Zm-9.35",
|
||||
TwitterNeutral: "M13.86 10.47", // even discord calls it twitter lmao
|
||||
InstagramNeutral: "4.12.07Zm.1 2c-",
|
||||
YoutubeNeutral: "11.5s0 3.95.5 5.85a3.",
|
||||
FacebookNeutral: "2.8V12h2.8V9",
|
||||
NintendoSwitchNeutral: "14V2.32c0",
|
||||
Pencil: "0-2.82 0l-1.38 1.38a1",
|
||||
AngleBrackets: "0-.4.8v1.98c0",
|
||||
NitroWheel: "2h3a1 1 0 1 1 0 2H5.5",
|
||||
Bill: "75.34.75.75C6 7.99 5 9",
|
||||
Chat: "2.2 22H12Z\",",
|
||||
ChatVoice: "22H12Zm2-5.26c0",
|
||||
ChatX: ".23.46-.48.47L12 22H2.",
|
||||
ChatSmile: "04-.61A10 10 0 1 1 22 ",
|
||||
ChatRetry: "14.07.3.09.44.04a7",
|
||||
ChatPlus: "1.24-.37V12a10 10 0 1 ",
|
||||
Bug: "1.1.27.1.37 0a6.66 6.6",
|
||||
B: "9V2.9c0-.5.4-.9.9-.9h7",
|
||||
Eye: "19.1 21 12 21c-7.11 0-",
|
||||
EyeSlash: "2.63-2.63c",
|
||||
EyePlus: "3.32ZM19 14a1 ",
|
||||
Heart: "0C9.43 20.48 1 15.09 1",
|
||||
Star: ".73-2.25h6.12l1.9-5.83Z",
|
||||
StarOutline: "3.1h5.26l1.62",
|
||||
StarShooting: "1.35l2.95 2.14",
|
||||
QrCode: "0v3ZM20",
|
||||
Friends: "12h1a8",
|
||||
PlusSmall: "0v-5h5a1",
|
||||
CircleQuestion: "10.58l-3.3-3.3a1",
|
||||
Pin: "1-.06-.63L6.16",
|
||||
PinUpright: "5H8v4.35l-3.39",
|
||||
PinUprightSlash: "1.56ZM11.08 ",
|
||||
ArrowsLeftRight: "18.58V3a1",
|
||||
XSmall: "13.42l5.3",
|
||||
XLarge: "13.42l7.3 7.3Z",
|
||||
XSmallBold: "12l4.94-4.94a1.5",
|
||||
XLargeBold: "12l6.94-6.94a1.5",
|
||||
Lock: "3Zm9-3v3H9V6a3",
|
||||
LockUnlocked: "1-1.33-1.5ZM14",
|
||||
Video: "1.45-.9V7.62a1",
|
||||
VideoSlash: "1.4l20-20ZM9.2",
|
||||
VideoLock: "1.32-.5V7.62a1",
|
||||
Fire: "14Zm9.26-.84a.57.57",
|
||||
Warning: "3.15H3.29c-1.74",
|
||||
Download: "1.42l3.3 3.3V3a1",
|
||||
Upload: "0ZM3 20a1 1",
|
||||
// QuestionMark: "0ZM5.5 7a1.5" Unknown name
|
||||
Quest: "10.47a.76.76",
|
||||
Play: "4.96v14.08c0",
|
||||
Emoji: " 0 0 0 0 22ZM6.5",
|
||||
Gif: "3H5Zm2.18 13.8",
|
||||
Trash: "2.81h8.36a3",
|
||||
Bell: "9.5v2.09c0",
|
||||
Screen: "0-3-3H5ZM13.5",
|
||||
ScreenArrow: "3V5Zm16",
|
||||
ScreenStream: " 2-2h3a2",
|
||||
ScreenSystemRequirements: "3V5Zm3", // a guess
|
||||
ScreenSlash: "5.8ZM17.15",
|
||||
ScreenX: "1-3-3V5Zm6.3.3a1",
|
||||
Plus: "0v8H3a1 1 0 1 0 0 2h8v8a1",
|
||||
Id: "15h2.04V7.34H6V17Zm4",
|
||||
Tv: "0-3-3H4ZM6 20a1",
|
||||
Crown: "1.18l.82.82-3.61",
|
||||
React: "04-4ZM16.96 4.08c",
|
||||
Camera: "1.34 1.71 1.34H20a3",
|
||||
Sticker: "1-.58.82l-4.24",
|
||||
StageX: "13.07-1.38ZM16.7",
|
||||
StageLock: "7.14-3.85ZM18.98",
|
||||
Stage: "20.03c-.25.72.12",
|
||||
ConnectionFine: "1 0 1 1-2 0A17 17 ",
|
||||
ConnectionAverage: "\"M3 7a1 1 0 0",
|
||||
ConnectionBad: "\"M2 13a1 1 0 0",
|
||||
ConnectionUnknown: "15.86-.6.9-.2.02",
|
||||
ChatWarning: ".54.5H2.2a1",
|
||||
ChatCheck: "22H12c.22",
|
||||
Hammer: "1.42ZM7.76",
|
||||
StickerSmall: "1-.5.5H7a4",
|
||||
StickerSad: "1.66-1.12 5.5",
|
||||
StickerDeny: "\"M21.76 14.83a", // a guess
|
||||
MagnifyingGlassPlus: "M11 7a1 1 0",
|
||||
MagnifyingGlassMinus: "3v12H5.5a1.5 1.5",
|
||||
// MagnifyingGlass: "???", // not quite possible
|
||||
ChatArrowRight: "2.43l.06",
|
||||
Bookmark: "1-1.67.74l",
|
||||
ChannelList: "1-1-1ZM2 8a1",
|
||||
ChannelListMagnifyingGlass: "2h18a1 1 0 1 0 0-2H3ZM2",
|
||||
Activities: "1h3a3 3 0 0 0 3-3Z\"",
|
||||
ActivitiesPlus: "14.35v1.29a",
|
||||
AnnouncementsLock: "1-2.46-1.28 3.86",
|
||||
AnnouncementsWarning: "1-2.46-1.28 3.85",
|
||||
Announcements: ".42.27.79.62",
|
||||
ShieldLock: "2.83v2.67a.5.5",
|
||||
ShieldUser: "9.77V6.75c0-.57.17",
|
||||
ShieldAt: "14.42-.35.75",
|
||||
Shield: "M4.27 5.22A2.66", // a guess
|
||||
Slash: "1-.43-.76L15.78",
|
||||
SlashBox: "0-3-3H5Zm12.79",
|
||||
Apps: "2.95H20a2 2 0",
|
||||
CheckmarkLarge: "1.4l-12 12a1",
|
||||
CheckmarkLargeBold: "2.12-2.12L9",
|
||||
CheckmarkSmallBold: "13.88l6.94-6.94a1.5",
|
||||
CheckmarkSmall: "1-1.4 0l-4-4a1",
|
||||
DoubleCheckmark: "1.4l4.5 4.5a1",
|
||||
NewUser: "0-.92h-.03a2", // a guess
|
||||
UserCheck: "0l1.8-1.8c.17",
|
||||
User: "2.9.06.24.26.",
|
||||
UserMinus: "3-3h5.02c.38",
|
||||
UserPlus: "2.07ZM12",
|
||||
UserPlay: "0-3.61-.71h-.94Z",
|
||||
UserBox: "0-3-3H5Zm10 6a3", // a guess
|
||||
Settings: "0ZM16 12a4",
|
||||
SettingsInfo: "10Zm1-4a1",
|
||||
Hashtag: "8 4.84a1", // a guess
|
||||
HashtagLocked: "2.02.31.03", // a guess
|
||||
HashtagWarning: "8h1.26Z", // a guess
|
||||
HashtagPlay: "52.88H9.85l", // a guess
|
||||
Flag: "5.85v7.3a2",
|
||||
Language: "5.43h3.85l",
|
||||
Lightbulb: "8.5ZM15.1 19c.5",
|
||||
Key: "23-.24ZM10 16a2",
|
||||
InBox: "3H5ZM4 5.5C4",
|
||||
BookmarkOutline: "0-1-1ZM7 2a3",
|
||||
Food: "7.58V8a1 1",
|
||||
CircleShield: "8 10.9999V17.9999C8"
|
||||
};
|
||||
|
||||
// 13l4.91-8.05a1.8
|
||||
|
||||
const namePatterns = new Map(Object.entries(IconsFinds));
|
||||
|
||||
export function getNameByIcon(Icon: Icon, defaultName: string) {
|
||||
for (const [name, pattern] of namePatterns) {
|
||||
if (String(Icon).includes(pattern)) {
|
||||
namePatterns.delete(name);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return defaultName;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
/* Icon grid */
|
||||
.vc-icons-tab-grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
|
||||
|
|
@ -13,7 +14,6 @@
|
|||
.vc-icon-container {
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
border: 3px solid transparent;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +22,6 @@
|
|||
}
|
||||
|
||||
.vc-icon-icon {
|
||||
color: var(--interactive-icon-default);
|
||||
transition: transform 0.15s ease, filter 0.15s ease;
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +34,6 @@
|
|||
font-size: 0.75rem;
|
||||
margin-top: 4px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 64px;
|
||||
|
|
@ -44,11 +42,10 @@
|
|||
.vc-icon-tab-search-bar-grid {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.vc-icon-tab-search-bar-grid > div:first-child {
|
||||
.vc-icon-tab-search-bar-grid>div:first-child {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
|
@ -56,32 +53,16 @@
|
|||
height: 32px;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.vc-ic-modal-header {
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
padding: 16px 16px 16px 24px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.vc-ic-modal-header-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.vc-ic-modal-header-trailing {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.vc-ic-modal-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.vc-ic-modal-main {
|
||||
|
|
@ -95,11 +76,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-image: repeating-linear-gradient(45deg,
|
||||
#ffffff1a 0,
|
||||
#ffffff1a 10px,
|
||||
#0000001a 10px,
|
||||
#0000001a 20px);
|
||||
background-image: repeating-linear-gradient(45deg, #ffffff1a 0, #ffffff1a 10px, #0000001a 10px, #0000001a 20px);
|
||||
border-radius: 8px;
|
||||
cursor: context-menu;
|
||||
}
|
||||
|
|
@ -123,18 +100,15 @@
|
|||
}
|
||||
|
||||
.vc-ic-modal-footer {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.vc-ic-use-as {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.vc-ic-unordered-list li {
|
||||
margin-left: 16px;
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
.vc-ic-modal-title {
|
||||
user-select: none;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
|
@ -4,13 +4,15 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { findAll, findByPropsLazy, waitFor } from "@webpack";
|
||||
import { Icon } from "@vencord/discord-types";
|
||||
import { findByPropsLazy, waitFor } from "@webpack";
|
||||
|
||||
import { CssColorData, IconSize } from "./types";
|
||||
|
||||
let colorKeys: string[] = [];
|
||||
|
||||
const Colors = findByPropsLazy("colors", "layout");
|
||||
const IconsModule = findByPropsLazy("AngleBracketsIcon", "StaffBadgeIcon") as Record<string, Icon>;
|
||||
|
||||
export const iconSizesInPx: Record<string, number> = findByPropsLazy("md", "lg", "xxs");
|
||||
export const iconSizes: IconSize[] = ["xxs", "xs", "sm", "md", "lg"];
|
||||
|
|
@ -35,14 +37,8 @@ export const cssColors = new Proxy({} as Record<number, CssColorData>, {
|
|||
}
|
||||
});
|
||||
|
||||
export function findAllIcons() {
|
||||
return findAll(m => {
|
||||
if (typeof m !== "function") return false;
|
||||
const str = m.toString?.() ?? "";
|
||||
if (str.includes("direction:")) return false;
|
||||
if (str.includes('viewBox:"0 0 272 143"')) return false;
|
||||
return str.includes("viewBox:") && str.includes("color:") && (str.includes("foreground:") || str.includes("colorClass:"));
|
||||
});
|
||||
export function getIconsModule(): Record<string, Icon> {
|
||||
return IconsModule;
|
||||
}
|
||||
|
||||
waitFor(["colors", "layout"], m => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue