diff --git a/.cursorrules b/.cursorrules index 0b0c009c..5015ab7e 100644 --- a/.cursorrules +++ b/.cursorrules @@ -27,3 +27,11 @@ - Follow TypeScript strict mode conventions - Use async/await instead of promises when possible - Prefer named exports over default exports for utilities and services + +## Comments + +- Keep comments concise and purposeful; avoid verbose explanations. +- Focus on the "why" or non-obvious context, not restating the code. +- Prefer self-explanatory naming and structure over excessive comments. +- Do not comment every line or obvious behavior; remove stale comments. +- Use docblocks only where they add value (public APIs, complex logic). diff --git a/.env.example b/.env.example index 3f914eb3..051d8aa3 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,4 @@ MAIN_VITE_AUTH_URL= MAIN_VITE_WS_URL= RENDERER_VITE_REAL_DEBRID_REFERRAL_ID= RENDERER_VITE_TORBOX_REFERRAL_CODE= +MAIN_VITE_LAUNCHER_SUBDOMAIN= diff --git a/.github/workflows/build-renderer.yml b/.github/workflows/build-renderer.yml index f7361883..34f7d303 100644 --- a/.github/workflows/build-renderer.yml +++ b/.github/workflows/build-renderer.yml @@ -6,23 +6,37 @@ concurrency: on: push: - branches: [main] + branches: + - release/** jobs: build: runs-on: ubuntu-latest + permissions: + contents: read + + env: + NODE_OPTIONS: --max-old-space-size=4096 + BRANCH_NAME: ${{ github.ref_name }} + steps: - name: Check out Git repository uses: actions/checkout@v4 + with: + fetch-depth: 0 - - name: Install Node.js + - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: 22.21.0 + cache: "yarn" + + - name: Enable Corepack (Yarn) + run: corepack enable - name: Install dependencies - run: yarn --frozen-lockfile --ignore-scripts + run: yarn install --frozen-lockfile --ignore-scripts - name: Build Renderer run: yarn build @@ -36,5 +50,5 @@ jobs: run: | npx --yes wrangler@3 pages deploy out/renderer \ --project-name="hydra" \ - --commit-dirty=true \ - --branch="main" + --branch "$BRANCH_NAME" \ + --commit-dirty diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 75ff209a..df01b358 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,8 @@ concurrency: on: push: - branches: [main] + branches: + - release/** jobs: build: @@ -61,7 +62,7 @@ jobs: RENDERER_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} RENDERER_VITE_REAL_DEBRID_REFERRAL_ID: ${{ vars.RENDERER_VITE_REAL_DEBRID_REFERRAL_ID }} RENDERER_VITE_TORBOX_REFERRAL_CODE: ${{ vars.RENDERER_VITE_TORBOX_REFERRAL_CODE }} - MAIN_VITE_RENDERER_URL: ${{ vars.MAIN_VITE_RENDERER_URL }} + MAIN_VITE_LAUNCHER_SUBDOMAIN: ${{ vars.MAIN_VITE_LAUNCHER_SUBDOMAIN }} - name: Build Windows if: matrix.os == 'windows-2022' @@ -78,7 +79,7 @@ jobs: RENDERER_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} RENDERER_VITE_REAL_DEBRID_REFERRAL_ID: ${{ vars.RENDERER_VITE_REAL_DEBRID_REFERRAL_ID }} RENDERER_VITE_TORBOX_REFERRAL_CODE: ${{ vars.RENDERER_VITE_TORBOX_REFERRAL_CODE }} - MAIN_VITE_RENDERER_URL: ${{ vars.MAIN_VITE_RENDERER_URL }} + MAIN_VITE_LAUNCHER_SUBDOMAIN: ${{ vars.MAIN_VITE_LAUNCHER_SUBDOMAIN }} - name: Create artifact uses: actions/upload-artifact@v4 diff --git a/.github/workflows/update-aur.yml b/.github/workflows/update-aur.yml index 2a3583bc..52fe907e 100644 --- a/.github/workflows/update-aur.yml +++ b/.github/workflows/update-aur.yml @@ -98,6 +98,7 @@ jobs: # Update pkgver in PKGBUILD cd hydra-launcher-bin NEW_VERSION="${{ steps.get-version.outputs.version }}" + NEW_VERSION="${NEW_VERSION#v}" echo "Updating PKGBUILD pkgver to $NEW_VERSION" @@ -137,6 +138,9 @@ jobs: COMMIT_MSG="v${{ steps.get-version.outputs.version }}" git commit -m "$COMMIT_MSG" + + export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa -F ~/.ssh/config -o UserKnownHostsFile=$SSH_PATH/known_hosts" + git push origin master echo "Successfully updated AUR package to version ${{ steps.get-version.outputs.version }}" fi diff --git a/package.json b/package.json index 9ed25fa9..5d84e763 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hydralauncher", - "version": "3.7.1", + "version": "3.7.2", "description": "Hydra", "main": "./out/main/index.js", "author": "Los Broxas", diff --git a/src/locales/es/translation.json b/src/locales/es/translation.json index dfa7f7a1..863b8332 100644 --- a/src/locales/es/translation.json +++ b/src/locales/es/translation.json @@ -541,7 +541,9 @@ "notification_preview": "Probar notificación de logro", "debrid": "Debrid", "debrid_description": "Los servicios Debrid son descargadores premium sin restricciones que te dejan descargar más rápido archivos alojados en servicios de alojamiento siendo que la única limitación es tu velocidad de internet.", - "enable_friend_start_game_notifications": "Cuando un amigo está jugando un juego" + "enable_friend_start_game_notifications": "Cuando un amigo está jugando un juego", + "autoplay_trailers_on_game_page": "Reproducir trailers automáticamente en la página del juego", + "hide_to_tray_on_game_start": "Ocultar Hydra en la bandeja al iniciar un juego" }, "notifications": { "download_complete": "Descarga completada", diff --git a/src/locales/hu/translation.json b/src/locales/hu/translation.json index 7d868aee..8aea356b 100644 --- a/src/locales/hu/translation.json +++ b/src/locales/hu/translation.json @@ -8,7 +8,7 @@ "no_results": "Nincs találat", "start_typing": "Kereséshez gépelj...", "hot": "Most felkapott", - "weekly": "📅 A hét felkapott játékai", + "weekly": "📅 A hét felkapottjai", "achievements": "🏆 Achievement támogatott" }, "sidebar": { @@ -26,7 +26,7 @@ "sign_in": "Bejelentkezés", "friends": "Barátok", "need_help": "Elakadtál?", - "favorites": "Kedvenc játékok", + "favorites": "Kedvenc Játékaim", "playable_button_title": "Csak az azonnal játszható játékokat mutasd", "add_custom_game_tooltip": "Saját játék hozzáadása", "show_playable_only_tooltip": "Csak játszható játék mutatása", @@ -224,7 +224,7 @@ "show_less": "Mutass kevesebbet", "reviews": "Vélemények", "leave_a_review": "Hagyd itt a véleményed", - "write_review_placeholder": "Oszd meg a gondolataid a játékról...", + "write_review_placeholder": "Oszd meg gondolatod a játékról...", "sort_newest": "Legújabb", "no_reviews_yet": "Még nem lett vélemény megosztva", "be_first_to_review": "Légy az első, aki megossza a véleményét a játékról!", @@ -252,7 +252,7 @@ "you_seemed_to_enjoy_this_game": "Úgy látszik élvezted ezt a játékot", "would_you_recommend_this_game": "Szeretnél véleményt írni erről a játékról?", "yes": "Igen", - "maybe_later": "Talán Később", + "maybe_later": "Talán később", "cloud_save": "Mentés felhőben", "cloud_save_description": "Mentsd el az előrehaladásod a felhőben, majd folytasd egy másik eszközön", "backups": "Biztonsági másolatok", @@ -356,13 +356,18 @@ "delete_review_modal_title": "Biztos vagy abban hogy törölni szeretnéd a véleményed?", "delete_review_modal_description": "Ez a lépés nem vonható vissza.", "delete_review_modal_delete_button": "Törlés", - "delete_review_modal_cancel_button": "Mégse" + "delete_review_modal_cancel_button": "Mégse", + "vote_failed": "A szavazatod nem regisztrálódott. Kérlek próbáld újra.", + "show_original": "Eredeti megjelenítése", + "show_translation": "Fordítás megjelenítése", + "show_original_translated_from": "Eredeti megjelenítése (fordítva: {{language}})", + "hide_original": "Eredeti elrejtése" }, "activation": { "title": "Hydra Aktiválása", "installation_id": "Telepítési Azonosító:", "enter_activation_code": "Írd be az aktiválási kódod", - "message": "Ha nem tudod hol kérdezz efelől, akkor nem kéne ilyened legyen.", + "message": "Ha nem tudod merre kérdezz efelől, akkor nem kéne ilyened legyen.", "activate": "Aktiválás", "loading": "Töltés…" }, @@ -386,7 +391,7 @@ "download_in_progress": "Folyamatban lévő", "queued_downloads": "Várakozósoron lévő letöltések", "downloads_completed": "Befejezett", - "queued": "Várakozási sorban", + "queued": "Várakozásban", "no_downloads_title": "Oly üres..", "no_downloads_description": "Még nem töltöttél le semmit a Hydra segítségével, de soha nem késő elkezdeni.", "checking_files": "Fájlok ellenőrzése…", @@ -419,20 +424,30 @@ "debrid_linked_message": "Fiók összekapcsolva: \"{{username}}\" ", "save_changes": "Változtatások mentése", "changes_saved": "Változtatások sikeresen mentve", - "download_sources_description": "A Hydra lefogja tölteni a letöltési linkeket a forrásokból. Az URL forrásnak közvetlen linknek kell lennie egy .json fájlhoz, ami tartalmazza a linkeket.", + "download_sources_description": "A Hydra lefogja tölteni a letöltési linkeket a forrásokból. Az URL Forrásnak közvetlen linknek kell lennie egy .json fájlhoz, ami tartalmazza a linkeket.", "validate_download_source": "Érvényesítés", "remove_download_source": "Eltávolítás", "add_download_source": "Forrás hozáadása", + "adding": "Hozzáadás…", + "failed_add_download_source": "Letöltési forrás hozzáadása sikertelen. Kérlek próbáld újra.", + "download_source_already_exists": "Ez a letöltési forrás URL már létezik.", "download_count_zero": "Nincs letöltési opció", "download_count_one": "{{countFormatted}} letöltési opció", "download_count_other": "{{countFormatted}} letöltési opció", - "download_source_url": "URL forrás:", + "download_source_url": "URL Forrás:", "add_download_source_description": "Helyezd be a .json fájl URL-jét", "download_source_up_to_date": "Naprakész", "download_source_errored": "Hiba történt", + "download_source_pending_matching": "Frissítés hamarosan", + "download_source_matched": "Naprakész", + "download_source_matching": "Frissítés..", + "download_source_failed": "Hiba", + "download_source_no_information": "Nincs elérhető információ", "sync_download_sources": "Források szinkronizálása", "removed_download_source": "Letöltési forrás eltávolítva", "removed_download_sources": "Letöltési források eltávolítva", + "removed_all_download_sources": "Összes letöltési forrás eltávolítva", + "download_sources_synced_successfully": "Az összes letöltési forrás szinkronizálva", "cancel_button_confirmation_delete_all_sources": "Nem", "confirm_button_confirmation_delete_all_sources": "Igen, törölj mindent", "title_confirmation_delete_all_sources": "Az összes letöltési forrás törlése", @@ -445,6 +460,7 @@ "found_download_option_one": "{{countFormatted}} Letöltési opció találva", "found_download_option_other": "{{countFormatted}} Letöltési opciók találva", "import": "Importálás", + "importing": "Importálás...", "public": "Publikus", "private": "Privát", "friends_only": "Csak barátok", @@ -462,6 +478,7 @@ "seed_after_download_complete": "Letöltés utáni seedelés", "show_hidden_achievement_description": "Rejtett achievementek leírásának megjelenítése feloldás előtt", "account": "Fiók", + "hydra_cloud": "Hydra Cloud", "no_users_blocked": "Nincsenek letiltott felhasználóid", "subscription_active_until": "Hydra Cloud előfizetésed aktív, eddig: {{date}}", "manage_subscription": "Előfizetés kezelése", @@ -498,14 +515,14 @@ "cancel": "Mégsem", "appearance": "Megjelenés", "debrid": "Debrid", - "debrid_description": "A Debrid szolgáltatások prémium szolgáltatások amelyek lehetővé teszik, hogy gyorsan letölts különböző fájltároló szolgáltatásokon tárolt fájlokat, csak az internet sebességed szab határt.", + "debrid_description": "A Debrid szolgáltatások prémium szolgáltatások amelyek lehetővé teszik, hogy gyorsan letölts különböző fájltároló szolgáltatásokon tárolt fájlokat, és csak az internet sebességed szab határt.", "enable_torbox": "TorBox bekapcsolása", "torbox_description": "A TorBox egy olyan premium seedbox szolgáltatás, amely még a piacon elérhető legjobb szerverekkel is felveszi a versenyt.", "torbox_account_linked": "TorBox fiók összekapcsolva", "create_real_debrid_account": "Kattints ide ha még nincs Real-Debrid fiókod", "create_torbox_account": "Kattints ide ha még nincs TorBox fiókod", "real_debrid_account_linked": "Real-Debrid fiók összekapcsolva", - "name_min_length": "A téma neve legalább 3 karakter hosszú legyen", + "name_min_length": "A téma neve legalább 3 karakter hosszú kell legyen", "import_theme": "Téma importálása", "import_theme_description": "Ezt a témát fogod importálni a Témaáruház-ból: {{theme}}", "error_importing_theme": "Hiba lépett fel a téma importálása közben", @@ -535,7 +552,9 @@ "hidden": "Rejtett", "test_notification": "Értesítés tesztelése", "notification_preview": "Achievement Értesítés Előnézete", - "enable_friend_start_game_notifications": "Amikor egy barátod elkezd játszani egy játékot" + "enable_friend_start_game_notifications": "Amikor egy barátod elkezd játszani egy játékot", + "autoplay_trailers_on_game_page": "Játékelőzetes automatikus lejátszása a játék oldalán", + "hide_to_tray_on_game_start": "Hydra elrejtése játék elindításakor a tálcára" }, "notifications": { "download_complete": "Letöltés befejezve", @@ -563,10 +582,10 @@ "available_one": "Elérhető", "available_other": "Elérhető", "no_downloads": "Nincs elérhető letöltés", - "calculating": "Feldolgozás" + "calculating": "Számítás alatt.." }, "binary_not_found_modal": { - "title": "A programok nincsenek telepítve", + "title": "Hiányzó programok", "description": "Wine vagy Lutris futtatható fájlok nem találhatók a rendszereden", "instructions": "Ellenőrízd hogy melyiket kell helyesen telepíteni a Linux disztribúciódra, hogy a játék megfelelően fusson" }, @@ -585,6 +604,7 @@ "activity": "Legutóbbi tevékenység", "library": "Könyvtár", "pinned": "Kitűzve", + "sort_by": "Rendezés:", "achievements_earned": "Elért achievementek", "played_recently": "Nemrég játszva", "playtime": "Játszottidő", @@ -654,7 +674,7 @@ "uploading_banner": "Borítókép feltöltése…", "background_image_updated": "Borítókép frissítve", "stats": "Statisztikák", - "achievements": "achievementek", + "achievements": "achievement", "games": "Játékok", "top_percentile": "Top {{percentile}}%", "ranking_updated_weekly": "A rangsor hetente frissül.", @@ -669,7 +689,7 @@ "game_added_to_pinned": "Játék hozzáadva a kitűzöttekhez", "karma": "Karma", "karma_count": "karma", - "karma_description": "Pozitív értékelésekre kapott pontok alapján" + "karma_description": "Pozitív értékelésekkel szerzett pontok" }, "achievement": { "achievement_unlocked": "Achievement feloldva", @@ -678,7 +698,7 @@ "unlocked_at": "Feloldva: {{date}}", "subscription_needed": "A tartalom megtekintéséhez Hydra Cloud előfizetés szükséges", "new_achievements_unlocked": "{{achievementCount}} új achievement feloldva {{gameCount}} játékban", - "achievement_progress": "{{unlockedCount}}/{{totalCount}} achievementek", + "achievement_progress": "{{unlockedCount}}/{{totalCount}} achievement", "achievements_unlocked_for_game": "{{achievementCount}} új achievement feloldva itt: {{gameTitle}}", "hidden_achievement_tooltip": "Ez egy rejtett achievement", "achievement_earn_points": "Szerezz be {{points}} pontot ezzel az achievement-el", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index c9e908ac..5bfc2af3 100755 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -538,7 +538,9 @@ "hidden": "Oculta", "test_notification": "Testar notificação", "notification_preview": "Prévia da Notificação de Conquistas", - "enable_friend_start_game_notifications": "Quando um amigo iniciar um jogo" + "enable_friend_start_game_notifications": "Quando um amigo iniciar um jogo", + "autoplay_trailers_on_game_page": "Reproduzir trailers automaticamente na página do jogo", + "hide_to_tray_on_game_start": "Ocultar o Hydra na bandeja ao iniciar um jogo" }, "notifications": { "download_complete": "Download concluído", diff --git a/src/locales/ru/translation.json b/src/locales/ru/translation.json index 886c7d07..15a9c9cb 100644 --- a/src/locales/ru/translation.json +++ b/src/locales/ru/translation.json @@ -212,6 +212,7 @@ "stats": "Статистика", "download_count": "Загрузки", "player_count": "Активные игроки", + "rating_count": "Оценка", "download_error": "Этот вариант загрузки недоступен", "download": "Скачать", "executable_path_in_use": "Исполняемый файл уже используется \"{{game}}\"", @@ -252,17 +253,6 @@ "would_you_recommend_this_game": "Хотите оставить отзыв об этой игре?", "yes": "Да", "maybe_later": "Возможно позже", - "rating_count": "Оценка", - "delete_review": "Удалить отзыв", - "remove_review": "Удалить отзыв", - "delete_review_modal_title": "Вы уверены, что хотите удалить свой отзыв?", - "delete_review_modal_description": "Это действие нельзя отменить.", - "delete_review_modal_delete_button": "Удалить", - "delete_review_modal_cancel_button": "Отмена", - "show_original": "Показать оригинал", - "show_translation": "Показать перевод", - "show_original_translated_from": "Показать оригинал (переведено с {{language}})", - "hide_original": "Скрыть оригинал", "cloud_save": "Облачное сохранение", "cloud_save_description": "Сохраняйте ваш прогресс в облаке и продолжайте играть на любом устройстве", "backups": "Резервные копии", @@ -360,7 +350,18 @@ "caption": "Субтитры", "audio": "Аудио", "filter_by_source": "Фильтр по источнику", - "no_repacks_found": "Источники для этой игры не найдены" + "no_repacks_found": "Источники для этой игры не найдены", + "delete_review": "Удалить отзыв", + "remove_review": "Удалить отзыв", + "delete_review_modal_title": "Вы уверены, что хотите удалить свой отзыв?", + "delete_review_modal_description": "Это действие нельзя отменить.", + "delete_review_modal_delete_button": "Удалить", + "delete_review_modal_cancel_button": "Отмена", + "vote_failed": "Не удалось зарегистрировать ваш голос. Пожалуйста, попробуйте снова.", + "show_original": "Показать оригинал", + "show_translation": "Показать перевод", + "show_original_translated_from": "Показать оригинал (переведено с {{language}})", + "hide_original": "Скрыть оригинал" }, "activation": { "title": "Активировать Hydra", @@ -427,6 +428,9 @@ "validate_download_source": "Проверить", "remove_download_source": "Удалить", "add_download_source": "Добавить источник", + "adding": "Добавление…", + "failed_add_download_source": "Не удалось добавить источник. Пожалуйста, попробуйте снова.", + "download_source_already_exists": "Этот URL источника уже существует.", "download_count_zero": "В списке нет загрузок", "download_count_one": "{{countFormatted}} загрузка в списке", "download_count_other": "{{countFormatted}} загрузок в списке", @@ -434,9 +438,16 @@ "add_download_source_description": "Вставьте ссылку на .json-файл", "download_source_up_to_date": "Обновлён", "download_source_errored": "Ошибка", + "download_source_pending_matching": "Скоро обновится", + "download_source_matched": "Обновлен", + "download_source_matching": "Обновление", + "download_source_failed": "Ошибка", + "download_source_no_information": "Информация отсутствует", "sync_download_sources": "Обновить источники", "removed_download_source": "Источник удален", "removed_download_sources": "Источники удалены", + "removed_all_download_sources": "Все источники удалены", + "download_sources_synced_successfully": "Все источники синхронизированы", "cancel_button_confirmation_delete_all_sources": "Нет", "confirm_button_confirmation_delete_all_sources": "Да, удалить все", "title_confirmation_delete_all_sources": "Удалить все источники", @@ -467,6 +478,7 @@ "seed_after_download_complete": "Раздавать после завершения загрузки", "show_hidden_achievement_description": "Показывать описание скрытых достижений перед их получением", "account": "Аккаунт", + "hydra_cloud": "Hydra Cloud", "no_users_blocked": "У вас нет заблокированных пользователей", "subscription_active_until": "Ваша подписка на Hydra Cloud активна до {{date}}", "manage_subscription": "Управлять подпиской", @@ -540,7 +552,9 @@ "hidden": "Скрытый", "test_notification": "Тестовое уведомление", "notification_preview": "Предварительный просмотр уведомления о достижении", - "enable_friend_start_game_notifications": "Когда друг начинает играть в игру" + "enable_friend_start_game_notifications": "Когда друг начинает играть в игру", + "autoplay_trailers_on_game_page": "Автоматически начинать воспроизведение трейлеров на странице игры", + "hide_to_tray_on_game_start": "Скрывать Hydra в трей при запуске игры" }, "notifications": { "download_complete": "Загрузка завершена", @@ -590,6 +604,7 @@ "activity": "Недавняя активность", "library": "Библиотека", "pinned": "Закрепленные", + "sort_by": "Сортировать по:", "achievements_earned": "Заработанные достижения", "played_recently": "Недавно сыгранные", "playtime": "Время игры", diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 118ff98b..673bf1a0 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -25,6 +25,7 @@ import type { } from "@types"; import { AuthPage, generateAchievementCustomNotificationTest } from "@shared"; import { isStaging } from "@main/constants"; +import { logger } from "./logger"; export class WindowManager { public static mainWindow: Electron.BrowserWindow | null = null; @@ -54,21 +55,25 @@ export class WindowManager { show: false, }; + private static formatVersionNumber(version: string) { + return version.replaceAll(".", "-"); + } + private static async loadWindowURL(window: BrowserWindow, hash: string = "") { // HMR for renderer base on electron-vite cli. // Load the remote URL for development or the local html file for production. if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { window.loadURL(`${process.env["ELECTRON_RENDERER_URL"]}#/${hash}`); - } else if (import.meta.env.MAIN_VITE_RENDERER_URL) { + } else if (import.meta.env.MAIN_VITE_LAUNCHER_SUBDOMAIN) { // Try to load from remote URL in production try { await window.loadURL( - `${import.meta.env.MAIN_VITE_RENDERER_URL}#/${hash}` + `https://release-v${this.formatVersionNumber(app.getVersion())}.${import.meta.env.MAIN_VITE_LAUNCHER_SUBDOMAIN}#/${hash}` ); } catch (error) { // Fall back to local file if remote URL fails - console.error( - "Failed to load from MAIN_VITE_RENDERER_URL, falling back to local file:", + logger.error( + "Failed to load from MAIN_VITE_LAUNCHER_SUBDOMAIN, falling back to local file:", error ); window.loadFile(path.join(__dirname, "../renderer/index.html"), { diff --git a/src/main/vite-env.d.ts b/src/main/vite-env.d.ts index c9b006d5..7b0ed536 100644 --- a/src/main/vite-env.d.ts +++ b/src/main/vite-env.d.ts @@ -7,7 +7,7 @@ interface ImportMetaEnv { readonly MAIN_VITE_CHECKOUT_URL: string; readonly MAIN_VITE_EXTERNAL_RESOURCES_URL: string; readonly MAIN_VITE_WS_URL: string; - readonly MAIN_VITE_RENDERER_URL: string; + readonly MAIN_VITE_LAUNCHER_SUBDOMAIN: string; readonly ELECTRON_RENDERER_URL: string; } diff --git a/src/renderer/src/pages/catalogue/pagination.tsx b/src/renderer/src/pages/catalogue/pagination.tsx index 9febc8f8..ecc2afe3 100644 --- a/src/renderer/src/pages/catalogue/pagination.tsx +++ b/src/renderer/src/pages/catalogue/pagination.tsx @@ -29,9 +29,11 @@ function JumpControl({ return isOpen ? ( ) { const { formatNumber } = useFormat(); const [isJumpOpen, setIsJumpOpen] = useState(false); @@ -87,13 +89,15 @@ export function Pagination({ } const onJumpChange = (e: ChangeEvent) => { - const val = e.target.value; - if (val === "") { + const raw = e.target.value; + const digitsOnly = raw.replaceAll(/\D+/g, ""); + if (digitsOnly === "") { setJumpValue(""); return; } - const num = Number(val); + const num = Number.parseInt(digitsOnly, 10); if (Number.isNaN(num)) { + setJumpValue(""); return; } if (num < 1) { @@ -104,19 +108,36 @@ export function Pagination({ setJumpValue(String(totalPages)); return; } - setJumpValue(val); + setJumpValue(String(num)); }; const onJumpKeyDown = (e: KeyboardEvent) => { + const controlKeys = [ + "Backspace", + "Delete", + "Tab", + "ArrowLeft", + "ArrowRight", + "Home", + "End", + ]; + + if (controlKeys.includes(e.key) || e.ctrlKey || e.metaKey) { + return; + } + if (e.key === "Enter") { - if (jumpValue.trim() === "") return; - const parsed = Number(jumpValue); + const sanitized = jumpValue.replaceAll(/\D+/g, ""); + if (sanitized.trim() === "") return; + const parsed = Number.parseInt(sanitized, 10); if (Number.isNaN(parsed)) return; const target = Math.max(1, Math.min(totalPages, parsed)); onPageChange(target); setIsJumpOpen(false); } else if (e.key === "Escape") { setIsJumpOpen(false); + } else if (!/^\d$/.test(e.key)) { + e.preventDefault(); } };