Equicord/src/components/settings/OnlineThemeCard.tsx

137 lines
4.8 KiB
TypeScript
Raw Normal View History

2025-08-24 13:53:09 -04:00
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import "./AddonCard.css";
import { Badge } from "@components/Badge";
2025-10-11 21:50:14 -04:00
import { BaseText } from "@components/BaseText";
2025-10-02 19:12:43 -04:00
import { Switch } from "@components/settings";
2025-12-19 21:32:50 -05:00
import { classNameFactory } from "@utils/css";
feat(i18n): Add translation keys and implement localization for 80+ p… (#772) * feat(i18n): Add translation keys and implement localization for 80+ plugins - Add comprehensive translation keys to i18n/en-US/vencord.json - Update all plugins to use t() function from @utils/translation - Replace hardcoded strings with translation function calls - Support plural forms with _one/_other suffixes - Use Translate component for strings with embedded JSX Plugins translated include: - Core: reviewDB, translate, voiceMessages, messageLogger - UI: showHiddenChannels, customRPC, clientTheme, permissionsViewer - Utility: betterSessions, betterSettings, memberCount, betterFolders - Social: relationshipNotifier, messageLatency, whoReacted - Media: imageZoom, viewIcons, viewRaw, decor, fakeNitro - And 60+ more plugins All changes pass TypeScript compilation. * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * feat(i18n): Add equicord.json for equicordplugins localization - Create i18n/en-US/equicord.json with messageLoggerEnhanced translation keys - Create empty equicord.json files for all other locales (Crowdin will handle translations) - Build system automatically picks up all JSON files in i18n/{locale}/ * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * feat(i18n): Add translations to 200 equicordplugins - Translate all user-facing strings in equicordplugins to use t() function - Add translation keys to i18n/en-US/equicord.json - Plugin names remain static strings for build system compatibility - Settings descriptions, tooltips, context menus, and UI strings now translatable * FileUpload: add sharex file support (#771) * FileUpload: add sharex file support Quick note, the settings seem to split pacal case with spaces for some reason, so `ShareX` renders as `Share X`. This is stupid and im upset and I dont think theres anything I can do about it * FileUpload: use Headers object to construct HTTP headers * Update vencord.json --------- Co-authored-by: Mishal <91066601+mishalhossin@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Key <keircn@proton.me> Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
2026-02-15 20:39:58 +06:00
import { t } from "@utils/translation";
2025-10-11 21:50:14 -04:00
import { useRef } from "@webpack/common";
2025-08-24 13:53:09 -04:00
import type { MouseEventHandler, ReactNode } from "react";
import { EditableText } from "./EditableText";
import { useTruncatedText } from "./tabs/plugins/components/truncateText";
const cl = classNameFactory("vc-addon-");
interface Props {
name: ReactNode;
description: ReactNode;
enabled: boolean;
setEnabled: (enabled: boolean) => void;
disabled?: boolean;
isNew?: boolean;
onMouseEnter?: MouseEventHandler<HTMLDivElement>;
onMouseLeave?: MouseEventHandler<HTMLDivElement>;
infoButton?: ReactNode;
footer?: ReactNode;
author?: ReactNode;
customName?: string;
customDescription?: string;
onEditName?: (newName: string) => void;
onEditDescription?: (newDescription: string) => void;
}
export function OnlineThemeCard({
disabled,
isNew,
name,
infoButton,
footer,
author,
enabled,
setEnabled,
description,
onMouseEnter,
onMouseLeave,
customName,
onEditName,
}: Props) {
const titleRef = useRef<HTMLDivElement>(null);
const titleContainerRef = useRef<HTMLDivElement>(null);
const { truncated, containerRef } = useTruncatedText(description ? description.toString() : "");
return (
<div
className={cl("card", { "card-disabled": disabled })}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<div className={cl("header")}>
<div className={cl("name-author")}>
2025-10-11 21:50:14 -04:00
<BaseText size="md" weight="bold" className={cl("name")}>
2025-08-24 13:53:09 -04:00
<div ref={titleContainerRef} className={cl("title-container")}>
<div
ref={titleRef}
className={cl("title")}
onMouseOver={() => {
const title = titleRef.current!;
const titleContainer = titleContainerRef.current!;
title.style.setProperty("--offset", `${titleContainer.clientWidth - title.scrollWidth}px`);
title.style.setProperty("--duration", `${Math.max(0.5, (title.scrollWidth - titleContainer.clientWidth) / 7)}s`);
}}
>
{onEditName ? (
<EditableText
value={customName || (name ? name.toString() : "")}
onChange={onEditName}
className={cl("editable")}
/>
) : (
customName || name
)}
</div>
</div>
2026-02-11 18:22:26 -05:00
{isNew && <Badge text={t("vencord.addonCard.new")} variant="danger" />}
2025-10-11 21:50:14 -04:00
</BaseText>
2025-08-24 13:53:09 -04:00
{!!author && (
<BaseText size="md" color="text-subtle" className={cl("author")}>
2025-08-24 13:53:09 -04:00
{author}
2025-10-11 21:50:14 -04:00
</BaseText>
2025-08-24 13:53:09 -04:00
)}
</div>
{infoButton}
<Switch
checked={enabled}
onChange={setEnabled}
disabled={disabled}
/>
</div>
<div
ref={containerRef}
className={cl("note")}
style={{ lineHeight: "1.25em", fontSize: "small" }}
title={description ? description.toString() : ""}
>
{truncated}
</div>
{footer && <div className={cl("footer")}>{footer}</div>}
2025-08-24 13:53:09 -04:00
</div>
);
}