From 8d9062f90a5a1358e7efe37eb08b4717d7a66ff6 Mon Sep 17 00:00:00 2001 From: prism Date: Thu, 4 Dec 2025 18:27:42 +0100 Subject: [PATCH] feat(UrlHighlighter): add plugin (#535) * feat(UrlHighlighter): add plugin * Update index.tsx --------- Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com> --- src/equicordplugins/urlHighlighter/index.tsx | 149 ++++++++++++++++++ src/equicordplugins/urlHighlighter/styles.css | 47 ++++++ 2 files changed, 196 insertions(+) create mode 100644 src/equicordplugins/urlHighlighter/index.tsx create mode 100644 src/equicordplugins/urlHighlighter/styles.css diff --git a/src/equicordplugins/urlHighlighter/index.tsx b/src/equicordplugins/urlHighlighter/index.tsx new file mode 100644 index 000000000..ad525c9e5 --- /dev/null +++ b/src/equicordplugins/urlHighlighter/index.tsx @@ -0,0 +1,149 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import "./styles.css"; + +import { definePluginSettings } from "@api/Settings"; +import { classNameFactory } from "@api/Styles"; +import { Button } from "@components/Button"; +import ErrorBoundary from "@components/ErrorBoundary"; +import { Heading } from "@components/Heading"; +import { EquicordDevs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; +import { findComponentByCodeLazy } from "@webpack"; +import { ColorPicker, TextInput } from "@webpack/common"; + +interface PatternEntry { + pattern: string; + color: string; +} + +const DEFAULT_COLOR = "#eb7396"; + +const cl = classNameFactory("vc-url-hl-"); + +const TrashIcon = findComponentByCodeLazy("2.81h8.36a3"); +const PlusIcon = findComponentByCodeLazy("0v-5h5a1"); + +const hexToInt = (hex: string): number => parseInt(hex.replace("#", ""), 16); +const intToHex = (n: number): string => "#" + n.toString(16).padStart(6, "0"); + +const PatternsComponent = ErrorBoundary.wrap(() => { + const { patterns } = settings.store; + + return ( +
+ URL Patterns + {patterns.map((entry, i) => ( +
+ { + patterns[i].pattern = v; + settings.store.patterns = patterns; + }} + placeholder="*.example.com" + /> +
+ { + patterns[i].color = intToHex(c); + settings.store.patterns = patterns; + }} + showEyeDropper={false} + /> +
+ +
+ ))} + +
+ ); +}, { noop: true }); + +const settings = definePluginSettings({ + patterns: { + type: OptionType.COMPONENT, + description: "URL patterns to highlight using glob patterns.", + default: [] as PatternEntry[], + component: PatternsComponent + }, + boldUrls: { + type: OptionType.BOOLEAN, + description: "Make highlighted URLs bold.", + default: false + }, + highlightEmbeds: { + type: OptionType.BOOLEAN, + description: "Also highlight URLs in embed content.", + default: false + } +}); + +function globToRegex(glob: string): RegExp { + const escaped = glob + .replace(/[.+^${}()|[\]\\]/g, "\\$&") + .replace(/\*/g, ".*") + .replace(/\?/g, "."); + return new RegExp(escaped, "i"); +} + +function getMatchingPattern(url: string): PatternEntry | null { + for (const entry of settings.store.patterns) { + const pattern = entry.pattern.trim(); + if (!pattern) continue; + if (globToRegex(pattern).test(url)) return entry; + } + return null; +} + +export default definePlugin({ + name: "UrlHighlighter", + description: "Highlights URLs in messages that match your patterns.", + authors: [EquicordDevs.Prism], + settings, + + patches: [ + { + find: '"messageId","channelId"', + replacement: { + match: /,children:null!=\i\?\i:\i/, + replace: "$&,...$self.getProps(arguments[0])" + } + } + ], + + getProps(props: { href?: string; title?: string; }) { + if (!props.href) return {}; + if (!settings.store.highlightEmbeds && props.href !== props.title) return {}; + + const match = getMatchingPattern(props.href); + if (!match) return {}; + + return { + className: cl(settings.store.boldUrls ? "marked" : "highlight"), + style: { "--vc-url-hl-color": match.color } as React.CSSProperties + }; + } +}); diff --git a/src/equicordplugins/urlHighlighter/styles.css b/src/equicordplugins/urlHighlighter/styles.css new file mode 100644 index 000000000..6f70231b4 --- /dev/null +++ b/src/equicordplugins/urlHighlighter/styles.css @@ -0,0 +1,47 @@ +.vc-url-hl-highlight { + color: var(--vc-url-hl-color) !important; +} + +.vc-url-hl-marked { + color: var(--vc-url-hl-color) !important; + font-weight: 600; +} + +.vc-url-hl-pattern-wrapper { + display: grid; + grid-template-columns: 1fr auto auto; + gap: 8px; + align-items: center; + padding-bottom: 12px; +} + +.vc-url-hl-color-picker { + display: flex; + align-items: center; +} + +.vc-url-hl-color-picker [class^="swatch"] { + width: 32px; + height: 32px; + border-radius: 4px; +} + +.vc-url-hl-remove-button { + width: 36px !important; + height: 36px !important; + min-width: 36px !important; + min-height: 36px !important; + padding: 0 !important; + box-sizing: border-box; +} + +.vc-url-hl-add-button { + display: flex; + align-items: center; + gap: 2px; +} + +.vc-url-hl-icon { + width: 20px; + height: 20px; +}