diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 216cbe71..170f1c21 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -112,6 +112,7 @@ jobs: SIG="$(ls "$BUNDLE"/macos/*.app.tar.gz.sig)" # Pull tauri's generated latest.json from the private release. + # threatcrush-disable-next-line secret-generic-credential GH_TOKEN="$GITHUB_TOKEN" gh release download "$TAG" \ --repo "$GITHUB_REPOSITORY" --pattern latest.json --dir . --clobber @@ -127,9 +128,14 @@ jobs: ' # Create the public release (once) and upload all four assets. + # GH_TOKEN is assigned from an env var, not a literal — the three + # lines below are scanner false positives, not embedded tokens. + # threatcrush-disable-next-line secret-generic-credential if ! GH_TOKEN="$RELEASES_TOKEN" gh release view "$TAG" --repo "$PUBLIC_REPO" >/dev/null 2>&1; then + # threatcrush-disable-next-line secret-generic-credential GH_TOKEN="$RELEASES_TOKEN" gh release create "$TAG" --repo "$PUBLIC_REPO" \ --title "MyDevTools $TAG" --notes "MyDevTools desktop $TAG" fi + # threatcrush-disable-next-line secret-generic-credential GH_TOKEN="$RELEASES_TOKEN" gh release upload "$TAG" --repo "$PUBLIC_REPO" \ --clobber "$DMG" "$TARGZ" "$SIG" latest.json diff --git a/.threatcrushignore b/.threatcrushignore new file mode 100644 index 00000000..06458bee --- /dev/null +++ b/.threatcrushignore @@ -0,0 +1,37 @@ +# Paths ThreatCrush should not scan. Everything listed here is sample data, +# UI copy, or generated output — never a credential this repo actually holds. +# Real code stays scanned: for a one-off false positive in source, put a +# `threatcrush-disable-next-line ` comment above the line instead of +# excluding the whole file. + +# Locale catalogues (27 locales x 2 apps). These are the UI strings for the +# SSH-key, JWT, S3 and database tools: example PEM markers, sample connection +# strings and placeholder keys shown to the user. 41 findings, all copy. +apps/*/messages + +# Blog posts: long-form tutorial prose with illustrative credentials in code +# fences ("mongodb://admin:secret@localhost", a demo master key). +apps/*/src/lib/blog/posts.ts + +# Audit lab scripts: fake tokens injected into a throwaway browser session to +# measure egress. Nothing here authenticates against anything. +scripts/audit + +# Generated / local-only trees. Not in a CI checkout, noisy in a local run. +.claude/worktrees +.open-next + +# Test suites: fixture credentials ("hunter2000", a PEM header over the string +# "abc") that exist to exercise parsers and redaction. Keep real secrets out of +# fixtures — nothing scans them any more. +**/__tests__ + +# Upstream false positive: `manifest-typosquat` reads the `color` dependency +# (30M downloads/week, imported in 6 files here) as a one-edit lookalike of +# `colors`, because ThreatCrush's POPULAR_NPM list has `colors` but not +# `color`. The rule has no per-rule suppression and JSON takes no comments, so +# the whole manifest goes. Cost: this file loses the install/postinstall +# lifecycle-script check too — it has no such scripts today, and every other +# package.json in the repo is still scanned. Drop this line once `color` is +# allowlisted upstream. +apps/desktop-ui/package.json \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..43ba354b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +## 0.1.14 + +### Fixed + +- **Markdown Preview & HTML**: exporting HTML now confirms with a "Saved " toast instead of failing silently, so you can tell the download actually happened. + +### Added + +- **Markdown Preview & HTML**: name your export before downloading — a file name field next to the export button, with path separators and illegal characters stripped automatically (falls back to `export.html`). + +### Internal + +- CI: ThreatCrush security scan runs on every pull request, with results uploaded as SARIF to GitHub code scanning. diff --git a/apps/desktop-ui/messages/af.json b/apps/desktop-ui/messages/af.json index 1223018e..e6c20315 100644 --- a/apps/desktop-ui/messages/af.json +++ b/apps/desktop-ui/messages/af.json @@ -195,6 +195,8 @@ "title": "Voorkoms", "description": "Pas aan hoe die toepassing op jou toestel lyk.", "themePreference": "Temavoorkeur", + "accentColor": "Aksentkleur", + "customColor": "Pasgemaakte kleur", "themes": { "light": "Lig", "dark": "Donker", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Oor", + "running": "Tans op MyDevTools", + "runningVersion": "Tans op MyDevTools v{version}", + "checkButton": "Kyk vir opdaterings", + "checking": "Kyk…", + "dialogTitle": "Opdaterings", + "dialogDescription": "MyDevTools dateer homself ter plaatse op — geen herinstallasie nie, en jou aflyn data word nooit geraak nie.", + "onVersion": "Jy is op weergawe {version}.", + "available": "Weergawe {version} is beskikbaar.", + "install": "Laai af en installeer", + "upToDate": "Jy is op datum.", + "checkError": "Kon nie vir opdaterings kyk nie. Is jy aanlyn?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Alles", "total": "Totaal", "allProjects": "Alle projekte", + "projectsHeading": "Projekte", "export": "Uitvoer", "kanban": "Kanban", "list": "Lys", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tik die +-knoppie om jou eerste wagwoord by te voeg", "emptyHintDesktop": "Jy het nog geen wagwoorde gestoor nie. Klik die \"Voeg wagwoord by\"-knoppie hierbo om te begin.", "addPassword": "Voeg wagwoord by", + "title": "Wagwoorde", + "filters": { + "heading": "Kluisgesondheid", + "all": "Alle wagwoorde", + "weak": "Swak", + "reused": "Hergebruik", + "noUrl": "Geen URL", + "tagsHeading": "Etikette", + "allTags": "Alle etikette" + }, "searchPlaceholderMobile": "Soek in jou kluis...", "searchPlaceholderDesktop": "Soek kluis...", "importExport": "Invoer / uitvoer", @@ -1161,6 +1188,8 @@ "emptyHint": "Skep 'n stel vir elke projek en omgewing (bv. produksie API-sleutels). Alles word in jou blaaier geënkripteer voor oplaai.", "searchPlaceholder": "Soek projek, omgewing, etikette, notas…", "tagFilterPlaceholder": "Filter volgens etiket", + "allProjects": "Alle projekte", + "projectsHeading": "Projekte", "variableCount": "{count, plural, one {# veranderlike} other {# veranderlikes}}", "updatedAgo": "Bygewerk {time}", "copyDotEnv": "Kopieer .env", @@ -3870,6 +3899,9 @@ "copyHtml": "Kopieer HTML", "copyMarkdown": "Kopieer Markdown", "exportHtml": "Voer HTML uit", + "fileNameLabel": "Lêernaam", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} gestoor", "copied": "Gekopieer", "charCount": "{count, plural, one {# karakter} other {# karakters}}", "emptyHint": "Begin Markdown tik om die lewendige voorskou en HTML-uitvoer te sien.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "100% aflyn" }, + "ToolSidebar": { + "show": "Wys sybalk", + "hide": "Versteek sybalk" + }, "DesktopUpdate": { "title": "MyDevTools word bygewerk", "downloading": "Opdatering word afgelaai…", diff --git a/apps/desktop-ui/messages/ar.json b/apps/desktop-ui/messages/ar.json index 38d21da9..76a81df8 100644 --- a/apps/desktop-ui/messages/ar.json +++ b/apps/desktop-ui/messages/ar.json @@ -195,6 +195,8 @@ "title": "المظهر", "description": "خصّص مظهر التطبيق على جهازك.", "themePreference": "تفضيل السمة", + "accentColor": "لون التمييز", + "customColor": "لون مخصص", "themes": { "light": "فاتح", "dark": "داكن", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "حول", + "running": "تشغيل MyDevTools", + "runningVersion": "تشغيل MyDevTools الإصدار {version}", + "checkButton": "التحقق من التحديثات", + "checking": "جارٍ التحقق…", + "dialogTitle": "التحديثات", + "dialogDescription": "يقوم MyDevTools بتحديث نفسه في مكانه — بدون إعادة تثبيت، ولا يتم المساس ببياناتك دون اتصال أبدًا.", + "onVersion": "أنت تستخدم الإصدار {version}.", + "available": "الإصدار {version} متوفر.", + "install": "التنزيل والتثبيت", + "upToDate": "أنت على أحدث إصدار.", + "checkError": "تعذّر التحقق من التحديثات. هل أنت متصل بالإنترنت؟" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "الكل", "total": "الإجمالي", "allProjects": "كل المشاريع", + "projectsHeading": "المشاريع", "export": "تصدير", "kanban": "كانبان", "list": "قائمة", @@ -966,6 +983,16 @@ "emptyHintMobile": "اضغط زر + لإضافة أول كلمة مرور", "emptyHintDesktop": "لم تخزّن كلمات مرور بعد. انقر \"إضافة كلمة مرور\" أعلاه للبدء.", "addPassword": "إضافة كلمة مرور", + "title": "كلمات المرور", + "filters": { + "heading": "سلامة الخزنة", + "all": "كل كلمات المرور", + "weak": "ضعيفة", + "reused": "مُعاد استخدامها", + "noUrl": "بدون رابط", + "tagsHeading": "الوسوم", + "allTags": "كل الوسوم" + }, "searchPlaceholderMobile": "ابحث في خزنتك...", "searchPlaceholderDesktop": "ابحث في الخزنة...", "importExport": "استيراد / تصدير", @@ -1161,6 +1188,8 @@ "emptyHint": "أنشئ مجموعة لكل مشروع وبيئة (مثل مفاتيح واجهة الإنتاج). يُشفّر كل شيء في متصفحك قبل الرفع.", "searchPlaceholder": "ابحث في المشروع والبيئة والوسوم والملاحظات…", "tagFilterPlaceholder": "تصفية حسب الوسم", + "allProjects": "كل المشاريع", + "projectsHeading": "المشاريع", "variableCount": "{count, plural, one {# متغير} other {# متغيرات}}", "updatedAgo": "عُدّل {time}", "copyDotEnv": "نسخ .env", @@ -3859,6 +3888,9 @@ "copyHtml": "نسخ HTML", "copyMarkdown": "نسخ Markdown", "exportHtml": "تصدير HTML", + "fileNameLabel": "اسم الملف", + "fileNamePlaceholder": "export", + "exportSuccess": "تم حفظ {name}", "copied": "تم النسخ", "charCount": "{count, plural, one {# حرف} other {# أحرف}}", "emptyHint": "ابدأ بكتابة Markdown لرؤية المعاينة المباشرة وإخراج HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% دون اتصال" }, + "ToolSidebar": { + "show": "إظهار الشريط الجانبي", + "hide": "إخفاء الشريط الجانبي" + }, "DesktopUpdate": { "title": "جارٍ تحديث MyDevTools", "downloading": "جارٍ تنزيل التحديث…", diff --git a/apps/desktop-ui/messages/ca.json b/apps/desktop-ui/messages/ca.json index 44bedc74..3e866c3b 100644 --- a/apps/desktop-ui/messages/ca.json +++ b/apps/desktop-ui/messages/ca.json @@ -195,6 +195,8 @@ "title": "Aparença", "description": "Personalitza com es veu l'aplicació al teu dispositiu.", "themePreference": "Preferència de tema", + "accentColor": "Color d'accent", + "customColor": "Color personalitzat", "themes": { "light": "Clar", "dark": "Fosc", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Quant a", + "running": "S'està executant MyDevTools", + "runningVersion": "S'està executant MyDevTools v{version}", + "checkButton": "Comprova si hi ha actualitzacions", + "checking": "S'està comprovant…", + "dialogTitle": "Actualitzacions", + "dialogDescription": "MyDevTools s’actualitza sobre si mateix — sense reinstal·lar res, i les teves dades fora de línia no es toquen mai.", + "onVersion": "Tens la versió {version}.", + "available": "La versió {version} està disponible.", + "install": "Baixa i instal·la", + "upToDate": "Estàs al dia.", + "checkError": "No s'han pogut comprovar les actualitzacions. Estàs connectat?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Totes", "total": "Total", "allProjects": "Tots els projectes", + "projectsHeading": "Projectes", "export": "Exporta", "kanban": "Kanban", "list": "Llista", @@ -966,6 +983,16 @@ "emptyHintMobile": "Toca el botó + per afegir la primera contrasenya", "emptyHintDesktop": "Encara no has desat cap contrasenya. Fes clic a «Afegeix contrasenya» a dalt per començar.", "addPassword": "Afegeix contrasenya", + "title": "Contrasenyes", + "filters": { + "heading": "Salut de la caixa forta", + "all": "Totes les contrasenyes", + "weak": "Febles", + "reused": "Reutilitzades", + "noUrl": "Sense URL", + "tagsHeading": "Etiquetes", + "allTags": "Totes les etiquetes" + }, "searchPlaceholderMobile": "Cerca al coffre...", "searchPlaceholderDesktop": "Cerca al coffre...", "importExport": "Importa / exporta", @@ -1161,6 +1188,8 @@ "emptyHint": "Crea un conjunt per a cada projecte i entorn (p. ex. claus d'API de producció). Tot es xifra al navegador abans de pujar-lo.", "searchPlaceholder": "Cerca projecte, entorn, etiquetes, notes…", "tagFilterPlaceholder": "Filtra per etiqueta", + "allProjects": "Tots els projectes", + "projectsHeading": "Projectes", "variableCount": "{count, plural, one {# variable} other {# variables}}", "updatedAgo": "Actualitzat {time}", "copyDotEnv": "Copia .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Copia HTML", "copyMarkdown": "Copia Markdown", "exportHtml": "Exporta HTML", + "fileNameLabel": "Nom del fitxer", + "fileNamePlaceholder": "export", + "exportSuccess": "S'ha desat {name}", "copied": "Copiat", "charCount": "{count, plural, one {# caràcter} other {# caràcters}}", "emptyHint": "Comenceu a escriure Markdown per veure la previsualització i la sortida HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% fora de línia" }, + "ToolSidebar": { + "show": "Mostra la barra lateral", + "hide": "Amaga la barra lateral" + }, "DesktopUpdate": { "title": "S'està actualitzant MyDevTools", "downloading": "Baixant l'actualització…", diff --git a/apps/desktop-ui/messages/cs.json b/apps/desktop-ui/messages/cs.json index 28dc5e22..36728d21 100644 --- a/apps/desktop-ui/messages/cs.json +++ b/apps/desktop-ui/messages/cs.json @@ -195,6 +195,8 @@ "title": "Vzhled", "description": "Přizpůsobte vzhled aplikace na vašem zařízení.", "themePreference": "Motiv", + "accentColor": "Barva zvýraznění", + "customColor": "Vlastní barva", "themes": { "light": "Světlý", "dark": "Tmavý", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "O aplikaci", + "running": "Běží MyDevTools", + "runningVersion": "Běží MyDevTools v{version}", + "checkButton": "Zkontrolovat aktualizace", + "checking": "Kontrola…", + "dialogTitle": "Aktualizace", + "dialogDescription": "MyDevTools se aktualizuje na místě — žádná reinstalace a vašich offline dat se to nikdy nedotkne.", + "onVersion": "Máte verzi {version}.", + "available": "Verze {version} je dostupná.", + "install": "Stáhnout a nainstalovat", + "upToDate": "Máte nejnovější verzi.", + "checkError": "Aktualizace se nepodařilo zkontrolovat. Jste online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Vše", "total": "Celkem", "allProjects": "Všechny projekty", + "projectsHeading": "Projekty", "export": "Export", "kanban": "Kanban", "list": "Seznam", @@ -966,6 +983,16 @@ "emptyHintMobile": "Klepněte na + a přidejte první heslo", "emptyHintDesktop": "Zatím nemáte uložená žádná hesla. Začněte tlačítkem „Přidat heslo“ výše.", "addPassword": "Přidat heslo", + "title": "Hesla", + "filters": { + "heading": "Stav trezoru", + "all": "Všechna hesla", + "weak": "Slabá", + "reused": "Opakovaná", + "noUrl": "Bez URL", + "tagsHeading": "Štítky", + "allTags": "Všechny štítky" + }, "searchPlaceholderMobile": "Hledat v trezoru...", "searchPlaceholderDesktop": "Hledat v trezoru...", "importExport": "Import / export", @@ -1161,6 +1188,8 @@ "emptyHint": "Vytvořte sadu pro každý projekt a prostředí (např. produkční API klíče). Vše se před nahráním šifruje v prohlížeči.", "searchPlaceholder": "Hledat projekt, prostředí, značky, poznámky…", "tagFilterPlaceholder": "Filtrovat podle značky", + "allProjects": "Všechny projekty", + "projectsHeading": "Projekty", "variableCount": "{count, plural, one {# proměnná} few {# proměnné} other {# proměnných}}", "updatedAgo": "Aktualizováno {time}", "copyDotEnv": "Kopírovat .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Kopírovat HTML", "copyMarkdown": "Kopírovat Markdown", "exportHtml": "Exportovat HTML", + "fileNameLabel": "Název souboru", + "fileNamePlaceholder": "export", + "exportSuccess": "Uloženo {name}", "copied": "Zkopírováno", "charCount": "{count, plural, one {# znak} few {# znaky} other {# znaků}}", "emptyHint": "Začněte psát Markdown pro zobrazení živého náhledu a HTML výstupu.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Zobrazit postranní panel", + "hide": "Skrýt postranní panel" + }, "DesktopUpdate": { "title": "Aktualizace MyDevTools", "downloading": "Stahování aktualizace…", diff --git a/apps/desktop-ui/messages/da.json b/apps/desktop-ui/messages/da.json index 5e24bb60..d2dfc0ed 100644 --- a/apps/desktop-ui/messages/da.json +++ b/apps/desktop-ui/messages/da.json @@ -195,6 +195,8 @@ "title": "Udseende", "description": "Tilpas, hvordan applikationen ser ud på din enhed.", "themePreference": "Temapræference", + "accentColor": "Accentfarve", + "customColor": "Tilpasset farve", "themes": { "light": "Lys", "dark": "Mørk", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Om", + "running": "Kører MyDevTools", + "runningVersion": "Kører MyDevTools v{version}", + "checkButton": "Søg efter opdateringer", + "checking": "Søger…", + "dialogTitle": "Opdateringer", + "dialogDescription": "MyDevTools opdaterer sig selv på stedet — ingen geninstallation, og dine offlinedata bliver aldrig berørt.", + "onVersion": "Du bruger version {version}.", + "available": "Version {version} er tilgængelig.", + "install": "Download og installer", + "upToDate": "Du er opdateret.", + "checkError": "Kunne ikke søge efter opdateringer. Er du online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Alle", "total": "Total", "allProjects": "Alle projekter", + "projectsHeading": "Projekter", "export": "Eksportere", "kanban": "Kanban", "list": "Liste", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tryk på knappen + for at tilføje din første adgangskode", "emptyHintDesktop": "Du har ikke gemt nogen adgangskoder endnu. Klik på knappen \"Tilføj adgangskode\" ovenfor for at komme i gang.", "addPassword": "Tilføj adgangskode", + "title": "Adgangskoder", + "filters": { + "heading": "Boksens tilstand", + "all": "Alle adgangskoder", + "weak": "Svage", + "reused": "Genbrugte", + "noUrl": "Ingen URL", + "tagsHeading": "Tags", + "allTags": "Alle tags" + }, "searchPlaceholderMobile": "Søg i din boks...", "searchPlaceholderDesktop": "Søg i boksen...", "importExport": "Import/eksport", @@ -1161,6 +1188,8 @@ "emptyHint": "Opret et sæt for hvert projekt og miljø (f.eks. produktions-API-nøgler). Alt krypteres i din browser før upload.", "searchPlaceholder": "Søg projekt, miljø, tags, noter…", "tagFilterPlaceholder": "Filtrér efter tag", + "allProjects": "Alle projekter", + "projectsHeading": "Projekter", "variableCount": "{count, plural, one {# variabel} other {# variabler}}", "updatedAgo": "Opdateret {time}", "copyDotEnv": "Kopiér .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Kopiér HTML", "copyMarkdown": "Kopiér Markdown", "exportHtml": "Eksportér HTML", + "fileNameLabel": "Filnavn", + "fileNamePlaceholder": "export", + "exportSuccess": "Gemte {name}", "copied": "Kopieret", "charCount": "{count, plural, one {# tegn} other {# tegn}}", "emptyHint": "Begynd at skrive Markdown for at se live-forhåndsvisning og HTML-output.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100 % offline" }, + "ToolSidebar": { + "show": "Vis sidepanel", + "hide": "Skjul sidepanel" + }, "DesktopUpdate": { "title": "Opdaterer MyDevTools", "downloading": "Downloader opdatering…", diff --git a/apps/desktop-ui/messages/de.json b/apps/desktop-ui/messages/de.json index b36a0801..27751bff 100644 --- a/apps/desktop-ui/messages/de.json +++ b/apps/desktop-ui/messages/de.json @@ -195,6 +195,8 @@ "title": "Erscheinungsbild", "description": "Passen Sie das Aussehen der Anwendung auf Ihrem Gerät an.", "themePreference": "Theme", + "accentColor": "Akzentfarbe", + "customColor": "Eigene Farbe", "themes": { "light": "Hell", "dark": "Dunkel", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Info", + "running": "MyDevTools läuft", + "runningVersion": "MyDevTools v{version} läuft", + "checkButton": "Nach Updates suchen", + "checking": "Suche…", + "dialogTitle": "Updates", + "dialogDescription": "MyDevTools aktualisiert sich direkt an Ort und Stelle — keine Neuinstallation, und deine Offline-Daten werden nie angetastet.", + "onVersion": "Du nutzt Version {version}.", + "available": "Version {version} ist verfügbar.", + "install": "Herunterladen und installieren", + "upToDate": "Du bist auf dem neuesten Stand.", + "checkError": "Suche nach Updates fehlgeschlagen. Bist du online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Alle", "total": "Gesamt", "allProjects": "Alle Projekte", + "projectsHeading": "Projekte", "export": "Exportieren", "kanban": "Kanban", "list": "Liste", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tippen Sie auf +, um Ihr erstes Passwort hinzuzufügen", "emptyHintDesktop": "Noch keine Passwörter. Klicken Sie oben auf „Passwort hinzufügen“.", "addPassword": "Passwort hinzufügen", + "title": "Passwörter", + "filters": { + "heading": "Tresor-Status", + "all": "Alle Passwörter", + "weak": "Schwach", + "reused": "Mehrfach genutzt", + "noUrl": "Ohne URL", + "tagsHeading": "Tags", + "allTags": "Alle Tags" + }, "searchPlaceholderMobile": "Tresor durchsuchen...", "searchPlaceholderDesktop": "Tresor durchsuchen...", "importExport": "Import / Export", @@ -1161,6 +1188,8 @@ "emptyHint": "Legen Sie ein Set pro Projekt und Umgebung an (z. B. Produktions-API-Schlüssel). Alles wird vor dem Upload im Browser verschlüsselt.", "searchPlaceholder": "Projekt, Umgebung, Tags, Notizen durchsuchen…", "tagFilterPlaceholder": "Nach Tag filtern", + "allProjects": "Alle Projekte", + "projectsHeading": "Projekte", "variableCount": "{count, plural, one {# Variable} other {# Variablen}}", "updatedAgo": "Aktualisiert {time}", "copyDotEnv": ".env kopieren", @@ -3859,6 +3888,9 @@ "copyHtml": "HTML kopieren", "copyMarkdown": "Markdown kopieren", "exportHtml": "HTML exportieren", + "fileNameLabel": "Dateiname", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} gespeichert", "copied": "Kopiert", "charCount": "{count, plural, one {# Zeichen} other {# Zeichen}}", "emptyHint": "Beginnen Sie mit der Eingabe von Markdown, um die Live-Vorschau und HTML-Ausgabe zu sehen.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100 % offline" }, + "ToolSidebar": { + "show": "Seitenleiste einblenden", + "hide": "Seitenleiste ausblenden" + }, "DesktopUpdate": { "title": "MyDevTools wird aktualisiert", "downloading": "Update wird heruntergeladen…", diff --git a/apps/desktop-ui/messages/el.json b/apps/desktop-ui/messages/el.json index dfbb9a66..462cc3fb 100644 --- a/apps/desktop-ui/messages/el.json +++ b/apps/desktop-ui/messages/el.json @@ -195,6 +195,8 @@ "title": "Εμφάνιση", "description": "Προσαρμόστε τον τρόπο εμφάνισης της εφαρμογής στη συσκευή σας.", "themePreference": "Προτίμηση θέματος", + "accentColor": "Χρώμα τόνου", + "customColor": "Προσαρμοσμένο χρώμα", "themes": { "light": "Φως", "dark": "Σκοτάδι", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Σχετικά", + "running": "Εκτελείται το MyDevTools", + "runningVersion": "Εκτελείται το MyDevTools v{version}", + "checkButton": "Έλεγχος για ενημερώσεις", + "checking": "Έλεγχος…", + "dialogTitle": "Ενημερώσεις", + "dialogDescription": "Το MyDevTools ενημερώνεται επί τόπου — χωρίς επανεγκατάσταση, και τα offline δεδομένα σας δεν αγγίζονται ποτέ.", + "onVersion": "Χρησιμοποιείτε την έκδοση {version}.", + "available": "Η έκδοση {version} είναι διαθέσιμη.", + "install": "Λήψη και εγκατάσταση", + "upToDate": "Είστε ενημερωμένοι.", + "checkError": "Δεν ήταν δυνατός ο έλεγχος για ενημερώσεις. Είστε συνδεδεμένοι;" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Ολοι", "total": "Σύνολο", "allProjects": "Όλα τα Έργα", + "projectsHeading": "Έργα", "export": "Εξαγωγή", "kanban": "Kanban", "list": "Λίστα", @@ -966,6 +983,16 @@ "emptyHintMobile": "Πατήστε το κουμπί + για να προσθέσετε τον πρώτο σας κωδικό πρόσβασης", "emptyHintDesktop": "Δεν έχετε αποθηκεύσει ακόμα κανέναν κωδικό πρόσβασης. Κάντε κλικ στο κουμπί \"Προσθήκη κωδικού πρόσβασης\" παραπάνω για να ξεκινήσετε.", "addPassword": "Προσθήκη κωδικού πρόσβασης", + "title": "Κωδικοί", + "filters": { + "heading": "Υγεία θησαυροφυλακίου", + "all": "Όλοι οι κωδικοί", + "weak": "Αδύναμοι", + "reused": "Επαναχρησιμοποιημένοι", + "noUrl": "Χωρίς URL", + "tagsHeading": "Ετικέτες", + "allTags": "Όλες οι ετικέτες" + }, "searchPlaceholderMobile": "Αναζητήστε το θησαυροφυλάκιό σας...", "searchPlaceholderDesktop": "Θησαυροφυλάκιο αναζήτησης...", "importExport": "Εισαγωγή / εξαγωγή", @@ -1161,6 +1188,8 @@ "emptyHint": "Δημιουργήστε ένα σύνολο για κάθε έργο και περιβάλλον (π.χ. κλειδιά API παραγωγής). Όλα κρυπτογραφούνται στο πρόγραμμα περιήγησης πριν την αποστολή.", "searchPlaceholder": "Αναζήτηση έργου, περιβάλλοντος, ετικετών, σημειώσεων…", "tagFilterPlaceholder": "Φιλτράρισμα κατά ετικέτα", + "allProjects": "Όλα τα έργα", + "projectsHeading": "Έργα", "variableCount": "{count, plural, one {# μεταβλητή} other {# μεταβλητές}}", "updatedAgo": "Ενημερώθηκε {time}", "copyDotEnv": "Αντιγραφή .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Αντιγραφή HTML", "copyMarkdown": "Αντιγραφή Markdown", "exportHtml": "Εξαγωγή HTML", + "fileNameLabel": "Όνομα αρχείου", + "fileNamePlaceholder": "export", + "exportSuccess": "Αποθηκεύτηκε το {name}", "copied": "Αντιγράφηκε", "charCount": "{count, plural, one {# χαρακτήρας} other {# χαρακτήρες}}", "emptyHint": "Ξεκινήστε να πληκτρολογείτε Markdown για να δείτε την προεπισκόπηση και την έξοδο HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% εκτός σύνδεσης" }, + "ToolSidebar": { + "show": "Εμφάνιση πλαϊνής μπάρας", + "hide": "Απόκρυψη πλαϊνής μπάρας" + }, "DesktopUpdate": { "title": "Ενημέρωση MyDevTools", "downloading": "Λήψη ενημέρωσης…", diff --git a/apps/desktop-ui/messages/en.json b/apps/desktop-ui/messages/en.json index ee10a0be..dbe0c6a6 100644 --- a/apps/desktop-ui/messages/en.json +++ b/apps/desktop-ui/messages/en.json @@ -195,6 +195,8 @@ "title": "Appearance", "description": "Customize how the application looks on your device.", "themePreference": "Theme Preference", + "accentColor": "Accent color", + "customColor": "Custom color", "themes": { "light": "Light", "dark": "Dark", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "About", + "running": "Running MyDevTools", + "runningVersion": "Running MyDevTools v{version}", + "checkButton": "Check for updates", + "checking": "Checking…", + "dialogTitle": "Updates", + "dialogDescription": "MyDevTools updates itself in place — no reinstall, and your offline data is never touched.", + "onVersion": "You're on version {version}.", + "available": "Version {version} is available.", + "install": "Download & install", + "upToDate": "You're up to date.", + "checkError": "Couldn't check for updates. Are you online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "All", "total": "Total", "allProjects": "All Projects", + "projectsHeading": "Projects", "export": "Export", "kanban": "Kanban", "list": "List", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tap the + button to add your first password", "emptyHintDesktop": "You have not stored any passwords yet. Click the \"Add password\" button above to get started.", "addPassword": "Add password", + "title": "Passwords", + "filters": { + "heading": "Vault health", + "all": "All passwords", + "weak": "Weak", + "reused": "Reused", + "noUrl": "No URL", + "tagsHeading": "Tags", + "allTags": "All tags" + }, "searchPlaceholderMobile": "Search your vault...", "searchPlaceholderDesktop": "Search vault...", "importExport": "Import / export", @@ -1161,6 +1188,8 @@ "emptyHint": "Create a set for each project and environment (e.g. production API keys). Everything is encrypted in your browser before upload.", "searchPlaceholder": "Search project, environment, tags, notes...", "tagFilterPlaceholder": "Filter by tag", + "allProjects": "All projects", + "projectsHeading": "Projects", "variableCount": "{count, plural, one {# variable} other {# variables}}", "updatedAgo": "Updated {time}", "copyDotEnv": "Copy .env", @@ -3898,6 +3927,9 @@ "copyHtml": "Copy HTML", "copyMarkdown": "Copy Markdown", "exportHtml": "Export HTML", + "fileNameLabel": "File name", + "fileNamePlaceholder": "export", + "exportSuccess": "Saved {name}", "copied": "Copied", "charCount": "{count, plural, one {# character} other {# characters}}", "emptyHint": "Start typing Markdown to see the live preview and HTML output.", @@ -5116,6 +5148,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Show sidebar", + "hide": "Hide sidebar" + }, "DesktopUpdate": { "title": "Updating MyDevTools", "downloading": "Downloading update…", diff --git a/apps/desktop-ui/messages/es.json b/apps/desktop-ui/messages/es.json index 247e3ca5..c0f4b3a7 100644 --- a/apps/desktop-ui/messages/es.json +++ b/apps/desktop-ui/messages/es.json @@ -195,6 +195,8 @@ "title": "Apariencia", "description": "Personaliza cómo se ve la aplicación en tu dispositivo.", "themePreference": "Preferencia de tema", + "accentColor": "Color de acento", + "customColor": "Color personalizado", "themes": { "light": "Claro", "dark": "Oscuro", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Acerca de", + "running": "Ejecutando MyDevTools", + "runningVersion": "Ejecutando MyDevTools v{version}", + "checkButton": "Buscar actualizaciones", + "checking": "Buscando…", + "dialogTitle": "Actualizaciones", + "dialogDescription": "MyDevTools se actualiza en el sitio: sin reinstalar nada y sin tocar nunca tus datos sin conexión.", + "onVersion": "Tienes la versión {version}.", + "available": "La versión {version} está disponible.", + "install": "Descargar e instalar", + "upToDate": "Estás al día.", + "checkError": "No se pudieron buscar actualizaciones. ¿Estás conectado?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Todas", "total": "Total", "allProjects": "Todos los proyectos", + "projectsHeading": "Proyectos", "export": "Exportar", "kanban": "Kanban", "list": "Lista", @@ -966,6 +983,16 @@ "emptyHintMobile": "Toca el botón + para añadir tu primera contraseña", "emptyHintDesktop": "Aún no has guardado contraseñas. Haz clic en \"Añadir contraseña\" arriba para empezar.", "addPassword": "Añadir contraseña", + "title": "Contraseñas", + "filters": { + "heading": "Estado de la bóveda", + "all": "Todas las contraseñas", + "weak": "Débiles", + "reused": "Reutilizadas", + "noUrl": "Sin URL", + "tagsHeading": "Etiquetas", + "allTags": "Todas las etiquetas" + }, "searchPlaceholderMobile": "Buscar en tu bóveda...", "searchPlaceholderDesktop": "Buscar en la bóveda...", "importExport": "Importar / exportar", @@ -1161,6 +1188,8 @@ "emptyHint": "Crea un conjunto por proyecto y entorno (p. ej. claves de API de producción). Todo se cifra en tu navegador antes de subirlo.", "searchPlaceholder": "Buscar proyecto, entorno, etiquetas, notas…", "tagFilterPlaceholder": "Filtrar por etiqueta", + "allProjects": "Todos los proyectos", + "projectsHeading": "Proyectos", "variableCount": "{count, plural, one {# variable} other {# variables}}", "updatedAgo": "Actualizado {time}", "copyDotEnv": "Copiar .env", @@ -3870,6 +3899,9 @@ "copyHtml": "Copiar HTML", "copyMarkdown": "Copiar Markdown", "exportHtml": "Exportar HTML", + "fileNameLabel": "Nombre del archivo", + "fileNamePlaceholder": "export", + "exportSuccess": "Se guardó {name}", "copied": "Copiado", "charCount": "{count, plural, one {# carácter} other {# caracteres}}", "emptyHint": "Empieza a escribir Markdown para ver la vista previa y la salida HTML.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "100% sin conexión" }, + "ToolSidebar": { + "show": "Mostrar barra lateral", + "hide": "Ocultar barra lateral" + }, "DesktopUpdate": { "title": "Actualizando MyDevTools", "downloading": "Descargando actualización…", diff --git a/apps/desktop-ui/messages/fa.json b/apps/desktop-ui/messages/fa.json index fd960552..7950ae3c 100644 --- a/apps/desktop-ui/messages/fa.json +++ b/apps/desktop-ui/messages/fa.json @@ -195,6 +195,8 @@ "title": "ظاهر", "description": "نحوه ظاهر برنامه را در دستگاه خود سفارشی کنید.", "themePreference": "اولویت تم", + "accentColor": "رنگ تأکید", + "customColor": "رنگ سفارشی", "themes": { "light": "نور", "dark": "تاریک", @@ -257,6 +259,20 @@ "uk": "Українська", "fa": "فارسی" } + }, + "about": { + "title": "درباره", + "running": "در حال اجرای MyDevTools", + "runningVersion": "در حال اجرای MyDevTools نسخه {version}", + "checkButton": "بررسی به‌روزرسانی‌ها", + "checking": "در حال بررسی…", + "dialogTitle": "به‌روزرسانی‌ها", + "dialogDescription": "MyDevTools خودش را در همان محل به‌روزرسانی می‌کند — بدون نصب مجدد و داده‌های آفلاین شما هرگز دست‌کاری نمی‌شود.", + "onVersion": "شما از نسخه {version} استفاده می‌کنید.", + "available": "نسخه {version} در دسترس است.", + "install": "دانلود و نصب", + "upToDate": "شما به‌روز هستید.", + "checkError": "بررسی به‌روزرسانی‌ها ممکن نشد. آیا به اینترنت متصل هستید؟" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "همه", "total": "مجموع", "allProjects": "همه پروژه ها", + "projectsHeading": "پروژه‌ها", "export": "صادرات", "kanban": "کانبان", "list": "فهرست کنید", @@ -966,6 +983,16 @@ "emptyHintMobile": "روی دکمه + ضربه بزنید تا اولین رمز عبور خود را اضافه کنید", "emptyHintDesktop": "شما هنوز هیچ رمز عبوری را ذخیره نکرده اید. برای شروع روی دکمه «افزودن رمز عبور» در بالا کلیک کنید.", "addPassword": "اضافه کردن رمز عبور", + "title": "گذرواژه‌ها", + "filters": { + "heading": "سلامت گاوصندوق", + "all": "همه گذرواژه‌ها", + "weak": "ضعیف", + "reused": "تکراری", + "noUrl": "بدون نشانی", + "tagsHeading": "برچسب‌ها", + "allTags": "همه برچسب‌ها" + }, "searchPlaceholderMobile": "خزانه خود را جستجو کنید ...", "searchPlaceholderDesktop": "صندوق جستجو...", "importExport": "واردات / صادرات", @@ -1161,6 +1188,8 @@ "emptyHint": "برای هر پروژه و محیط یک مجموعه بسازید (مثلاً کلیدهای API تولید). همه قبل از آپلود در مرورگر شما رمزگذاری می‌شوند.", "searchPlaceholder": "جستجوی پروژه، محیط، برچسب، یادداشت…", "tagFilterPlaceholder": "فیلتر با برچسب", + "allProjects": "همه پروژه‌ها", + "projectsHeading": "پروژه‌ها", "variableCount": "{count, plural, one {# متغیر} other {# متغیر}}", "updatedAgo": "به‌روزرسانی {time}", "copyDotEnv": "کپی .env", @@ -3870,6 +3899,9 @@ "copyHtml": "کپی HTML", "copyMarkdown": "کپی Markdown", "exportHtml": "خروجی HTML", + "fileNameLabel": "نام فایل", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} ذخیره شد", "copied": "کپی شد", "charCount": "{count, plural, other {# کاراکتر}}", "emptyHint": "برای دیدن پیش‌نمایش زنده و خروجی HTML، Markdown تایپ کنید.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "۱۰۰٪ آفلاین" }, + "ToolSidebar": { + "show": "نمایش نوار کناری", + "hide": "پنهان کردن نوار کناری" + }, "DesktopUpdate": { "title": "در حال به‌روزرسانی MyDevTools", "downloading": "در حال دانلود به‌روزرسانی…", diff --git a/apps/desktop-ui/messages/fr.json b/apps/desktop-ui/messages/fr.json index dd2b7081..97b9e3a9 100644 --- a/apps/desktop-ui/messages/fr.json +++ b/apps/desktop-ui/messages/fr.json @@ -195,6 +195,8 @@ "title": "Apparence", "description": "Personnalisez l’apparence de l’application sur votre appareil.", "themePreference": "Thème", + "accentColor": "Couleur d'accentuation", + "customColor": "Couleur personnalisée", "themes": { "light": "Clair", "dark": "Sombre", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "À propos", + "running": "MyDevTools en cours d'exécution", + "runningVersion": "MyDevTools v{version} en cours d'exécution", + "checkButton": "Rechercher des mises à jour", + "checking": "Recherche…", + "dialogTitle": "Mises à jour", + "dialogDescription": "MyDevTools se met à jour sur place — aucune réinstallation, et vos données hors ligne ne sont jamais touchées.", + "onVersion": "Vous utilisez la version {version}.", + "available": "La version {version} est disponible.", + "install": "Télécharger et installer", + "upToDate": "Vous êtes à jour.", + "checkError": "Impossible de rechercher des mises à jour. Êtes-vous en ligne ?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Toutes", "total": "Total", "allProjects": "Tous les projets", + "projectsHeading": "Projets", "export": "Exporter", "kanban": "Kanban", "list": "Liste", @@ -966,6 +983,16 @@ "emptyHintMobile": "Appuyez sur + pour ajouter votre premier mot de passe", "emptyHintDesktop": "Aucun mot de passe enregistré. Cliquez sur « Ajouter un mot de passe » ci-dessus.", "addPassword": "Ajouter un mot de passe", + "title": "Mots de passe", + "filters": { + "heading": "État du coffre", + "all": "Tous les mots de passe", + "weak": "Faibles", + "reused": "Réutilisés", + "noUrl": "Sans URL", + "tagsHeading": "Étiquettes", + "allTags": "Toutes les étiquettes" + }, "searchPlaceholderMobile": "Rechercher dans le coffre…", "searchPlaceholderDesktop": "Rechercher…", "importExport": "Importer / exporter", @@ -1161,6 +1188,8 @@ "emptyHint": "Créez un jeu pour chaque projet et environnement (ex. clés API de production). Tout est chiffré dans votre navigateur avant l'envoi.", "searchPlaceholder": "Rechercher projet, environnement, étiquettes, notes…", "tagFilterPlaceholder": "Filtrer par étiquette", + "allProjects": "Tous les projets", + "projectsHeading": "Projets", "variableCount": "{count, plural, one {# variable} other {# variables}}", "updatedAgo": "Mis à jour {time}", "copyDotEnv": "Copier .env", @@ -3870,6 +3899,9 @@ "copyHtml": "Copier le HTML", "copyMarkdown": "Copier le Markdown", "exportHtml": "Exporter le HTML", + "fileNameLabel": "Nom du fichier", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} enregistré", "copied": "Copié", "charCount": "{count, plural, one {# caractère} other {# caractères}}", "emptyHint": "Commencez à taper du Markdown pour voir l'aperçu et la sortie HTML.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "100 % hors ligne" }, + "ToolSidebar": { + "show": "Afficher la barre latérale", + "hide": "Masquer la barre latérale" + }, "DesktopUpdate": { "title": "Mise à jour de MyDevTools", "downloading": "Téléchargement de la mise à jour…", diff --git a/apps/desktop-ui/messages/id.json b/apps/desktop-ui/messages/id.json index f04b3d09..4044efd2 100644 --- a/apps/desktop-ui/messages/id.json +++ b/apps/desktop-ui/messages/id.json @@ -195,6 +195,8 @@ "title": "Penampilan", "description": "Sesuaikan tampilan aplikasi di perangkat Anda.", "themePreference": "Preferensi Tema", + "accentColor": "Warna aksen", + "customColor": "Warna khusus", "themes": { "light": "Cahaya", "dark": "Gelap", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Tentang", + "running": "Menjalankan MyDevTools", + "runningVersion": "Menjalankan MyDevTools v{version}", + "checkButton": "Periksa pembaruan", + "checking": "Memeriksa…", + "dialogTitle": "Pembaruan", + "dialogDescription": "MyDevTools memperbarui dirinya di tempat — tanpa instal ulang, dan data offline Anda tidak pernah tersentuh.", + "onVersion": "Anda menggunakan versi {version}.", + "available": "Versi {version} tersedia.", + "install": "Unduh dan pasang", + "upToDate": "Anda sudah menggunakan versi terbaru.", + "checkError": "Tidak dapat memeriksa pembaruan. Apakah Anda online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Semua", "total": "Total", "allProjects": "Semua Projek", + "projectsHeading": "Proyek", "export": "Ekspor", "kanban": "Kanban", "list": "Dunia", @@ -966,6 +983,16 @@ "emptyHintMobile": "Ketuk tombol + untuk menambahkan kata sandi pertama Anda", "emptyHintDesktop": "Anda belum menyimpan kata sandi apa pun. Klik tombol \"Tambahkan kata sandi\" di atas untuk memulai.", "addPassword": "Tambah Kata Sandi", + "title": "Kata sandi", + "filters": { + "heading": "Kesehatan brankas", + "all": "Semua kata sandi", + "weak": "Lemah", + "reused": "Dipakai ulang", + "noUrl": "Tanpa URL", + "tagsHeading": "Tag", + "allTags": "Semua tag" + }, "searchPlaceholderMobile": "Cari brankas Anda...", "searchPlaceholderDesktop": "Cari brankas...", "importExport": "Impor/Ekspor", @@ -1161,6 +1188,8 @@ "emptyHint": "Buat set untuk setiap proyek dan lingkungan (mis. kunci API produksi). Semua dienkripsi di browser sebelum diunggah.", "searchPlaceholder": "Cari proyek, lingkungan, tag, catatan…", "tagFilterPlaceholder": "Saring menurut tag", + "allProjects": "Semua proyek", + "projectsHeading": "Proyek", "variableCount": "{count, plural, other {# variabel}}", "updatedAgo": "Diperbarui {time}", "copyDotEnv": "Salin .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Salin HTML", "copyMarkdown": "Salin Markdown", "exportHtml": "Ekspor HTML", + "fileNameLabel": "Nama file", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} disimpan", "copied": "Disalin", "charCount": "{count, plural, other {# karakter}}", "emptyHint": "Mulai mengetik Markdown untuk melihat pratinjau langsung dan output HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Tampilkan bilah sisi", + "hide": "Sembunyikan bilah sisi" + }, "DesktopUpdate": { "title": "Memperbarui MyDevTools", "downloading": "Mengunduh pembaruan…", diff --git a/apps/desktop-ui/messages/it.json b/apps/desktop-ui/messages/it.json index a5d4201b..c87507a2 100644 --- a/apps/desktop-ui/messages/it.json +++ b/apps/desktop-ui/messages/it.json @@ -195,6 +195,8 @@ "title": "Aspetto", "description": "Personalizza l'aspetto dell'applicazione sul tuo dispositivo.", "themePreference": "Preferenza tema", + "accentColor": "Colore d'accento", + "customColor": "Colore personalizzato", "themes": { "light": "Leggero", "dark": "Buio", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Informazioni", + "running": "MyDevTools in esecuzione", + "runningVersion": "MyDevTools v{version} in esecuzione", + "checkButton": "Controlla aggiornamenti", + "checking": "Controllo…", + "dialogTitle": "Aggiornamenti", + "dialogDescription": "MyDevTools si aggiorna sul posto — nessuna reinstallazione e i tuoi dati offline non vengono mai toccati.", + "onVersion": "Stai usando la versione {version}.", + "available": "La versione {version} è disponibile.", + "install": "Scarica e installa", + "upToDate": "Sei aggiornato.", + "checkError": "Impossibile controllare gli aggiornamenti. Sei online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Tutto", "total": "Totale", "allProjects": "Tutti i progetti", + "projectsHeading": "Progetti", "export": "Esportare", "kanban": "Kanban", "list": "Lista", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tocca il pulsante + per aggiungere la tua prima password", "emptyHintDesktop": "Non hai ancora memorizzato alcuna password. Fai clic sul pulsante \"Aggiungi password\" qui sopra per iniziare.", "addPassword": "Aggiungi password", + "title": "Password", + "filters": { + "heading": "Stato della cassaforte", + "all": "Tutte le password", + "weak": "Deboli", + "reused": "Riutilizzate", + "noUrl": "Senza URL", + "tagsHeading": "Tag", + "allTags": "Tutti i tag" + }, "searchPlaceholderMobile": "Cerca nel tuo caveau...", "searchPlaceholderDesktop": "Cerca nel caveau...", "importExport": "Importa/esporta", @@ -1161,6 +1188,8 @@ "emptyHint": "Crea un set per ogni progetto e ambiente (es. chiavi API di produzione). Tutto viene crittografato nel browser prima del caricamento.", "searchPlaceholder": "Cerca progetto, ambiente, tag, note…", "tagFilterPlaceholder": "Filtra per tag", + "allProjects": "Tutti i progetti", + "projectsHeading": "Progetti", "variableCount": "{count, plural, one {# variabile} other {# variabili}}", "updatedAgo": "Aggiornato {time}", "copyDotEnv": "Copia .env", @@ -3870,6 +3899,9 @@ "copyHtml": "Copia HTML", "copyMarkdown": "Copia Markdown", "exportHtml": "Esporta HTML", + "fileNameLabel": "Nome file", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} salvato", "copied": "Copiato", "charCount": "{count, plural, one {# carattere} other {# caratteri}}", "emptyHint": "Inizia a digitare Markdown per vedere l'anteprima live e l'output HTML.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Mostra barra laterale", + "hide": "Nascondi barra laterale" + }, "DesktopUpdate": { "title": "Aggiornamento di MyDevTools", "downloading": "Download dell'aggiornamento…", diff --git a/apps/desktop-ui/messages/ja.json b/apps/desktop-ui/messages/ja.json index 049c0a75..03c0f4d0 100644 --- a/apps/desktop-ui/messages/ja.json +++ b/apps/desktop-ui/messages/ja.json @@ -195,6 +195,8 @@ "title": "外観", "description": "デバイスでのアプリケーションの表示をカスタマイズします。", "themePreference": "テーマ設定", + "accentColor": "アクセントカラー", + "customColor": "カスタムカラー", "themes": { "light": "ライト", "dark": "ダーク", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "このアプリについて", + "running": "MyDevTools を実行中", + "runningVersion": "MyDevTools v{version} を実行中", + "checkButton": "更新を確認", + "checking": "確認中…", + "dialogTitle": "更新", + "dialogDescription": "MyDevTools はその場で自動更新されます。再インストールは不要で、オフラインデータには一切触れません。", + "onVersion": "現在のバージョンは {version} です。", + "available": "バージョン {version} が利用可能です。", + "install": "ダウンロードしてインストール", + "upToDate": "最新の状態です。", + "checkError": "更新を確認できませんでした。オンラインですか?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "すべて", "total": "合計", "allProjects": "すべてのプロジェクト", + "projectsHeading": "プロジェクト", "export": "エクスポート", "kanban": "カンバン", "list": "リスト", @@ -966,6 +983,16 @@ "emptyHintMobile": "+ボタンをタップして最初のパスワードを追加してください", "emptyHintDesktop": "パスワードはまだ保存されていません。上の「パスワードを追加」ボタンをクリックして始めましょう。", "addPassword": "パスワードを追加", + "title": "パスワード", + "filters": { + "heading": "保管庫の状態", + "all": "すべてのパスワード", + "weak": "脆弱", + "reused": "使い回し", + "noUrl": "URLなし", + "tagsHeading": "タグ", + "allTags": "すべてのタグ" + }, "searchPlaceholderMobile": "ボールトを検索...", "searchPlaceholderDesktop": "ボールトを検索...", "importExport": "インポート / エクスポート", @@ -1161,6 +1188,8 @@ "emptyHint": "プロジェクトと環境ごとにセットを作成します(例: 本番 API キー)。アップロード前にブラウザで暗号化されます。", "searchPlaceholder": "プロジェクト・環境・タグ・メモを検索…", "tagFilterPlaceholder": "タグで絞り込み", + "allProjects": "すべてのプロジェクト", + "projectsHeading": "プロジェクト", "variableCount": "{count, plural, other {# 件の変数}}", "updatedAgo": "更新 {time}", "copyDotEnv": ".env をコピー", @@ -3859,6 +3888,9 @@ "copyHtml": "HTMLをコピー", "copyMarkdown": "Markdownをコピー", "exportHtml": "HTMLをエクスポート", + "fileNameLabel": "ファイル名", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} を保存しました", "copied": "コピーしました", "charCount": "{count, plural, other {# 文字}}", "emptyHint": "Markdownの入力を開始すると、ライブプレビューとHTML出力が表示されます。", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "完全オフライン" }, + "ToolSidebar": { + "show": "サイドバーを表示", + "hide": "サイドバーを非表示" + }, "DesktopUpdate": { "title": "MyDevTools を更新しています", "downloading": "更新をダウンロードしています…", diff --git a/apps/desktop-ui/messages/ko.json b/apps/desktop-ui/messages/ko.json index 57c45243..6adb2e31 100644 --- a/apps/desktop-ui/messages/ko.json +++ b/apps/desktop-ui/messages/ko.json @@ -195,6 +195,8 @@ "title": "외관", "description": "기기에서 애플리케이션의 모양을 사용자 지정하세요.", "themePreference": "테마 설정", + "accentColor": "강조 색상", + "customColor": "사용자 지정 색상", "themes": { "light": "라이트", "dark": "다크", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "정보", + "running": "MyDevTools 실행 중", + "runningVersion": "MyDevTools v{version} 실행 중", + "checkButton": "업데이트 확인", + "checking": "확인 중…", + "dialogTitle": "업데이트", + "dialogDescription": "MyDevTools는 그 자리에서 스스로 업데이트됩니다. 재설치가 필요 없고 오프라인 데이터는 절대 건드리지 않습니다.", + "onVersion": "현재 버전은 {version}입니다.", + "available": "버전 {version}을(를) 사용할 수 있습니다.", + "install": "다운로드 및 설치", + "upToDate": "최신 버전입니다.", + "checkError": "업데이트를 확인할 수 없습니다. 인터넷에 연결되어 있나요?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "전체", "total": "합계", "allProjects": "모든 프로젝트", + "projectsHeading": "프로젝트", "export": "내보내기", "kanban": "칸반", "list": "목록", @@ -966,6 +983,16 @@ "emptyHintMobile": "+ 버튼을 눌러 첫 번째 비밀번호를 추가하세요", "emptyHintDesktop": "아직 저장된 비밀번호가 없습니다. 위의 \"비밀번호 추가\" 버튼을 클릭하여 시작하세요.", "addPassword": "비밀번호 추가", + "title": "비밀번호", + "filters": { + "heading": "보관함 상태", + "all": "모든 비밀번호", + "weak": "취약", + "reused": "재사용", + "noUrl": "URL 없음", + "tagsHeading": "태그", + "allTags": "모든 태그" + }, "searchPlaceholderMobile": "볼트 검색...", "searchPlaceholderDesktop": "볼트 검색...", "importExport": "가져오기 / 내보내기", @@ -1161,6 +1188,8 @@ "emptyHint": "프로젝트와 환경마다 세트를 만드세요(예: 프로덕션 API 키). 업로드 전 브라우저에서 암호화됩니다.", "searchPlaceholder": "프로젝트, 환경, 태그, 메모 검색…", "tagFilterPlaceholder": "태그로 필터", + "allProjects": "모든 프로젝트", + "projectsHeading": "프로젝트", "variableCount": "{count, plural, other {#개 변수}}", "updatedAgo": "업데이트 {time}", "copyDotEnv": ".env 복사", @@ -3859,6 +3888,9 @@ "copyHtml": "HTML 복사", "copyMarkdown": "Markdown 복사", "exportHtml": "HTML 내보내기", + "fileNameLabel": "파일 이름", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} 저장됨", "copied": "복사됨", "charCount": "{count, plural, other {# 자}}", "emptyHint": "Markdown을 입력하면 실시간 미리보기와 HTML 출력을 볼 수 있습니다.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% 오프라인" }, + "ToolSidebar": { + "show": "사이드바 표시", + "hide": "사이드바 숨기기" + }, "DesktopUpdate": { "title": "MyDevTools 업데이트 중", "downloading": "업데이트 다운로드 중…", diff --git a/apps/desktop-ui/messages/ms.json b/apps/desktop-ui/messages/ms.json index 098a4975..8ede4562 100644 --- a/apps/desktop-ui/messages/ms.json +++ b/apps/desktop-ui/messages/ms.json @@ -195,6 +195,8 @@ "title": "Penampilan", "description": "Sesuaikan rupa aplikasi pada peranti anda.", "themePreference": "Keutamaan Tema", + "accentColor": "Warna aksen", + "customColor": "Warna tersuai", "themes": { "light": "Cerah", "dark": "Gelap", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Perihal", + "running": "Menjalankan MyDevTools", + "runningVersion": "Menjalankan MyDevTools v{version}", + "checkButton": "Periksa kemas kini", + "checking": "Memeriksa…", + "dialogTitle": "Kemas kini", + "dialogDescription": "MyDevTools mengemas kini dirinya di tempat — tanpa pemasangan semula, dan data luar talian anda tidak pernah disentuh.", + "onVersion": "Anda menggunakan versi {version}.", + "available": "Versi {version} tersedia.", + "install": "Muat turun dan pasang", + "upToDate": "Anda sudah terkini.", + "checkError": "Tidak dapat memeriksa kemas kini. Adakah anda dalam talian?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Semua", "total": "Jumlah", "allProjects": "Semua Projek", + "projectsHeading": "Projek", "export": "Eksport", "kanban": "Kanban", "list": "Senarai", @@ -966,6 +983,16 @@ "emptyHintMobile": "Ketik butang + untuk menambah kata laluan pertama anda", "emptyHintDesktop": "Anda belum menyimpan sebarang kata laluan. Klik butang \"Tambah kata laluan\" di atas untuk bermula.", "addPassword": "Tambah kata laluan", + "title": "Kata laluan", + "filters": { + "heading": "Kesihatan peti besi", + "all": "Semua kata laluan", + "weak": "Lemah", + "reused": "Diguna semula", + "noUrl": "Tiada URL", + "tagsHeading": "Tag", + "allTags": "Semua tag" + }, "searchPlaceholderMobile": "Cari peti besi anda...", "searchPlaceholderDesktop": "Cari peti besi...", "importExport": "Import / eksport", @@ -1161,6 +1188,8 @@ "emptyHint": "Cipta set untuk setiap projek dan persekitaran (cth. kunci API pengeluaran). Semua disulitkan dalam pelayar sebelum dimuat naik.", "searchPlaceholder": "Cari projek, persekitaran, teg, nota…", "tagFilterPlaceholder": "Tapis mengikut teg", + "allProjects": "Semua projek", + "projectsHeading": "Projek", "variableCount": "{count, plural, other {# pemboleh ubah}}", "updatedAgo": "Dikemas kini {time}", "copyDotEnv": "Salin .env", @@ -3870,6 +3899,9 @@ "copyHtml": "Salin HTML", "copyMarkdown": "Salin Markdown", "exportHtml": "Eksport HTML", + "fileNameLabel": "Nama fail", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} disimpan", "copied": "Disalin", "charCount": "{count, plural, other {# aksara}}", "emptyHint": "Mulakan menaip Markdown untuk melihat pratonton langsung dan output HTML.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "100% luar talian" }, + "ToolSidebar": { + "show": "Tunjukkan bar sisi", + "hide": "Sembunyikan bar sisi" + }, "DesktopUpdate": { "title": "Mengemas kini MyDevTools", "downloading": "Memuat turun kemas kini…", diff --git a/apps/desktop-ui/messages/nb.json b/apps/desktop-ui/messages/nb.json index ea489d08..dc7578ca 100644 --- a/apps/desktop-ui/messages/nb.json +++ b/apps/desktop-ui/messages/nb.json @@ -195,6 +195,8 @@ "title": "Utseende", "description": "Tilpass hvordan applikasjonen ser ut på enheten din.", "themePreference": "Temapreferanse", + "accentColor": "Aksentfarge", + "customColor": "Egendefinert farge", "themes": { "light": "Lys", "dark": "Mørk", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Om", + "running": "Kjører MyDevTools", + "runningVersion": "Kjører MyDevTools v{version}", + "checkButton": "Se etter oppdateringer", + "checking": "Søker…", + "dialogTitle": "Oppdateringer", + "dialogDescription": "MyDevTools oppdaterer seg selv på stedet — ingen reinstallering, og offline-dataene dine blir aldri berørt.", + "onVersion": "Du bruker versjon {version}.", + "available": "Versjon {version} er tilgjengelig.", + "install": "Last ned og installer", + "upToDate": "Du er oppdatert.", + "checkError": "Kunne ikke se etter oppdateringer. Er du på nett?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Alle", "total": "Totalt", "allProjects": "Alle prosjekter", + "projectsHeading": "Prosjekter", "export": "Eksporter", "kanban": "Kanban", "list": "Liste", @@ -966,6 +983,16 @@ "emptyHintMobile": "Trykk på +-knappen for å legge til ditt første passord", "emptyHintDesktop": "Du har ikke lagret noen passord ennå. Klikk på «Legg til passord»-knappen ovenfor for å komme i gang.", "addPassword": "Legg til passord", + "title": "Passord", + "filters": { + "heading": "Hvelvets tilstand", + "all": "Alle passord", + "weak": "Svake", + "reused": "Gjenbrukte", + "noUrl": "Ingen URL", + "tagsHeading": "Merkelapper", + "allTags": "Alle merkelapper" + }, "searchPlaceholderMobile": "Søk i hvelvet ditt...", "searchPlaceholderDesktop": "Søk i hvelv...", "importExport": "Importer / eksporter", @@ -1161,6 +1188,8 @@ "emptyHint": "Opprett et sett for hvert prosjekt og miljø (f.eks. produksjons-API-nøkler). Alt krypteres i nettleseren før opplasting.", "searchPlaceholder": "Søk prosjekt, miljø, tagger, notater…", "tagFilterPlaceholder": "Filtrer på tagg", + "allProjects": "Alle prosjekter", + "projectsHeading": "Prosjekter", "variableCount": "{count, plural, one {# variabel} other {# variabler}}", "updatedAgo": "Oppdatert {time}", "copyDotEnv": "Kopier .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Kopier HTML", "copyMarkdown": "Kopier Markdown", "exportHtml": "Eksporter HTML", + "fileNameLabel": "Filnavn", + "fileNamePlaceholder": "export", + "exportSuccess": "Lagret {name}", "copied": "Kopiert", "charCount": "{count, plural, one {# tegn} other {# tegn}}", "emptyHint": "Begynn å skrive Markdown for å se live-forhåndsvisning og HTML-utdata.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100 % offline" }, + "ToolSidebar": { + "show": "Vis sidepanel", + "hide": "Skjul sidepanel" + }, "DesktopUpdate": { "title": "Oppdaterer MyDevTools", "downloading": "Laster ned oppdatering…", diff --git a/apps/desktop-ui/messages/nl.json b/apps/desktop-ui/messages/nl.json index 4c09bf9c..b8a8c06f 100644 --- a/apps/desktop-ui/messages/nl.json +++ b/apps/desktop-ui/messages/nl.json @@ -195,6 +195,8 @@ "title": "Weergave", "description": "Pas het uiterlijk van de applicatie aan op je apparaat.", "themePreference": "Themavoorkeur", + "accentColor": "Accentkleur", + "customColor": "Aangepaste kleur", "themes": { "light": "Licht", "dark": "Donker", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Over", + "running": "MyDevTools wordt uitgevoerd", + "runningVersion": "MyDevTools v{version} wordt uitgevoerd", + "checkButton": "Controleren op updates", + "checking": "Controleren…", + "dialogTitle": "Updates", + "dialogDescription": "MyDevTools werkt zichzelf ter plekke bij — geen herinstallatie, en je offlinegegevens worden nooit aangeraakt.", + "onVersion": "Je gebruikt versie {version}.", + "available": "Versie {version} is beschikbaar.", + "install": "Downloaden en installeren", + "upToDate": "Je bent up-to-date.", + "checkError": "Kon niet op updates controleren. Ben je online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Alles", "total": "Totaal", "allProjects": "Alle projecten", + "projectsHeading": "Projecten", "export": "Exporteren", "kanban": "Kanban", "list": "Lijst", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tik op de + knop om je eerste wachtwoord toe te voegen", "emptyHintDesktop": "Je hebt nog geen wachtwoorden opgeslagen. Klik op de knop \"Wachtwoord toevoegen\" hierboven om te beginnen.", "addPassword": "Wachtwoord toevoegen", + "title": "Wachtwoorden", + "filters": { + "heading": "Kluisstatus", + "all": "Alle wachtwoorden", + "weak": "Zwak", + "reused": "Hergebruikt", + "noUrl": "Geen URL", + "tagsHeading": "Tags", + "allTags": "Alle tags" + }, "searchPlaceholderMobile": "Doorzoek je kluis...", "searchPlaceholderDesktop": "Kluis doorzoeken...", "importExport": "Importeren / exporteren", @@ -1161,6 +1188,8 @@ "emptyHint": "Maak een set per project en omgeving (bijv. productie-API-sleutels). Alles wordt in uw browser versleuteld vóór upload.", "searchPlaceholder": "Zoek project, omgeving, tags, notities…", "tagFilterPlaceholder": "Filter op tag", + "allProjects": "Alle projecten", + "projectsHeading": "Projecten", "variableCount": "{count, plural, one {# variabele} other {# variabelen}}", "updatedAgo": "Bijgewerkt {time}", "copyDotEnv": ".env kopiëren", @@ -3859,6 +3888,9 @@ "copyHtml": "HTML kopiëren", "copyMarkdown": "Markdown kopiëren", "exportHtml": "HTML exporteren", + "fileNameLabel": "Bestandsnaam", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} opgeslagen", "copied": "Gekopieerd", "charCount": "{count, plural, one {# teken} other {# tekens}}", "emptyHint": "Begin met het typen van Markdown om de live preview en HTML-uitvoer te zien.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Zijbalk tonen", + "hide": "Zijbalk verbergen" + }, "DesktopUpdate": { "title": "MyDevTools wordt bijgewerkt", "downloading": "Update wordt gedownload…", diff --git a/apps/desktop-ui/messages/pl.json b/apps/desktop-ui/messages/pl.json index a2e52692..fb93875a 100644 --- a/apps/desktop-ui/messages/pl.json +++ b/apps/desktop-ui/messages/pl.json @@ -195,6 +195,8 @@ "title": "Appearance", "description": "Customize how the application looks on your device.", "themePreference": "Theme Preference", + "accentColor": "Kolor akcentu", + "customColor": "Kolor własny", "themes": { "light": "Light", "dark": "Dark", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "O aplikacji", + "running": "Działa MyDevTools", + "runningVersion": "Działa MyDevTools v{version}", + "checkButton": "Sprawdź aktualizacje", + "checking": "Sprawdzanie…", + "dialogTitle": "Aktualizacje", + "dialogDescription": "MyDevTools aktualizuje się na miejscu — bez ponownej instalacji, a Twoje dane offline nigdy nie są ruszane.", + "onVersion": "Używasz wersji {version}.", + "available": "Wersja {version} jest dostępna.", + "install": "Pobierz i zainstaluj", + "upToDate": "Masz najnowszą wersję.", + "checkError": "Nie udało się sprawdzić aktualizacji. Czy jesteś online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "All", "total": "Total", "allProjects": "All Projects", + "projectsHeading": "Projekty", "export": "Export", "kanban": "Kanban", "list": "List", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tap the + button to add your first password", "emptyHintDesktop": "You have not stored any passwords yet. Click the \"Add password\" button above to get started.", "addPassword": "Add password", + "title": "Hasła", + "filters": { + "heading": "Stan sejfu", + "all": "Wszystkie hasła", + "weak": "Słabe", + "reused": "Powtórzone", + "noUrl": "Bez adresu URL", + "tagsHeading": "Tagi", + "allTags": "Wszystkie tagi" + }, "searchPlaceholderMobile": "Search your vault...", "searchPlaceholderDesktop": "Search vault...", "importExport": "Import / export", @@ -1161,6 +1188,8 @@ "emptyHint": "Utwórz zestaw dla każdego projektu i środowiska (np. klucze API produkcji). Wszystko jest szyfrowane w przeglądarce przed wysłaniem.", "searchPlaceholder": "Szukaj projektu, środowiska, tagów, notatek…", "tagFilterPlaceholder": "Filtruj według tagu", + "allProjects": "Wszystkie projekty", + "projectsHeading": "Projekty", "variableCount": "{count, plural, one {# zmienna} few {# zmienne} other {# zmiennych}}", "updatedAgo": "Zaktualizowano {time}", "copyDotEnv": "Kopiuj .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Kopiuj HTML", "copyMarkdown": "Kopiuj Markdown", "exportHtml": "Eksportuj HTML", + "fileNameLabel": "Nazwa pliku", + "fileNamePlaceholder": "export", + "exportSuccess": "Zapisano {name}", "copied": "Skopiowano", "charCount": "{count, plural, one {# znak} few {# znaki} other {# znaków}}", "emptyHint": "Zacznij wpisywać Markdown, aby zobaczyć podgląd na żywo i wyjście HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Pokaż pasek boczny", + "hide": "Ukryj pasek boczny" + }, "DesktopUpdate": { "title": "Aktualizowanie MyDevTools", "downloading": "Pobieranie aktualizacji…", diff --git a/apps/desktop-ui/messages/pt-BR.json b/apps/desktop-ui/messages/pt-BR.json index b683c90e..0f0fb14f 100644 --- a/apps/desktop-ui/messages/pt-BR.json +++ b/apps/desktop-ui/messages/pt-BR.json @@ -195,6 +195,8 @@ "title": "Aparência", "description": "Personalize a aparência do aplicativo no seu dispositivo.", "themePreference": "Preferência de Tema", + "accentColor": "Cor de destaque", + "customColor": "Cor personalizada", "themes": { "light": "Claro", "dark": "Escuro", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Sobre", + "running": "Executando o MyDevTools", + "runningVersion": "Executando o MyDevTools v{version}", + "checkButton": "Verificar atualizações", + "checking": "Verificando…", + "dialogTitle": "Atualizações", + "dialogDescription": "O MyDevTools se atualiza no lugar — sem reinstalar nada, e seus dados offline nunca são tocados.", + "onVersion": "Você está na versão {version}.", + "available": "A versão {version} está disponível.", + "install": "Baixar e instalar", + "upToDate": "Você está atualizado.", + "checkError": "Não foi possível verificar atualizações. Você está online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Todas", "total": "Total", "allProjects": "Todos os Projetos", + "projectsHeading": "Projetos", "export": "Exportar", "kanban": "Kanban", "list": "Lista", @@ -966,6 +983,16 @@ "emptyHintMobile": "Toque no botão + para adicionar sua primeira senha", "emptyHintDesktop": "Você ainda não armazenou nenhuma senha. Clique no botão \"Adicionar senha\" acima para começar.", "addPassword": "Adicionar senha", + "title": "Senhas", + "filters": { + "heading": "Saúde do cofre", + "all": "Todas as senhas", + "weak": "Fracas", + "reused": "Reutilizadas", + "noUrl": "Sem URL", + "tagsHeading": "Tags", + "allTags": "Todas as tags" + }, "searchPlaceholderMobile": "Buscar no cofre...", "searchPlaceholderDesktop": "Buscar no cofre...", "importExport": "Importar / exportar", @@ -1161,6 +1188,8 @@ "emptyHint": "Crie um conjunto para cada projeto e ambiente (ex.: chaves de API de produção). Tudo é criptografado no navegador antes do envio.", "searchPlaceholder": "Buscar projeto, ambiente, tags, notas…", "tagFilterPlaceholder": "Filtrar por tag", + "allProjects": "Todos os projetos", + "projectsHeading": "Projetos", "variableCount": "{count, plural, one {# variável} other {# variáveis}}", "updatedAgo": "Atualizado {time}", "copyDotEnv": "Copiar .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Copiar HTML", "copyMarkdown": "Copiar Markdown", "exportHtml": "Exportar HTML", + "fileNameLabel": "Nome do arquivo", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} salvo", "copied": "Copiado", "charCount": "{count, plural, one {# caractere} other {# caracteres}}", "emptyHint": "Comece a digitar Markdown para ver a pré-visualização ao vivo e a saída HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Mostrar barra lateral", + "hide": "Ocultar barra lateral" + }, "DesktopUpdate": { "title": "Atualizando o MyDevTools", "downloading": "Baixando atualização…", diff --git a/apps/desktop-ui/messages/pt.json b/apps/desktop-ui/messages/pt.json index 0ebe342f..58e141e1 100644 --- a/apps/desktop-ui/messages/pt.json +++ b/apps/desktop-ui/messages/pt.json @@ -195,6 +195,8 @@ "title": "Aparência", "description": "Personaliza o aspeto da aplicação no teu dispositivo.", "themePreference": "Preferência de Tema", + "accentColor": "Cor de destaque", + "customColor": "Cor personalizada", "themes": { "light": "Claro", "dark": "Escuro", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Acerca de", + "running": "A executar o MyDevTools", + "runningVersion": "A executar o MyDevTools v{version}", + "checkButton": "Procurar atualizações", + "checking": "A procurar…", + "dialogTitle": "Atualizações", + "dialogDescription": "O MyDevTools atualiza-se no local — sem reinstalar nada, e os seus dados offline nunca são tocados.", + "onVersion": "Está na versão {version}.", + "available": "A versão {version} está disponível.", + "install": "Transferir e instalar", + "upToDate": "Está atualizado.", + "checkError": "Não foi possível procurar atualizações. Está online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Todas", "total": "Total", "allProjects": "Todos os Projetos", + "projectsHeading": "Projetos", "export": "Exportar", "kanban": "Kanban", "list": "Lista", @@ -966,6 +983,16 @@ "emptyHintMobile": "Toca no botão + para adicionar a tua primeira palavra-passe", "emptyHintDesktop": "Ainda não armazenaste nenhuma palavra-passe. Clica no botão \"Adicionar palavra-passe\" acima para começar.", "addPassword": "Adicionar palavra-passe", + "title": "Palavras-passe", + "filters": { + "heading": "Estado do cofre", + "all": "Todas as palavras-passe", + "weak": "Fracas", + "reused": "Reutilizadas", + "noUrl": "Sem URL", + "tagsHeading": "Etiquetas", + "allTags": "Todas as etiquetas" + }, "searchPlaceholderMobile": "Pesquisar no cofre...", "searchPlaceholderDesktop": "Pesquisar no cofre...", "importExport": "Importar / exportar", @@ -1161,6 +1188,8 @@ "emptyHint": "Crie um conjunto por projeto e ambiente (ex.: chaves API de produção). Tudo é encriptado no navegador antes do envio.", "searchPlaceholder": "Pesquisar projeto, ambiente, etiquetas, notas…", "tagFilterPlaceholder": "Filtrar por etiqueta", + "allProjects": "Todos os projetos", + "projectsHeading": "Projetos", "variableCount": "{count, plural, one {# variável} other {# variáveis}}", "updatedAgo": "Atualizado {time}", "copyDotEnv": "Copiar .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Copiar HTML", "copyMarkdown": "Copiar Markdown", "exportHtml": "Exportar HTML", + "fileNameLabel": "Nome do ficheiro", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} guardado", "copied": "Copiado", "charCount": "{count, plural, one {# carácter} other {# caracteres}}", "emptyHint": "Comece a escrever Markdown para ver a pré-visualização em tempo real e a saída HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% offline" }, + "ToolSidebar": { + "show": "Mostrar barra lateral", + "hide": "Ocultar barra lateral" + }, "DesktopUpdate": { "title": "A atualizar o MyDevTools", "downloading": "A transferir a atualização…", diff --git a/apps/desktop-ui/messages/ru.json b/apps/desktop-ui/messages/ru.json index 279dd21f..f61cc826 100644 --- a/apps/desktop-ui/messages/ru.json +++ b/apps/desktop-ui/messages/ru.json @@ -195,6 +195,8 @@ "title": "Внешний вид", "description": "Настройте внешний вид приложения на вашем устройстве.", "themePreference": "Тема оформления", + "accentColor": "Акцентный цвет", + "customColor": "Свой цвет", "themes": { "light": "Светлая", "dark": "Тёмная", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "О приложении", + "running": "MyDevTools запущен", + "runningVersion": "MyDevTools v{version} запущен", + "checkButton": "Проверить обновления", + "checking": "Проверка…", + "dialogTitle": "Обновления", + "dialogDescription": "MyDevTools обновляется на месте — без переустановки, и ваши офлайн-данные никогда не затрагиваются.", + "onVersion": "У вас версия {version}.", + "available": "Доступна версия {version}.", + "install": "Скачать и установить", + "upToDate": "У вас последняя версия.", + "checkError": "Не удалось проверить обновления. Вы онлайн?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Все", "total": "Итого", "allProjects": "Все проекты", + "projectsHeading": "Проекты", "export": "Экспорт", "kanban": "Канбан", "list": "Список", @@ -966,6 +983,16 @@ "emptyHintMobile": "Нажмите кнопку +, чтобы добавить первый пароль", "emptyHintDesktop": "У вас пока нет сохранённых паролей. Нажмите «Добавить пароль», чтобы начать.", "addPassword": "Добавить пароль", + "title": "Пароли", + "filters": { + "heading": "Состояние хранилища", + "all": "Все пароли", + "weak": "Слабые", + "reused": "Повторяющиеся", + "noUrl": "Без URL", + "tagsHeading": "Теги", + "allTags": "Все теги" + }, "searchPlaceholderMobile": "Поиск по хранилищу...", "searchPlaceholderDesktop": "Поиск по хранилищу...", "importExport": "Импорт / экспорт", @@ -1161,6 +1188,8 @@ "emptyHint": "Создайте набор для каждого проекта и среды (например, ключи API продакшена). Всё шифруется в браузере перед загрузкой.", "searchPlaceholder": "Поиск по проекту, среде, тегам, заметкам…", "tagFilterPlaceholder": "Фильтр по тегу", + "allProjects": "Все проекты", + "projectsHeading": "Проекты", "variableCount": "{count, plural, one {# переменная} few {# переменные} other {# переменных}}", "updatedAgo": "Обновлено {time}", "copyDotEnv": "Копировать .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Копировать HTML", "copyMarkdown": "Копировать Markdown", "exportHtml": "Экспорт HTML", + "fileNameLabel": "Имя файла", + "fileNamePlaceholder": "export", + "exportSuccess": "Сохранено: {name}", "copied": "Скопировано", "charCount": "{count, plural, one {# символ} few {# символа} other {# символов}}", "emptyHint": "Начните вводить Markdown, чтобы увидеть предпросмотр и HTML вывод.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% офлайн" }, + "ToolSidebar": { + "show": "Показать боковую панель", + "hide": "Скрыть боковую панель" + }, "DesktopUpdate": { "title": "Обновление MyDevTools", "downloading": "Загрузка обновления…", diff --git a/apps/desktop-ui/messages/sv.json b/apps/desktop-ui/messages/sv.json index f44fa205..d0ce5555 100644 --- a/apps/desktop-ui/messages/sv.json +++ b/apps/desktop-ui/messages/sv.json @@ -195,6 +195,8 @@ "title": "Utseende", "description": "Anpassa hur applikationen ser ut på din enhet.", "themePreference": "Temainställning", + "accentColor": "Accentfärg", + "customColor": "Anpassad färg", "themes": { "light": "Ljust", "dark": "Mörkt", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Om", + "running": "Kör MyDevTools", + "runningVersion": "Kör MyDevTools v{version}", + "checkButton": "Sök efter uppdateringar", + "checking": "Söker…", + "dialogTitle": "Uppdateringar", + "dialogDescription": "MyDevTools uppdaterar sig själv på plats — ingen ominstallation, och dina offlinedata berörs aldrig.", + "onVersion": "Du använder version {version}.", + "available": "Version {version} är tillgänglig.", + "install": "Ladda ner och installera", + "upToDate": "Du är uppdaterad.", + "checkError": "Kunde inte söka efter uppdateringar. Är du online?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Alla", "total": "Totalt", "allProjects": "Alla projekt", + "projectsHeading": "Projekt", "export": "Exportera", "kanban": "Kanban", "list": "Lista", @@ -966,6 +983,16 @@ "emptyHintMobile": "Tryck på +-knappen för att lägga till ditt första lösenord", "emptyHintDesktop": "Du har inte lagrat några lösenord ännu. Klicka på knappen \"Lägg till lösenord\" ovan för att komma igång.", "addPassword": "Lägg till lösenord", + "title": "Lösenord", + "filters": { + "heading": "Valvets status", + "all": "Alla lösenord", + "weak": "Svaga", + "reused": "Återanvända", + "noUrl": "Ingen URL", + "tagsHeading": "Taggar", + "allTags": "Alla taggar" + }, "searchPlaceholderMobile": "Sök i ditt valv...", "searchPlaceholderDesktop": "Sök i valvet...", "importExport": "Importera / exportera", @@ -1161,6 +1188,8 @@ "emptyHint": "Skapa en uppsättning för varje projekt och miljö (t.ex. produktions-API-nycklar). Allt krypteras i webbläsaren före uppladdning.", "searchPlaceholder": "Sök projekt, miljö, taggar, anteckningar…", "tagFilterPlaceholder": "Filtrera på tagg", + "allProjects": "Alla projekt", + "projectsHeading": "Projekt", "variableCount": "{count, plural, one {# variabel} other {# variabler}}", "updatedAgo": "Uppdaterad {time}", "copyDotEnv": "Kopiera .env", @@ -3870,6 +3899,9 @@ "copyHtml": "Kopiera HTML", "copyMarkdown": "Kopiera Markdown", "exportHtml": "Exportera HTML", + "fileNameLabel": "Filnamn", + "fileNamePlaceholder": "export", + "exportSuccess": "Sparade {name}", "copied": "Kopierat", "charCount": "{count, plural, one {# tecken} other {# tecken}}", "emptyHint": "Börja skriva Markdown för att se live-förhandsgranskning och HTML-utdata.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "100 % offline" }, + "ToolSidebar": { + "show": "Visa sidopanel", + "hide": "Dölj sidopanel" + }, "DesktopUpdate": { "title": "Uppdaterar MyDevTools", "downloading": "Laddar ner uppdatering…", diff --git a/apps/desktop-ui/messages/tr.json b/apps/desktop-ui/messages/tr.json index 796be883..4b580bdf 100644 --- a/apps/desktop-ui/messages/tr.json +++ b/apps/desktop-ui/messages/tr.json @@ -195,6 +195,8 @@ "title": "Görünüm", "description": "Uygulamanın cihazınızda nasıl göründüğünü özelleştirin.", "themePreference": "Tema Tercihi", + "accentColor": "Vurgu rengi", + "customColor": "Özel renk", "themes": { "light": "Açık", "dark": "Koyu", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Hakkında", + "running": "MyDevTools çalışıyor", + "runningVersion": "MyDevTools v{version} çalışıyor", + "checkButton": "Güncellemeleri denetle", + "checking": "Denetleniyor…", + "dialogTitle": "Güncellemeler", + "dialogDescription": "MyDevTools kendini yerinde günceller — yeniden kurulum gerekmez ve çevrimdışı verilerinize asla dokunulmaz.", + "onVersion": "{version} sürümünü kullanıyorsunuz.", + "available": "{version} sürümü kullanılabilir.", + "install": "İndir ve kur", + "upToDate": "En son sürümü kullanıyorsunuz.", + "checkError": "Güncellemeler denetlenemedi. Çevrimiçi misiniz?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Tümü", "total": "Toplam", "allProjects": "Tüm Projeler", + "projectsHeading": "Projeler", "export": "Dışa Aktar", "kanban": "Kanban", "list": "Liste", @@ -966,6 +983,16 @@ "emptyHintMobile": "İlk şifrenizi eklemek için + düğmesine dokunun", "emptyHintDesktop": "Henüz kayıtlı şifreniz yok. Başlamak için yukarıdaki \"Şifre ekle\" düğmesine tıklayın.", "addPassword": "Şifre ekle", + "title": "Parolalar", + "filters": { + "heading": "Kasa durumu", + "all": "Tüm parolalar", + "weak": "Zayıf", + "reused": "Tekrar kullanılan", + "noUrl": "URL yok", + "tagsHeading": "Etiketler", + "allTags": "Tüm etiketler" + }, "searchPlaceholderMobile": "Kasanızda arayın...", "searchPlaceholderDesktop": "Kasada ara...", "importExport": "İçe / dışa aktar", @@ -1161,6 +1188,8 @@ "emptyHint": "Her proje ve ortam için bir küme oluşturun (ör. üretim API anahtarları). Yüklemeden önce her şey tarayıcınızda şifrelenir.", "searchPlaceholder": "Proje, ortam, etiket, not ara…", "tagFilterPlaceholder": "Etikete göre filtrele", + "allProjects": "Tüm projeler", + "projectsHeading": "Projeler", "variableCount": "{count, plural, one {# değişken} other {# değişken}}", "updatedAgo": "Güncellendi {time}", "copyDotEnv": ".env kopyala", @@ -3870,6 +3899,9 @@ "copyHtml": "HTML'yi Kopyala", "copyMarkdown": "Markdown'ı Kopyala", "exportHtml": "HTML'yi Dışa Aktar", + "fileNameLabel": "Dosya adı", + "fileNamePlaceholder": "export", + "exportSuccess": "{name} kaydedildi", "copied": "Kopyalandı", "charCount": "{count, plural, one {# karakter} other {# karakter}}", "emptyHint": "Canlı önizleme ve HTML çıktısını görmek için Markdown yazmaya başlayın.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "%100 çevrimdışı" }, + "ToolSidebar": { + "show": "Kenar çubuğunu göster", + "hide": "Kenar çubuğunu gizle" + }, "DesktopUpdate": { "title": "MyDevTools güncelleniyor", "downloading": "Güncelleme indiriliyor…", diff --git a/apps/desktop-ui/messages/uk.json b/apps/desktop-ui/messages/uk.json index ec3ee262..40c7e97e 100644 --- a/apps/desktop-ui/messages/uk.json +++ b/apps/desktop-ui/messages/uk.json @@ -195,6 +195,8 @@ "title": "Зовнішній вигляд", "description": "Налаштуйте вигляд програми на вашому пристрої.", "themePreference": "Вибір теми", + "accentColor": "Акцентний колір", + "customColor": "Власний колір", "themes": { "light": "Світла", "dark": "Темна", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Про програму", + "running": "MyDevTools запущено", + "runningVersion": "MyDevTools v{version} запущено", + "checkButton": "Перевірити оновлення", + "checking": "Перевірка…", + "dialogTitle": "Оновлення", + "dialogDescription": "MyDevTools оновлюється на місці — без перевстановлення, і ваші офлайн-дані ніколи не змінюються.", + "onVersion": "У вас версія {version}.", + "available": "Доступна версія {version}.", + "install": "Завантажити й встановити", + "upToDate": "У вас найновіша версія.", + "checkError": "Не вдалося перевірити оновлення. Ви онлайн?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Усі", "total": "Всього", "allProjects": "Усі проєкти", + "projectsHeading": "Проєкти", "export": "Експорт", "kanban": "Канбан", "list": "Список", @@ -966,6 +983,16 @@ "emptyHintMobile": "Натисніть кнопку +, щоб додати перший пароль", "emptyHintDesktop": "Ви ще не зберегли жодного паролю. Натисніть кнопку «Додати пароль» вище, щоб почати.", "addPassword": "Додати пароль", + "title": "Паролі", + "filters": { + "heading": "Стан сховища", + "all": "Усі паролі", + "weak": "Слабкі", + "reused": "Повторювані", + "noUrl": "Без URL", + "tagsHeading": "Теги", + "allTags": "Усі теги" + }, "searchPlaceholderMobile": "Пошук у сховищі...", "searchPlaceholderDesktop": "Пошук у сховищі...", "importExport": "Імпорт / експорт", @@ -1161,6 +1188,8 @@ "emptyHint": "Створіть набір для кожного проєкту й середовища (наприклад, ключі API продакшену). Усе шифрується в браузері перед завантаженням.", "searchPlaceholder": "Пошук за проєктом, середовищем, тегами, нотатками…", "tagFilterPlaceholder": "Фільтр за тегом", + "allProjects": "Усі проєкти", + "projectsHeading": "Проєкти", "variableCount": "{count, plural, one {# змінна} few {# змінні} other {# змінних}}", "updatedAgo": "Оновлено {time}", "copyDotEnv": "Копіювати .env", @@ -3870,6 +3899,9 @@ "copyHtml": "Копіювати HTML", "copyMarkdown": "Копіювати Markdown", "exportHtml": "Експортувати HTML", + "fileNameLabel": "Назва файлу", + "fileNamePlaceholder": "export", + "exportSuccess": "Збережено: {name}", "copied": "Скопійовано", "charCount": "{count, plural, one {# символ} few {# символи} other {# символів}}", "emptyHint": "Почніть вводити Markdown, щоб побачити попередній перегляд і HTML вивід.", @@ -5106,6 +5138,10 @@ "ToolPageHeader": { "offline": "100% офлайн" }, + "ToolSidebar": { + "show": "Показати бічну панель", + "hide": "Сховати бічну панель" + }, "DesktopUpdate": { "title": "Оновлення MyDevTools", "downloading": "Завантаження оновлення…", diff --git a/apps/desktop-ui/messages/vi.json b/apps/desktop-ui/messages/vi.json index e1f27695..25a6eece 100644 --- a/apps/desktop-ui/messages/vi.json +++ b/apps/desktop-ui/messages/vi.json @@ -195,6 +195,8 @@ "title": "Giao diện", "description": "Tùy chỉnh giao diện ứng dụng trên thiết bị của bạn.", "themePreference": "Tùy chọn giao diện", + "accentColor": "Màu nhấn", + "customColor": "Màu tùy chỉnh", "themes": { "light": "Sáng", "dark": "Tối", @@ -257,6 +259,20 @@ "tr": "Türkçe", "uk": "Українська" } + }, + "about": { + "title": "Giới thiệu", + "running": "Đang chạy MyDevTools", + "runningVersion": "Đang chạy MyDevTools v{version}", + "checkButton": "Kiểm tra bản cập nhật", + "checking": "Đang kiểm tra…", + "dialogTitle": "Bản cập nhật", + "dialogDescription": "MyDevTools tự cập nhật ngay tại chỗ — không cần cài lại và dữ liệu ngoại tuyến của bạn không bao giờ bị ảnh hưởng.", + "onVersion": "Bạn đang dùng phiên bản {version}.", + "available": "Đã có phiên bản {version}.", + "install": "Tải xuống và cài đặt", + "upToDate": "Bạn đang dùng bản mới nhất.", + "checkError": "Không thể kiểm tra bản cập nhật. Bạn có đang trực tuyến không?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "Tất cả", "total": "Tổng", "allProjects": "Tất cả dự án", + "projectsHeading": "Dự án", "export": "Xuất", "kanban": "Kanban", "list": "Danh sách", @@ -966,6 +983,16 @@ "emptyHintMobile": "Nhấn nút + để thêm mật khẩu đầu tiên", "emptyHintDesktop": "Bạn chưa lưu mật khẩu nào. Nhấn nút \"Thêm mật khẩu\" ở trên để bắt đầu.", "addPassword": "Thêm mật khẩu", + "title": "Mật khẩu", + "filters": { + "heading": "Tình trạng kho", + "all": "Tất cả mật khẩu", + "weak": "Yếu", + "reused": "Dùng lại", + "noUrl": "Không có URL", + "tagsHeading": "Thẻ", + "allTags": "Tất cả thẻ" + }, "searchPlaceholderMobile": "Tìm trong kho...", "searchPlaceholderDesktop": "Tìm trong kho...", "importExport": "Nhập / xuất", @@ -1161,6 +1188,8 @@ "emptyHint": "Tạo một bộ cho mỗi dự án và môi trường (ví dụ khóa API production). Mọi thứ được mã hóa trong trình duyệt trước khi tải lên.", "searchPlaceholder": "Tìm dự án, môi trường, thẻ, ghi chú…", "tagFilterPlaceholder": "Lọc theo thẻ", + "allProjects": "Tất cả dự án", + "projectsHeading": "Dự án", "variableCount": "{count, plural, other {# biến}}", "updatedAgo": "Cập nhật {time}", "copyDotEnv": "Sao chép .env", @@ -3859,6 +3888,9 @@ "copyHtml": "Sao chép HTML", "copyMarkdown": "Sao chép Markdown", "exportHtml": "Xuất HTML", + "fileNameLabel": "Tên tệp", + "fileNamePlaceholder": "export", + "exportSuccess": "Đã lưu {name}", "copied": "Đã sao chép", "charCount": "{count, plural, other {# ký tự}}", "emptyHint": "Bắt đầu nhập Markdown để xem bản xem trước trực tiếp và đầu ra HTML.", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% ngoại tuyến" }, + "ToolSidebar": { + "show": "Hiện thanh bên", + "hide": "Ẩn thanh bên" + }, "DesktopUpdate": { "title": "Đang cập nhật MyDevTools", "downloading": "Đang tải bản cập nhật…", diff --git a/apps/desktop-ui/messages/zh.json b/apps/desktop-ui/messages/zh.json index 3e9414ec..6b7fbaa2 100644 --- a/apps/desktop-ui/messages/zh.json +++ b/apps/desktop-ui/messages/zh.json @@ -195,6 +195,8 @@ "title": "外观", "description": "自定义应用在你设备上的显示方式。", "themePreference": "主题偏好", + "accentColor": "强调色", + "customColor": "自定义颜色", "themes": { "light": "浅色", "dark": "深色", @@ -257,6 +259,20 @@ "sv": "Svenska", "tr": "Türkçe" } + }, + "about": { + "title": "关于", + "running": "正在运行 MyDevTools", + "runningVersion": "正在运行 MyDevTools v{version}", + "checkButton": "检查更新", + "checking": "检查中…", + "dialogTitle": "更新", + "dialogDescription": "MyDevTools 会就地自我更新——无需重新安装,且绝不会触碰你的离线数据。", + "onVersion": "你当前使用的版本是 {version}。", + "available": "版本 {version} 可用。", + "install": "下载并安装", + "upToDate": "已是最新版本。", + "checkError": "无法检查更新。你是否已联网?" } }, "Dashboard": { @@ -709,6 +725,7 @@ "all": "全部", "total": "总计", "allProjects": "所有项目", + "projectsHeading": "项目", "export": "导出", "kanban": "看板", "list": "列表", @@ -966,6 +983,16 @@ "emptyHintMobile": "点击 + 添加第一条密码", "emptyHintDesktop": "尚未保存任何密码。点击上方「添加密码」开始。", "addPassword": "添加密码", + "title": "密码", + "filters": { + "heading": "保险库健康度", + "all": "所有密码", + "weak": "弱密码", + "reused": "重复使用", + "noUrl": "无网址", + "tagsHeading": "标签", + "allTags": "所有标签" + }, "searchPlaceholderMobile": "搜索保险库…", "searchPlaceholderDesktop": "搜索保险库…", "importExport": "导入 / 导出", @@ -1161,6 +1188,8 @@ "emptyHint": "为每个项目与环境创建集合(例如生产环境 API 密钥)。上传前均在浏览器中加密。", "searchPlaceholder": "搜索项目、环境、标签、备注…", "tagFilterPlaceholder": "按标签筛选", + "allProjects": "所有项目", + "projectsHeading": "项目", "variableCount": "{count, plural, other {# 个变量}}", "updatedAgo": "更新于 {time}", "copyDotEnv": "复制 .env", @@ -3859,6 +3888,9 @@ "copyHtml": "复制 HTML", "copyMarkdown": "复制 Markdown", "exportHtml": "导出 HTML", + "fileNameLabel": "文件名", + "fileNamePlaceholder": "export", + "exportSuccess": "已保存 {name}", "copied": "已复制", "charCount": "{count, plural, other {# 个字符}}", "emptyHint": "开始输入 Markdown 以查看实时预览和 HTML 输出。", @@ -5095,6 +5127,10 @@ "ToolPageHeader": { "offline": "100% 离线" }, + "ToolSidebar": { + "show": "显示侧边栏", + "hide": "隐藏侧边栏" + }, "DesktopUpdate": { "title": "正在更新 MyDevTools", "downloading": "正在下载更新…", diff --git a/apps/desktop-ui/scripts/build-tauri.mjs b/apps/desktop-ui/scripts/build-tauri.mjs index 9e991686..29b3534e 100644 --- a/apps/desktop-ui/scripts/build-tauri.mjs +++ b/apps/desktop-ui/scripts/build-tauri.mjs @@ -65,5 +65,7 @@ if (result.status !== 0) { } const outDir = path.join(uiRoot, "out"); +// outDir is derived from this script's own location and quoted by JSON.stringify. +// threatcrush-disable-next-line js-shell-exec-interpolation const pageCount = execSync(`find ${JSON.stringify(outDir)} -name '*.html' | wc -l`).toString().trim(); console.log(`build-tauri: OK — ${pageCount} HTML pages in apps/desktop-ui/out/`); diff --git a/apps/desktop-ui/src/app/app/api-keys/page.tsx b/apps/desktop-ui/src/app/app/api-keys/page.tsx index 2e644108..a4d39fae 100644 --- a/apps/desktop-ui/src/app/app/api-keys/page.tsx +++ b/apps/desktop-ui/src/app/app/api-keys/page.tsx @@ -4,7 +4,6 @@ import { useEffect, useRef } from "react" import { AddApiKeyDialog } from "@/components/api-key-vault/add-api-key-dialog" import { ApiKeyList } from "@/components/api-key-vault/api-key-list" import { useApiKeyVaultStore, type ApiKeyEntry } from "@/store/api-key-vault-store" -import { ToolHeader } from "@/components/tools/tool-header" import { useVaultGuard } from "@/hooks/use-vault-guard" import { VaultLockedPlaceholder } from "@/components/vault-locked-placeholder" import { VaultRestoringSkeleton } from "@/components/vault-restoring-skeleton" @@ -104,25 +103,11 @@ export default function ApiKeyVaultPage() { if (!user) return null + // Tool identity and the add action live in the ToolSidebarLayout header + // that ApiKeyList renders — no separate page header row. return ( -
- - -
- -
- +
+ {isMobile && }
) diff --git a/apps/desktop-ui/src/app/app/data-explorer/page.tsx b/apps/desktop-ui/src/app/app/data-explorer/page.tsx index 0ff02bd3..9da9816e 100644 --- a/apps/desktop-ui/src/app/app/data-explorer/page.tsx +++ b/apps/desktop-ui/src/app/app/data-explorer/page.tsx @@ -3,14 +3,12 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslations } from "next-intl"; import { toast } from "sonner"; -import { IconAlertTriangle, IconMenu2 } from "@tabler/icons-react"; +import { IconAlertTriangle, IconDatabase, IconPlus } from "@tabler/icons-react"; import { Button } from "@/components/ui/button"; -import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet"; -import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; import useAuth from "@/utils/useAuth"; import { useMasterKeyStore } from "@/store/master-key-store"; import { useVaultGuard } from "@/hooks/use-vault-guard"; -import { useMediaQuery } from "@/hooks/use-media-query"; +import { ToolSidebarLayout } from "@/components/tools/tool-sidebar"; import { VaultLockedPlaceholder } from "@/components/vault-locked-placeholder"; import { VaultRestoringSkeleton } from "@/components/vault-restoring-skeleton"; import { UnifiedTabBar } from "@/components/data-explorer/unified-tab-bar"; @@ -31,12 +29,10 @@ export default function DataExplorerPage() { const { user } = useAuth(); const { encryptionKey } = useMasterKeyStore(); const { isUnlocked, isRestoring } = useVaultGuard(); - const isWide = useMediaQuery("(min-width: 768px)"); const [connections, setConnections] = useState([]); const [tabs, setTabs] = useState([]); const [activeTabId, setActiveTabId] = useState(null); - const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); const [isInitialized, setIsInitialized] = useState(false); const [connectionDialogOpen, setConnectionDialogOpen] = useState(false); const [editingConnection, setEditingConnection] = useState(null); @@ -108,7 +104,6 @@ export default function DataExplorerPage() { const openTab = useCallback( (connection: UnifiedConnection, req: OpenTabRequest) => { const id = `${connection.id}:${req.key}`; - setMobileSidebarOpen(false); setTabs((prev) => { if (prev.some((tab) => tab.id === id)) return prev; return [ @@ -253,35 +248,24 @@ export default function DataExplorerPage() { })(); return ( -
- {isWide ? ( -
{sidebar}
- ) : ( - - - - {t("title")} - - {sidebar} - - - )} + + + + } + sidebar={sidebar} + >
- {/* Narrow viewports keep the sidebar in the Sheet; without this - trigger there is no way to add a connection or open a tab. */} - {!isWide && ( -
- -
- )} void reloadConnections()} /> -
+
); } diff --git a/apps/desktop-ui/src/app/app/environment-manager/page.tsx b/apps/desktop-ui/src/app/app/environment-manager/page.tsx index 450d7fa4..3d8a95ad 100644 --- a/apps/desktop-ui/src/app/app/environment-manager/page.tsx +++ b/apps/desktop-ui/src/app/app/environment-manager/page.tsx @@ -3,7 +3,6 @@ import { useEffect, useRef } from "react" import { AddEnvironmentSetDialog } from "@/components/environment-manager/add-environment-set-dialog" import { EnvironmentSetList } from "@/components/environment-manager/environment-set-list" -import { ToolHeader } from "@/components/tools/tool-header" import { useEnvironmentManagerStore, type EnvSetEntry } from "@/store/environment-manager-store" import { useVaultGuard } from "@/hooks/use-vault-guard" import { VaultLockedPlaceholder } from "@/components/vault-locked-placeholder" @@ -110,22 +109,11 @@ export default function EnvironmentManagerPage() { if (!user) return null + // Tool identity lives in the ToolSidebarLayout header EnvironmentSetList + // renders — no separate page header row. return ( -
- {!isMobile && ( - - )} - -
- -
- +
+ {isMobile && }
) diff --git a/apps/desktop-ui/src/app/app/layout.tsx b/apps/desktop-ui/src/app/app/layout.tsx index 6d19ddd7..12b60cbd 100644 --- a/apps/desktop-ui/src/app/app/layout.tsx +++ b/apps/desktop-ui/src/app/app/layout.tsx @@ -1,26 +1,13 @@ import { Suspense } from "react"; -import { cookies } from "next/headers"; -import { SidebarProvider } from "@/components/ui/sidebar"; import { AppContent } from "./app-content"; -// Static export (Tauri desktop) cannot use request APIs; fall back to defaults there. -const isTauriBuild = process.env.TAURI_BUILD === "1"; - -export default async function Layout({ children }: { children: React.ReactNode }) { - let defaultOpen = true; - if (!isTauriBuild) { - const cookieStore = await cookies(); - defaultOpen = cookieStore.get("sidebar:state")?.value !== "false"; - } - +export default function Layout({ children }: { children: React.ReactNode }) { return ( - - {/* Suspense boundary so tool pages that read useSearchParams() (base64, - jwt-decoder, hash-generator, url-encode, json-formatter, qr-code) pass - the static export prerender instead of erroring on a CSR bailout. */} - - {children} - - + // Suspense boundary so tool pages that read useSearchParams() (base64, + // jwt-decoder, hash-generator, url-encode, json-formatter, qr-code) pass + // the static export prerender instead of erroring on a CSR bailout. + + {children} + ); } diff --git a/apps/desktop-ui/src/app/app/notes/context/NotesContext.tsx b/apps/desktop-ui/src/app/app/notes/context/NotesContext.tsx index c80c09ec..5fbf1dae 100644 --- a/apps/desktop-ui/src/app/app/notes/context/NotesContext.tsx +++ b/apps/desktop-ui/src/app/app/notes/context/NotesContext.tsx @@ -37,8 +37,6 @@ interface NotesUI { setActiveNoteId: (id: string | null) => void; focusMode: boolean; setFocusMode: (v: boolean) => void; - sidebarOpen: boolean; - setSidebarOpen: (v: boolean) => void; } interface NotesActions { @@ -65,7 +63,6 @@ export function NotesProvider({ children }: { children: React.ReactNode }) { const [isContentLoading, setIsContentLoading] = useState(false); const [activeNoteId, setActiveNoteId] = useState(null); const [focusMode, setFocusMode] = useState(false); - const [sidebarOpen, setSidebarOpen] = useState(true); // Decrypted bodies, tagged with the key they were decrypted under: a vault // lock/unlock invalidates the whole map on read, with no reset effect. const [contentStore, setContentStore] = useState({ key: null, map: EMPTY_CONTENT }); @@ -81,6 +78,9 @@ export function NotesProvider({ children }: { children: React.ReactNode }) { useEffect(() => { warmedKeyRef.current = warmedKey; }, [warmedKey]); const warmInFlight = useRef | null>(null); const contentLoadedIds = useRef>(new Set()); + // Cipher key the loaded bodies were decrypted under — a mismatch invalidates + // them (see the body-loading effect below). + const loadedUnderKey = useRef(null); // Notes whose content is an envelope we couldn't decrypt (vault locked). Their // in-state `content` is a null placeholder — writing it back would clobber the // real body, so content writes are blocked until unlock. @@ -156,7 +156,19 @@ export function NotesProvider({ children }: { children: React.ReactNode }) { setNotes([...allNotes].sort((a, b) => a.createdAt.localeCompare(b.createdAt))); }, [apiRequest]); + // Body of the active note. Runs on cipherKey change too: a note opened while + // the vault was locked holds a null placeholder, and the plain-text cache is + // module state — both must be invalidated and refetched under the new key, or + // the editor shows an empty document and the next keystroke saves that over + // the real body. (Invalidation lives here, not in its own [cipherKey] effect, + // so it can't run *after* this one and leave the refetch skipped.) useEffect(() => { + if (loadedUnderKey.current !== cipherKey) { + loadedUnderKey.current = cipherKey; + contentLoadedIds.current.clear(); + lockedIds.current.clear(); + clearPlainTextCache(); + } if (!activeNoteId || contentLoadedIds.current.has(activeNoteId)) return; let cancelled = false; setIsContentLoading(true); @@ -175,7 +187,7 @@ export function NotesProvider({ children }: { children: React.ReactNode }) { .catch(() => { /* note may have been deleted */ }) .finally(() => { if (!cancelled) setIsContentLoading(false); }); return () => { cancelled = true; }; - }, [activeNoteId, apiRequest, decryptBody, setContent]); + }, [activeNoteId, cipherKey, apiRequest, decryptBody, setContent]); // Flush parked updatedAt bumps from body saves when the user leaves a note — // one re-render per switch instead of one per autosave. @@ -203,16 +215,6 @@ export function NotesProvider({ children }: { children: React.ReactNode }) { // on the vault key. Bodies are handled by the effect below. }, [refreshNotes]); - // Vault lock/unlock: bodies and the search index invalidate themselves (both - // are tagged with their key), but the plain-text cache is module state — - // clear it so decrypted text doesn't outlive the unlocked session. The - // active note then refetches under the new key state. No mass refetch. - useEffect(() => { - contentLoadedIds.current.clear(); - lockedIds.current.clear(); - clearPlainTextCache(); - }, [cipherKey]); - /** * Decrypt every note body once into the plain-text search cache. Only the * extracted text is retained — raw bodies are dropped — so memory doesn't @@ -402,8 +404,8 @@ export function NotesProvider({ children }: { children: React.ReactNode }) { ); const uiValue = useMemo( - () => ({ activeNoteId, setActiveNoteId, focusMode, setFocusMode, sidebarOpen, setSidebarOpen }), - [activeNoteId, focusMode, sidebarOpen] + () => ({ activeNoteId, setActiveNoteId, focusMode, setFocusMode }), + [activeNoteId, focusMode] ); const actionsValue = useMemo( diff --git a/apps/desktop-ui/src/app/app/notes/notes-client-layout.tsx b/apps/desktop-ui/src/app/app/notes/notes-client-layout.tsx index 615ce2c7..94cc182a 100644 --- a/apps/desktop-ui/src/app/app/notes/notes-client-layout.tsx +++ b/apps/desktop-ui/src/app/app/notes/notes-client-layout.tsx @@ -2,69 +2,33 @@ import { NotesProvider, useNotesUI } from "./context/NotesContext"; import NotesSidebar from "@/components/notes/NotesSidebar"; -import { useMediaQuery } from "@/hooks/use-media-query"; -import { Sheet, SheetContent, SheetTrigger, SheetHeader, SheetTitle } from "@/components/ui/sheet"; -import { Menu, PanelLeftOpen, NotebookPen } from "lucide-react"; -import { Button } from "@/components/ui/button"; +import { ToolSidebarLayout } from "@/components/tools/tool-sidebar"; +import { NotebookPen } from "lucide-react"; import { useTranslations } from "next-intl"; function NotesLayout({ children }: { children: React.ReactNode }) { - const t = useTranslations("Notes.layout"); const tSidebar = useTranslations("Notes.sidebar"); - const isDesktop = useMediaQuery("(min-width: 768px)"); - const { focusMode, sidebarOpen, setSidebarOpen } = useNotesUI(); - const sidebarCollapsed = isDesktop && !focusMode && !sidebarOpen; + const { focusMode } = useNotesUI(); - return ( -
- {isDesktop && !focusMode && sidebarOpen && } - -
- {sidebarCollapsed && ( -
- -
- - - - {tSidebar("title")} -
-
- )} - {!isDesktop && !focusMode && ( -
- - - - - - - {t("mobileNavTitle")} - - - - -
- )} + // Focus mode drops the panel entirely — no column, no re-open affordance. + if (focusMode) { + return ( +
{children}
-
+ ); + } + + return ( + } + className="bg-background mobile-nav-offset" + > + {children} + ); } diff --git a/apps/desktop-ui/src/app/app/password-manager/page.tsx b/apps/desktop-ui/src/app/app/password-manager/page.tsx index 7a34f0ff..fd29359a 100644 --- a/apps/desktop-ui/src/app/app/password-manager/page.tsx +++ b/apps/desktop-ui/src/app/app/password-manager/page.tsx @@ -20,9 +20,6 @@ import { fetchAllPages } from "@/lib/fetch-all-pages" import { EncryptedToolPlaceholder } from "@/components/encrypted-tool-placeholder" import { useActiveWorkspace } from "@/store/workspace-store" import { hasWorkspaceEncryption } from "@/lib/workspace-rbac" -import { IconShieldLock } from "@tabler/icons-react" -import { CATEGORY_ACCENT } from "@/components/dashboard/types" -import { cn } from "@/lib/utils" const PASSWORDS_PAGE_SIZE = 500 @@ -122,34 +119,11 @@ export default function PasswordManagerPage() { if (!user) return null + // Tool identity and the add action live in the ToolSidebarLayout header + // PasswordList renders — no separate page header row. return ( -
- {!isMobile && ( -
-
- - - -

{t("title")}

-
- -
- )} - +
- {isMobile && }
) diff --git a/apps/desktop-ui/src/app/app/s3-drive/page.tsx b/apps/desktop-ui/src/app/app/s3-drive/page.tsx index f41dca8f..1baab488 100644 --- a/apps/desktop-ui/src/app/app/s3-drive/page.tsx +++ b/apps/desktop-ui/src/app/app/s3-drive/page.tsx @@ -12,9 +12,9 @@ import { listConnections } from "@/lib/s3-drive-api" import { decryptData } from "@/lib/encryption" import { BucketSidebar } from "@/components/s3-drive/bucket-sidebar" import { FileBrowser } from "@/components/s3-drive/file-browser" +import { ToolSidebarLayout } from "@/components/tools/tool-sidebar" import { IconBucket, IconCloud, IconArrowRight } from "@tabler/icons-react" import { Skeleton } from "@/components/ui/skeleton" -import { cn } from "@/lib/utils" import { DesktopOnlineGate } from "@/components/desktop/desktop-online-gate" export default function S3DrivePage() { @@ -67,7 +67,7 @@ function S3DriveInner() { return (
{/* Sidebar skeleton */} -
+
@@ -120,11 +120,12 @@ function S3DriveInner() { const activeConn = connections.find((c) => c.id === activeConnectionId) ?? null return ( -
-
- -
- + } + >
{activeConn ? ( )}
-
+ ) } diff --git a/apps/desktop-ui/src/app/app/to-do/TaskContainer.tsx b/apps/desktop-ui/src/app/app/to-do/TaskContainer.tsx index 99be9f73..8f5f43ee 100644 --- a/apps/desktop-ui/src/app/app/to-do/TaskContainer.tsx +++ b/apps/desktop-ui/src/app/app/to-do/TaskContainer.tsx @@ -19,6 +19,11 @@ import { useTaskContext } from "@/app/app/to-do/context/TaskContext"; import { useWorkspaceMembers, memberLabel } from "@/app/app/to-do/hooks/useWorkspaceMembers"; import { useProjectContext } from "@/app/app/to-do/context/ProjectContext"; import { ListTodo, Circle, LayoutGrid, List, Search, X, Plus, Folder, Archive, ArchiveRestore, UserRound } from "lucide-react"; +import { + ToolSidebarFilterList, + ToolSidebarLayout, + type ToolSidebarFilterItem, +} from "@/components/tools/tool-sidebar"; import { Button } from "@/components/ui/button"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { STATUS_CONFIG } from "./config/constants"; @@ -35,7 +40,6 @@ import { DrawerClose, DrawerTrigger, } from "@/components/ui/drawer"; -import { SidebarTrigger } from "@/components/ui/sidebar"; import { Badge } from "@/components/ui/badge"; import { Select, @@ -200,7 +204,25 @@ export const TaskContainer = () => { return () => window.removeEventListener("keydown", handleKeyDown); }, [hasSearchFilter, isMobile]); + const projectFilters: ToolSidebarFilterItem[] = [ + { id: "all", label: tFilters("allProjects") }, + ...projects.map((project) => ({ id: project.id, label: project.name, dot: project.color })), + ]; + return ( + + } + >
{liveStatsMessage} @@ -212,8 +234,6 @@ export const TaskContainer = () => { style={{ paddingTop: "calc(env(safe-area-inset-top, 0px) + 0.5rem)" }} >
- -
{
-
- - - -
-

- {tPage("myTasksTitle")} -

-

- {tPage("statsLineDesktop", { total: allTaskStats.total, percent: completionRate })} -

-
-
+ {/* Tool name + icon live in the ToolSidebarLayout panel header. */} +

+ {tPage("statsLineDesktop", { total: allTaskStats.total, percent: completionRate })} +

{/* Enhanced Stats with Progress Bars - Hidden on mobile to save space */}
@@ -397,27 +408,7 @@ export const TaskContainer = () => { )}
- {/* Project Filter */} - + {/* Project filter lives in the ToolSidebarLayout panel. */} {/* Assignee Filter — only meaningful in a shared workspace */} {isShared && ( @@ -739,5 +730,6 @@ export const TaskContainer = () => { )}
+ ); }; diff --git a/apps/desktop-ui/src/app/app/to-do/utils/__tests__/statusOrder.test.ts b/apps/desktop-ui/src/app/app/to-do/utils/__tests__/statusOrder.test.ts new file mode 100644 index 00000000..83e81bec --- /dev/null +++ b/apps/desktop-ui/src/app/app/to-do/utils/__tests__/statusOrder.test.ts @@ -0,0 +1,51 @@ +import { insertOrder, needsRespread, ORDER_STEP } from "../statusOrder"; + +describe("insertOrder", () => { + it("starts at 0 in an empty column", () => { + expect(insertOrder([], 0)).toBe(0); + }); + + it("appends a step past the last card", () => { + expect(insertOrder([0, 1000], 2)).toBe(2000); + }); + + it("prepends a step before the first card", () => { + expect(insertOrder([0, 1000], 0)).toBe(-ORDER_STEP); + }); + + it("lands between two neighbours", () => { + expect(insertOrder([0, 1000], 1)).toBe(500); + }); + + it("always returns an integer — Rust reads statusOrder with as_i64", () => { + // An odd gap must not produce a fraction, or the row is skipped server-side. + expect(Number.isInteger(insertOrder([0, 1], 1))).toBe(true); + expect(Number.isInteger(insertOrder([0, 7], 1))).toBe(true); + }); + + it("clamps an out-of-range index instead of returning NaN", () => { + expect(insertOrder([0, 1000], 99)).toBe(2000); + expect(insertOrder([0, 1000], -5)).toBe(-ORDER_STEP); + }); + + it("keeps legacy 1/2/3 orders sortable without a migration", () => { + // Rows written before statusOrder meant "position" are tightly packed. + const order = insertOrder([1, 2, 3], 3); + expect(order).toBeGreaterThan(3); + }); +}); + +describe("needsRespread", () => { + it("is false when the insert found room", () => { + expect(needsRespread([0, 1000], 1, 500)).toBe(false); + }); + + it("is true when the gap between neighbours is exhausted", () => { + // No integer exists strictly between 5 and 6. + expect(needsRespread([5, 6], 1, insertOrder([5, 6], 1))).toBe(true); + }); + + it("is false at the head of a column, where there is always room", () => { + expect(needsRespread([0, 1000], 0, -ORDER_STEP)).toBe(false); + }); +}); diff --git a/apps/desktop-ui/src/app/app/to-do/utils/statusOrder.ts b/apps/desktop-ui/src/app/app/to-do/utils/statusOrder.ts new file mode 100644 index 00000000..c86f5df5 --- /dev/null +++ b/apps/desktop-ui/src/app/app/to-do/utils/statusOrder.ts @@ -0,0 +1,36 @@ +/** + * Position of a card within its board column. + * + * Cards are spaced `ORDER_STEP` apart so that dropping one between two neighbours is a + * single PATCH of the moved card instead of a renumber of the whole column. When the gap + * between two neighbours is used up, the column is respread — see `needsRespread`. + * + * Integers only: the Rust handler reads `statusOrder` with `as_i64` inside a `filter_map`, + * so a fractional value is silently skipped when it computes the next order on create. + */ +export const ORDER_STEP = 1000; + +/** + * The `statusOrder` for a card inserted at `index` of a column whose existing cards have + * `orders` (ascending, excluding the card being moved). + */ +export function insertOrder(orders: number[], index: number): number { + const at = Math.max(0, Math.min(index, orders.length)); + const prev = orders[at - 1]; + const next = orders[at]; + + if (prev === undefined && next === undefined) return 0; + if (prev === undefined) return next - ORDER_STEP; + if (next === undefined) return prev + ORDER_STEP; + return Math.floor((prev + next) / 2); +} + +/** + * True when `insertOrder` could not find room between the neighbours, so the column has to + * be respread at even intervals before the position is meaningful. + */ +export function needsRespread(orders: number[], index: number, order: number): boolean { + const at = Math.max(0, Math.min(index, orders.length)); + const prev = orders[at - 1]; + return prev !== undefined && order <= prev; +} diff --git a/apps/desktop-ui/src/app/globals.css b/apps/desktop-ui/src/app/globals.css index 0ab5234a..99f3e29f 100644 --- a/apps/desktop-ui/src/app/globals.css +++ b/apps/desktop-ui/src/app/globals.css @@ -101,129 +101,9 @@ body { --sidebar-ring: 235 84% 67%; } - /* User-selectable accent overrides (ColorThemeProvider toggles these - classes on ). Light + dark variants; everything accent-colored - flows through --primary / --ring / --sidebar-primary. */ - :root.blue { - --primary: 217.2 91.2% 59.8%; - --primary-foreground: 0 0% 98%; - --ring: 217.2 91.2% 59.8%; - --sidebar-primary: 217.2 91.2% 59.8%; - --sidebar-ring: 217.2 91.2% 59.8%; - } - - :root.purple { - --primary: 258.3 89.5% 66.3%; - --primary-foreground: 0 0% 98%; - --ring: 258.3 89.5% 66.3%; - --sidebar-primary: 258.3 89.5% 66.3%; - --sidebar-ring: 258.3 89.5% 66.3%; - } - - :root.green { - --primary: 142.1 76.2% 36.3%; - --primary-foreground: 0 0% 98%; - --ring: 142.1 76.2% 36.3%; - --sidebar-primary: 142.1 76.2% 36.3%; - --sidebar-ring: 142.1 76.2% 36.3%; - } - - :root.orange { - --primary: 24.6 95% 53.1%; - --primary-foreground: 0 0% 98%; - --ring: 24.6 95% 53.1%; - --sidebar-primary: 24.6 95% 53.1%; - --sidebar-ring: 24.6 95% 53.1%; - } - - :root.red { - --primary: 0 72.2% 50.6%; - --primary-foreground: 0 0% 98%; - --ring: 0 72.2% 50.6%; - --sidebar-primary: 0 72.2% 50.6%; - --sidebar-ring: 0 72.2% 50.6%; - } - - :root.pink { - --primary: 340.7 82.1% 52.7%; - --primary-foreground: 0 0% 98%; - --ring: 340.7 82.1% 52.7%; - --sidebar-primary: 340.7 82.1% 52.7%; - --sidebar-ring: 340.7 82.1% 52.7%; - } - - :root.cyan { - --primary: 199.1 89.1% 48.2%; - --primary-foreground: 0 0% 98%; - --ring: 199.1 89.1% 48.2%; - --sidebar-primary: 199.1 89.1% 48.2%; - --sidebar-ring: 199.1 89.1% 48.2%; - } - - :root.indigo { - --primary: 235 84% 67%; - --primary-foreground: 0 0% 100%; - --ring: 235 84% 67%; - --sidebar-primary: 235 84% 67%; - --sidebar-ring: 235 84% 67%; - } - - /* Dark mode: same hues, tuned lightness where needed */ - .dark.blue { - --primary: 217.2 91.2% 59.8%; - --ring: 217.2 91.2% 59.8%; - --sidebar-primary: 217.2 91.2% 59.8%; - --sidebar-ring: 217.2 91.2% 59.8%; - } - - .dark.purple { - --primary: 258.3 89.5% 66.3%; - --ring: 258.3 89.5% 66.3%; - --sidebar-primary: 258.3 89.5% 66.3%; - --sidebar-ring: 258.3 89.5% 66.3%; - } - - .dark.green { - --primary: 142.1 70.6% 45.3%; - --ring: 142.1 70.6% 45.3%; - --sidebar-primary: 142.1 70.6% 45.3%; - --sidebar-ring: 142.1 70.6% 45.3%; - } - - .dark.orange { - --primary: 24.6 95% 53.1%; - --ring: 24.6 95% 53.1%; - --sidebar-primary: 24.6 95% 53.1%; - --sidebar-ring: 24.6 95% 53.1%; - } - - .dark.red { - --primary: 0 72.2% 50.6%; - --ring: 0 72.2% 50.6%; - --sidebar-primary: 0 72.2% 50.6%; - --sidebar-ring: 0 72.2% 50.6%; - } - - .dark.pink { - --primary: 340.7 82.1% 52.7%; - --ring: 340.7 82.1% 52.7%; - --sidebar-primary: 340.7 82.1% 52.7%; - --sidebar-ring: 340.7 82.1% 52.7%; - } - - .dark.cyan { - --primary: 199.1 89.1% 48.2%; - --ring: 199.1 89.1% 48.2%; - --sidebar-primary: 199.1 89.1% 48.2%; - --sidebar-ring: 199.1 89.1% 48.2%; - } - - .dark.indigo { - --primary: 235 84% 67%; - --ring: 235 84% 67%; - --sidebar-primary: 235 84% 67%; - --sidebar-ring: 235 84% 67%; - } + /* Accent overrides live in JS: ColorThemeProvider writes --primary / --ring / + --sidebar-primary inline on (see lib/accent-color.ts), which also + lets a custom hex from the picker work without a CSS class per color. */ } /* Hidden scrollbar (element still scrolls) — used by the top-nav strip. */ diff --git a/apps/desktop-ui/src/app/settings/page.tsx b/apps/desktop-ui/src/app/settings/page.tsx index ee664f2d..fd193c4b 100644 --- a/apps/desktop-ui/src/app/settings/page.tsx +++ b/apps/desktop-ui/src/app/settings/page.tsx @@ -4,7 +4,7 @@ import React, { useState, useEffect } from 'react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' -import { Sun, Globe, Palette, Check, Lock } from 'lucide-react' +import { Sun, Globe, Palette, Lock, Pipette } from 'lucide-react' import { IDLE_TIMEOUT_KEY, getIdleTimeoutMinutes } from '@/lib/use-idle-lock' import { Switch } from '@/components/ui/switch' import { getVaultIconsEnabled, setVaultIconsEnabled } from '@/lib/vault-icon-pref' @@ -13,21 +13,12 @@ import { useTheme } from 'next-themes' import { cn } from '@/lib/utils' import { useLocale, useTranslations } from 'next-intl' import { useRouter } from 'next/navigation' -import { COLOR_THEME_OPTIONS, type ColorTheme, useColorTheme } from '@/hooks/use-color-theme' +import { useColorTheme } from '@/hooks/use-color-theme' +import { ACCENT_PRESETS, accentHex, isCustomAccent } from '@/lib/accent-color' import { ProfileCard } from '@/components/settings/profile-card' import { AppVersionLabel } from '@/components/desktop/app-version-label' import { useActiveWorkspace } from '@/store/workspace-store' import { Briefcase } from 'lucide-react' -const colorDisplay: Record = { - cyan: { swatchClass: 'bg-cyan-500', name: 'Teal' }, - blue: { swatchClass: 'bg-blue-500', name: 'Blue' }, - indigo: { swatchClass: 'bg-indigo-500', name: 'Indigo' }, - purple: { swatchClass: 'bg-purple-500', name: 'Purple' }, - green: { swatchClass: 'bg-green-500', name: 'Green' }, - orange: { swatchClass: 'bg-orange-500', name: 'Orange' }, - red: { swatchClass: 'bg-red-500', name: 'Red' }, - pink: { swatchClass: 'bg-pink-500', name: 'Pink' }, -} export default function SettingsPage() { const t = useTranslations('SettingsPage') @@ -57,6 +48,8 @@ export default function SettingsPage() { return null // Avoid hydration mismatch } + const customAccent = isCustomAccent(colorTheme) + const handleLanguageChange = (value: string) => { document.cookie = `NEXT_LOCALE=${value}; path=/; max-age=31536000; SameSite=Lax` router.refresh() @@ -100,7 +93,11 @@ export default function SettingsPage() {
- + {/* Fixed-height label rows keep both dropdowns on the same baseline, + even though only the accent label carries an icon. */} +
+ +
-
-
- - +
+
+ +
-
- {COLOR_THEME_OPTIONS.map((color) => { - const isSelected = colorTheme === color - const { swatchClass, name } = colorDisplay[color] +
+ {/* Trigger is w-full by default: flex-1 keeps it from squeezing the + picker swatch out of the row. */} + - return ( - - ) - })} + {/* Native picker: no dependency, and the OS eyedropper comes free. */} +
diff --git a/apps/desktop-ui/src/components/api-client/api-client.tsx b/apps/desktop-ui/src/components/api-client/api-client.tsx index 3a62396a..943e9519 100644 --- a/apps/desktop-ui/src/components/api-client/api-client.tsx +++ b/apps/desktop-ui/src/components/api-client/api-client.tsx @@ -29,6 +29,7 @@ import { parseCurlCommand } from "@/utils/curl-parser" import { generateCode } from "./generate-code" import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard" import { CollectionsSidebar } from "./collections/collections-sidebar" +import { ToolSidebarLayout } from "@/components/tools/tool-sidebar" import dynamic from "next/dynamic" import { RequestMethod, @@ -44,13 +45,11 @@ import type { ScriptContext } from "./workers/scripts-runner.worker" import { useTranslations } from "next-intl" import { toast } from "sonner" import { useIsMobile } from "@/components/hooks/use-mobile" -import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet" import { Button } from "@/components/ui/button" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" -import { FolderOpen, PanelRight, MoreVertical, MoreHorizontal, Cookie, Download, Activity, Keyboard } from "lucide-react" +import { FolderOpen, MoreVertical, MoreHorizontal, Cookie, Download, Activity, Keyboard } from "lucide-react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from "@/components/ui/dropdown-menu" import { IconCode, IconSettings } from "@tabler/icons-react" -import { cn } from "@/lib/utils" import { ensureHttpScheme } from "@/lib/url-normalize" import { encodeBasicCredentials } from "@/lib/basic-auth" import { ensureFreshToken } from "@/lib/oauth2" @@ -131,8 +130,6 @@ function ApiClientInner() { const sessionVarsRef = React.useRef>({}) const isMobile = useIsMobile() - const [collectionsOpen, setCollectionsOpen] = React.useState(false) - const [sidebarOpen, setSidebarOpen] = React.useState(true) const [mobilePanel, setMobilePanel] = React.useState<'request' | 'response'>('request') const [envMgrOpen, setEnvMgrOpen] = React.useState(false) const [codeGenOpen, setCodeGenOpen] = React.useState(false) @@ -1105,31 +1102,15 @@ function ApiClientInner() { ) return ( -
+ } + className="mobile-nav-offset" + >
- {/* Mobile Collections Button */} - {isMobile && ( - - - - - -
-
- { - handleLoadRequest(request) - setCollectionsOpen(false) - }} - /> -
- - - )}
{isMobile ? ( /* Mobile: secondary actions collapsed into dropdown */ @@ -1270,15 +1251,6 @@ function ApiClientInner() {
- )} {/* Dialogs rendered outside the conditional so state is preserved */} @@ -1462,22 +1434,7 @@ function ApiClientInner() {
- - {/* Desktop Collections Sidebar */} - {!isMobile && ( -
- setSidebarOpen(false)} - /> -
- )} -
+ ) } diff --git a/apps/desktop-ui/src/components/api-client/collections/collections-sidebar.tsx b/apps/desktop-ui/src/components/api-client/collections/collections-sidebar.tsx index 1e8c41b6..d4164ce7 100644 --- a/apps/desktop-ui/src/components/api-client/collections/collections-sidebar.tsx +++ b/apps/desktop-ui/src/components/api-client/collections/collections-sidebar.tsx @@ -6,7 +6,7 @@ import { Checkbox } from "@/components/ui/checkbox" import { ScrollArea } from "@/components/ui/scroll-area" import { Collection, CollectionRequest } from "../types" import { CollectionItem } from "./collection-item" -import { FolderPlus, Trash2, Pencil, MoreHorizontal, Search, X, FileDown, Play, Server, Link2, Globe, PanelRightClose } from "lucide-react" +import { FolderPlus, Trash2, Pencil, MoreHorizontal, Search, X, FileDown, Play, Server, Link2, Globe } from "lucide-react" import { buildShareUrl } from "@/lib/share-link" import { apiFetch } from "@/lib/desktop/api-fetch" import { toast } from "sonner" @@ -47,16 +47,23 @@ import { useHistoryState, useHistoryActions } from "../context/history-context" import { CollectionsSidebarSkeleton, HistoryListSkeleton } from "../skeletons" import { useDebouncedValue } from "@/lib/use-debounced-value" import { isDesktop } from "@/lib/desktop/is-desktop" +import { ToolSidebarActions, useToolSidebarPanel } from "@/components/tools/tool-sidebar" interface CollectionsSidebarProps { onLoadRequest: (request: CollectionRequest) => void - onCollapse?: () => void } -export function CollectionsSidebar({ - onLoadRequest, - onCollapse, -}: CollectionsSidebarProps) { +export function CollectionsSidebar({ onLoadRequest: loadRequest }: CollectionsSidebarProps) { + const panel = useToolSidebarPanel() + // On mobile the panel is a sheet over the request pane — loading a request + // has to dismiss it or the loaded request stays hidden behind the sheet. + const onLoadRequest = React.useCallback( + (request: CollectionRequest) => { + loadRequest(request) + if (panel?.isMobile) panel.close() + }, + [loadRequest, panel], + ) const { collections, isLoading } = useCollectionsState() const { addFolder: onAddFolder, deleteItem: onDelete, toggleFolder: onToggle, createCollection: onCreateCollection, renameCollection: onRenameCollection, renameFolder: onRenameFolder, patchFolder, deleteMultipleCollections: onDeleteMultiple } = useCollectionsActions() const { history, isLoading: isHistoryLoading } = useHistoryState() @@ -189,45 +196,34 @@ export function CollectionsSidebar({ } return ( -
+ // Header (icon, title, collapse) is owned by ToolSidebarLayout in + // components/api-client/api-client.tsx — this renders the body only. + <> + + {selectedCollections.size > 0 && ( + + )} + + +
-
-

{t("title")}

-
- {selectedCollections.size > 0 && ( - - )} - - {onCollapse && ( - - )} -
-
+ ) } diff --git a/apps/desktop-ui/src/components/api-client/request-tabs.tsx b/apps/desktop-ui/src/components/api-client/request-tabs.tsx index d257efa8..d12e2e4f 100644 --- a/apps/desktop-ui/src/components/api-client/request-tabs.tsx +++ b/apps/desktop-ui/src/components/api-client/request-tabs.tsx @@ -1189,6 +1189,7 @@ export function RequestTabs({