Compare commits

..

24 Commits

Author SHA1 Message Date
Zamitto
260a11ba6a Merge pull request #1465 from hydralauncher/fix/lazy-loading-messing-up-custom-css
fix: lazy loading messing up custom css
2025-02-19 18:40:37 -03:00
Zamitto
adf3bf38a8 chore: fix gh actions concurrency 2025-02-18 22:36:49 -03:00
Zamitto
b6193636dd chore: fix gh actions concurrency 2025-02-18 22:33:48 -03:00
Zamitto
923601bdef feat: add readonly to test pipeline 2025-02-18 22:32:13 -03:00
Zamitto
58855a93a8 feat: add readonly to test pipeline 2025-02-18 22:31:19 -03:00
Zamitto
d879f2e3df chore: bump version 2025-02-18 22:29:38 -03:00
Zamitto
73ab3872a7 fix: lazy loading messing up custom css 2025-02-18 22:25:41 -03:00
Zamitto
726a39a430 chore: bump version 2025-02-17 22:44:09 -03:00
Zamitto
741364e922 Merge pull request #1459 from hydrasources/patch-12
Update RU translation.json
2025-02-17 22:43:50 -03:00
Zamitto
92ac5b0d1a Merge pull request #1462 from hydralauncher/feat/improve-theming
Feat/improve theming
2025-02-17 22:41:42 -03:00
Zamitto
4641b1967e Merge branch 'main' into patch-12 2025-02-17 22:41:29 -03:00
Zamitto
0bf70ffebd Merge pull request #1463 from hydralauncher/feat/user-badges
Feat/user badges
2025-02-17 22:38:21 -03:00
Hachi-R
21cec50e2e lint 2025-02-17 22:32:07 -03:00
Hachi-R
0724a40cb7 fix: improve theme import modal flow and navigation 2025-02-17 22:29:42 -03:00
Zamitto
e066ea3503 feat: css 2025-02-17 21:14:32 -03:00
Zamitto
cf202c8f01 feat: add user badges 2025-02-17 21:04:33 -03:00
Hachi-R
75a44bed3f refactor: minor hero panel formatting cleanup 2025-02-17 20:07:16 -03:00
Hachi-R
c5206c68ee refactor: simplify game details hero section layout and scrolling 2025-02-17 20:06:39 -03:00
Hachi-R
0b4c3a6cd2 fix: make title bar overlay fully transparent 2025-02-17 18:59:57 -03:00
Zamitto
86847ec50e Merge branch 'main' into patch-12 2025-02-17 17:58:05 -03:00
Zamitto
e086369b13 Merge pull request #1461 from 7ROBE/patch-8
Update translation.json
2025-02-17 17:57:40 -03:00
7ROBE
e695d599de Update translation.json 2025-02-17 22:38:36 +03:00
hydrasources
ad55165078 Update translation.json 2025-02-17 11:21:15 +03:00
hydrasources
385e29262c Update translation.json 2025-02-17 08:29:52 +03:00
22 changed files with 340 additions and 209 deletions

View File

@@ -1,5 +1,9 @@
name: Build
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: pull_request
jobs:

View File

@@ -1,5 +1,9 @@
name: Lint
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: pull_request
jobs:

View File

@@ -1,5 +1,9 @@
name: Release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches: main

View File

