mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: updating translations
This commit is contained in:
commit
730184de77
14 changed files with 110 additions and 99 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "hydralauncher",
|
"name": "hydralauncher",
|
||||||
"version": "3.1.5",
|
"version": "3.2.0",
|
||||||
"description": "Hydra",
|
"description": "Hydra",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "Los Broxas",
|
"author": "Los Broxas",
|
||||||
|
|
|
@ -311,7 +311,7 @@
|
||||||
"web_store": "Web store",
|
"web_store": "Web store",
|
||||||
"clear_themes": "Clear",
|
"clear_themes": "Clear",
|
||||||
"add_theme": "Add",
|
"add_theme": "Add",
|
||||||
"add_theme_modal_title": "Add custom theme",
|
"add_theme_modal_title": "Create custom theme",
|
||||||
"add_theme_modal_description": "Create a new theme to customize Hydra's appearance",
|
"add_theme_modal_description": "Create a new theme to customize Hydra's appearance",
|
||||||
"theme_name": "Name",
|
"theme_name": "Name",
|
||||||
"insert_theme_name": "Insert theme name",
|
"insert_theme_name": "Insert theme name",
|
||||||
|
|
|
@ -294,6 +294,26 @@
|
||||||
"subscription_renew_cancelled": "A renovação automática está desativada",
|
"subscription_renew_cancelled": "A renovação automática está desativada",
|
||||||
"subscription_renews_on": "Sua assinatura renova dia {{date}}",
|
"subscription_renews_on": "Sua assinatura renova dia {{date}}",
|
||||||
"bill_sent_until": "Sua próxima cobrança será enviada até esse dia",
|
"bill_sent_until": "Sua próxima cobrança será enviada até esse dia",
|
||||||
|
"no_themes": "Parace que você ainda não tem nenhum tema. Não se preocupe, clique aqui para criar sua primeira obra de arte.",
|
||||||
|
"editor_tab_code": "Código",
|
||||||
|
"editor_tab_info": "Info",
|
||||||
|
"editor_tab_save": "Salvar",
|
||||||
|
"web_store": "Loja de temas",
|
||||||
|
"clear_themes": "Limpar",
|
||||||
|
"add_theme": "Adicionar",
|
||||||
|
"add_theme_modal_title": "Criar tema customizado",
|
||||||
|
"add_theme_modal_description": "Criar novo tema para customizar a aparência do Hydra",
|
||||||
|
"theme_name": "Nome",
|
||||||
|
"insert_theme_name": "Insira o nome do tema",
|
||||||
|
"set_theme": "Habilitar tema",
|
||||||
|
"unset_theme": "Desabilitar tema",
|
||||||
|
"delete_theme": "Deletar tema",
|
||||||
|
"edit_theme": "Editar tema",
|
||||||
|
"delete_all_themes": "Deletar todos os temas",
|
||||||
|
"delete_all_themes_description": "Isso irá deletar todos os seus temas",
|
||||||
|
"delete_theme_description": "Isso irá deletar o tema {{theme}}",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"appearance": "Aparência",
|
||||||
"enable_torbox": "Habilitar Torbox",
|
"enable_torbox": "Habilitar Torbox",
|
||||||
"torbox_description": "TorBox é o seu serviço de seedbox premium que rivaliza até com os melhores servidores do mercado.",
|
"torbox_description": "TorBox é o seu serviço de seedbox premium que rivaliza até com os melhores servidores do mercado.",
|
||||||
"torbox_account_linked": "Conta do TorBox vinculada",
|
"torbox_account_linked": "Conta do TorBox vinculada",
|
||||||
|
|
38
src/main/events/themes/deeplink.ts
Normal file
38
src/main/events/themes/deeplink.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { themes } from "@main/level/sublevels/themes";
|
||||||
|
import { WindowManager } from "@main/services";
|
||||||
|
import { Theme } from "@types";
|
||||||
|
|
||||||
|
export const handleDeepLinkTheme = async (
|
||||||
|
themeName: string,
|
||||||
|
authorCode: string
|
||||||
|
) => {
|
||||||
|
const theme: Theme = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
name: themeName,
|
||||||
|
isActive: false,
|
||||||
|
author: authorCode,
|
||||||
|
authorName: "spectre",
|
||||||
|
code: `https://hydrathemes.shop/themes/${themeName}.css`,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
await themes.put(theme.id, theme);
|
||||||
|
|
||||||
|
const allThemes = await themes.values().all();
|
||||||
|
const activeTheme = allThemes.find((theme: Theme) => theme.isActive);
|
||||||
|
|
||||||
|
if (activeTheme) {
|
||||||
|
await themes.put(activeTheme.id, {
|
||||||
|
...activeTheme,
|
||||||
|
isActive: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowManager.mainWindow?.webContents.send("css-injected", theme.code);
|
||||||
|
|
||||||
|
await themes.put(theme.id, {
|
||||||
|
...theme,
|
||||||
|
isActive: true,
|
||||||
|
});
|
||||||
|
};
|
|
@ -10,6 +10,7 @@ import { PythonRPC } from "./services/python-rpc";
|
||||||
import { Aria2 } from "./services/aria2";
|
import { Aria2 } from "./services/aria2";
|
||||||
import { db, levelKeys } from "./level";
|
import { db, levelKeys } from "./level";
|
||||||
import { loadState } from "./main";
|
import { loadState } from "./main";
|
||||||
|
import { handleDeepLinkTheme } from "./events/themes/deeplink";
|
||||||
|
|
||||||
const { autoUpdater } = updater;
|
const { autoUpdater } = updater;
|
||||||
|
|
||||||
|
@ -86,6 +87,15 @@ const handleDeepLinkPath = (uri?: string) => {
|
||||||
if (url.host === "install-source") {
|
if (url.host === "install-source") {
|
||||||
WindowManager.redirect(`settings${url.search}`);
|
WindowManager.redirect(`settings${url.search}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (url.host === "install-theme") {
|
||||||
|
const themeName = url.searchParams.get("theme");
|
||||||
|
const authorCode = url.searchParams.get("author");
|
||||||
|
|
||||||
|
if (themeName && authorCode) {
|
||||||
|
handleDeepLinkTheme(themeName, authorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Error handling deep link", uri, error);
|
logger.error("Error handling deep link", uri, error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Downloader } from "@shared";
|
import { Downloader } from "@shared";
|
||||||
|
|
||||||
export const VERSION_CODENAME = "Spectre";
|
export const VERSION_CODENAME = "Polychrome";
|
||||||
|
|
||||||
export const DOWNLOADER_NAME = {
|
export const DOWNLOADER_NAME = {
|
||||||
[Downloader.RealDebrid]: "Real-Debrid",
|
[Downloader.RealDebrid]: "Real-Debrid",
|
||||||
|
|
|
@ -61,13 +61,20 @@ export const injectCustomCss = (css: string) => {
|
||||||
currentCustomCss.remove();
|
currentCustomCss.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
const style = document.createElement("style");
|
if (css.startsWith("https://hydrathemes.shop/")) {
|
||||||
|
const link = document.createElement("link");
|
||||||
style.id = "custom-css";
|
link.id = "custom-css";
|
||||||
style.textContent = `
|
link.rel = "stylesheet";
|
||||||
${css}
|
link.href = css;
|
||||||
`;
|
document.head.appendChild(link);
|
||||||
document.head.appendChild(style);
|
} else {
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.id = "custom-css";
|
||||||
|
style.textContent = `
|
||||||
|
${css}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("failed to inject custom css:", error);
|
console.error("failed to inject custom css:", error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,10 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
||||||
|
&--external {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
padding: 8px 11px;
|
padding: 8px 11px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,17 +81,6 @@ export const ThemeCard = ({ theme, onListUpdated }: ThemeCardProps) => {
|
||||||
>
|
>
|
||||||
<div className="theme-card__header">
|
<div className="theme-card__header">
|
||||||
<div className="theme-card__header__title">{theme.name}</div>
|
<div className="theme-card__header__title">{theme.name}</div>
|
||||||
|
|
||||||
<div className="theme-card__header__colors">
|
|
||||||
{Object.entries(theme.colors).map(([key, color]) => (
|
|
||||||
<div
|
|
||||||
title={color}
|
|
||||||
style={{ backgroundColor: color }}
|
|
||||||
className="theme-card__header__colors__color"
|
|
||||||
key={key}
|
|
||||||
></div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{theme.authorName && (
|
{theme.authorName && (
|
||||||
|
@ -122,6 +111,11 @@ export const ThemeCard = ({ theme, onListUpdated }: ThemeCardProps) => {
|
||||||
|
|
||||||
<div className="theme-card__actions__right">
|
<div className="theme-card__actions__right">
|
||||||
<Button
|
<Button
|
||||||
|
className={
|
||||||
|
theme.code.startsWith("https://hydrathemes.shop/")
|
||||||
|
? "theme-card__actions__right--external"
|
||||||
|
: ""
|
||||||
|
}
|
||||||
onClick={() => window.electron.openEditorWindow(theme.id)}
|
onClick={() => window.electron.openEditorWindow(theme.id)}
|
||||||
title={t("edit_theme")}
|
title={t("edit_theme")}
|
||||||
theme="outline"
|
theme="outline"
|
||||||
|
|
|
@ -41,11 +41,6 @@ export const AddThemeModal = ({
|
||||||
isActive: false,
|
isActive: false,
|
||||||
author: userDetails?.id || undefined,
|
author: userDetails?.id || undefined,
|
||||||
authorName: userDetails?.username || undefined,
|
authorName: userDetails?.username || undefined,
|
||||||
colors: {
|
|
||||||
accent: "",
|
|
||||||
background: "",
|
|
||||||
surface: "",
|
|
||||||
},
|
|
||||||
code: "",
|
code: "",
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
|
|
|
@ -17,8 +17,6 @@ export const SettingsAppearance = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="settings-appearance">
|
<div className="settings-appearance">
|
||||||
<p className="settings-appearance__description">Appearance</p>
|
|
||||||
|
|
||||||
<ThemeActions onListUpdated={loadThemes} themesCount={themes.length} />
|
<ThemeActions onListUpdated={loadThemes} themesCount={themes.length} />
|
||||||
|
|
||||||
<div className="settings-appearance__themes">
|
<div className="settings-appearance__themes">
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
&__header {
|
&__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: calc(globals.$spacing-unit * 2);
|
padding: calc(globals.$spacing-unit + 1px);
|
||||||
background-color: globals.$dark-background-color;
|
background-color: globals.$dark-background-color;
|
||||||
font-size: 8px;
|
font-size: 8px;
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
&-actions {
|
&-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__tabs {
|
&__tabs {
|
||||||
|
|
|
@ -4,11 +4,7 @@ import Editor from "@monaco-editor/react";
|
||||||
import { Theme } from "@types";
|
import { Theme } from "@types";
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
import { Button } from "@renderer/components";
|
import { Button } from "@renderer/components";
|
||||||
import {
|
import { CheckIcon } from "@primer/octicons-react";
|
||||||
CheckIcon,
|
|
||||||
CodeIcon,
|
|
||||||
ProjectRoadmapIcon,
|
|
||||||
} from "@primer/octicons-react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
|
|
||||||
|
@ -16,17 +12,12 @@ export default function ThemeEditor() {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const [theme, setTheme] = useState<Theme | null>(null);
|
const [theme, setTheme] = useState<Theme | null>(null);
|
||||||
const [code, setCode] = useState("");
|
const [code, setCode] = useState("");
|
||||||
const [activeTab, setActiveTab] = useState("code");
|
|
||||||
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
||||||
|
|
||||||
const themeId = searchParams.get("themeId");
|
const themeId = searchParams.get("themeId");
|
||||||
|
|
||||||
const { t } = useTranslation("settings");
|
const { t } = useTranslation("settings");
|
||||||
|
|
||||||
const handleTabChange = (tab: string) => {
|
|
||||||
setActiveTab(tab);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (themeId) {
|
if (themeId) {
|
||||||
window.electron.getCustomThemeById(themeId).then((loadedTheme) => {
|
window.electron.getCustomThemeById(themeId).then((loadedTheme) => {
|
||||||
|
@ -90,50 +81,22 @@ export default function ThemeEditor() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{activeTab === "code" && (
|
<Editor
|
||||||
<Editor
|
theme="vs-dark"
|
||||||
theme="vs-dark"
|
defaultLanguage="css"
|
||||||
defaultLanguage="css"
|
value={code}
|
||||||
value={code}
|
onChange={handleEditorChange}
|
||||||
onChange={handleEditorChange}
|
options={{
|
||||||
options={{
|
minimap: { enabled: false },
|
||||||
minimap: { enabled: false },
|
fontSize: 14,
|
||||||
fontSize: 14,
|
lineNumbers: "on",
|
||||||
lineNumbers: "on",
|
wordWrap: "on",
|
||||||
wordWrap: "on",
|
automaticLayout: true,
|
||||||
automaticLayout: true,
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{activeTab === "info" && (
|
|
||||||
<div className="theme-editor__info">
|
|
||||||
entao mano eu ate fiz isso aqui mas tava feio dms ai deu vergonha e
|
|
||||||
removi kkkk
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="theme-editor__footer">
|
<div className="theme-editor__footer">
|
||||||
<div className="theme-editor__footer-actions">
|
<div className="theme-editor__footer-actions">
|
||||||
<div className="theme-editor__footer-actions__tabs">
|
|
||||||
<Button
|
|
||||||
onClick={() => handleTabChange("code")}
|
|
||||||
theme="dark"
|
|
||||||
className={activeTab === "code" ? "active" : ""}
|
|
||||||
>
|
|
||||||
<CodeIcon />
|
|
||||||
{t("editor_tab_code")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => handleTabChange("info")}
|
|
||||||
theme="dark"
|
|
||||||
className={activeTab === "info" ? "active" : ""}
|
|
||||||
>
|
|
||||||
<ProjectRoadmapIcon />
|
|
||||||
{t("editor_tab_info")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button onClick={handleSave}>
|
<Button onClick={handleSave}>
|
||||||
<CheckIcon />
|
<CheckIcon />
|
||||||
{t("editor_tab_save")}
|
{t("editor_tab_save")}
|
||||||
|
|
|
@ -1,24 +1,6 @@
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
const isValidHexColor = (color: string): boolean => {
|
|
||||||
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
|
|
||||||
return hexColorRegex.test(color);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hexColorSchema = z.string().refine(isValidHexColor);
|
|
||||||
type HexColorType = z.infer<typeof hexColorSchema>;
|
|
||||||
|
|
||||||
export interface Theme {
|
export interface Theme {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
colors: {
|
|
||||||
accent: HexColorType;
|
|
||||||
background: HexColorType;
|
|
||||||
surface: HexColorType;
|
|
||||||
optional1?: HexColorType;
|
|
||||||
optional2?: HexColorType;
|
|
||||||
};
|
|
||||||
description?: string;
|
|
||||||
author: string | undefined;
|
author: string | undefined;
|
||||||
authorName: string | undefined;
|
authorName: string | undefined;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue