From 6e3275c05c85432c069ea03ff9c0b04e1b2f77d6 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Wed, 4 Feb 2026 00:35:17 -0800 Subject: [PATCH] add explicit / clean indicators for album and song titles (#1634) --- .../components/item-card/item-card.tsx | 18 +++++++- .../columns/title-artist-column.tsx | 3 ++ .../item-table-list/columns/title-column.tsx | 3 ++ .../columns/title-combined-column.tsx | 3 ++ .../explicit-indicator.module.css | 41 +++++++++++++++++++ .../explicit-indicator/explicit-indicator.tsx | 41 +++++++++++++++++++ 6 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/shared/components/explicit-indicator/explicit-indicator.module.css create mode 100644 src/shared/components/explicit-indicator/explicit-indicator.tsx diff --git a/src/renderer/components/item-card/item-card.tsx b/src/renderer/components/item-card/item-card.tsx index a0d949592..f8725a6c2 100644 --- a/src/renderer/components/item-card/item-card.tsx +++ b/src/renderer/components/item-card/item-card.tsx @@ -28,6 +28,7 @@ import { formatRating, } from '/@/renderer/utils/format'; import { SEPARATOR_STRING } from '/@/shared/api/utils'; +import { ExplicitIndicator } from '/@/shared/components/explicit-indicator/explicit-indicator'; import { Group } from '/@/shared/components/group/group'; import { Icon } from '/@/shared/components/icon/icon'; import { Separator } from '/@/shared/components/separator/separator'; @@ -1010,6 +1011,7 @@ export const getDataRows = (type?: 'compact' | 'default' | 'poster'): DataRow[] return [ { format: (data) => { + const explicitStatus = 'explicitStatus' in data ? data.explicitStatus : null; if ('name' in data && data.name) { if ('id' in data && data.id) { if ('_itemType' in data) { @@ -1022,6 +1024,7 @@ export const getDataRows = (type?: 'compact' | 'default' | 'poster'): DataRow[] albumId: data.id, })} > + {data.name} ); @@ -1036,6 +1039,7 @@ export const getDataRows = (type?: 'compact' | 'default' | 'poster'): DataRow[] }, )} > + {data.name} ); @@ -1062,11 +1066,21 @@ export const getDataRows = (type?: 'compact' | 'default' | 'poster'): DataRow[] ); default: - return data.name; + return ( + <> + + {data.name} + + ); } } } - return data.name; + return ( + <> + + {data.name} + + ); } return ''; }, diff --git a/src/renderer/components/item-list/item-table-list/columns/title-artist-column.tsx b/src/renderer/components/item-list/item-table-list/columns/title-artist-column.tsx index 9fd6c4a23..c2a4d61f1 100644 --- a/src/renderer/components/item-list/item-table-list/columns/title-artist-column.tsx +++ b/src/renderer/components/item-list/item-table-list/columns/title-artist-column.tsx @@ -13,6 +13,7 @@ import { } from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; import { useIsActiveRow } from '/@/renderer/components/item-list/item-table-list/item-table-list-context'; import { JoinedArtists } from '/@/renderer/features/albums/components/joined-artists'; +import { ExplicitIndicator } from '/@/shared/components/explicit-indicator/explicit-indicator'; import { Icon } from '/@/shared/components/icon/icon'; import { Text } from '/@/shared/components/text/text'; import { Folder, LibraryItem, QueueSong } from '/@/shared/types/domain-types'; @@ -52,6 +53,7 @@ export const DefaultTitleArtistColumn = (props: ItemTableListInnerColumn) => { })} > + {item.name as string}
@@ -120,6 +122,7 @@ export const QueueSongTitleArtistColumn = (props: ItemTableListInnerColumn) => { size="md" {...titleLinkProps} > + {row.name as string} {song?.trackSubtitle && props.itemType !== LibraryItem.QUEUE_SONG && ( + {row} @@ -103,6 +105,7 @@ function QueueSongTitleColumn(props: ItemTableListInnerColumn) { isNoSelect {...titleLinkProps} > + {row} {song?.trackSubtitle && props.itemType !== LibraryItem.QUEUE_SONG && ( { })} > + {item.name as string}
@@ -289,6 +291,7 @@ export const QueueSongTitleCombinedColumn = (props: ItemTableListInnerColumn) => size="md" {...titleLinkProps} > + {row.name as string} {song?.trackSubtitle && props.itemType !== LibraryItem.QUEUE_SONG && ( { + explicitStatus: ExplicitStatus | null | undefined; + size?: ExplicitIndicatorSize; + withSpace?: boolean; +} + +export type ExplicitIndicatorSize = '2xl' | '3xl' | '4xl' | 'lg' | 'md' | 'sm' | 'xl' | 'xs'; + +export const ExplicitIndicator = ({ + className, + explicitStatus, + size = 'lg', + withSpace = true, + ...rest +}: ExplicitIndicatorProps) => { + if (explicitStatus !== ExplicitStatus.EXPLICIT && explicitStatus !== ExplicitStatus.CLEAN) { + return null; + } + + const symbol = explicitStatus === ExplicitStatus.EXPLICIT ? EXPLICIT_SYMBOL : CLEAN_SYMBOL; + + return ( + + {withSpace ? `${symbol} ` : symbol} + + ); +};