From 5860b44129dddf0e053b50a8c922d788114bbbe9 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 8 Jul 2026 17:24:05 -0400 Subject: [PATCH 1/4] Refactor purple haze to use base theme --- src/themes/_base/_theme.scss | 120 +++++- src/themes/appletv/theme.scss | 14 +- src/themes/purplehaze/index.ts | 29 +- src/themes/purplehaze/theme.scss | 624 ++++++------------------------- 4 files changed, 250 insertions(+), 537 deletions(-) diff --git a/src/themes/_base/_theme.scss b/src/themes/_base/_theme.scss index e2ecac7735..c9f19b850c 100644 --- a/src/themes/_base/_theme.scss +++ b/src/themes/_base/_theme.scss @@ -2,6 +2,8 @@ // Theme options $dark: true !default; +// Enable rounded person cards (e.g. for actors/directors) +$rounded-person-cards: false !default; // Color palette $common-white: palette.$common-white !default; @@ -39,11 +41,23 @@ $button-inheritContainedBg: #424242 !default; $button-inheritContainedHoverBg: #616161 !default; $snackbarContent-bg: #303030 !default; $snackbarContent-color: rgba(255, 255, 255, 0.87) !default; +// Secondary/accent color used for focus and interactive states. +// Defaults to $primary-main so all existing themes are unaffected. +$secondary-main: $primary-main !default; +$secondary-contrastText: $primary-contrastText !default; +// Background for legacy Jellyfin surface elements (paperList, visualCardBox, etc.). +// Kept separate from $background-paper so themes can use a translucent overlay here +// while $background-paper stays solid for MUI components (menus, dropdowns). +$surface-overlay: $background-paper !default; +// Optional CSS gradient applied over $appBar-defaultBg on the header and detail ribbon. +// Set to a CSS gradient value to enable; leave as none to use only the solid colour. +$appBar-gradient: none !default; // Assign custom css variables not part of the MUI theme palette :root { --jf-palette-background-defaultImage: #{$background-defaultImage}; --jf-palette-AppBar-transparentBg: #{$appBar-transparentBg}; + --jf-palette-AppBar-gradient: #{$appBar-gradient}; --jf-card-borderRadius: #{$card-borderRadius}; } @@ -71,12 +85,21 @@ html { border-color: var(--jf-palette-divider, $divider); } -.skinHeader-withBackground { +.skinHeader-withBackground, +.detailRibbon { background-color: var(--jf-palette-AppBar-defaultBg, $appBar-defaultBg); + background-image: var(--jf-palette-AppBar-gradient, $appBar-gradient); +} + +.detailRibbon { + .layout-tv & { + background: none; + } } .skinHeader.semiTransparent { background-color: var(--jf-palette-AppBar-transparentBg, $appBar-transparentBg); + background-image: none; backdrop-filter: none !important; .layout-tv & { @@ -100,9 +123,7 @@ html { } .backgroundContainer, -.dialog, .nowPlayingPlaylist, -.nowPlayingContextMenu, html { background-color: var(--jf-palette-background-default, $background-default); background-image: var(--jf-palette-background-defaultImage, $background-defaultImage); @@ -115,6 +136,11 @@ html { opacity: 0.86; } +.dialog, +.nowPlayingContextMenu { + background-color: var(--jf-palette-background-default, $background-default); +} + @media (hover: hover) and (pointer: fine) { .paper-icon-button-light:hover:not(:disabled) { color: var(--jf-palette-primary-main, $primary-main); @@ -130,7 +156,7 @@ html { } .paper-icon-button-light.show-focus:focus { - color: var(--jf-palette-primary-main, $primary-main); + color: var(--jf-palette-secondary-main, $secondary-main); } .emby-scrollbuttons { @@ -143,20 +169,27 @@ a[data-role="button"], background: var(--jf-palette-Button-inheritContainedBg, $button-inheritContainedBg); color: var(--jf-palette-text-secondary, $text-secondary); - &:focus, &:hover { background: var(--jf-palette-Button-inheritContainedHoverBg, $button-inheritContainedHoverBg); } + + &:focus { + background: var(--jf-palette-secondary-main, $secondary-main); + } } .button-submit { background: var(--jf-palette-primary-main, $primary-main); color: var(--jf-palette-primary-contrastText, $primary-contrastText); - &:focus, &:hover { background: var(--jf-palette-primary-dark, $primary-dark); } + + &:focus { + background: var(--jf-palette-secondary-main, $secondary-main); + color: var(--jf-palette-secondary-contrastText, $secondary-contrastText); + } } .button-delete { @@ -179,7 +212,7 @@ a[data-role="button"], .inputLabelFocused, .selectLabelFocused, .textareaLabelFocused { - color: var(--jf-palette-primary-main, $primary-main); + color: var(--jf-palette-secondary-main, $secondary-main); } .checkboxOutline { @@ -189,12 +222,12 @@ a[data-role="button"], .collapseContent, .formDialogFooter:not(.formDialogFooter-clear), .formDialogHeader:not(.formDialogHeader-clear) { - background-color: var(--jf-palette-background-paper, $background-paper); + background-color: $surface-overlay; } .paperList, .visualCardBox { - background-color: var(--jf-palette-background-paper, $background-paper); + background-color: $surface-overlay; border-radius: var(--jf-card-borderRadius, $card-borderRadius); } @@ -207,6 +240,14 @@ a[data-role="button"], border-radius: var(--jf-card-borderRadius, $card-borderRadius); } +.cardBox:not(.visualCardBox) .cardPadder { + background-color: $surface-overlay; +} + +.cardPadder .cardImageIcon { + color: $surface-overlay; +} + .layout-tv .formDialogFooter:not(.formDialogFooter-clear) { background-color: transparent; } @@ -230,6 +271,39 @@ a[data-role="button"], opacity: 0.5; } +@if $rounded-person-cards { + .personCard { + .cardScalable { + border-radius: 50% !important; + border: 1px solid transparent; + } + + .overflowPortraitCard { + width: 40vw; + } + + .coveredImage { + background-position-y: 20%; + border-radius: 50%; + } + + .cardOverlayContainer { + clip-path: circle(50% at 50% 50%); + } + + .cardOverlayButton-br { + right: 20%; + } + + .cardPadder-overflowPortrait, + .cardPadder-portrait { + padding-bottom: 100%; + contain: strict; + border-radius: 50% !important; + } + } +} + .toast { background: var(--jf-palette-SnackbarContent-bg, $snackbarContent-bg); color: var(--jf-palette-SnackbarContent-color, $snackbarContent-color); @@ -274,8 +348,8 @@ a[data-role="button"], } &-tv:focus { - background-color: var(--jf-palette-primary-main, $primary-main); - color: var(--jf-palette-primary-contrastText, $primary-contrastText); + background-color: var(--jf-palette-secondary-main, $secondary-main); + color: var(--jf-palette-secondary-contrastText, $secondary-contrastText); } } @@ -328,7 +402,7 @@ a[data-role="button"], border-radius: 0.2em; &:focus { - border-color: var(--jf-palette-primary-main, $primary-main); + border-color: var(--jf-palette-secondary-main, $secondary-main); } } @@ -349,12 +423,12 @@ a[data-role="button"], } .emby-select-withcolor:focus { - border-color: var(--jf-palette-primary-main, $primary-main) !important; + border-color: var(--jf-palette-secondary-main, $secondary-main) !important; } .emby-select-tv-withcolor:focus { - background-color: var(--jf-palette-primary-main, $primary-main) !important; - color: var(--jf-palette-primary-contrastText, $primary-contrastText) !important; + background-color: var(--jf-palette-secondary-main, $secondary-main) !important; + color: var(--jf-palette-secondary-contrastText, $secondary-contrastText) !important; } .emby-checkbox:checked + span + .checkboxOutline { @@ -362,7 +436,7 @@ a[data-role="button"], } .emby-checkbox:focus + span + .checkboxOutline { - border-color: var(--jf-palette-common-white, $common-white); + border-color: var(--jf-palette-secondary-main, $secondary-main); } .emby-checkbox:checked + span + .checkboxOutline, @@ -371,7 +445,7 @@ a[data-role="button"], } .emby-checkbox:focus:not(:checked) + span + .checkboxOutline { - border-color: var(--jf-palette-primary-main, $primary-main); + border-color: var(--jf-palette-secondary-main, $secondary-main); } .itemProgressBarForeground-recording { @@ -415,7 +489,7 @@ a[data-role="button"], .emby-tab-button.show-focus:focus, .emby-tab-button:hover { - color: var(--jf-palette-primary-main, $primary-main); + color: var(--jf-palette-secondary-main, $secondary-main); } .channelPrograms, @@ -461,7 +535,7 @@ a[data-role="button"], .guide-date-tab-button.emby-tab-button-active, .guide-date-tab-button:focus { - color: var(--jf-palette-primary-main, $primary-main); + color: var(--jf-palette-secondary-main, $secondary-main); } .guide-date-tab-button.show-focus:focus { @@ -487,7 +561,7 @@ a[data-role="button"], .card:focus .cardBox.visualCardBox, .card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: var(--jf-palette-primary-main, $primary-main) !important; + border-color: var(--jf-palette-secondary-main, $secondary-main) !important; border-radius: var(--jf-card-borderRadius, $card-borderRadius); } @@ -556,3 +630,9 @@ a[data-role="button"], color: var(--jf-palette-primary-main, $primary-main); } } + +/* emby-radio style override */ +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles svg .mdl-radio__outer-circle, +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles svg .mdl-radio__inner-circle { + color: var(--jf-palette-secondary-main, $secondary-main); +} diff --git a/src/themes/appletv/theme.scss b/src/themes/appletv/theme.scss index 0c8fca81f7..69a11d83e1 100644 --- a/src/themes/appletv/theme.scss +++ b/src/themes/appletv/theme.scss @@ -21,6 +21,7 @@ $header-gradient: linear-gradient(to right, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, $divider: rgba(0, 0, 0, 0.158), // Components $appBar-defaultBg: $header-background, + $appBar-gradient: $header-gradient, $appBar-transparentBg: rgba(213, 233, 242, 0.86), $filledInput-bg: rgba(255, 255, 255, 0.9), $filledInput-borderColor: rgba(0, 0, 0, 0.158), @@ -61,8 +62,7 @@ $header-gradient: linear-gradient(to right, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, background-color: #f57f17; } -/* Gradient header, footer, and ribbon — used throughout the appletv theme */ -.skinHeader-withBackground, +/* Gradient footer, form dialog header/footer, and ribbon — skinHeader and detailRibbon handled by base */ .formDialogHeader:not(.formDialogHeader-clear), .formDialogFooter:not(.formDialogFooter-clear), .appfooter, @@ -106,16 +106,6 @@ $header-gradient: linear-gradient(to right, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, background: #fff; } -/* Detail ribbon on item details pages */ -.detailRibbon { - background: $header-background; - background: $header-gradient; - - .layout-tv & { - background: none; - } -} - /* Inner card footer spacing and rounding */ .innerCardFooter { border-radius: 0.14rem; diff --git a/src/themes/purplehaze/index.ts b/src/themes/purplehaze/index.ts index 0ab57ad097..b442810114 100644 --- a/src/themes/purplehaze/index.ts +++ b/src/themes/purplehaze/index.ts @@ -4,7 +4,8 @@ import { buildCustomColorScheme } from 'themes/utils'; const theme = buildCustomColorScheme({ palette: { background: { - paper: '#000420' + default: '#230c33', + paper: '#230c33' }, primary: { main: '#48c3c8' @@ -12,8 +13,32 @@ const theme = buildCustomColorScheme({ secondary: { main: '#ff77f1' }, + text: { + primary: '#f8f8fe', + secondary: 'rgba(248, 248, 254, 0.973)' + }, + action: { + focus: 'rgba(0, 0, 0, 0.3)', + hover: '#12122f' + }, + divider: 'rgba(255, 255, 255, 0.14)', + Alert: { + infoFilledBg: '#dbe6ff', + infoFilledColor: '#0e0f2d' + }, AppBar: { - defaultBg: '#000420' + defaultBg: '#230c33' + }, + Button: { + inheritContainedBg: 'rgba(0, 0, 0, 0.5)', + inheritContainedHoverBg: 'rgb(12, 232, 214)' + }, + FilledInput: { + bg: 'rgba(0, 0, 0, 0.5)' + }, + SnackbarContent: { + bg: '#303030', + color: 'rgba(255, 255, 255, 0.87)' } } }); diff --git a/src/themes/purplehaze/theme.scss b/src/themes/purplehaze/theme.scss index e05c3c922e..c99ff80d8a 100644 --- a/src/themes/purplehaze/theme.scss +++ b/src/themes/purplehaze/theme.scss @@ -1,193 +1,98 @@ -.skinHeader, -html { - color: #f8f8fe; - color: rgba(248, 248, 254, 0.973); -} +@use "../_base/palette" as palette; -.wizardStartForm, -.ui-corner-all, -.ui-shadow { - background-color: #303030; -} +/* Background color for headers and detail ribbon */ +$header-background: #230c33; +/* Accent teal for indicators, progress bar and checked state (brighter than primary) */ +$teal-bright: rgb(12, 232, 214); +/* Background color for footers */ +$footer-blue: #06256f; +/* Background color for info badges */ +$info-background: #dbe6ff; +/* Transparent backdrop for dialogs and overlays */ +$surface: rgba(0, 0, 0, 0.5); +/* Primary text color */ +$text-primary: #f8f8fe; +/* Gradient used across headers, footers, and detail ribbon */ +$header-gradient: linear-gradient(to right, #000420 0%, $footer-blue 18%, #2b052b 38%, #2b052b 68%, $footer-blue 81%, #000420 100%); -.emby-collapsible-button { - border-color: #383838; - border-color: rgba(255, 255, 255, 0.135); -} +/* Import the base theme with overrides */ +@use "../_base/theme" with ( + // Theme options + $dark: true, + $rounded-person-cards: true, -.skinHeader-withBackground { - background: #000420; - background: linear-gradient(to right, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); -} - -.skinHeader.semiTransparent { - backdrop-filter: none !important; - background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); - background-color: rgba(0, 0, 0, 0.3); -} - -.layout-tv .skinHeader.semiTransparent { - background: none; -} - -.pageTitleWithDefaultLogo { - background-image: url(@jellyfin/ux-web/banner-light.png); -} - -.layout-tv .pageTitleWithDefaultLogo { - background-image: url(@jellyfin/ux-web/icon-transparent.png); -} - -.dialog, -.nowPlayingPlaylist, -.nowPlayingContextMenu, -html { - background-color: #230c33; -} - -.backgroundContainer { - background: url(bg.jpg) center top no-repeat #030322; - background-size: cover; -} - -.backgroundContainer.withBackdrop { - opacity: 0.86; -} + // Color palette + $background-default: $header-background, + $background-defaultImage: url(bg.jpg), + $background-paper: $header-background, + $primary-main: #48c3c8, + $secondary-main: #ff77f1, + $text-primary: $text-primary, + $text-secondary: rgba(248, 248, 254, 0.973), + $action-focus: rgba(0, 0, 0, 0.3), + $action-hover: #12122f, + $divider: rgba(255, 255, 255, 0.14), + // Components + $appBar-defaultBg: $header-background, + $appBar-gradient: $header-gradient, + $appBar-transparentBg: rgba(0, 0, 0, 0.3), + $surface-overlay: $surface, + $filledInput-bg: $surface, + $filledInput-borderColor: transparent, + $card-borderRadius: 0.8em, + $alert-infoFilledBg: $info-background, + $alert-infoFilledColor: #0e0f2d, + $button-inheritContainedBg: $surface, + $button-inheritContainedHoverBg: $teal-bright, + $snackbarContent-bg: #303030, + $snackbarContent-color: rgba(255, 255, 255, 0.87) +); +/* Adjust background position for portrait orientation */ @media (orientation: portrait) { .backgroundContainer { background-position: 30% top; } } +/* Icon buttons: hover/active icon colour is bright teal, not primary */ @media (hover: hover) and (pointer: fine) { .paper-icon-button-light:hover:not(:disabled) { - color: rgb(12, 232, 214); - background-color: rgba(0, 164, 220, 0.2); + color: $teal-bright; } } .paper-icon-button-light:active:not(:disabled) { - color: rgb(12, 232, 214); - background-color: rgba(0, 164, 220, 0.2); -} - -.paper-icon-button-light.show-focus:focus { - color: #ff77f1; -} - -progress { - border-radius: 0.4em; -} - -progress::-webkit-progress-bar { - border-radius: 0.4em; -} - -progress::-moz-progress-bar { - border-radius: 0.4em; + color: $teal-bright; } +/* Rounded progress bars */ +progress, +progress::-webkit-progress-bar, +progress::-moz-progress-bar, progress::-webkit-progress-value { border-radius: 0.4em; } -.fab, -.raised { - background: rgba(0, 0, 0, 0.5); - color: rgba(255, 255, 255, 0.87); -} - -.fab:focus, -.raised:focus { - background: #ff77f1; -} - -div[data-role="controlgroup"] .controlGroupButton.ui-btn-active, -div[data-role="controlgroup"] a.ui-btn-active { - background: #55828b !important; - color: #e1e5f2 !important; -} - -.controlGroupButton, -a[data-role="button"] { - background: rgba(2, 43, 58, 0.521) !important; -} - -#btnDeleteImage, -.submit, -.btnBrowse, -.mini, -.btnRefresh, -.btnManual, -.button-submit, -.viewTabButton, -.button-alt, -.btnOption { - background: rgb(72, 195, 200); - color: rgb(225, 229, 242); -} - -#btnResetPassword, -.btnForgotPassword, -.btnCancel, -.button-cancel { - background: rgba(0, 0, 0, 0.5); - color: rgba(255, 255, 255, 0.87); -} - -.alphaPickerButton { - color: #999; - color: rgba(255, 255, 255, 0.5); - background-color: transparent; -} - -#btnResetPassword:hover, -#btnRestart:hover, -#btnDeleteImage:hover, -#btnShutdown:hover, -.button-cancel:hover, -.fab:hover, -.raised:hover, -.alphaPickerButton:hover, -.submit:hover, -.btnBrowse:hover, -.mini:hover, -.btnRefresh:hover, -.button-submit:hover, -.viewTabButton:hover, -.button-alt:hover, -.btnOption:hover, -.btnManual:hover, -.block:hover { - background: rgb(12, 232, 214); - color: rgba(255, 255, 255, 0.87); -} - -.button-submit:focus { - background: #ff77f1; -} - -.button-delete { - background: rgb(247, 0, 0); - color: rgba(255, 255, 255, 0.87); -} - -.itemName { - color: #f1f7ee; -} - +/* Item titles and section headings */ +.itemName, .textareaLabel, -.sectionTitle, -.fieldDescription, -.checkboxLabel { +.sectionTitle { color: #f1f7ee; } -.checkboxLabel { - color: inherit; +/* Subdued secondary text — more transparent than $text-secondary */ +.cardText-secondary, +.fieldDescription, +.guide-programNameCaret, +.listItem .secondary, +.nowPlayingBarSecondaryText, +.programSecondaryTitle, +.secondaryText { + color: rgba(255, 255, 255, 0.5); } +/* Form labels use a blue-white rather than $text-secondary */ .selectLabel, .checkboxLabel, .checkboxListLabel, @@ -198,42 +103,18 @@ a[data-role="button"] { color: rgb(191, 219, 247); } -.inputLabelFocused, -.selectLabelFocused, -.textareaLabelFocused { - color: #ff77f1; -} - -.checkboxOutline { - border-color: currentColor; -} - -.cardContent { - border-radius: 0.8em; -} - +/* Form dialog header/footer and collapsible also get border-radius */ .collapseContent, .formDialogFooter:not(.formDialogFooter-clear), -.formDialogHeader:not(.formDialogHeader-clear), -.paperList, -.visualCardBox { - background-color: rgba(0, 0, 0, 0.5); +.formDialogHeader:not(.formDialogHeader-clear) { border-radius: 0.8em; } .layout-tv .formDialogFooter:not(.formDialogFooter-clear) { - background-color: transparent; border-radius: 0; } -.cardOverlayContainer { - border-radius: 0.8em; -} - -.blurhash-canvas { - border-radius: 0.8em; -} - +/* Default card background colours */ .defaultCardBackground1 { background-color: #9c20ab; } @@ -254,37 +135,19 @@ a[data-role="button"] { background-color: #ab8820; } -.cardText-secondary, -.fieldDescription, -.guide-programNameCaret, -.listItem .secondary, -.nowPlayingBarSecondaryText, -.programSecondaryTitle, -.secondaryText { - color: #999; +/* Alpha picker */ +.alphaPickerButton { color: rgba(255, 255, 255, 0.5); + + &-selected { + color: $teal-bright; + } } -.actionsheetDivider { - background: #444; - background: rgba(255, 255, 255, 0.14); -} - -.cardFooter-vibrant .cardText-secondary { - color: inherit; - opacity: 0.5; -} - -.toast { - background: #303030; - color: #f8f8fe; - color: rgba(255, 255, 255, 0.87); -} - +/* Footer uses a deep-blue accent instead of $background-paper */ .appfooter, .playlistSectionButton { - background: #06256f; - color: #ccc; + background: $footer-blue; color: rgba(255, 255, 255, 0.78); } @@ -295,264 +158,79 @@ a[data-role="button"] { } } -.itemSelectionPanel { - border: 1px solid #48c3c8; -} - -.selectionCommandsPanel { - background: #48c3c8; - color: #f8f8fe; -} - -.upNextDialog-countdownText { - color: #48c3c8; -} - -.alphaPickerButton-selected { - color: #0ce8d6; -} - -.alphaPickerButton-tv:focus { - background: #ff77f1; - color: #f8f8fe !important; -} - -.detailRibbon { - background: #000420; - background: linear-gradient(to right, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); -} - -.layout-tv .detailRibbon { - background: none; -} - -.noBackdropTransparency .detailPagePrimaryContainer, -.noBackdropTransparency .detailPageSecondaryContainer { - background: url(bg.jpg) center top no-repeat #030322; - background-size: cover; - background-attachment: fixed; -} - .detailTableBodyRow-shaded:nth-child(even) { - background: #1c1c1c; background: rgba(30, 30, 30, 0.9); } -.listItem-border { - border-color: rgba(255, 255, 255, 0.1) !important; -} - -.listItem:focus { - background: rgba(0, 0, 0, 0.3); -} - -.listItem:hover { - background: #12122f; -} - .actionSheetMenuItem:hover { - background-color: rgba(0, 0, 0, 0.5); -} - -.progressring-spiner { - border-color: #48c3c8; -} - -.button-flat:hover { - color: #48c3c8; -} - -.button-link { - color: #48c3c8; -} - -.mediaInfoText { - color: #f8f8fe; - background: rgba(170, 170, 190, 0.2); -} - -.emby-input, -.emby-textarea { - color: inherit; - background: rgba(0, 0, 0, 0.5); - border: 0.16em solid transparent; - border-radius: 0.2em; -} - -.emby-input:focus, -.emby-textarea:focus { - border-color: #ff77f1; -} - -.emby-select-withcolor { - color: inherit; - background: rgba(0, 0, 0, 0.5); - border: 0.07em solid transparent; -} - -.emby-select-withcolor > option { - color: inherit; - background: #030322d7; -} - -.emby-select-withcolor:focus { - border-color: #ff77f1 !important; -} - -.emby-select-tv-withcolor:focus { - background-color: #ff77f1 !important; - color: #fff !important; -} - -.emby-checkbox:checked + span + .checkboxOutline { - background-color: #030322; - border: 0.14em solid rgb(72, 195, 200); -} - -.emby-checkbox:checked + span + .checkboxOutline > .checkboxIcon-checked { - color: rgb(12, 232, 214); -} - -.emby-checkbox:focus + span + .checkboxOutline { - border-color: #ff77f1; -} - -.emby-checkbox:focus:not(:checked) + span + .checkboxOutline { - border: 0.14em solid #ff77f1; -} - -.itemProgressBarForeground { - background-color: rgb(12, 232, 214); -} - -.itemProgressBarForeground-recording { - background-color: #cb272a; -} - -.countIndicator, -.fullSyncIndicator, -.mediaSourceIndicator, -.playedIndicator { - background: rgb(12, 232, 214); -} - -.fullSyncIndicator { - color: #fff; + background-color: $surface; } +/* Translucent drawer surfaces */ .mainDrawer { - color: #f8f8fe; - background: rgba(0, 0, 0, 0.5); + background: $surface; } .drawer-open { background-color: #030322; } -.navMenuOption:hover { - background: rgba(221, 221, 221, 0.068); -} - +/* Selected nav item uses a custom purple */ .navMenuOption-selected { background: #6f0765 !important; - color: #f8f8fe; + color: $text-primary; } +/* Emby button focus uses a distinct light teal (different from primary or secondary) */ .emby-button.show-focus:focus { background: #8ae9c1; - color: #f8f8fe; -} - -.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles svg .mdl-radio__outer-circle, -.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles svg .mdl-radio__inner-circle { - color: #ff77f1; + color: $text-primary; } +/* Radio button focus-ring circle uses the global default primary, not PH's primary */ .mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles .mdl-radio__focus-circle { - background: #00a4dc; + background: palette.$primary-main; } -.emby-tab-button { - color: #999; -} - -.emby-tab-button-active { - color: #f8f8fe; -} - -.emby-tab-button.show-focus:focus { - color: #ff77f1; -} - -.emby-tab-button:hover { - color: #ff77f1; -} - -.channelPrograms, -.guide-channelHeaderCell, -.programCell { - border-color: rgba(255, 255, 255, 0.05); -} - -.programCell-sports { - background: #3949ab !important; -} - -.programCell-movie { - background: #5e35b1 !important; -} - -.programCell-kids { - background: #039be5 !important; -} - -.programCell-news { - background: #43a047 !important; +/* Guide date tab — dimmed by default */ +.guide-date-tab-button { + color: rgba(255, 255, 255, 0.3); } .programCell-active { background: rgba(0, 0, 0, 0.4) !important; } -.guide-channelHeaderCell:focus, -.programCell:focus { - background-color: #48c3c8 !important; - color: #fff !important; +/* Select element uses a narrower border than base inputs */ +.emby-select-withcolor { + border-width: 0.07em; } -.guide-programTextIcon { - color: #1e1e1e; - background: #555; +/* Select option uses the dark page colour as background */ +.emby-select-withcolor > option { + background: #030322d7; // $bg-base at 85% opacity } -.guide-headerTimeslots { - color: inherit; +/* Checkbox checked state uses primary teal accent */ +.emby-checkbox:checked + span + .checkboxOutline { + background-color: #030322; + border: 0.14em solid #48c3c8; } -.guide-date-tab-button { - color: #555; - color: rgba(255, 255, 255, 0.3); +.emby-checkbox:checked + span + .checkboxOutline > .checkboxIcon-checked { + color: $teal-bright; } -.guide-date-tab-button.emby-tab-button-active, -.guide-date-tab-button:focus { - color: #ff77f1; +/* Progress bar and playback indicators use bright teal */ +.itemProgressBarForeground { + background-color: $teal-bright; } -.guide-date-tab-button.show-focus:focus { - background-color: #48c3c8; - color: #fff; -} - -.infoBanner { - color: #0e0f2d; - background: #dbe6ff; - padding: 1em; - border-radius: 0.25em; -} - -.ratingbutton-icon-withrating { - color: #c33; +.countIndicator, +.fullSyncIndicator, +.mediaSourceIndicator, +.playedIndicator { + background: $teal-bright; } .downloadbutton-icon-complete, @@ -560,98 +238,38 @@ a[data-role="button"] { color: #4285f4; } -.playstatebutton-icon-played { - color: #c33; -} - +/* buttonActive retains the global default primary blue, not PH's primary */ .buttonActive { - color: #00a4dc !important; -} - -.personCard .cardScalable { - border-radius: 50% !important; - border: 1px solid transparent; -} - -.cardBox:not(.visualCardBox) .cardPadder { - background-color: rgba(0, 0, 0, 0.5); - border-radius: 0.8em; -} - -.cardPadder .cardImageIcon { - color: rgba(0, 0, 0, 0.5); -} - -.card:focus .cardBox.visualCardBox, -.card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #ff77f1 !important; -} - -.card.show-focus:not(.show-animation) .cardBox.visualCardBox, -.card.show-focus:not(.show-animation) .cardBox:not(.visualCardBox) .cardScalable { - border-radius: 1.3em; + color: palette.$primary-main !important; } +/* Custom scrollbar colours */ .layout-desktop, .scrollY { scrollbar-width: thin; scrollbar-color: #888 rgba(59, 59, 59, 0.5); } -::-webkit-scrollbar-track { - box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); +.layout-desktop ::-webkit-scrollbar, +.layout-tv ::-webkit-scrollbar { + height: 1em; } ::-webkit-scrollbar-track-piece { background-color: rgba(59, 59, 59, 0.5); } -.layout-desktop ::-webkit-scrollbar, -.layout-tv ::-webkit-scrollbar { - width: 0.4em; - height: 1em; -} - -::-webkit-scrollbar-thumb:horizontal, -::-webkit-scrollbar-thumb:vertical { - border-radius: 2px; - background: center no-repeat #888; -} - -.timeslotHeaders-desktop::-webkit-scrollbar { - height: 0.7em; +.mediaInfoText { + color: $text-primary; + background: rgba(170, 170, 190, 0.2); } .mediaInfoOfficialRating { border: 0.09em solid #583fa0; - background-color: #dbe6ff; + background-color: $info-background; color: #0e0f2d; } .metadataSidebarIcon { - color: #dbe6ff; -} - -.personCard .overflowPortraitCard { - width: 40vw; -} - -.personCard .coveredImage { - background-position-y: 20%; - border-radius: 50%; -} - -.personCard .cardOverlayContainer { - clip-path: circle(50% at 50% 50%); -} - -.personCard .cardOverlayButton-br { - right: 20%; -} - -.personCard .cardPadder-overflowPortrait, -.personCard .cardPadder-portrait { - padding-bottom: 100%; - contain: strict; - border-radius: 50% !important; + color: $info-background; } From 561401dce8cd700994acf539e3c8f7a17fa3c336 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 8 Jul 2026 17:24:49 -0400 Subject: [PATCH 2/4] Reduce elevation on app bars to better match theme color --- src/apps/dashboard/AppLayout.tsx | 1 - src/apps/modern/AppLayout.tsx | 2 +- src/themes/purplehaze/theme.scss | 6 ++++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/apps/dashboard/AppLayout.tsx b/src/apps/dashboard/AppLayout.tsx index 5164e929de..c9f42e18c2 100644 --- a/src/apps/dashboard/AppLayout.tsx +++ b/src/apps/dashboard/AppLayout.tsx @@ -59,7 +59,6 @@ export const Component: FC = () => { { }} > - + Date: Thu, 9 Jul 2026 15:19:10 -0400 Subject: [PATCH 3/4] Fix secondary color in default theme to match primary --- src/themes/_base/theme.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/_base/theme.ts b/src/themes/_base/theme.ts index 4c8a27a09f..31ced1db8f 100644 --- a/src/themes/_base/theme.ts +++ b/src/themes/_base/theme.ts @@ -11,7 +11,7 @@ export const DEFAULT_COLOR_SCHEME: ColorSystemOptions = { main: '#00a4dc' }, secondary: { - main: '#aa5cc3' + main: '#00a4dc' }, background: { default: '#101010', From fa918a02bca3bf94943897a642c4fbcdcfcfe6b3 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 29 Jul 2026 16:38:42 -0400 Subject: [PATCH 4/4] Remove unused nowPlayingContextMenu class from base theme --- src/themes/_base/_theme.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/themes/_base/_theme.scss b/src/themes/_base/_theme.scss index c9f19b850c..7d7217284b 100644 --- a/src/themes/_base/_theme.scss +++ b/src/themes/_base/_theme.scss @@ -136,8 +136,7 @@ html { opacity: 0.86; } -.dialog, -.nowPlayingContextMenu { +.dialog { background-color: var(--jf-palette-background-default, $background-default); }