diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json
index c134d2fe..a0f93d16 100644
--- a/src/assets/locales/en.json
+++ b/src/assets/locales/en.json
@@ -1104,6 +1104,9 @@
"carouselView": "Carousel view",
"carouselViewDescription": "Display your currently watching and bookmark sections as carousels instead of a grid. Disabled by default.",
"carouselViewLabel": "Carousel view",
+ "minimalCards": "Minimal cards",
+ "minimalCardsDescription": "Hide text content (title, type, year) on media cards, showing only the poster image.",
+ "minimalCardsLabel": "Minimal cards",
"forceCompactEpisodeView": "Force compact episode view",
"forceCompactEpisodeViewDescription": "Force the episode carousel in the player to use the \"classic\" compact vertical view. Disabled by default.",
"homeSectionOrder": "Home section order",
diff --git a/src/backend/accounts/settings.ts b/src/backend/accounts/settings.ts
index 53fe9120..bac9b02c 100644
--- a/src/backend/accounts/settings.ts
+++ b/src/backend/accounts/settings.ts
@@ -20,6 +20,7 @@ export interface SettingsInput {
enableDetailsModal?: boolean;
enableImageLogos?: boolean;
enableCarouselView?: boolean;
+ enableMinimalCards?: boolean;
forceCompactEpisodeView?: boolean;
sourceOrder?: string[] | null;
enableSourceOrder?: boolean;
@@ -56,6 +57,7 @@ export interface SettingsResponse {
enableDetailsModal?: boolean;
enableImageLogos?: boolean;
enableCarouselView?: boolean;
+ enableMinimalCards?: boolean;
forceCompactEpisodeView?: boolean;
sourceOrder?: string[] | null;
enableSourceOrder?: boolean;
diff --git a/src/components/media/MediaCard.tsx b/src/components/media/MediaCard.tsx
index 4fd28646..bc426739 100644
--- a/src/components/media/MediaCard.tsx
+++ b/src/components/media/MediaCard.tsx
@@ -136,6 +136,7 @@ function MediaCardContent({
const dotListContent = [t(`media.types.${media.type}`)];
const [searchQuery] = useSearchQuery();
+ const enableMinimalCards = usePreferencesStore((s) => s.enableMinimalCards);
// Simple intersection observer for lazy loading images
const { targetRef, isIntersecting } = useIntersectionObserver({
@@ -185,10 +186,11 @@ function MediaCardContent({
>
-
- {media.title}
-
-
-
-
+ {!enableMinimalCards && (
+ <>
+
+ {media.title}
+
+
+
+
- {!closable && (
-
-
-
- )}
- {editable && closable && (
-
-
-
+ {!closable && (
+
+
+
+ )}
+ {editable && closable && (
+
+
+
+ )}
+ >
)}
diff --git a/src/hooks/auth/useAuthData.ts b/src/hooks/auth/useAuthData.ts
index 0de5e210..b8325f83 100644
--- a/src/hooks/auth/useAuthData.ts
+++ b/src/hooks/auth/useAuthData.ts
@@ -94,6 +94,9 @@ export function useAuthData() {
const setKeyboardShortcuts = usePreferencesStore(
(s) => s.setKeyboardShortcuts,
);
+ const setEnableMinimalCards = usePreferencesStore(
+ (s) => s.setEnableMinimalCards,
+ );
const login = useCallback(
async (
@@ -282,6 +285,10 @@ export function useAuthData() {
if (settings.keyboardShortcuts !== undefined) {
setKeyboardShortcuts(settings.keyboardShortcuts);
}
+
+ if (settings.enableMinimalCards !== undefined) {
+ setEnableMinimalCards(settings.enableMinimalCards);
+ }
},
[
replaceBookmarks,
@@ -319,6 +326,7 @@ export function useAuthData() {
setEnableDoubleClickToSeek,
setEnableAutoResumeOnPlaybackError,
setKeyboardShortcuts,
+ setEnableMinimalCards,
],
);
diff --git a/src/hooks/useSettingsState.ts b/src/hooks/useSettingsState.ts
index b9e7dd37..40b3ea7b 100644
--- a/src/hooks/useSettingsState.ts
+++ b/src/hooks/useSettingsState.ts
@@ -72,6 +72,7 @@ export function useSettingsState(
enableSkipCredits: boolean,
enableImageLogos: boolean,
enableCarouselView: boolean,
+ enableMinimalCards: boolean,
forceCompactEpisodeView: boolean,
enableLowPerformanceMode: boolean,
enableNativeSubtitles: boolean,
@@ -221,6 +222,12 @@ export function useSettingsState(
resetEnableCarouselView,
enableCarouselViewChanged,
] = useDerived(enableCarouselView);
+ const [
+ enableMinimalCardsState,
+ setEnableMinimalCardsState,
+ resetEnableMinimalCards,
+ enableMinimalCardsChanged,
+ ] = useDerived(enableMinimalCards);
const [
forceCompactEpisodeViewState,
setForceCompactEpisodeViewState,
@@ -299,6 +306,7 @@ export function useSettingsState(
resetDisabledEmbeds();
resetProxyTmdb();
resetEnableCarouselView();
+ resetEnableMinimalCards();
resetForceCompactEpisodeView();
resetEnableLowPerformanceMode();
resetEnableNativeSubtitles();
@@ -338,6 +346,7 @@ export function useSettingsState(
disabledEmbedsChanged ||
proxyTmdbChanged ||
enableCarouselViewChanged ||
+ enableMinimalCardsChanged ||
forceCompactEpisodeViewChanged ||
enableLowPerformanceModeChanged ||
enableNativeSubtitlesChanged ||
@@ -490,6 +499,11 @@ export function useSettingsState(
set: setEnableCarouselViewState,
changed: enableCarouselViewChanged,
},
+ enableMinimalCards: {
+ state: enableMinimalCardsState,
+ set: setEnableMinimalCardsState,
+ changed: enableMinimalCardsChanged,
+ },
forceCompactEpisodeView: {
state: forceCompactEpisodeViewState,
set: setForceCompactEpisodeViewState,
diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx
index 4b3b97e0..96d24cf0 100644
--- a/src/pages/Settings.tsx
+++ b/src/pages/Settings.tsx
@@ -448,6 +448,11 @@ export function SettingsPage() {
(s) => s.setEnableCarouselView,
);
+ const enableMinimalCards = usePreferencesStore((s) => s.enableMinimalCards);
+ const setEnableMinimalCards = usePreferencesStore(
+ (s) => s.setEnableMinimalCards,
+ );
+
const forceCompactEpisodeView = usePreferencesStore(
(s) => s.forceCompactEpisodeView,
);
@@ -563,6 +568,7 @@ export function SettingsPage() {
enableSkipCredits,
enableImageLogos,
enableCarouselView,
+ enableMinimalCards,
forceCompactEpisodeView,
enableLowPerformanceMode,
enableNativeSubtitles,
@@ -631,6 +637,7 @@ export function SettingsPage() {
state.disabledSources.changed ||
state.proxyTmdb.changed ||
state.enableCarouselView.changed ||
+ state.enableMinimalCards.changed ||
state.forceCompactEpisodeView.changed ||
state.enableLowPerformanceMode.changed ||
state.enableHoldToBoost.changed ||
@@ -660,6 +667,7 @@ export function SettingsPage() {
disabledSources: state.disabledSources.state,
proxyTmdb: state.proxyTmdb.state,
enableCarouselView: state.enableCarouselView.state,
+ enableMinimalCards: state.enableMinimalCards.state,
forceCompactEpisodeView: state.forceCompactEpisodeView.state,
enableLowPerformanceMode: state.enableLowPerformanceMode.state,
enableHoldToBoost: state.enableHoldToBoost.state,
@@ -716,6 +724,7 @@ export function SettingsPage() {
setdebridService(state.debridService.state);
setProxyTmdb(state.proxyTmdb.state);
setEnableCarouselView(state.enableCarouselView.state);
+ setEnableMinimalCards(state.enableMinimalCards.state);
setForceCompactEpisodeView(state.forceCompactEpisodeView.state);
setEnableLowPerformanceMode(state.enableLowPerformanceMode.state);
setEnableHoldToBoost(state.enableHoldToBoost.state);
@@ -771,6 +780,7 @@ export function SettingsPage() {
setBackendUrl,
setProxyTmdb,
setEnableCarouselView,
+ setEnableMinimalCards,
setForceCompactEpisodeView,
setEnableLowPerformanceMode,
setEnableHoldToBoost,
@@ -886,6 +896,8 @@ export function SettingsPage() {
setEnableImageLogos={state.enableImageLogos.set}
enableCarouselView={state.enableCarouselView.state}
setEnableCarouselView={state.enableCarouselView.set}
+ enableMinimalCards={state.enableMinimalCards.state}
+ setEnableMinimalCards={state.enableMinimalCards.set}
forceCompactEpisodeView={state.forceCompactEpisodeView.state}
setForceCompactEpisodeView={state.forceCompactEpisodeView.set}
homeSectionOrder={state.homeSectionOrder.state}
diff --git a/src/pages/parts/settings/AppearancePart.tsx b/src/pages/parts/settings/AppearancePart.tsx
index bae45075..fb72bc28 100644
--- a/src/pages/parts/settings/AppearancePart.tsx
+++ b/src/pages/parts/settings/AppearancePart.tsx
@@ -245,6 +245,9 @@ export function AppearancePart(props: {
enableCarouselView: boolean;
setEnableCarouselView: (v: boolean) => void;
+ enableMinimalCards: boolean;
+ setEnableMinimalCards: (v: boolean) => void;
+
forceCompactEpisodeView: boolean;
setForceCompactEpisodeView: (v: boolean) => void;
@@ -510,6 +513,30 @@ export function AppearancePart(props: {
+ {/* Minimal Cards */}
+
+
+ {t("settings.appearance.options.minimalCards")}
+
+
+ {t("settings.appearance.options.minimalCardsDescription")}
+
+
+ props.setEnableMinimalCards(!props.enableMinimalCards)
+ }
+ className={classNames(
+ "bg-dropdown-background hover:bg-dropdown-hoverBackground select-none my-4 cursor-pointer space-x-3 flex items-center max-w-[25rem] py-3 px-4 rounded-lg",
+ "cursor-pointer opacity-100 pointer-events-auto",
+ )}
+ >
+
+
+ {t("settings.appearance.options.minimalCardsLabel")}
+
+
+
+
{/* Force Compact Episode View */}
diff --git a/src/stores/preferences/index.tsx b/src/stores/preferences/index.tsx
index 9a16bd35..7bc02648 100644
--- a/src/stores/preferences/index.tsx
+++ b/src/stores/preferences/index.tsx
@@ -16,6 +16,7 @@ export interface PreferencesStore {
enableDetailsModal: boolean;
enableImageLogos: boolean;
enableCarouselView: boolean;
+ enableMinimalCards: boolean;
forceCompactEpisodeView: boolean;
sourceOrder: string[];
enableSourceOrder: boolean;
@@ -46,6 +47,7 @@ export interface PreferencesStore {
setEnableDetailsModal(v: boolean): void;
setEnableImageLogos(v: boolean): void;
setEnableCarouselView(v: boolean): void;
+ setEnableMinimalCards(v: boolean): void;
setForceCompactEpisodeView(v: boolean): void;
setSourceOrder(v: string[]): void;
setEnableSourceOrder(v: boolean): void;
@@ -80,6 +82,7 @@ export const usePreferencesStore = create(
enableDetailsModal: false,
enableImageLogos: true,
enableCarouselView: false,
+ enableMinimalCards: false,
forceCompactEpisodeView: false,
sourceOrder: [],
enableSourceOrder: false,
@@ -141,6 +144,11 @@ export const usePreferencesStore = create(
s.enableCarouselView = v;
});
},
+ setEnableMinimalCards(v) {
+ set((s) => {
+ s.enableMinimalCards = v;
+ });
+ },
setForceCompactEpisodeView(v) {
set((s) => {
s.forceCompactEpisodeView = v;