diff --git a/src/plugins/characterCounter/README.md b/src/plugins/characterCounter/README.md new file mode 100644 index 000000000..7064707ee --- /dev/null +++ b/src/plugins/characterCounter/README.md @@ -0,0 +1,7 @@ +# Character Counter + +Adds a character counter to the message input box + +![](https://github.com/user-attachments/assets/57f8c01e-a122-46d2-afda-679edb7a996b) + +![](https://github.com/user-attachments/assets/640bcca4-77a3-4407-8aa0-15c490dd9256) diff --git a/src/plugins/characterCounter/index.tsx b/src/plugins/characterCounter/index.tsx new file mode 100644 index 000000000..209924bc2 --- /dev/null +++ b/src/plugins/characterCounter/index.tsx @@ -0,0 +1,74 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import "./style.css"; + +import { definePluginSettings } from "@api/Settings"; +import ErrorBoundary from "@components/ErrorBoundary"; +import { Devs } from "@utils/constants"; +import { classNameFactory } from "@utils/css"; +import definePlugin, { OptionType } from "@utils/types"; +import { UserStore } from "@webpack/common"; + +const cl = classNameFactory("vc-charCounter-"); + +const settings = definePluginSettings({ + colorEffects: { + type: OptionType.BOOLEAN, + description: "Enable yellow/red colouring as you get closer to the character limit", + default: true, + } +}); + +function getCounterColor(percentage: number) { + if (!settings.store.colorEffects) return "var(--primary-330)"; + if (percentage < 50) return "var(--text-muted)"; + if (percentage < 75) return "var(--yellow-330)"; + if (percentage < 90) return "var(--orange-330)"; + return "var(--red-360)"; +} + +export default definePlugin({ + name: "CharacterCounter", + description: "Adds a character counter to the chat input", + authors: [Devs.thororen], + settings, + patches: [ + { + find: ".CREATE_FORUM_POST||", + replacement: [ + { + match: /(?<=textValue:(\i),editorHeight:\i,channelId:\i\.id\}\)),\i/, + replace: ",$self.renderCharCounter({text:$1})" + } + ] + }, + { + find: "#{intl::PREMIUM_MESSAGE_LENGTH_UPSELL_TOOLTIP}", + replacement: { + match: /return \i\?\i\(\):\i\(\)(?<=#{intl::PREMIUM_MESSAGE_LENGTH_UPSELL_TOOLTIP_WITHOUT_LINK}.{0,200}?)/, + replace: "return null" + } + } + ], + + renderCharCounter: ErrorBoundary.wrap(({ text }: { text: string; }) => { + if (!text.length) return null; + + const premiumType = UserStore.getCurrentUser().premiumType ?? 0; + const charMax = premiumType === 2 ? 4000 : 2000; + + const color = getCounterColor((text.length / charMax) * 100); + + return ( +
+ {text.length} + / + {charMax} +
+ ); + }, { noop: true }) +}); diff --git a/src/plugins/characterCounter/style.css b/src/plugins/characterCounter/style.css new file mode 100644 index 000000000..072d42bef --- /dev/null +++ b/src/plugins/characterCounter/style.css @@ -0,0 +1,15 @@ +.vc-charCounter-counter { + font-size: 12px; + color: var(--text-muted); + position: absolute; + bottom: 4px; + right: 11px; + pointer-events: none; + z-index: 2; + background: transparent; + transition: color 0.3s ease; +} + +.vc-charCounter-count { + transition: color 0.3s ease; +} \ No newline at end of file