@@ -1,6 +1,6 @@
{
"name": "hydralauncher",
"version": "3.2.0",
"version": "3.2.2",
"description": "Hydra",
"main": "./out/main/index.js",
"author": "Los Broxas",

View File

@@ -7,18 +7,18 @@
"featured": "مميز",
"surprise_me": "مفاجئني",
"no_results": "لم يتم العثور على نتائج",
"start_typing": "ابدأ الكتابة للبحث...",
"hot": "الأكثر شيوعًا الآن",
"start_typing": "ابدأ بالكتابة للبحث...",
"hot": "الأكثر شهرة الآن",
"weekly": "📅 أفضل ألعاب الأسبوع",
"achievements": "🏆 ألعاب للتغلب عليها"
"achievements": "🏆 ألعاب يجب إكمالها"
},
"sidebar": {
"catalogue": "الكـتالوج",
"catalogue": "الفهرس",
"downloads": "التنزيلات",
"settings": "الإعدادات",
"my_library": "مكتبتي",
"downloading_metadata": "{{title}} (جارٍ تنزيل البيانات الوصفية...)",
"paused": "{{title}} (معلّق)",
"downloading_metadata": "{{title}} (جاري تنزيل البيانات الوصفية...)",
"paused": "{{title}} (معلق)",
"downloading": "{{title}} ({{percentage}} - جاري التنزيل...)",
"filter": "تصفية المكتبة",
"home": "الرئيسية",
@@ -26,12 +26,13 @@
"game_has_no_executable": "اللعبة لا تحتوي على ملف تشغيل",
"sign_in": "تسجيل الدخول",
"friends": "الأصدقاء",
"need_help": "تحتاج مساعدة؟"
"need_help": "تحتاج مساعدة؟",
"favorites": "المفضلة"
},
"header": {
"search": "ابحث عن الألعاب",
"search": "بحث الألعاب",
"home": "الرئيسية",
"catalogue": "الكـتالوج",
"catalogue": "الفهرس",
"downloads": "التنزيلات",
"search_results": "نتائج البحث",
"settings": "الإعدادات",
@@ -40,16 +41,16 @@
},
"bottom_panel": {
"no_downloads_in_progress": "لا توجد تنزيلات قيد التقدم",
"downloading_metadata": "جارٍ تنزيل البيانات الوصفية لـ {{title}}...",
"downloading": "جارٍ تنزيل {{title}}... ({{percentage}} اكتمال) - الوقت المتبقي {{eta}} - السرعة {{speed}}",
"calculating_eta": "جارٍ تنزيل {{title}}... ({{percentage}} اكتمال) - جاري حساب الوقت المتبقي...",
"checking_files": "جارٍ فحص ملفات {{title}}... ({{percentage}} اكتمال)"
"downloading_metadata": "جاري تنزيل بيانات {{title}} الوصفية...",
"downloading": "جاري تنزيل {{title}}... ({{percentage}} مكتمل) - الوقت المتبقي {{eta}} - السرعة {{speed}}",
"calculating_eta": "جاري تنزيل {{title}}... ({{percentage}} مكتمل) - جاري حساب الوقت المتبقي...",
"checking_files": "جاري فحص ملفات {{title}}... ({{percentage}} مكتمل)"
},
"catalogue": {
"search": "تصفية...",
"developers": "المطورون",
"genres": "الأنواع",
"tags": "العلامات",
"tags": "الوسوم",
"publishers": "الناشرون",
"download_sources": "مصادر التنزيل",
"result_count": "{{resultCount}} نتيجة",
@@ -68,34 +69,34 @@
"cancel": "إلغاء",
"remove": "إزالة",
"space_left_on_disk": "{{space}} متبقي على القرص",
"eta": "الانتهاء {{eta}}",
"calculating_eta": "جارٍ حساب الوقت المتبقي...",
"downloading_metadata": "جارٍ تنزيل البيانات الوصفية...",
"filter": "تصفية الحزم المعاد تعبئتها",
"eta": "الانتهاء المتوقع {{eta}}",
"calculating_eta": "جاري حساب الوقت المتبقي...",
"downloading_metadata": "جاري تنزيل البيانات الوصفية...",
"filter": "تصفية الإصدارات المعادة",
"requirements": "متطلبات النظام",
"minimum": "الحد الأدنى",
"recommended": ُوصى به",
"paused": "معلّق",
"recommended": ستحسن",
"paused": "معلق",
"release_date": "تاريخ الإصدار {{date}}",
"publisher": "نشر بواسطة {{publisher}}",
"hours": "ساعات",
"minutes": "دقائق",
"amount_hours": "{{amount}} ساعات",
"amount_minutes": "{{amount}} دقائق",
"amount_hours": "{{amount}} ساعة",
"amount_minutes": "{{amount}} دقيقة",
"accuracy": "دقة {{accuracy}}%",
"add_to_library": "إضافة إلى المكتبة",
"remove_from_library": "إزالة من المكتبة",
"no_downloads": "لا توجد تنزيلات متاحة",
"play_time": "لعب لمدة {{amount}}",
"last_time_played": "آخر تشغيل {{period}}",
"play_time": "وقت اللعب {{amount}}",
"last_time_played": "آخر مرة لعب {{period}}",
"not_played_yet": "لم تلعب {{title}} بعد",
"next_suggestion": "الاقتراح التالي",
"play": "تشغيل",
"deleting": "جارٍ حذف المثبت...",
"deleting": "جاري حذف المثبت...",
"close": "إغلاق",
"playing_now": تم التشغيل الآن",
"playing_now": "جاري التشغيل الآن",
"change": "تغيير",
"repacks_modal_description": "اختر الحزمة المعاد تعبئتها التي تريد تنزيلها",
"repacks_modal_description": "اختر الإصدار المعاد الذي تريد تنزيله",
"select_folder_hint": "لتغيير المجلد الافتراضي، انتقل إلى <0>الإعدادات</0>",
"download_now": "تنزيل الآن",
"no_shop_details": "تعذر الحصول على تفاصيل المتجر.",
@@ -110,12 +111,12 @@
"select_executable": "تحديد",
"no_executable_selected": "لم يتم تحديد ملف تشغيل",
"open_folder": "فتح المجلد",
"open_download_location": "عرض الملفات المحملة",
"open_download_location": "عرض الملفات المنزلة",
"create_shortcut": "إنشاء اختصار على سطح المكتب",
"clear": "مسح",
"remove_files": "إزالة الملفات",
"remove_from_library_title": "هل أنت متأكد؟",
"remove_from_library_description": "سيؤدي هذا إلى إزالة {{game}} من مكتبتك",
"remove_from_library_description": "سيتم إزالة {{game}} من مكتبتك",
"options": "خيارات",
"executable_section_title": "ملف التشغيل",
"executable_section_description": "مسار الملف الذي سيتم تشغيله عند النقر على \"تشغيل\"",
@@ -123,35 +124,35 @@
"downloads_section_description": "تحقق من التحديثات أو الإصدارات الأخرى لهذه اللعبة",
"danger_zone_section_title": "منطقة الخطر",
"danger_zone_section_description": "إزالة هذه اللعبة من مكتبتك أو الملفات التي تم تنزيلها بواسطة Hydra",
"download_in_progress": "تنزيل قيد التقدم",
"download_in_progress": "جاري التنزيل",
"download_paused": "التنزيل معلق",
"last_downloaded_option": "خيار التنزيل الأخير",
"create_shortcut_success": "تم إنشاء الاختصار بنجاح",
"create_shortcut_error": "خطأ في إنشاء الاختصار",
"nsfw_content_title": "هذه اللعبة تحتوي على محتوى غير لائق",
"nsfw_content_description": "{{title}} يحتوي على محتوى قد لا يناسب جميع الأعمار. هل تريد المتابعة؟",
"nsfw_content_description": "{{title}} يحتوي على محتوى قد لا يكون مناسبًا لجميع الأعمار. هل تريد المتابعة؟",
"allow_nsfw_content": "متابعة",
"refuse_nsfw_content": "رجوع",
"stats": "الإحصائيات",
"download_count": "مرات التنزيل",
"download_count": "التنزيلات",
"player_count": "اللاعبون النشطون",
"download_error": "خيار التنزيل هذا غير متاح",
"download": "تنزيل",
"executable_path_in_use": "مسار التشغيل مستخدم بالفعل بواسطة \"{{game}}\"",
"warning": "تحذير:",
"hydra_needs_to_remain_open": "لهذا التنزيل، يجب أن يبقى Hydra مفتوحًا حتى اكتماله. إذا أغلق Hydra قبل الاكتمال، ستفقد تقدمك.",
"hydra_needs_to_remain_open": "لهذا التنزيل، يجب أن يظل Hydra مفتوحًا حتى اكتماله. إذا تم إغلاق Hydra قبل الاكتمال، ستفقد تقدمك.",
"achievements": "الإنجازات",
"achievements_count": "الإنجازات {{unlockedCount}}/{{achievementsCount}}",
"cloud_save": "حفظ سحابي",
"cloud_save_description": "احفظ تقدمك على السحابة واستمر في اللعب من أي جهاز",
"cloud_save_description": "احفظ تقدمك في السحابة واستمر في اللعب من أي جهاز",
"backups": "النسخ الاحتياطية",
"install_backup": "تثبيت",
"delete_backup": "حذف",
"create_backup": "نسخة احتياطية جديدة",
"last_backup_date": "آخر نسخة احتياطية في {{date}}",
"no_backup_preview": "لم يتم العثور على حفظات لهذا العنوان",
"restoring_backup": "جارٍ استعادة النسخة الاحتياطية ({{progress}} اكتمال)...",
"uploading_backup": "جارٍ رفع النسخة الاحتياطية...",
"restoring_backup": "جاري استعادة النسخة الاحتياطية ({{progress}} مكتمل)...",
"uploading_backup": "جاري رفع النسخة الاحتياطية...",
"no_backups": "لم تقم بإنشاء أي نسخ احتياطية لهذه اللعبة بعد",
"backup_uploaded": "تم رفع النسخة الاحتياطية",
"backup_deleted": "تم حذف النسخة الاحتياطية",
@@ -164,61 +165,67 @@
"files_automatically_mapped": "تم تعيين الملفات تلقائيًا",
"no_backups_created": "لم يتم إنشاء نسخ احتياطية لهذه اللعبة",
"manage_files": "إدارة الملفات",
"loading_save_preview": "جارٍ البحث عن حفظات الألعاب...",
"loading_save_preview": "جاري البحث عن حفظات اللعبة...",
"wine_prefix": "بادئة Wine",
"wine_prefix_description": "بادئة Wine المستخدمة لتشغيل هذه اللعبة",
"launch_options": "خيارات التشغيل",
"launch_options_description": "يمكن للمستخدمين المتقدمين إدخال تعديلات على خيارات التشغيل (ميزة تجريبية)",
"launch_options_placeholder": م يتم تحديد أي معاملات",
"launch_options_placeholder": ا توجد معلمات محددة",
"no_download_option_info": "لا توجد معلومات متاحة",
"backup_deletion_failed": "فشل حذف النسخة الاحتياطية",
"max_number_of_artifacts_reached": "تم الوصول إلى الحد الأقصى لعدد النسخ الاحتياطية لهذه اللعبة",
"achievements_not_sync": "تعرف على كيفية مزامنة إنجازاتك",
"backup_deletion_failed": "فشل في حذف النسخة الاحتياطية",
"max_number_of_artifacts_reached": "تم الوصول إلى الحد الأقصى من النسخ الاحتياطية لهذه اللعبة",
"achievements_not_sync": "شاهد كيفية مزامنة إنجازاتك",
"manage_files_description": "إدارة الملفات التي سيتم نسخها احتياطيًا واستعادتها",
"select_folder": "حدد المجلد",
"backup_from": "نسخة احتياطية من {{date}}",
"custom_backup_location_set": "تم تعيين موقع نسخ احتياطي مخصص",
"no_directory_selected": "لم يتم تحديد مجلد",
"no_write_permission": "لا يمكن التنزيل إلى هذا المجلد. انقر هنا لمعرفة المزيد.",
"no_write_permission": "لا يمكن التنزيل إلى هذا المجلد. انقر هنا للمزيد من المعلومات.",
"reset_achievements": "إعادة تعيين الإنجازات",
"reset_achievements_description": "سيؤدي هذا إلى إعادة تعيين جميع إنجازات {{game}}",
"reset_achievements_title": "هل أنت متأكد؟",
"reset_achievements_success": "تم إعادة تعيين الإنجازات بنجاح",
"reset_achievements_error": "فشل إعادة تعيين الإنجازات"
"reset_achievements_error": "فشل في إعادة تعيين الإنجازات",
"download_error_gofile_quota_exceeded": "لقد تجاوزت الحصة الشهرية لـ Gofile. يرجى الانتظار حتى إعادة تعيين الحصة.",
"download_error_real_debrid_account_not_authorized": "حساب Real-Debrid الخاص بك غير مصرح له بإجراء تنزيلات جديدة. يرجى مراجعة إعدادات الحساب والمحاولة مرة أخرى.",
"download_error_not_cached_in_real_debrid": "هذا التنزيل غير متوفر على Real-Debrid وجلب حالة التنزيل من Real-Debrid غير متاح حاليًا.",
"download_error_not_cached_in_torbox": "هذا التنزيل غير متوفر على Torbox وجلب حالة التنزيل من Torbox غير متاح حاليًا.",
"game_removed_from_favorites": "تمت إزالة اللعبة من المفضلة",
"game_added_to_favorites": "تمت إضافة اللعبة إلى المفضلة"
},
"activation": {
"title": "تفعيل Hydra",
"installation_id": "معرف التثبيت:",
"enter_activation_code": "أدخل رمز التفعيل الخاص بك",
"message": "إذا كنت لا تعرف أين تطلب هذا، فلا يجب أن يكون لديك هذا.",
"message": "إذا كنت لا تعرف أين تطلب هذا، فأنت لا يجب أن يكون لديك هذا.",
"activate": "تفعيل",
"loading": "جارٍ التحميل..."
"loading": "جاري التحميل..."
},
"downloads": {
"resume": "استئناف",
"pause": "إيقاف مؤقت",
"eta": "الانتهاء {{eta}}",
"paused": "معلّق",
"verifying": "جارٍ التحقق...",
"eta": "الانتهاء المتوقع {{eta}}",
"paused": "معلق",
"verifying": "جاري التحقق...",
"completed": "مكتمل",
"removed": "غير محمل",
"removed": "غير منزّل",
"cancel": "إلغاء",
"filter": "تصفية الألعاب المحملة",
"filter": "تصفية الألعاب المنزلة",
"remove": "إزالة",
"downloading_metadata": "جارٍ تنزيل البيانات الوصفية...",
"deleting": "جارٍ حذف المثبت...",
"delete": "إزالة المثبت",
"downloading_metadata": "جاري تنزيل البيانات الوصفية...",
"deleting": "جاري حذف المثبت...",
"delete": "حذف المثبت",
"delete_modal_title": "هل أنت متأكد؟",
"delete_modal_description": "سيؤدي هذا إلى إزالة جميع ملفات التثبيت من جهازك",
"install": "تثبيت",
"download_in_progress": "قيد التقدم",
"queued_downloads": "التنزيلات في قائمة الانتظار",
"downloads_completed": "مكتمل",
"downloads_completed": "مكتملة",
"queued": "في قائمة الانتظار",
"no_downloads_title": "فارغ جدًا",
"no_downloads_title": "لا شيء هنا",
"no_downloads_description": "لم تقم بتنزيل أي شيء باستخدام Hydra بعد، ولكن لم يفت الأوان للبدء.",
"checking_files": "جارٍ فحص الملفات...",
"seeding": "التوزيع",
"checking_files": "جاري فحص الملفات...",
"seeding": "جاري التوزيع",
"stop_seeding": "إيقاف التوزيع",
"resume_seeding": "استئناف التوزيع",
"options": "إدارة"
@@ -228,8 +235,8 @@
"change": "تحديث",
"notifications": "الإشعارات",
"enable_download_notifications": "عند اكتمال التنزيل",
"enable_repack_list_notifications": "عند إضافة حزمة معاد تعبئتها جديدة",
"real_debrid_api_token_label": "رمز واجهة برمجة تطبيقات Real-Debrid",
"enable_repack_list_notifications": "عند إضافة إصدار معاد جديد",
"real_debrid_api_token_label": "رمز Real-Debrid API",
"quit_app_instead_hiding": "لا تخفي Hydra عند الإغلاق",
"launch_with_system": "تشغيل Hydra مع بدء النظام",
"general": "عام",
@@ -238,21 +245,21 @@
"language": "اللغة",
"api_token": "رمز API",
"enable_real_debrid": "تفعيل Real-Debrid",
"real_debrid_description": "Real-Debrid هو أداة تنزيل غير مقيدة تتيح لك تنزيل الملفات بسرعة، مقيدة فقط بسرعة الإنترنت لديك.",
"real_debrid_description": "Real-Debrid هو أداة تنزيل غير مقيدة تتيح لك تنزيل الملفات بسرعة، محدودة فقط بسرعة اتصالك بالإنترنت.",
"debrid_invalid_token": "رمز API غير صالح",
"debrid_api_token_hint": "يمكنك الحصول على رمز API الخاص بك <0>هنا</0>",
"real_debrid_free_account_error": "الحساب \"{{username}}\" هو حساب مجاني. يرجى الاشتراك في Real-Debrid",
"real_debrid_free_account_error": "الحساب \"{{username}}\" حساب مجاني. يرجى الاشتراك في Real-Debrid",
"debrid_linked_message": "تم ربط الحساب \"{{username}}\"",
"save_changes": "حفظ التغييرات",
"changes_saved": "تم حفظ التغييرات بنجاح",
"download_sources_description": "سيقوم Hydra بجلب روابط التنزيل من هذه المصادر. يجب أن يكون عنوان URL المصدر رابطًا مباشرًا لملف .json يحتوي على روابط التنزيل.",
"download_sources_description": "سيقوم Hydra بجلب روابط التنزيل من هذه المصادر. يجب أن يكون عنوان URL للمصدر رابطًا مباشرًا لملف .json يحتوي على روابط التنزيل.",
"validate_download_source": "تحقق",
"remove_download_source": "إزالة",
"add_download_source": "إضافة مصدر",
"download_count_zero": "لا توجد خيارات تنزيل",
"download_count_one": "{{countFormatted}} خيار تنزيل",
"download_count_other": "{{countFormatted}} خيارات تنزيل",
"download_source_url": "عنوان URL لمصدر التنزيل",
"download_source_url": "عنوان مصدر التنزيل",
"add_download_source_description": "أدخل عنوان URL لملف .json",
"download_source_up_to_date": "محدث",
"download_source_errored": "خطأ",
@@ -272,13 +279,13 @@
"profile_visibility": "رؤية الملف الشخصي",
"profile_visibility_description": "اختر من يمكنه رؤية ملفك الشخصي ومكتبتك",
"required_field": "هذا الحقل مطلوب",
"source_already_exists": "تمت إضافة هذا المصدر مسبقًا",
"must_be_valid_url": "يجب أن يكون المصدر عنوان URL صالحًا",
"source_already_exists": "هذا المصدر مضاف مسبقًا",
"must_be_valid_url": "يجب أن يكون المصدر عنوان URL صالح",
"blocked_users": "المستخدمون المحظورون",
"user_unblocked": "تم إلغاء حظر المستخدم",
"enable_achievement_notifications": "عند فتح إنجاز",
"launch_minimized": "تشغيل Hydra مصغرًا",
"disable_nsfw_alert": "تعطيل تنبيه المحتوى غير اللائق",
"disable_nsfw_alert": "تعطيل تنبيهات المحتوى غير اللائق",
"seed_after_download_complete": "التوزيع بعد اكتمال التنزيل",
"show_hidden_achievement_description": "عرض وصف الإنجازات المخفية قبل فتحها",
"account": "الحساب",
@@ -296,18 +303,47 @@
"become_subscriber": "كن مشتركًا في Hydra Cloud",
"subscription_renew_cancelled": "تم تعطيل التجديد التلقائي",
"subscription_renews_on": "سيتم تجديد اشتراكك في {{date}}",
"bill_sent_until": "سيتم إرسال فاتورتك التالية حتى هذا اليوم"
"bill_sent_until": "سيتم إرسال فاتورتك القادمة حتى هذا اليوم",
"no_themes": "يبدو أنه ليس لديك أي سمات بعد، لكن لا تقلق، انقر هنا لإنشاء أول تحفة فنية لك.",
"editor_tab_code": "الكود",
"editor_tab_info": "معلومات",
"editor_tab_save": "حفظ",
"web_store": "المتجر الإلكتروني",
"clear_themes": "مسح",
"create_theme": "إنشاء",
"create_theme_modal_title": "إنشاء سمة مخصصة",
"create_theme_modal_description": "إنشاء سمة جديدة لتخصيص مظهر Hydra",
"theme_name": "الاسم",
"insert_theme_name": "أدخل اسم السمة",
"set_theme": "تعيين السمة",
"unset_theme": "إلغاء تعيين السمة",
"delete_theme": "حذف السمة",
"edit_theme": "تعديل السمة",
"delete_all_themes": "حذف جميع السمات",
"delete_all_themes_description": "سيؤدي هذا إلى حذف جميع السمات المخصصة الخاصة بك",
"delete_theme_description": "سيؤدي هذا إلى حذف السمة {{theme}}",
"cancel": "إلغاء",
"appearance": "المظهر",
"enable_torbox": "تفعيل Torbox",
"torbox_description": "TorBox هي خدمة seedbox متميزة تنافس أفضل الخوادم في السوق.",
"torbox_account_linked": "تم ربط حساب TorBox",
"real_debrid_account_linked": "تم ربط حساب Real-Debrid",
"name_min_length": "يجب أن يكون اسم السمة على الأقل 3 أحرف",
"import_theme": "استيراد سمة",
"import_theme_description": "ستقوم باستيراد {{theme}} من متجر السمات",
"error_importing_theme": "خطأ في استيراد السمة",
"theme_imported": "تم استيراد السمة بنجاح"
},
"notifications": {
"download_complete": "اكتمل التنزيل",
"game_ready_to_install": "{{title}} جاهز للتثبيت",
"repack_list_updated": "تم تحديث قائمة الحزم المعاد تعبئتها",
"repack_count_one": "تمت إضافة {{count}} حزمة معاد تعبئتها",
"repack_count_other": "تمت إضافة {{count}} حزم معاد تعبئتها",
"repack_list_updated": "تم تحديث قائمة الإصدارات المعادة",
"repack_count_one": "تمت إضافة {{count}} إصدار معاد",
"repack_count_other": "تمت إضافة {{count}} إصدارات معادة",
"new_update_available": "الإصدار {{version}} متوفر",
"restart_to_install_update": "أعد تشغيل Hydra لتثبيت التحديث",
"notification_achievement_unlocked_title": "تم فتح إنجاز لـ {{game}}",
"notification_achievement_unlocked_body": "{{achievement}} و {{count}} آخرين تم فتحهم"
"notification_achievement_unlocked_body": "{{achievement}} و {{count}} أخرى تم فتحها"
},
"system_tray": {
"open": "فتح Hydra",
@@ -319,7 +355,7 @@
"binary_not_found_modal": {
"title": "البرامج غير مثبتة",
"description": "لم يتم العثور على ملفات تشغيل Wine أو Lutris على نظامك",
"instructions": "تحقق من الطريقة الصحيحة لتثبيت أي منها على توزيعة لينكس الخاصة بك حتى تعمل اللعبة بشكل طبيعي"
"instructions": "تحقق من الطريقة الصحيحة لتثبيت أي منها على توزيعة Linux الخاصة بك حتى تعمل اللعبة بشكل طبيعي"
},
"modal": {
"close": "زر الإغلاق"
@@ -328,16 +364,16 @@
"toggle_password_visibility": "تبديل رؤية كلمة المرور"
},
"user_profile": {
"amount_hours": "{{amount}} ساعات",
"amount_minutes": "{{amount}} دقائق",
"last_time_played": "آخر تشغيل {{period}}",
"amount_hours": "{{amount}} ساعة",
"amount_minutes": "{{amount}} دقيقة",
"last_time_played": "آخر مرة لعب {{period}}",
"activity": "النشاط الأخير",
"library": "المكتبة",
"total_play_time": "إجمالي وقت اللعب",
"no_recent_activity_title": "همم... لا شيء هنا",
"no_recent_activity_title": "لا شيء هنا...",
"no_recent_activity_description": "لم تلعب أي ألعاب مؤخرًا. حان الوقت لتغيير ذلك!",
"display_name": "اسم العرض",
"saving": "جارٍ الحفظ",
"saving": "جاري الحفظ",
"save": "حفظ",
"edit_profile": "تعديل الملف الشخصي",
"saved_successfully": "تم الحفظ بنجاح",
@@ -346,13 +382,13 @@
"cancel": "إلغاء",
"successfully_signed_out": "تم تسجيل الخروج بنجاح",
"sign_out": "تسجيل الخروج",
"playing_for": "يلعب لمدة {{amount}}",
"sign_out_modal_text": "مكتبتك مرتبطة بحسابك الحالي. عند تسجيل الخروج، لن تكون مكتبتك مرئية بعد الآن، ولن يتم حفظ أي تقدم. هل تتابع تسجيل الخروج؟",
"playing_for": "جاري اللعب لمدة {{amount}}",
"sign_out_modal_text": "مكتبتك مرتبطة بحسابك الحالي. عند تسجيل الخروج، لن تكون مكتبتك مرئية، ولن يتم حفظ أي تقدم. هل تتابع تسجيل الخروج؟",
"add_friends": "إضافة أصدقاء",
"add": "إضافة",
"friend_code": "رمز الصديق",
"see_profile": "عرض الملف الشخصي",
"sending": "جارٍ الإرسال",
"sending": "جاري الإرسال",
"friend_request_sent": "تم إرسال طلب الصداقة",
"friends": "الأصدقاء",
"friends_list": "قائمة الأصدقاء",
@@ -371,19 +407,19 @@
"blocked_users": "المستخدمون المحظورون",
"unblock": "إلغاء الحظر",
"no_friends_added": "ليس لديك أصدقاء مضافون",
"pending": يد الانتظار",
"pending": "معلق",
"no_pending_invites": "ليس لديك دعوات معلقة",
"no_blocked_users": "ليس لديك مستخدمون محظورون",
"friend_code_copied": "تم نسخ رمز الصديق",
"undo_friendship_modal_text": "سيؤدي هذا إلى إلغاء صداقتك مع {{displayName}}",
"privacy_hint": "لضبط من يمكنه رؤية هذا، انتقل إلى <0>الإعدادات</0>",
"locked_profile": "هذا الملف الشخصي خاص",
"image_process_failure": "فشل معالجة الصورة",
"image_process_failure": "فشل في معالجة الصورة",
"required_field": "هذا الحقل مطلوب",
"displayname_min_length": "يجب أن يكون اسم العرض على الأقل 3 أحرف",
"displayname_max_length": "يجب ألا يتجاوز اسم العرض 50 حرفًا",
"report_profile": "الإبلاغ عن هذا الملف الشخصي",
"report_reason": "لماذا تقوم بالإبلاغ عن هذا الملف الشخصي؟",
"displayname_max_length": "يجب أن لا يتجاوز اسم العرض 50 حرفًا",
"report_profile": "الإبلاغ عن هذا الملف",
"report_reason": "لماذا تقوم بالإبلاغ عن هذا الملف؟",
"report_description": "معلومات إضافية",
"report_description_placeholder": "معلومات إضافية",
"report": "الإبلاغ",
@@ -393,32 +429,32 @@
"report_reason_spam": "بريد عشوائي",
"report_reason_other": "أخرى",
"profile_reported": "تم الإبلاغ عن الملف الشخصي",
"your_friend_code": "رمز صديقك:",
"upload_banner": "تحميل بانر",
"uploading_banner": "جارٍ تحميل البانر...",
"your_friend_code": "رمز الصديق الخاص بك:",
"upload_banner": "رفع بانر",
"uploading_banner": "جاري رفع البانر...",
"background_image_updated": "تم تحديث صورة الخلفية",
"stats": "الإحصائيات",
"achievements": "إنجازات",
"achievements": "الإنجازات",
"games": "الألعاب",
"top_percentile": "ال{{percentile}}% الأعلى",
"top_percentile": "الأعلى {{percentile}}%",
"ranking_updated_weekly": "يتم تحديث التصنيف أسبوعيًا",
"playing": "يلعب {{game}}",
"playing": "جاري لعب {{game}}",
"achievements_unlocked": "الإنجازات المفتوحة",
"earned_points": "النقاط المكتسبة",
"show_achievements_on_profile": "عرض إنجازاتك على ملفك الشخصي",
"show_points_on_profile": "عرض نقاطك المكتسبة على ملفك الشخصي"
"show_achievements_on_profile": "عرض إنجازاتك في ملفك الشخصي",
"show_points_on_profile": "عرض نقاطك المكتسبة في ملفك الشخصي"
},
"achievement": {
"achievement_unlocked": "تم فتح الإنجاز",
"user_achievements": "إنجازات {{displayName}}",
"your_achievements": "إنجازاتك",
"unlocked_at": "تم الفتح في: {{date}}",
"subscription_needed": "يحتاج إلى اشتراك Hydra Cloud لرؤية هذا المحتوى",
"subscription_needed": "يحتاج إلى اشتراك Hydra Cloud لعرض هذا المحتوى",
"new_achievements_unlocked": "تم فتح {{achievementCount}} إنجازات جديدة من {{gameCount}} ألعاب",
"achievement_progress": "{{unlockedCount}}/{{totalCount}} إنجازات",
"achievements_unlocked_for_game": "تم فتح {{achievementCount}} إنجازات جديدة لـ {{gameTitle}}",
"hidden_achievement_tooltip": "هذا إنجاز مخفي",
"achievement_earn_points": "اكسب {{points}} نقطة مع هذا الإنجاز",
"achievement_earn_points": "احصل على {{points}} نقاط مع هذا الإنجاز",
"earned_points": "النقاط المكتسبة:",
"available_points": "النقاط المتاحة:",
"how_to_earn_achievements_points": "كيفية كسب نقاط الإنجازات؟"
@@ -428,10 +464,10 @@
"subscribe_now": "اشترك الآن",
"cloud_saving": "حفظ سحابي",
"cloud_achievements": "احفظ إنجازاتك على السحابة",
"animated_profile_picture": "صورة ملف شخصي متحركة",
"animated_profile_picture": "صورة ملف متحركة",
"premium_support": "دعم ممتاز",
"show_and_compare_achievements": "اعرض وقارن إنجازاتك مع المستخدمين الآخرين",
"animated_profile_banner": "بانر ملف شخصي متحرك",
"animated_profile_banner": "بانر ملف متحرك",
"hydra_cloud": "Hydra Cloud",
"hydra_cloud_feature_found": "لقد اكتشفت ميزة Hydra Cloud!",
"learn_more": "معرفة المزيد"

View File

@@ -444,6 +444,9 @@
"show_achievements_on_profile": "Show your achievements on your profile",
"show_points_on_profile": "Show your earned points on your profile"
},
"badge": {
"badge_description_theme_creator": "Awarded to those who created a custom theme"
},
"achievement": {
"achievement_unlocked": "Achievement unlocked",
"user_achievements": "{{displayName}}'s Achievements",

View File

@@ -440,6 +440,9 @@
"show_achievements_on_profile": "Exiba suas conquistas no perfil",
"show_points_on_profile": "Exiba seus pontos ganhos no perfil"
},
"badge": {
"badge_description_theme_creator": "Concedido àqueles que criaram um tema customizado"
},
"achievement": {
"achievement_unlocked": "Conquista desbloqueada",
"your_achievements": "Suas Conquistas",

View File

@@ -183,7 +183,13 @@
"no_write_permission": "Невозможно загрузить в эту директорию. Нажмите здесь, чтобы узнать больше.",
"reset_achievements_title": "Вы уверены?",
"reset_achievements_success": "Достижения успешно сброшены",
"reset_achievements_error": "Не удалось сбросить достижения"
"reset_achievements_error": "Не удалось сбросить достижения",
"download_error_gofile_quota_exceeded": "Вы превысили месячную квоту Gofile. Пожалуйста, подождите, пока квота не будет восстановлена.",
"download_error_real_debrid_account_not_authorized": "Ваш аккаунт Real-Debrid не авторизован для осуществления новых загрузок. Пожалуйста, проверьте настройки учетной записи и повторите попытку.",
"download_error_not_cached_in_real_debrid": "Эта загрузка недоступна на Real-Debrid, а опрос статуса загрузки с Real-Debrid пока недоступен.",
"download_error_not_cached_in_torbox": "Эта загрузка недоступна на Torbox, и опросить статус загрузки с Torbox пока невозможно.",
"game_added_to_favorites": "Игра добавлена в избранное",
"game_removed_from_favorites": "Игра удалена из избранного"
},
"activation": {
"title": "Активировать Hydra",
@@ -295,7 +301,36 @@
"become_subscriber": "Станьте обладателем Hydra Cloud",
"subscription_renew_cancelled": "Автоматическое продление отключено",
"subscription_renews_on": "Ваша подписка продлевается на {{date}}",
"bill_sent_until": "Ваш следующий счет будет отправлен до этого дня"
"bill_sent_until": "Ваш следующий счет будет отправлен до этого дня",
"no_themes": "Похоже, что у вас еще нет тем, но не волнуйтесь, нажмите здесь, чтобы создать свой первый шедевр",
"editor_tab_code": "Код",
"editor_tab_info": "Информация",
"editor_tab_save": "Сохранить",
"web_store": "Веб-магазин",
"clear_themes": "Очистить",
"create_theme": "Создать",
"create_theme_modal_title": "Создать пользовательскую тему",
"create_theme_modal_description": "Создать новую тему для настройки внешнего вида Hydra",
"theme_name": "Название",
"insert_theme_name": "Вставить название темы",
"set_theme": "Установить тему",
"unset_theme": "Снять тему",
"delete_theme": "Удалить тему",
"edit_theme": "Редактировать тему",
"delete_all_themes": "Удалить все темы",
"delete_all_themes_description": "Это удалит все ваши пользовательские темы",
"delete_theme_description": "Это приведет к удалению темы {{theme}}",
"cancel": "Отменить",
"appearance": "Внешний вид",
"enable_torbox": "Включить Torbox",
"torbox_description": "TorBox - это ваш премиум-сервис, конкурирующий даже с лучшими серверами на рынке.",
"torbox_account_linked": "Аккаунт TorBox привязан",
"real_debrid_account_linked": "Аккаунт Real-Debrid привязан",
"name_min_length": "Название темы должно содержать не менее 3 символов",
"import_theme": "Импортировать тему",
"import_theme_description": "Вы импортируете {{theme}} из магазина тем",
"error_importing_theme": "Ошибка при импорте темы",
"theme_imported": "Тема успешно импортирована"
},
"notifications": {
"download_complete": "Загрузка завершена",

View File

@@ -57,7 +57,7 @@ export class WindowManager {
trafficLightPosition: { x: 16, y: 16 },
titleBarOverlay: {
symbolColor: "#DADBE1",
color: "#151515",
color: "#00000000",
height: 34,
},
webPreferences: {

View File

@@ -263,9 +263,7 @@ export function App() {
useEffect(() => {
const unsubscribe = window.electron.onCssInjected((cssString) => {
if (cssString) {
injectCustomCss(cssString);
}
injectCustomCss(cssString);
});
return () => unsubscribe();

View File

@@ -0,0 +1,29 @@
<svg width="240" height="246" viewBox="0 0 240 246" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M117.681 8.44054C120.27 4.75592 125.73 4.75592 128.319 8.44054L149.273 38.2669C151.08 40.8399 154.301 42.0121 157.339 41.203L192.563 31.8236C196.914 30.6649 201.097 34.1747 200.712 38.6612L197.591 74.9784C197.322 78.1113 199.036 81.0795 201.884 82.4128L234.895 97.8691C238.974 99.7785 239.922 105.156 236.743 108.345L211.008 134.16C208.788 136.387 208.193 139.762 209.517 142.614L224.871 175.674C226.767 179.758 224.037 184.486 219.552 184.886L183.245 188.119C180.113 188.398 177.487 190.601 176.669 193.637L167.18 228.832C166.007 233.179 160.876 235.047 157.184 232.47L127.292 211.609C124.714 209.809 121.286 209.809 118.708 211.609L88.8163 232.47C85.1236 235.047 79.9927 233.179 78.8204 228.832L69.3314 193.637C68.5129 190.601 65.8873 188.398 62.7553 188.119L26.4479 184.886C21.9627 184.486 19.2326 179.758 21.1293 175.674L36.4827 142.614C37.8072 139.762 37.212 136.387 34.992 134.16L9.25738 108.345C6.07823 105.156 7.02639 99.7785 11.1045 97.8691L44.1164 82.4128C46.9642 81.0795 48.6778 78.1113 48.4087 74.9784L45.2883 38.6611C44.9028 34.1747 49.0856 30.6649 53.437 31.8236L88.6606 41.203C91.6992 42.0121 94.9198 40.8399 96.7274 38.2669L117.681 8.44054Z" fill="url(#paint0_linear_1378_2496)"/>
<path d="M117.681 8.44054C120.27 4.75592 125.73 4.75592 128.319 8.44054L149.273 38.2669C151.08 40.8399 154.301 42.0121 157.339 41.203L192.563 31.8236C196.914 30.6649 201.097 34.1747 200.712 38.6612L197.591 74.9784C197.322 78.1113 199.036 81.0795 201.884 82.4128L234.895 97.8691C238.974 99.7785 239.922 105.156 236.743 108.345L211.008 134.16C208.788 136.387 208.193 139.762 209.517 142.614L224.871 175.674C226.767 179.758 224.037 184.486 219.552 184.886L183.245 188.119C180.113 188.398 177.487 190.601 176.669 193.637L167.18 228.832C166.007 233.179 160.876 235.047 157.184 232.47L127.292 211.609C124.714 209.809 121.286 209.809 118.708 211.609L88.8163 232.47C85.1236 235.047 79.9927 233.179 78.8204 228.832L69.3314 193.637C68.5129 190.601 65.8873 188.398 62.7553 188.119L26.4479 184.886C21.9627 184.486 19.2326 179.758 21.1293 175.674L36.4827 142.614C37.8072 139.762 37.212 136.387 34.992 134.16L9.25738 108.345C6.07823 105.156 7.02639 99.7785 11.1045 97.8691L44.1164 82.4128C46.9642 81.0795 48.6778 78.1113 48.4087 74.9784L45.2883 38.6611C44.9028 34.1747 49.0856 30.6649 53.437 31.8236L88.6606 41.203C91.6992 42.0121 94.9198 40.8399 96.7274 38.2669L117.681 8.44054Z" fill="url(#paint1_linear_1378_2496)"/>
<path d="M117.681 8.44054C120.27 4.75592 125.73 4.75592 128.319 8.44054L149.273 38.2669C151.08 40.8399 154.301 42.0121 157.339 41.203L192.563 31.8236C196.914 30.6649 201.097 34.1747 200.712 38.6612L197.591 74.9784C197.322 78.1113 199.036 81.0795 201.884 82.4128L234.895 97.8691C238.974 99.7785 239.922 105.156 236.743 108.345L211.008 134.16C208.788 136.387 208.193 139.762 209.517 142.614L224.871 175.674C226.767 179.758 224.037 184.486 219.552 184.886L183.245 188.119C180.113 188.398 177.487 190.601 176.669 193.637L167.18 228.832C166.007 233.179 160.876 235.047 157.184 232.47L127.292 211.609C124.714 209.809 121.286 209.809 118.708 211.609L88.8163 232.47C85.1236 235.047 79.9927 233.179 78.8204 228.832L69.3314 193.637C68.5129 190.601 65.8873 188.398 62.7553 188.119L26.4479 184.886C21.9627 184.486 19.2326 179.758 21.1293 175.674L36.4827 142.614C37.8072 139.762 37.212 136.387 34.992 134.16L9.25738 108.345C6.07823 105.156 7.02639 99.7785 11.1045 97.8691L44.1164 82.4128C46.9642 81.0795 48.6778 78.1113 48.4087 74.9784L45.2883 38.6611C44.9028 34.1747 49.0856 30.6649 53.437 31.8236L88.6606 41.203C91.6992 42.0121 94.9198 40.8399 96.7274 38.2669L117.681 8.44054Z" stroke="url(#paint2_linear_1378_2496)"/>
<g opacity="0.9">
<g style="mix-blend-mode:overlay">
<path d="M113.207 107.103L113.873 107.307L114.295 106.754C120.652 98.4238 129.53 87.9999 139.582 79.6678C149.661 71.3136 160.772 65.1865 171.609 65.1865C172.421 65.1865 173.2 65.5092 173.775 66.0835C174.349 66.6578 174.672 67.4368 174.672 68.249C174.672 79.0868 168.546 90.1972 160.192 100.276C151.861 110.328 141.437 119.207 133.105 125.563L132.551 125.985L132.755 126.651C134.104 131.057 134.402 135.718 133.623 140.26C132.844 144.802 131.011 149.098 128.271 152.803C125.531 156.508 121.96 159.519 117.845 161.594C113.73 163.668 109.186 164.749 104.578 164.749H65.9851C65.3296 164.748 64.6916 164.538 64.1649 164.147C63.6381 163.757 63.2505 163.208 63.059 162.581C62.8674 161.954 62.8821 161.283 63.1008 160.665C63.3195 160.047 63.7307 159.515 64.274 159.149L64.2813 159.144C64.8739 158.736 75.1093 151.439 75.1093 135.28C75.1093 130.672 76.19 126.128 78.2646 122.013C80.3393 117.898 83.35 114.328 87.055 111.587C90.76 108.847 95.056 107.014 99.598 106.235C104.14 105.457 108.801 105.754 113.207 107.103ZM120.25 109.05L119.585 109.911L120.499 110.501C124.047 112.792 127.067 115.811 129.357 119.359L129.948 120.275L130.809 119.608C133.07 117.857 135.204 116.141 137.212 114.46L137.904 113.881L137.399 113.133C134.556 108.926 130.933 105.302 126.725 102.459L125.979 101.955L125.4 102.645C123.714 104.65 121.997 106.785 120.25 109.05ZM141.909 108.878L142.566 109.805L143.402 109.036C161.044 92.7992 166.529 80.4502 168.029 72.9963L168.328 71.5152L166.848 71.8195C159.403 73.3505 147.056 78.8076 130.817 96.4511L130.048 97.2872L130.975 97.9442C135.21 100.946 138.907 104.643 141.909 108.878Z" fill="black"/>
<path d="M113.207 107.103L113.873 107.307L114.295 106.754C120.652 98.4238 129.53 87.9999 139.582 79.6678C149.661 71.3136 160.772 65.1865 171.609 65.1865C172.421 65.1865 173.2 65.5092 173.775 66.0835C174.349 66.6578 174.672 67.4368 174.672 68.249C174.672 79.0868 168.546 90.1972 160.192 100.276C151.861 110.328 141.437 119.207 133.105 125.563L132.551 125.985L132.755 126.651C134.104 131.057 134.402 135.718 133.623 140.26C132.844 144.802 131.011 149.098 128.271 152.803C125.531 156.508 121.96 159.519 117.845 161.594C113.73 163.668 109.186 164.749 104.578 164.749H65.9851C65.3296 164.748 64.6916 164.538 64.1649 164.147C63.6381 163.757 63.2505 163.208 63.059 162.581C62.8674 161.954 62.8821 161.283 63.1008 160.665C63.3195 160.047 63.7307 159.515 64.274 159.149L64.2813 159.144C64.8739 158.736 75.1093 151.439 75.1093 135.28C75.1093 130.672 76.19 126.128 78.2646 122.013C80.3393 117.898 83.35 114.328 87.055 111.587C90.76 108.847 95.056 107.014 99.598 106.235C104.14 105.457 108.801 105.754 113.207 107.103ZM120.25 109.05L119.585 109.911L120.499 110.501C124.047 112.792 127.067 115.811 129.357 119.359L129.948 120.275L130.809 119.608C133.07 117.857 135.204 116.141 137.212 114.46L137.904 113.881L137.399 113.133C134.556 108.926 130.933 105.302 126.725 102.459L125.979 101.955L125.4 102.645C123.714 104.65 121.997 106.785 120.25 109.05ZM141.909 108.878L142.566 109.805L143.402 109.036C161.044 92.7992 166.529 80.4502 168.029 72.9963L168.328 71.5152L166.848 71.8195C159.403 73.3505 147.056 78.8076 130.817 96.4511L130.048 97.2872L130.975 97.9442C135.21 100.946 138.907 104.643 141.909 108.878Z" stroke="url(#paint3_linear_1378_2496)" stroke-width="2"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_1378_2496" x1="5.63736e-07" y1="12.92" x2="246" y2="233.08" gradientUnits="userSpaceOnUse">
<stop stop-color="#0CF1CA"/>
<stop offset="1" stop-color="#1DCCEB"/>
</linearGradient>
<linearGradient id="paint1_linear_1378_2496" x1="19.8951" y1="-3.50306e-06" x2="226.105" y2="246" gradientUnits="userSpaceOnUse">
<stop stop-color="#0DDEBB"/>
<stop offset="1" stop-color="#052520"/>
</linearGradient>
<linearGradient id="paint2_linear_1378_2496" x1="-1.9947e-06" y1="18.0561" x2="246" y2="227.944" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0.7"/>
<stop offset="1" stop-color="white" stop-opacity="0.1"/>
</linearGradient>
<linearGradient id="paint3_linear_1378_2496" x1="61.9253" y1="71.6411" x2="164.664" y2="169.814" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0.2"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -6,7 +6,10 @@ export interface BackdropProps {
children: React.ReactNode;
}
export function Backdrop({ isClosing = false, children }: BackdropProps) {
export function Backdrop({
isClosing = false,
children,
}: Readonly<BackdropProps>) {
return (
<div
className={cn("backdrop", {

View File

@@ -15,7 +15,7 @@ export function Button({
theme = "primary",
className,
...props
}: ButtonProps) {
}: Readonly<ButtonProps>) {
return (
<button
type="button"

View File

@@ -41,7 +41,7 @@ export interface UserProfileContextProviderProps {
export function UserProfileContextProvider({
children,
userId,
}: UserProfileContextProviderProps) {
}: Readonly<UserProfileContextProviderProps>) {
const { userDetails } = useAppSelector((state) => state.userDetails);
const [userStats, setUserStats] = useState<UserStats | null>(null);

View File

@@ -18,26 +18,17 @@ import { store } from "./store";
import resources from "@locales";
import { SuspenseWrapper } from "./components";
import { logger } from "./logger";
import { addCookieInterceptor } from "./cookies";
const Home = React.lazy(() => import("./pages/home/home"));
const GameDetails = React.lazy(
() => import("./pages/game-details/game-details")
);
const Downloads = React.lazy(() => import("./pages/downloads/downloads"));
const Settings = React.lazy(() => import("./pages/settings/settings"));
const Catalogue = React.lazy(() => import("./pages/catalogue/catalogue"));
const Profile = React.lazy(() => import("./pages/profile/profile"));
const Achievements = React.lazy(
() => import("./pages/achievements/achievements")
);
const ThemeEditor = React.lazy(
() => import("./pages/theme-editor/theme-editor")
);
import * as Sentry from "@sentry/react";
import Catalogue from "./pages/catalogue/catalogue";
import Home from "./pages/home/home";
import Downloads from "./pages/downloads/downloads";
import GameDetails from "./pages/game-details/game-details";
import Settings from "./pages/settings/settings";
import Profile from "./pages/profile/profile";
import Achievements from "./pages/achievements/achievements";
import ThemeEditor from "./pages/theme-editor/theme-editor";
Sentry.init({
dsn: import.meta.env.RENDERER_VITE_SENTRY_DSN,
@@ -82,37 +73,16 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
<HashRouter>
<Routes>
<Route element={<App />}>
<Route path="/" element={<SuspenseWrapper Component={Home} />} />
<Route
path="/catalogue"
element={<SuspenseWrapper Component={Catalogue} />}
/>
<Route
path="/downloads"
element={<SuspenseWrapper Component={Downloads} />}
/>
<Route
path="/game/:shop/:objectId"
element={<SuspenseWrapper Component={GameDetails} />}
/>
<Route
path="/settings"
element={<SuspenseWrapper Component={Settings} />}
/>
<Route
path="/profile/:userId"
element={<SuspenseWrapper Component={Profile} />}
/>
<Route
path="/achievements"
element={<SuspenseWrapper Component={Achievements} />}
/>
<Route path="/" element={<Home />} />
<Route path="/catalogue" element={<Catalogue />} />
<Route path="/downloads" element={<Downloads />} />
<Route path="/game/:shop/:objectId" element={<GameDetails />} />
<Route path="/settings" element={<Settings />} />
<Route path="/profile/:userId" element={<Profile />} />
<Route path="/achievements" element={<Achievements />} />
</Route>
<Route
path="/theme-editor"
element={<SuspenseWrapper Component={ThemeEditor} />}
/>
<Route path="/theme-editor" element={<ThemeEditor />} />
</Routes>
</HashRouter>
</Provider>

View File

@@ -16,13 +16,8 @@ import { useUserDetails } from "@renderer/hooks";
import { useSubscription } from "@renderer/hooks/use-subscription";
import "./game-details.scss";
const HERO_HEIGHT = 300;
const HERO_ANIMATION_THRESHOLD = 25;
export function GameDetailsContent() {
const heroRef = useRef<HTMLDivElement | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
const [isHeaderStuck, setIsHeaderStuck] = useState(false);
const { t } = useTranslation("game_details");
@@ -61,7 +56,7 @@ export function GameDetailsContent() {
return t("no_shop_details");
}, [shopDetails, t]);
const [backdropOpactiy, setBackdropOpacity] = useState(1);
const [backdropOpacity, setBackdropOpacity] = useState(1);
const handleHeroLoad = async () => {
const output = await average(steamUrlBuilder.libraryHero(objectId!), {
@@ -80,26 +75,6 @@ export function GameDetailsContent() {
setBackdropOpacity(1);
}, [objectId]);
const onScroll: React.UIEventHandler<HTMLElement> = (event) => {
const heroHeight = heroRef.current?.clientHeight ?? HERO_HEIGHT;
const scrollY = (event.target as HTMLDivElement).scrollTop;
const opacity = Math.max(
0,
1 - scrollY / (heroHeight - HERO_ANIMATION_THRESHOLD)
);
if (scrollY >= heroHeight && !isHeaderStuck) {
setIsHeaderStuck(true);
}
if (scrollY <= heroHeight && isHeaderStuck) {
setIsHeaderStuck(false);
}
setBackdropOpacity(opacity);
};
const handleCloudSaveButtonClick = () => {
if (!userDetails) {
window.electron.openAuthWindow(AuthPage.SignIn);
@@ -122,31 +97,25 @@ export function GameDetailsContent() {
<div
className={`game-details__wrapper ${hasNSFWContentBlocked ? "game-details__wrapper--blurred" : ""}`}
>
<img
src={steamUrlBuilder.libraryHero(objectId!)}
className="game-details__hero-image"
alt={game?.title}
onLoad={handleHeroLoad}
/>
<section
ref={containerRef}
onScroll={onScroll}
className="game-details__container"
>
<section className="game-details__container">
<div ref={heroRef} className="game-details__hero">
<img
src={steamUrlBuilder.libraryHero(objectId!)}
className="game-details__hero-image"
alt={game?.title}
onLoad={handleHeroLoad}
/>
<div
className="game-details__hero-backdrop"
style={{
backgroundColor: gameColor,
flex: 1,
opacity: Math.min(1, 1 - backdropOpactiy),
}}
/>
<div
className="game-details__hero-logo-backdrop"
style={{ opacity: backdropOpactiy }}
style={{ opacity: backdropOpacity }}
>
<div className="game-details__hero-content">
<img
@@ -173,7 +142,7 @@ export function GameDetailsContent() {
</div>
</div>
<HeroPanel isHeaderStuck={isHeaderStuck} />
<HeroPanel />
<div className="game-details__description-container">
<div className="game-details__description-content">

View File

@@ -9,11 +9,7 @@ import { HeroPanelPlaytime } from "./hero-panel-playtime";
import { gameDetailsContext } from "@renderer/context";
import "./hero-panel.scss";
export interface HeroPanelProps {
isHeaderStuck: boolean;
}
export function HeroPanel({ isHeaderStuck }: HeroPanelProps) {
export function HeroPanel() {
const { t } = useTranslation("game_details");
const { formatDate } = useDate();
@@ -54,10 +50,7 @@ export function HeroPanel({ isHeaderStuck }: HeroPanelProps) {
game?.download?.status === "paused";
return (
<div
style={{ backgroundColor: gameColor }}
className={`hero-panel ${isHeaderStuck ? "hero-panel--stuck" : ""}`}
>
<div style={{ backgroundColor: gameColor }} className="hero-panel">
<div className="hero-panel__content">{getInfo()}</div>
<div className="hero-panel__actions">
<HeroPanelActions />

View File

@@ -65,6 +65,12 @@
overflow: hidden;
}
&__display-name-container {
display: flex;
gap: globals.$spacing-unit;
align-items: center;
}
&__display-name {
font-weight: bold;
overflow: hidden;
@@ -76,6 +82,12 @@
text-shadow: 0 0 5px rgb(0 0 0 / 40%);
}
&__display-name-badges-container {
display: flex;
gap: globals.$spacing-unit;
align-items: center;
}
&__current-game {
&-wrapper {
display: flex;

View File

@@ -25,6 +25,7 @@ import { EditProfileModal } from "../edit-profile-modal/edit-profile-modal";
import Skeleton from "react-loading-skeleton";
import { UploadBackgroundImageButton } from "../upload-background-image-button/upload-background-image-button";
import "./profile-hero.scss";
import { UserBadges } from "./user-badges";
type FriendAction =
| FriendRequestAction
@@ -307,9 +308,12 @@ export function ProfileHero() {
<div className="profile-hero__information">
{userProfile ? (
<h2 className="profile-hero__display-name">
{userProfile?.displayName}
</h2>
<div className="profile-hero__display-name-container">
<h2 className="profile-hero__display-name">
{userProfile?.displayName}
</h2>
<UserBadges />
</div>
) : (
<Skeleton width={150} height={28} />
)}

View File

@@ -0,0 +1,40 @@
import BadgeThemeCreator from "@renderer/assets/icons/badge-theme-creator.svg?react";
import "./profile-hero.scss";
import { useContext } from "react";
import { userProfileContext } from "@renderer/context";
import { UserBadge } from "@types";
import { useTranslation } from "react-i18next";
export function UserBadges() {
const { t } = useTranslation("badge");
const { userProfile } = useContext(userProfileContext);
if (!userProfile?.badges?.length) return null;
const getBadgeIcon = (badge: UserBadge) => {
if (badge === "THEME_CREATOR") {
return <BadgeThemeCreator width={24} height={24} />;
}
return null;
};
return (
<div className="profile-hero__display-name-badges-container">
{userProfile.badges.map((badge) => {
const badgeIcon = getBadgeIcon(badge);
if (!badgeIcon) return null;
return (
<div
className={`badge__${badge.toLowerCase()}`}
key={badge}
title={t(`badge_description_${badge.toLowerCase()}`)}
>
{badgeIcon}
</div>
);
})}
</div>
);
}

View File

@@ -4,6 +4,7 @@ import { ThemeActions, ThemeCard, ThemePlaceholder } from "./index";
import type { Theme } from "@types";
import { ImportThemeModal } from "./modals/import-theme-modal";
import { settingsContext } from "@renderer/context";
import { useNavigate } from "react-router-dom";
interface SettingsAppearanceProps {
appearance: {
@@ -24,8 +25,10 @@ export function SettingsAppearance({
authorId: string;
authorName: string;
} | null>(null);
const [hasShownModal, setHasShownModal] = useState(false);
const { clearTheme } = useContext(settingsContext);
const navigate = useNavigate();
const loadThemes = useCallback(async () => {
const themesList = await window.electron.getAllCustomThemes();
@@ -45,20 +48,37 @@ export function SettingsAppearance({
}, [loadThemes]);
useEffect(() => {
if (appearance.theme && appearance.authorId && appearance.authorName) {
if (
appearance.theme &&
appearance.authorId &&
appearance.authorName &&
!hasShownModal
) {
setIsImportThemeModalVisible(true);
setImportTheme({
theme: appearance.theme,
authorId: appearance.authorId,
authorName: appearance.authorName,
});
setHasShownModal(true);
navigate("/settings", { replace: true });
clearTheme();
}
}, [appearance.theme, appearance.authorId, appearance.authorName]);
}, [
appearance.theme,
appearance.authorId,
appearance.authorName,
navigate,
hasShownModal,
clearTheme,
]);
const onThemeImported = useCallback(() => {
setIsImportThemeModalVisible(false);
setImportTheme(null);
loadThemes();
}, [clearTheme, loadThemes]);
}, [loadThemes]);
return (
<div className="settings-appearance">
@@ -90,6 +110,7 @@ export function SettingsAppearance({
onClose={() => {
setIsImportThemeModalVisible(false);
clearTheme();
setHasShownModal(false);
}}
onThemeImported={onThemeImported}
themeName={importTheme.theme}

View File

@@ -130,6 +130,8 @@ export interface UserProfileCurrentGame extends Omit<GameRunning, "objectId"> {
export type ProfileVisibility = "PUBLIC" | "PRIVATE" | "FRIENDS";
export type UserBadge = "THEME_CREATOR";
export interface UserDetails {
id: string;
username: string;
@@ -164,6 +166,7 @@ export interface UserProfile {
quirks: {
backupsPerGameLimit: number;
};
badges: UserBadge[];
}
export interface UpdateProfileRequest {