-
- {t('settings.preloadHotCacheMutualExclusive')}
-
-
- {/* Preload mode */}
-
-
-
{t('settings.preloadMode')}
-
{t('settings.preloadModeDesc')}
-
-
-
- {auth.preloadMode !== 'off' && (
- <>
-
- {(['balanced', 'early', 'custom'] as const).map(mode => (
-
- ))}
-
- {auth.preloadMode === 'custom' && (
-
- auth.setPreloadCustomSeconds(parseInt(e.target.value))}
- style={{ flex: 1, minWidth: 80, maxWidth: 200 }}
- />
-
- {t('settings.preloadCustomSeconds', { n: auth.preloadCustomSeconds })}
-
-
- )}
- >
- )}
-
-
-
- {/* Hot Cache */}
-
-
-
{t('settings.hotCacheTitle')}
-
{t('settings.hotCacheDisclaimer')}
-
-
-
-
- {auth.hotCacheEnabled && (
-
-
-
- {auth.hotCacheDownloadDir && (
-
- )}
-
-
- {auth.hotCacheDownloadDir && (
-
- {t('settings.hotCacheDirHint')}
-
- )}
-
-
-
-
-
- {t('settings.cacheUsedHot')}
- {hotCacheBytes !== null ? formatBytes(hotCacheBytes) : '…'}
-
-
- {t('settings.hotCacheTrackCount')}
- {hotCacheTrackCount}
-
-
-
-
-
{t('settings.hotCacheMaxMb')}
-
- auth.setHotCacheMaxMb(parseInt(e.target.value, 10))} style={{ flex: 1, minWidth: 80, maxWidth: 200 }} id="hot-cache-max-mb-slider" />
- {snapHotCacheMb(auth.hotCacheMaxMb)} MB
-
-
-
-
{t('settings.hotCacheDebounce')}
-
- auth.setHotCacheDebounceSec(parseInt(e.target.value, 10))} style={{ flex: 1, minWidth: 80, maxWidth: 200 }} id="hot-cache-debounce-slider" />
-
- {Math.min(600, Math.max(0, auth.hotCacheDebounceSec)) === 0
- ? t('settings.hotCacheDebounceImmediate')
- : t('settings.hotCacheDebounceSeconds', { n: Math.min(600, Math.max(0, auth.hotCacheDebounceSec)) })}
-
-
-
-
-
-
-
- )}
-
-
-
-
>
)}
@@ -2323,32 +2255,29 @@ export default function Settings() {
title={t('settings.sidebarLyricsStyle')}
icon={
-
- {(['classic', 'apple'] as const).map(style => {
- const key = style === 'classic' ? 'Classic' : 'Apple';
- return (
-
- );
- })}
-
+
+ {(['classic', 'apple'] as const).map(style => {
+ const key = style === 'classic' ? 'Classic' : 'Apple';
+ const other = style === 'classic' ? 'apple' : 'classic';
+ return (
+
+
+
+
{t(`settings.sidebarLyricsStyle${key}` as any)}
+
{t(`settings.sidebarLyricsStyle${key}Desc` as any)}
+
+
+
+
+ );
+ })}
>
@@ -2615,10 +2544,11 @@ export default function Settings() {
{/* ── Library (legacy 'general' + 'server') ────────────────────────────── */}
{activeTab === 'library' && (
<>
- {/* Random Mix */}
+ {/* Random Mix Blacklist */}
}
+ defaultOpen
>
@@ -2805,7 +2735,7 @@ export default function Settings() {
>
)}
- {/* ── Storage & Downloads ───────────────────────────────────────────────── */}
+ {/* ── Offline & Cache ──────────────────────────────────────────────────── */}
{activeTab === 'storage' && (
<>
{/* Offline Library (In-App) — includes cache settings */}
@@ -2904,6 +2834,187 @@ export default function Settings() {
+ {/* Next Track Buffering */}
+
}
+ >
+
+
+ {t('settings.preloadHotCacheMutualExclusive')}
+
+
+ {/* Preload mode */}
+
+
+
{t('settings.preloadMode')}
+
{t('settings.preloadModeDesc')}
+
+
+
+ {auth.preloadMode !== 'off' && (
+ <>
+
+ {(['balanced', 'early', 'custom'] as const).map(mode => (
+
+ ))}
+
+ {auth.preloadMode === 'custom' && (
+
+ auth.setPreloadCustomSeconds(parseInt(e.target.value))}
+ style={{ flex: 1, minWidth: 80, maxWidth: 200 }}
+ />
+
+ {t('settings.preloadCustomSeconds', { n: auth.preloadCustomSeconds })}
+
+
+ )}
+ >
+ )}
+
+
+
+ {/* Hot Cache */}
+
+
+
{t('settings.hotCacheTitle')}
+
{t('settings.hotCacheDisclaimer')}
+
+
+
+
+ {auth.hotCacheEnabled && (
+
+
+
+ {auth.hotCacheDownloadDir && (
+
+ )}
+
+
+ {auth.hotCacheDownloadDir && (
+
+ {t('settings.hotCacheDirHint')}
+
+ )}
+
+
+
+
+
+ {t('settings.cacheUsedHot')}
+ {hotCacheBytes !== null ? formatBytes(hotCacheBytes) : '…'}
+
+
+ {t('settings.hotCacheTrackCount')}
+ {hotCacheTrackCount}
+
+
+
+
+
{t('settings.hotCacheMaxMb')}
+
+ auth.setHotCacheMaxMb(parseInt(e.target.value, 10))} style={{ flex: 1, minWidth: 80, maxWidth: 200 }} id="hot-cache-max-mb-slider" />
+ {snapHotCacheMb(auth.hotCacheMaxMb)} MB
+
+
+
+
{t('settings.hotCacheDebounce')}
+
+ auth.setHotCacheDebounceSec(parseInt(e.target.value, 10))} style={{ flex: 1, minWidth: 80, maxWidth: 200 }} id="hot-cache-debounce-slider" />
+
+ {Math.min(600, Math.max(0, auth.hotCacheDebounceSec)) === 0
+ ? t('settings.hotCacheDebounceImmediate')
+ : t('settings.hotCacheDebounceSeconds', { n: Math.min(600, Math.max(0, auth.hotCacheDebounceSec)) })}
+
+
+
+
+
+
+
+ )}
+
+
+
+
{/* ZIP Export & Archiving */}
= {
+ library: 'settings.tabLibrary',
+ servers: 'settings.tabServers',
+ audio: 'settings.tabAudio',
+ lyrics: 'settings.tabLyrics',
+ appearance: 'settings.tabAppearance',
+ personalisation: 'settings.tabPersonalisation',
+ integrations: 'settings.tabIntegrations',
+ input: 'settings.tabInput',
+ storage: 'settings.tabStorage',
+ system: 'settings.tabSystem',
+ users: 'settings.tabUsers',
+};
+
function HomeCustomizer() {
const { t } = useTranslation();
const { sections, toggleSection } = useHomeStore();
@@ -4125,73 +4250,46 @@ function LyricsSourcesCustomizer() {
{/* Mode switch — standard three-provider pipeline vs. YouLyPlus karaoke.
YouLyPlus misses silently fall back to the standard pipeline. */}
-
-
-
-
-
-
-
- {/* Static-only toggle — suppresses line/word tracking in both modes. */}
-
{t('settings.lyricsStaticOnly')}
-
{t('settings.lyricsStaticOnlyDesc')}
+
{t('settings.lyricsModeLyricsplus')}
+
{t('settings.lyricsModeLyricsplusDesc')}
-
+
+
+
+
+
{t('settings.lyricsModeStandard')}
+
{t('settings.lyricsModeStandardDesc')}
+
+
+ { if (e.target.checked) setLyricsMode('standard'); else setLyricsMode('lyricsplus'); }}
+ />
{lyricsMode === 'standard' && (
-
+
{lyricsSources.map((src, i) => {
const label = t(LYRICS_SOURCE_LABEL_KEYS[src.id]);
const isBefore = isPsyDragging && dropTarget?.idx === i && dropTarget.before;
@@ -4217,6 +4315,20 @@ function LyricsSourcesCustomizer() {
})}
)}
+
+ {/* Static-only toggle — suppresses line/word tracking in both modes. */}
+
+
+
+
{t('settings.lyricsStaticOnly')}
+
{t('settings.lyricsStaticOnlyDesc')}
+
+
+ setLyricsStaticOnly(e.target.checked)} />
+
+
+
+
);
}
diff --git a/src/styles/components.css b/src/styles/components.css
index 4cdcac08..60620316 100644
--- a/src/styles/components.css
+++ b/src/styles/components.css
@@ -2605,6 +2605,66 @@
text-align: center;
}
+.settings-search-other-tabs {
+ margin-top: var(--space-4);
+ margin-bottom: var(--space-6);
+ padding: var(--space-3);
+ border-radius: var(--radius-md);
+ background: var(--bg-card);
+ border: 1px solid var(--border-subtle);
+}
+.settings-search-other-tabs-title {
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ color: var(--text-muted);
+ margin-bottom: var(--space-2);
+}
+.settings-search-other-tabs-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+}
+.settings-search-other-tab-item {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ gap: var(--space-2);
+ padding: 8px 10px;
+ background: transparent;
+ border: 1px solid transparent;
+ border-radius: var(--radius-sm);
+ color: var(--text-primary);
+ text-align: left;
+ cursor: pointer;
+ font-size: 13px;
+ transition: background 0.12s, border-color 0.12s;
+}
+.settings-search-other-tab-item:hover {
+ background: var(--bg-hover);
+ border-color: var(--border);
+}
+.settings-search-other-tab-badge {
+ flex-shrink: 0;
+ font-size: 11px;
+ font-weight: 500;
+ padding: 2px 8px;
+ border-radius: 999px;
+ background: color-mix(in srgb, var(--accent) 15%, transparent);
+ color: var(--accent);
+}
+.settings-search-other-tab-title {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
/* ── Mitwirkende: Card-Grid mit klappbaren Beitragslisten ────────────────── */
.contributors-grid {
display: grid;