From 10fc489ce9d0c3674ce5fecea9977a7f8552d8a0 Mon Sep 17 00:00:00 2001 From: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com> Date: Sun, 7 Jun 2026 11:48:23 +0200 Subject: [PATCH] fix(themes): offline banner for the Theme Store (#1013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(themes): show an offline banner when the Theme Store is unavailable When the registry can't be fetched and no catalogue is cached, the store now shows a clear offline banner (icon, message, retry) in place of the list, and hides the search/filter toolbar — there is nothing to browse. The cached-catalogue fallback with its offline indicator is unchanged, so the store still works offline when a catalogue was previously cached. * docs(themes): note the offline-banner PR in the Theme Store entry Add PR #1013 to the still-unreleased Theme Store changelog and credits entry, alongside the other follow-ups. --- CHANGELOG.md | 2 +- .../settings/ThemeStoreSection.test.tsx | 10 ++++++ src/components/settings/ThemeStoreSection.tsx | 32 ++++++++++++++++--- src/config/settingsCredits.ts | 2 +- src/locales/de/settings.ts | 1 + src/locales/en/settings.ts | 1 + src/locales/es/settings.ts | 1 + src/locales/fr/settings.ts | 1 + src/locales/nb/settings.ts | 1 + src/locales/nl/settings.ts | 1 + src/locales/ro/settings.ts | 1 + src/locales/ru/settings.ts | 1 + src/locales/zh/settings.ts | 1 + 13 files changed, 48 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06bdea55..797d4dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,7 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Themes — community Theme Store -**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#1009](https://github.com/Psychotoxical/psysonic/pull/1009), [#1011](https://github.com/Psychotoxical/psysonic/pull/1011), [#1012](https://github.com/Psychotoxical/psysonic/pull/1012)** +**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#1009](https://github.com/Psychotoxical/psysonic/pull/1009), [#1011](https://github.com/Psychotoxical/psysonic/pull/1011), [#1012](https://github.com/Psychotoxical/psysonic/pull/1012), [#1013](https://github.com/Psychotoxical/psysonic/pull/1013)** * New **Settings → Themes** tab: pick a theme, set the day/night scheduler, and browse a built-in **Theme Store** to install, update and uninstall community themes — with search, a dark/light filter, and full-size thumbnail previews. * The app now bundles six core themes (Catppuccin Mocha & Latte, Kanagawa Wave, Stark HUD, and the colour-blind-safe Vision Dark / Vision Navy); every other palette installs on demand from the [psysonic-themes](https://github.com/Psysonic/psysonic-themes) repo. Installed themes are saved locally and apply instantly at startup, even offline. diff --git a/src/components/settings/ThemeStoreSection.test.tsx b/src/components/settings/ThemeStoreSection.test.tsx index 5cf8e343..523c0bdd 100644 --- a/src/components/settings/ThemeStoreSection.test.tsx +++ b/src/components/settings/ThemeStoreSection.test.tsx @@ -143,4 +143,14 @@ describe('ThemeStoreSection — pagination & refresh', () => { await waitFor(() => expect(container.querySelector('.animate-spin')).toBeNull()); expect(rows(container)).toHaveLength(12); }); + + it('shows an offline banner and hides the toolbar when the registry is unavailable', async () => { + fetchRegistryMock.mockRejectedValue(new Error('offline')); + renderWithProviders(); + + expect(await screen.findByText('The Theme Store is offline')).toBeInTheDocument(); + // No catalogue to browse → the search/filter toolbar is not rendered. + expect(screen.queryByRole('searchbox')).not.toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Retry' })).toBeInTheDocument(); + }); }); diff --git a/src/components/settings/ThemeStoreSection.tsx b/src/components/settings/ThemeStoreSection.tsx index 0ca205ec..708b27ab 100644 --- a/src/components/settings/ThemeStoreSection.tsx +++ b/src/components/settings/ThemeStoreSection.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Check, ChevronLeft, ChevronRight, Download, RefreshCw, Trash2 } from 'lucide-react'; +import { Check, ChevronLeft, ChevronRight, Download, RefreshCw, Trash2, WifiOff } from 'lucide-react'; import { open as openUrl } from '@tauri-apps/plugin-shell'; import CoverLightbox from '../CoverLightbox'; import { useThemeStore } from '../../store/themeStore'; @@ -159,7 +159,9 @@ export function ThemeStoreSection() { - {/* Toolbar: search + mode filter + refresh */} + {/* Toolbar: search + mode filter + refresh. Hidden when offline with no + catalogue to browse — the offline banner below stands in for it. */} + {!error && (
+ )} {!loading && stale && (
@@ -207,9 +210,28 @@ export function ThemeStoreSection() { )} {!loading && error && ( -
-

{t('settings.themeStoreError')}

- +
+
)} diff --git a/src/config/settingsCredits.ts b/src/config/settingsCredits.ts index f1116eec..5ce2ee68 100644 --- a/src/config/settingsCredits.ts +++ b/src/config/settingsCredits.ts @@ -356,7 +356,7 @@ const CONTRIBUTOR_ENTRIES = [ 'Performance Probe: Monitor/Toggles redesign, live CPU/RSS/thread metrics, overlay pins and sparklines, macOS snapshots (PR #890)', 'Performance Probe: opt-in thread-group CPU poll toggle and includeThreadGroups IPC fix (PR #891)', 'Queue: switchable display mode — Queue (upcoming only) vs Playlist (full list), with header toggle and settings entry (PR #922)', - 'Community Theme Store: semantic-token refactor, dedicated Themes tab with day/night scheduler, install/update/uninstall, local .zip import with full contract validation, and 80+ palettes moved to an on-demand CDN repo (PR #1009, #1011, #1012)', + 'Community Theme Store: semantic-token refactor, dedicated Themes tab with day/night scheduler, install/update/uninstall, local .zip import with full contract validation, and 80+ palettes moved to an on-demand CDN repo (PR #1009, #1011, #1012, #1013)', ], }, { diff --git a/src/locales/de/settings.ts b/src/locales/de/settings.ts index cff81874..04e4e63a 100644 --- a/src/locales/de/settings.ts +++ b/src/locales/de/settings.ts @@ -336,6 +336,7 @@ export const settings = { themeStoreLoading: 'Themes werden geladen…', themeStoreError: 'Theme-Store konnte nicht geladen werden. Prüfe deine Verbindung.', themeStoreRetry: 'Erneut versuchen', + themeStoreOfflineTitle: 'Der Theme-Store ist offline', themeStoreEmpty: 'Keine Themes passen zu deinen Filtern.', themeStoreActive: 'Aktiv', themeStoreEnlarge: 'Vorschau vergrößern', diff --git a/src/locales/en/settings.ts b/src/locales/en/settings.ts index 799f4d8c..aed36368 100644 --- a/src/locales/en/settings.ts +++ b/src/locales/en/settings.ts @@ -403,6 +403,7 @@ export const settings = { themeStoreLoading: 'Loading themes…', themeStoreError: 'Could not load the theme store. Check your connection.', themeStoreRetry: 'Retry', + themeStoreOfflineTitle: 'The Theme Store is offline', themeStoreEmpty: 'No themes match your filters.', themeStoreActive: 'Active', themeStoreEnlarge: 'Enlarge preview', diff --git a/src/locales/es/settings.ts b/src/locales/es/settings.ts index 6187a462..fba37b14 100644 --- a/src/locales/es/settings.ts +++ b/src/locales/es/settings.ts @@ -334,6 +334,7 @@ export const settings = { themeStoreLoading: 'Cargando temas…', themeStoreError: 'No se pudo cargar la tienda de temas. Comprueba tu conexión.', themeStoreRetry: 'Reintentar', + themeStoreOfflineTitle: 'La tienda de temas está sin conexión', themeStoreEmpty: 'Ningún tema coincide con tus filtros.', themeStoreActive: 'Activo', themeStoreEnlarge: 'Ampliar vista previa', diff --git a/src/locales/fr/settings.ts b/src/locales/fr/settings.ts index 23d6555f..433dd989 100644 --- a/src/locales/fr/settings.ts +++ b/src/locales/fr/settings.ts @@ -332,6 +332,7 @@ export const settings = { themeStoreLoading: 'Chargement des thèmes…', themeStoreError: 'Impossible de charger la boutique de thèmes. Vérifiez votre connexion.', themeStoreRetry: 'Réessayer', + themeStoreOfflineTitle: 'Le Theme Store est hors ligne', themeStoreEmpty: 'Aucun thème ne correspond à vos filtres.', themeStoreActive: 'Actif', themeStoreEnlarge: "Agrandir l'aperçu", diff --git a/src/locales/nb/settings.ts b/src/locales/nb/settings.ts index fa9eff0a..0153d9f8 100644 --- a/src/locales/nb/settings.ts +++ b/src/locales/nb/settings.ts @@ -335,6 +335,7 @@ export const settings = { themeStoreLoading: 'Laster temaer…', themeStoreError: 'Kunne ikke laste temabutikken. Sjekk tilkoblingen din.', themeStoreRetry: 'Prøv igjen', + themeStoreOfflineTitle: 'Theme Store er frakoblet', themeStoreEmpty: 'Ingen temaer samsvarer med filtrene dine.', themeStoreActive: 'Aktiv', themeStoreEnlarge: 'Forstørr forhåndsvisning', diff --git a/src/locales/nl/settings.ts b/src/locales/nl/settings.ts index ef7d2ddb..b65f9476 100644 --- a/src/locales/nl/settings.ts +++ b/src/locales/nl/settings.ts @@ -332,6 +332,7 @@ export const settings = { themeStoreLoading: "Thema's laden…", themeStoreError: 'Kan de themawinkel niet laden. Controleer je verbinding.', themeStoreRetry: 'Opnieuw proberen', + themeStoreOfflineTitle: 'De Theme Store is offline', themeStoreEmpty: "Geen thema's komen overeen met je filters.", themeStoreActive: 'Actief', themeStoreEnlarge: 'Voorbeeld vergroten', diff --git a/src/locales/ro/settings.ts b/src/locales/ro/settings.ts index 8a29a075..9fb5677b 100644 --- a/src/locales/ro/settings.ts +++ b/src/locales/ro/settings.ts @@ -338,6 +338,7 @@ export const settings = { themeStoreLoading: 'Se încarcă temele…', themeStoreError: 'Magazinul de teme nu a putut fi încărcat. Verifică conexiunea.', themeStoreRetry: 'Reîncearcă', + themeStoreOfflineTitle: 'Theme Store este offline', themeStoreEmpty: 'Nicio temă nu corespunde filtrelor tale.', themeStoreActive: 'Activă', themeStoreEnlarge: 'Mărește previzualizarea', diff --git a/src/locales/ru/settings.ts b/src/locales/ru/settings.ts index b2b803ff..360f3f27 100644 --- a/src/locales/ru/settings.ts +++ b/src/locales/ru/settings.ts @@ -414,6 +414,7 @@ export const settings = { themeStoreLoading: 'Загрузка тем…', themeStoreError: 'Не удалось загрузить магазин тем. Проверьте подключение.', themeStoreRetry: 'Повторить', + themeStoreOfflineTitle: 'Магазин тем недоступен', themeStoreEmpty: 'Нет тем, соответствующих фильтрам.', themeStoreActive: 'Активна', themeStoreEnlarge: 'Увеличить превью', diff --git a/src/locales/zh/settings.ts b/src/locales/zh/settings.ts index 094cd1c0..ed988477 100644 --- a/src/locales/zh/settings.ts +++ b/src/locales/zh/settings.ts @@ -331,6 +331,7 @@ export const settings = { themeStoreLoading: '正在加载主题…', themeStoreError: '无法加载主题商店。请检查网络连接。', themeStoreRetry: '重试', + themeStoreOfflineTitle: '主题商店已离线', themeStoreEmpty: '没有符合筛选条件的主题。', themeStoreActive: '使用中', themeStoreEnlarge: '放大预览',