Restructure project: add base theme and all modules like example

This commit is contained in:
2026-02-15 19:25:13 +03:00
parent 22e6c07715
commit a49d90a98d
26 changed files with 1495 additions and 11 deletions

View File

@@ -9,17 +9,39 @@ Modern CSS theme for Jellyfin media server with custom fonts, smooth animations
1. Go to Jellyfin Dashboard → General → Custom CSS
2. Paste this code:
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/darkvar.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/complete.css");
```
3. Click Save
### Method 2: Manual
1. Download `theme/darkvar.css` from this repository
1. Download `theme/complete.css` from this repository
2. Go to Jellyfin Dashboard → General → Custom CSS
3. Paste the contents of the file
4. Click Save
### Method 3: Custom Modules
You can also import individual modules with base.css:
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/base.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/static-sidebar.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/change-logo.css");
/* Add more modules as needed */
```
Available modules:
- `static-sidebar.css` - Static sidebar on desktop
- `central-libraries-small.css` - Centered libraries on homepage
- `change-logo.css` - Custom logo/banner
- `count-indicators.css` - Custom count indicators
- `forgot-password.css` - Hide forgot password button
- `hide-my-media.css` - Hide "My Media" section
- `moving-cards.css` - Card hover animation
- `smaller-cast.css` - Smaller cast cards
- `floating-progress.css` - Floating progress bars
## Features
- 🎨 Modern design with improved aesthetics

792
example/base.css Normal file
View File

@@ -0,0 +1,792 @@
/*
Jamfin - Another Jellyfin Theme aimed to please the masses.
Please note that this theme is still in development and may not be fully functional.
This theme is based on the Jellyfin default theme.
This theme is licensed under the MIT License.
*/
:root {
/* Colours */
--theme-background-colour: #101010;
--theme-sidebar-background-colour: #222222;
--theme-menu-background-colour: #3a3a3a80;
--theme-menu-shadow-colour: #fff3;
--theme-base-colour: #696969;
--theme-text-colour: #dbdbdb;
--theme-restart-colour: #da87287e;
--theme-shutdown-colour: #c21c1c9d;
--theme-progress-bar-colour: #cfcfcf;
--theme-progress-bar-background-colour: #2c2c2c;
--theme-progress-bar-transcoding-colour: #eb7e25;
--theme-chapter-marker-colour: #dbdbdb;
--theme-chapter-marker-watched-colour: #4a4a4a;
/* General Appearance */
--theme-roundness: .75rem;
--theme-blur: 16px;
}
/* Remove the Default Focus Outline */
*:focus-visible {
outline: none;
}
/* Change Background Colours */
.backgroundContainer,
.mainDrawer,
.drawer-open,
.nowPlayingPlaylist,
.nowPlayingContextMenu,
html {
background-color: var(--theme-background-colour);
}
/* Re-design the Header */
.layout-desktop [dir="ltr"] .pageTitle {
margin-left: 1.2em;
}
[dir="ltr"] .sidebarHeader {
padding-left: 2em;
font-weight: bold;
}
[dir="ltr"] .navMenuOption {
padding: .9em 1.2em !important;
}
.pageTitleWithLogo {
height: 50px;
}
.skinHeader {
background-color: transparent;
}
.layout-desktop .headerLeft,
.layout-desktop .headerRight {
margin-top: 1rem;
}
.layout-mobile .headerRight {
margin: 0 .29em;
}
.layout-mobile .libraryPage:not(.noSecondaryNavPage) {
padding-top: 8.5em !important;
}
.paper-icon-button-light > div {
width: 25px;
height: 25px;
transform: unset;
}
.skinHeader.semiTransparent {
background-color: unset;
}
.headerTabs,
.headerRight,
.dialog,
.raised,
.fab,
.paper-icon-button-light:not(
.headerRight,
.headerRight .paper-icon-button-light
),
.osdHeader .headerLeft .paper-icon-button-light,
.detailButton,
.sliderBubble,
.MuiDataGrid-root,
.MuiMenu-list,
.MuiButton-root,
.toast.toastVisible,
.guide-date-tab-button.emby-tab-button-active,
.guide-date-tab-button:focus,
.MuiTabs-centered .MuiTab-root,
#skipIntro .emby-button,
.chapterThumbContainer,
.chapterThumbTextContainer {
color: var(--theme-text-colour);
border-radius: var(--theme-roundness);
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
background-color: var(--theme-menu-background-colour);
backdrop-filter: blur(var(--theme-blur)) !important;
-webkit-backdrop-filter: blur(var(--theme-blur)) !important;
-moz-backdrop-filter: blur(var(--theme-blur)) !important;
-o-backdrop-filter: blur(var(--theme-blur)) !important;
-ms-backdrop-filter: blur(var(--theme-blur)) !important;
}
.dialogBackdrop {
background-color: #111;
}
.headerTabs .emby-tabs-slider {
display: flex;
align-items: center;
}
.headerTabs .emby-tab-button,
.headerRight .paper-icon-button-light,
.detailButton,
.sessionCardButton,
.guideOptions,
.MuiTabs-centered .MuiTab-root {
padding: .556em !important;
margin: 0 .29em !important;
border-radius: var(--theme-roundness);
}
.layout-desktop .headerTabs,
.layout-desktop .headerLeft,
.layout-desktop .headerRight,
.layout-desktop .emby-tabs-slider,
.layout-desktop .raised {
height: 50px;
}
.layout-mobile .headerTabs,
.layout-mobile .headerRight,
.layout-mobile .emby-tabs-slider,
.layout-mobile .raised {
height: 40px;
}
.layout-desktop .headerTabs {
margin-left: 250px;
}
@media (max-width: 1599px) {
.layout-desktop .sectionTabs {
width: auto;
align-self: center;
margin-top: -58px;
}
.layout-desktop .headerRight {
margin-right: .8em;
}
.layout-mobile .headerTabs {
margin: 20px auto;
width: auto;
}
.layout-mobile .pageTitleWithLogo {
height: 40px;
}
}
.layout-tv .sectionTabs {
width: unset;
}
@media (min-width: 100em) {
.layout-tv .headerTabs {
margin-top: unset;
}
.layout-mobile .headerTabs {
margin-top: -1.3em;
}
}
@media (max-width: 100em) {
.layout-tv .sectionTabs {
width: fit-content;
align-self: center;
font-size: 125%;
}
}
@media (max-width: 50em) {
.homeLibraryButton {
width: 100% !important;
}
}
/* Main Drawer */
.layout-desktop,
.touch-menu-la.transition {
transition: none;
}
.layout-mobile .mainDrawer {
padding-top: 1.2em;
}
.layout-desktop .mainDrawer-scrollContainer {
margin-top: 100px;
}
.navMenuOption,
.navMenuOption-selected,
.navMenuOption:hover,
.MuiListItem-root,
.MuiDrawer-paperAnchorLeft .MuiButtonBase-root {
border-radius: var(--theme-roundness) !important;
width: 80%;
margin: auto !important;
}
.navMenuOption:hover,
.listItem:hover,
.MuiButton-root:hover {
background-color: var(--theme-menu-shadow-colour);
}
.navMenuOption-selected,
.Mui-selected {
background: var(--theme-menu-shadow-colour) !important;
}
/* Main Cards */
.section0 .sectionTitle {
padding-top: 1em !important;
}
.layout-desktop .section0 .emby-scrollbuttons,
.layout-desktop .section1 .emby-scrollbuttons {
padding-top: unset;
}
.cardContent:not(.dashboardSection .cardContent),
.cardPadder:not(.dashboardSection .cardPadder),
.blurhash-canvas,
.dialog,
.itemSelectionPanel {
border-radius: var(--theme-roundness) !important;
box-shadow: inset 0 1px var(--theme-menu-shadow-colour) !important;
transition: 0.2s;
}
.cardOverlayContainer {
border-radius: var(--theme-roundness) !important;
box-shadow: inset 0 2px var(--theme-menu-shadow-colour) !important;
transition: unset;
}
.layout-mobile .cardOverlayButton {
padding: unset;
margin: 5px;
}
.layout-mobile .cardOverlayButtonIcon {
background: unset !important;
}
.layout-desktop .cardOverlayContainer > .cardOverlayButton-br .cardOverlayButton {
padding: unset;
margin: 5px;
}
.defaultCardBackground1,
.defaultCardBackground2,
.defaultCardBackground3,
.defaultCardBackground4,
.defaultCardBackground5,
.cardOverlayContainer > .cardOverlayFab-primary {
background-color: var(--theme-menu-background-colour);
font-size: 110%;
}
.button-submit:focus,
.paper-icon-button-light:hover:not(:disabled, .btnDelete),
.raised:hover,
.emby-tab-button:hover,
.detailButton:hover,
.emby-tab-button.show-focus:focus,
.paper-icon-button-light.show-focus:focus,
.emby-button.show-focus:focus,
.alphaPickerButton-tv:focus,
#skipIntro .emby-button:hover,
.multiSelectCheckboxOutline {
border-radius: var(--theme-roundness) !important;
transform: unset !important;
-webkit-transform: unset !important;
-moz-transform: unset !important;
-o-transform: unset !important;
-ms-transform: unset !important;
color: var(--theme-text-colour);
background-color: var(--theme-menu-shadow-colour) !important;
}
.layout-tv .itemDetailsGroup .emby-button.show-focus:focus {
padding: 5px 10px;
}
/* User Settings */
.readOnlyContent h2,
.sectionTitle,
.dashboardSection h3,
.MuiListSubheader-root {
font-weight: bold;
}
.listItem-border,
.itemSelectionPanel {
border: unset;
}
.listItem {
padding-left: 1.2em !important;
}
.listItem:hover,
.MuiButtonBase-root,
.MuiButtonBase-root:hover,
.emby-tab-button,
progress {
border-radius: var(--theme-roundness);
}
.collapseContent,
.formDialogFooter:not(.formDialogFooter-clear),
.formDialogHeader:not(.formDialogHeader-clear),
.paperList,
.visualCardBox,
.emby-select-withcolor,
.emby-input,
.emby-textarea {
background-color: var(--theme-menu-background-colour);
border-radius: var(--theme-roundness);
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
border: unset;
padding: 10px;
}
.emby-select[disabled] {
box-shadow: unset;
}
.trackSelections .selectContainer .detailTrackSelect {
padding: 0 10px;
}
/* Content Details */
.layout-desktop .detailImageContainer .card {
width: 250px;
max-width: unset;
top: 1.5em;
left: 0;
}
/* Backwards Compatibility for versions before 10.11.0 */
.layout-desktop .infoWrapper .detailImageContainer .card {
padding-top: 8.5em;
}
.layout-desktop .detailPagePrimaryContent {
padding-top: 135px;
padding-left: 300px;
min-height: 325px;
}
.layout-desktop .mainDetailButtons {
margin-top: 350px;
margin-left: 292px;
position: absolute;
}
.layout-mobile .mainDetailButtons {
display: flex;
flex-flow: wrap;
gap: 10px;
}
.mainDetailButtons .detailButton {
display: inline-flex;
align-items: center;
padding-left: 50px;
position: relative;
}
.btnPlay .detailButton-content:before {
content: "Play";
}
.btnReplay .detailButton-content:before {
content: "Replay";
}
.btnDownload .detailButton-content:before {
content: "Download";
}
.btnPlayTrailer .detailButton-content:before {
content: "Trailer";
}
.btnInstantMix .detailButton-content:before {
content: "Instant Mix";
}
.btnShuffle .detailButton-content:before {
content: "Shuffle";
}
.btnCancelSeriesTimer .detailButton-content:before {
content: "Cancel Programme";
}
.btnCancelTimer .detailButton-content:before {
content: "Stop Recording";
}
.btnPlaystate .detailButton-content:before {
content: "Watched";
}
.btnUserRating .detailButton-content:before {
content: "Favourite";
}
.btnSplitVersions .detailButton-content:before {
content: "Split Versions";
}
.btnMoreCommands .detailButton-content:before {
content: "Options";
}
.detailButton-content:before {
position: relative;
margin-left: 30px;
}
.detailButton-icon:before {
position: absolute;
top: 7px;
left: 7px;
}
.mainDetailButtons .material-icons {
height: unset;
}
.layout-desktop .detailPagePrimaryContainer,
.layout-desktop .detailPageContent {
padding-left: 3.3% !important;
}
.detailRibbon {
background: unset;
padding-left: 0 !important;
}
.layout-desktop .infoWrapper {
padding-top: 226px;
padding-left: 300px;
}
.itemBackdrop::before {
content: '';
position: absolute;
top: 0; /* cover the full element */
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(180deg, transparent 5%, var(--theme-background-colour));
pointer-events: none; /* ensures it's non-interactive */
z-index: 1; /* sits on top of the image */
}
.layout-mobile .itemBackdrop {
margin-top: unset;
-webkit-animation: backdrop-fadein .8s ease-in normal both;
animation: backdrop-fadein .8s ease-in normal both;
}
.layout-mobile .detailImageContainer .card {
filter: unset;
-webkit-filter: unset;
-moz-filter: unset;
-o-filter: unset;
-ms-filter: unset;
padding-left: 2em;
}
.layout-desktop .detailLogo {
left: 3%;
right: unset;
z-index: 1;
}
.layout-desktop .backgroundContainer.withBackdrop,
.MuiPaper-root,
.MuiTabs-indicator {
background-color: unset;
background-image: unset;
box-shadow: unset;
}
.layout-desktop .backdropImage {
filter: blur(5px);
-webkit-filter: blur(5px);
-moz-filter: blur(5px);
-o-filter: blur(5px);
-ms-filter: blur(5px);
}
.darkenContent {
backdrop-filter: blur(5px) brightness(0.75);
-webkit-backdrop-filter: blur(5px) brightness(0.75);
-moz-backdrop-filter: blur(5px) brightness(0.75);
-o-backdrop-filter: blur(5px) brightness(0.75);
-ms-backdrop-filter: blur(5px) brightness(0.75);
background: -webkit-linear-gradient(180deg, transparent, var(--theme-background-colour));
background: -moz-linear-gradient(180deg, transparent, var(--theme-background-colour));
background: -o-linear-gradient(180deg, transparent, var(--theme-background-colour));
background: -ms-linear-gradient(180deg, transparent, var(--theme-background-colour));
background: linear-gradient(180deg, transparent, var(--theme-background-colour));
}
.itemsContainer-tv {
margin-left: 10px;
}
/* Admin Settings */
#btnRestartServer {
box-shadow: inset 0 1px var(--theme-restart-colour) !important;
}
#btnRestartServer:hover,
.notifications,
.MuiChip-filledInfo {
color: var(--theme-text-colour) !important;
background-color: var(--theme-restart-colour) !important;
}
#btnShutdown,
.btnDelete {
box-shadow: inset 0 1px var(--theme-shutdown-colour) !important;
}
#btnShutdown:hover,
.btnDelete:hover,
.notification_important,
.MuiChip-filledError {
color: var(--theme-text-colour) !important;
background-color: var(--theme-shutdown-colour) !important;
}
.listItemIcon:not(.listItemIcon-transparent) {
border-radius: var(--theme-roundness);
}
.sessionCardButtons {
margin: .29em 0;
}
.dashboardSection .cardContent {
border-top-left-radius: var(--theme-roundness);
border-top-right-radius: var(--theme-roundness);
}
div[data-role="controlgroup"] a[data-role="button"]:first-child {
border-bottom-left-radius: var(--theme-roundness);
border-top-left-radius: var(--theme-roundness);
}
div[data-role="controlgroup"] a[data-role="button"]:last-child {
border-bottom-right-radius: var(--theme-roundness);
border-top-right-radius: var(--theme-roundness);
}
.dashboardColumn {
flex-shrink: inherit;
}
/* Base Colours */
.selectLabelFocused,
.textareaLabelFocused,
.inputLabelFocused,
.mdl-slider,
.metadataSidebarIcon,
.button-link,
.guide-date-tab-button.emby-tab-button-active,
.guide-date-tab-button:focus,
#divRunningTasks span,
.MuiAlert-icon,
.listItemBodyText span {
color: var(--theme-text-colour) !important;
}
.emby-checkbox:checked + span + .checkboxOutline,
.listItemIcon:not(
.listItemIcon-transparent,
.notification_important,
.notifications
),
.guide-channelHeaderCell:focus,
.programCell:focus,
.emby-button.show-focus:focus,
::selection,
div[data-role="controlgroup"] a.ui-btn-active,
.MuiAvatar-root,
.selectionCommandsPanel {
background-color: var(--theme-base-colour) !important;
}
.emby-checkbox + span + .checkboxOutline,
.emby-checkbox:checked + span + .checkboxOutline,
.emby-checkbox:focus:not(:checked) + span + .checkboxOutline,
.mdl-spinner__layer-1,
.mdl-spinner__layer-2,
.mdl-spinner__layer-3,
.mdl-spinner__layer-4 {
border-color: var(--theme-base-colour) !important;
}
.mdl-slider {
-webkit-appearance: none;
appearance: none;
width: 100%;
background: transparent;
}
.mdl-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 0;
height: 0;
background: transparent;
cursor: pointer;
}
.mdl-slider::-moz-range-thumb {
width: 0;
height: 0;
background: transparent;
cursor: pointer;
}
.mdl-slider::-ms-thumb {
width: 0;
height: 0;
background: transparent;
cursor: pointer;
}
.mdl-slider-background-flex,
.mdl-slider-background-lower,
.mdl-slider-background-upper {
border-radius: var(--theme-roundness);
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
height: 10px;
}
/* Chapter Markers */
.sliderMarkerContainer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 10px;
pointer-events: none;
z-index: 1;
}
.sliderMarker {
position: absolute;
top: 0;
width: 2px;
height: 10px;
background-color: var(--theme-chapter-marker-colour);
opacity: 0.6;
border-radius: 1px;
pointer-events: auto;
cursor: pointer;
transition: opacity 0.2s ease, width 0.2s ease, background-color 0.2s ease;
}
.sliderMarker.unwatched {
background-color: var(--theme-chapter-marker-colour);
}
.sliderMarker.watched {
background-color: var(--theme-chapter-marker-watched-colour);
}
.mdl-slider-background-upper {
margin-left: -3px;
}
.mdl-slider-background-flex-container {
top: 5px;
}
.innerCardFooter .itemProgressBarForeground,
.playbackProgress > div,
.mdl-slider-background-lower,
.iconOsdProgressInner,
.taskProgressInner,
progress {
background-color: var(--theme-progress-bar-colour) !important;
}
/* These need to remain separate for browser compatibility */
progress::-moz-progress-bar {
background-color: var(--theme-progress-bar-colour);
}
progress::-webkit-progress-bar {
background-color: var(--theme-progress-bar-colour);
}
progress::-ms-thumb {
background-color: var(--theme-progress-bar-colour);
}
.transcodingProgress > div {
background-color: var(--theme-progress-bar-transcoding-colour) !important;
}
.innerCardFooter .itemProgressBar,
.backgroundProgress > div,
.mdl-slider-background-flex,
.taskProgressOuter,
progress {
background-color: var(--theme-progress-bar-background-colour) !important;
}
.layout-desktop .dashboardDocument .content-primary:not(.layout-desktop #dashboardPage .content-primary) {
padding-left: 2.5em;
padding-right: 2.5em;
}
[dir="ltr"] .formDialogHeaderTitle:first-child {
margin-left: unset;
}
/* Login Form */
#loginPage {
background-color: var(--theme-menu-background-colour);
border-radius: var(--theme-roundness);
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
padding: unset !important;
max-width: 750px;
max-height: 500px;
margin: 150px auto 0;
}
.manualLoginForm .raised.button-submit.block.emby-button {
margin-bottom: -3px;
}
.chapterThumbTextContainer {
width: fit-content;
margin: auto;
}
.chapterThumbText {
width: fit-content;
}

16
example/complete.css Normal file
View File

@@ -0,0 +1,16 @@
/*
The complete pack of the Jamfin theme. This file includes all the modules and the main theme.
If you wish to use only some of the modules, you can import them individually.
You can grab the base theme by changing jamfin.css to base.css in the first line.
*/
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/base.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/static-sidebar.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/central-libraries-small.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/change-logo.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/count-indicators.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/forgot-password.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/hide-my-media.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/moving-cards.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/smaller-cast.css");
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/floating-progress.css");

34
example/modules/README.md Normal file
View File

@@ -0,0 +1,34 @@
<div align="center">
<img src="https://github.com/JamsRepos/Jamfin/blob/main/assets/logo.png?raw=true" alt="Logo" width="125"/>
## 🧩 Modules
Here you can find our assortment of modules. These are included within the complete pack of the theme however can be used in conjunction with the base theme or any other theme of your choosing.
## 🔌 Installation
The general format to install a module is as followed, you will need to replace the `<name>` with the file name of the module you wish to install.
<div align="left">
```css
@import url("https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/theme/modules/<name>.css");
```
</div>
#### ❓Where do I install it?
Locate the `Custom CSS code` option under your General settings in the admin panel and simply paste one of the lines above within the box.
If you wish to just install this for yourself only, you can do so by going to your users Display settings and copy the following settings.
- [x] Disable server-provided custom CSS code
Then enter the theme into the `Custom CSS code` option and save your settings.
## 🖌️ Customisation
Each module has it's own individual customisation parameters. Please read the respective README by going into each modules folder.
</div>

View File

@@ -0,0 +1,10 @@
/*
This module will change "My Media (small)" to be centered on the homepage.
This is useful to make the homepage look more balanced.
This can be used as a standalone module.
*/
#indexPage .section0 .itemsContainer.padded-left.padded-right {
justify-content: center !important;
padding-top: 15px !important;
}

View File

@@ -0,0 +1,14 @@
/*
This module will change the Jellyfin logo to a custom one.
This allows you to white-label your Jellyfin instance slightly.
This can be used as a standalone module.
*/
:root {
--logo-url: url('https://cdn.jsdelivr.net/gh/JamsRepos/Jamfin@latest/assets/banner.png');
}
.pageTitleWithDefaultLogo,
.spashLogo {
background-image: var(--logo-url) !important;
}

View File

@@ -0,0 +1,26 @@
/*
This module change the color of the count indicators.
This is a simple and effective way to make your Jellyfin instance look more modern.
This can be used as a standalone module.
*/
:root {
--show-count-indicators: flex; /* none to hide */
--count-indicator-colour: rgba(200, 200, 200, 0.75);
--played-indicator-colour: rgba(32, 139, 36, 0.75);
}
.countIndicator {
display: var(--show-count-indicators);
}
.countIndicator,
.fullSyncIndicator,
.mediaSourceIndicator,
.playedIndicator {
background: var(--count-indicator-colour);
}
.playedIndicator {
background: var(--played-indicator-colour);
}

View File

@@ -0,0 +1,45 @@
/*
This module will make progress bars float from the bottom of the card.
This is useful if you wish to make the progress bar more visible.
This can be used as a standalone module.
*/
:root {
--floating-progress-roundness: .75rem;
--floating-progress-height: 10px;
}
.sessionNowPlayingDetails {
padding-bottom: 10px;
}
.fullInnerCardFooter,
.activeSession .backgroundProgress,
.activeSession .playbackProgress,
.activeSession .transcodingProgress {
width: 95%;
bottom: 10px;
margin: 0 auto;
height: var(--floating-progress-height);
border-radius: var(--floating-progress-roundness) !important;
-webkit-border-radius: var(--floating-progress-roundness) !important;
-moz-border-radius: var(--floating-progress-roundness) !important;
}
.itemProgressBar {
height: var(--floating-progress-height);
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-webkit-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-moz-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
}
.playbackProgress > div,
.backgroundProgress > div,
.transcodingProgress > div {
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-webkit-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-moz-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
border-radius: var(--floating-progress-roundness);
-webkit-border-radius: var(--floating-progress-roundness);
-moz-border-radius: var(--floating-progress-roundness);
}

View File

@@ -0,0 +1,14 @@
/*
This module will remove the "Forgot Password" button from the login page.
This is useful if you have a third-party user management system.
This can be used as a standalone module.
*/
#btnResetPassword,
.btnForgotPassword {
display: none !important;
}
#loginPage {
max-height: 450px;
}

View File

@@ -0,0 +1,17 @@
/*
This module will hide the "My Media" section from the Jellyfin homepage.
This is useful if you want an even more minimalistic homepage.
This can be used as a standalone module.
*/
#indexPage .section0 .sectionTitle {
display: none;
}
#indexPage .section0 {
padding-top: 1em;
}
#indexPage .verticalSection.section0 {
padding-top: 3em;
}

View File

@@ -0,0 +1,13 @@
/*
This module will make your Jellyfin cards lift up slightly when hovered over.
This is a simple and effective way to make your Jellyfin instance look more modern.
This can be used as a standalone module.
*/
.cardBox:hover {
transform: translateY(-2.5px);
-webkit-transform: translateY(-2.5px);
-moz-transform: translateY(-2.5px);
-ms-transform: translateY(-2.5px);
-o-transform: translateY(-2.5px);
}

View File

@@ -0,0 +1,82 @@
/*
This module will make the cast cards smaller when viewing content details.
This is useful if you want a more compact view of the cast.
This can be used as a standalone module.
Original Code: https://jellyfin.org/docs/general/clients/css-customization/#stylized-and-smaller-cast--crew-info
*/
#castContent .card.overflowPortraitCard.personCard.card-hoverable.card-withuserdata {
width: 4.2cm;
font-size: 90%;
}
#castContent .card.overflowPortraitCard.personCard.card-withuserdata {
width: 4.2cm;
font-size: 90%;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.cardContent.cardContent-shadow.itemAction.lazy {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground1.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground2.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground3.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground4.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground5.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardScalable {
width: 3.8cm;
height: 3.8cm;
}
#castContent .cardOverlayButton-br {
bottom: 4%;
right: 15%;
width: 70%;
}
#castContent .cardOverlayButton.cardOverlayButton-hover.itemAction.paper-icon-button-light {
margin: auto;
}
#castContent .cardBox:not(.visualCardBox) .cardPadder {
background-color: unset;
}
#castContent .cardBox:not(.visualCardBox) .cardPadder,
#castContent .cardContent-shadow {
box-shadow: unset;
}

View File

@@ -0,0 +1,34 @@
/*
This module will allow you to make the sidebar static, meaning it will not scroll with the rest of the page.
This is a simple and effective way to make your Jellyfin instance look more modern.
This can be used as a standalone module.
*/
.layout-desktop .mainDrawer,
.MuiDrawer-paperAnchorLeft {
left: 0 !important;
top: 0;
width: 250px !important;
background-color: var(--theme-sidebar-background-colour) !important;
z-index: 100;
}
.layout-desktop .mainDrawerButton,
.layout-desktop .headerHomeButton {
display: none;
}
.layout-desktop .libraryPage:not(#editItemMetadataPage) {
margin-left: 250px;
width: calc(100% - 250px);
}
.layout-desktop #slides-container {
margin-left: 320px;
width: calc(100% - 385px);
}
.layout-desktop .hide-scroll .mainDrawer,
.layout-desktop .hideMainDrawer .mainDrawer {
display: none;
}

View File

@@ -4,7 +4,7 @@
"version": "1.0.0",
"author": "OlegTolchin",
"repository": "https://github.com/OlegTolchin/Tolfin",
"url": "https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/darkvar.css",
"url": "https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/complete.css",
"target": "jellyfin",
"categories": ["theme", "css"]
}

View File

@@ -1,3 +1,10 @@
/*
========================================
TOLFIN - Базовая тема для Jellyfin
========================================
Модернизированная тема с кастомными шрифтами,
плавными анимациями и адаптивным дизайном.
*/
/* ========================================
ПЕРЕМЕННЫЕ ТЕМЫ
@@ -912,11 +919,3 @@ progress {
.chapterThumbText {
width: fit-content;
}
/* ========================================
МОДУЛИ ТЕМЫ
======================================== */
/* Импорт модуля для замены логотипа */
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/change-logo.css");

21
theme/complete.css Normal file
View File

@@ -0,0 +1,21 @@
/*
========================================
TOLFIN - Полная тема для Jellyfin
========================================
Полная тема включающая все модули.
Импортирует базовую тему и все модули.
*/
/* Импорт базовой темы */
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/base.css");
/* Импорт модулей */
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/static-sidebar.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/central-libraries-small.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/change-logo.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/count-indicators.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/forgot-password.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/hide-my-media.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/moving-cards.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/smaller-cast.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/floating-progress.css");

109
theme/modules/README.md Normal file
View File

@@ -0,0 +1,109 @@
# Tolfin Modules
Модули темы Tolfin для Jellyfin. Каждый модуль может использоваться отдельно или в сочетании с другими.
## Доступные модули
### static-sidebar.css
Делает боковую панель статичной (не прокручивается вместе со страницей) на десктопе.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/static-sidebar.css");
```
---
### central-libraries-small.css
Центрирует секцию "Мои медиа (small)" на главной странице.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/central-libraries-small.css");
```
---
### change-logo.css
Заменяет логотип Jellyfin на кастомный.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/change-logo.css");
```
---
### count-indicators.css
Изменяет цвет индикаторов счётчиков (количество эпизодов, и т.д.).
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/count-indicators.css");
```
---
### forgot-password.css
Убирает кнопку "Забыли пароль" со страницы входа.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/forgot-password.css");
```
---
### hide-my-media.css
Скрывает секцию "Мои медиа" с главной страницы Jellyfin.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/hide-my-media.css");
```
---
### moving-cards.css
Делает карточки Jellyfin немного приподнимающимися при наведении.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/moving-cards.css");
```
---
### smaller-cast.css
Делает карточки актёров меньше при просмотре деталей контента.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/smaller-cast.css");
```
---
### floating-progress.css
Делает прогресс-бары плавающими от низа карточки.
**Использование:**
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/floating-progress.css");
```
---
## Использование модулей
### С базовой темой:
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/base.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/static-sidebar.css");
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/modules/change-logo.css");
```
### Полная тема (все модули):
```css
@import url("https://cdn.jsdelivr.net/gh/OlegTolchin/Tolfin@latest/theme/complete.css");
```

View File

@@ -0,0 +1,10 @@
/*
Этот модуль центрирует секцию "Мои медиа (small)" на главной странице.
Полезно для более сбалансированного вида главной страницы.
Может использоваться как отдельный модуль.
*/
#indexPage .section0 .itemsContainer.padded-left.padded-right {
justify-content: center !important;
padding-top: 15px !important;
}

View File

@@ -0,0 +1,26 @@
/*
Этот модуль изменяет цвет индикаторов счётчиков.
Простой способ сделать Jellyfin более современным.
Может использоваться как отдельный модуль.
*/
:root {
--show-count-indicators: flex; /* none для скрытия */
--count-indicator-colour: rgba(200, 200, 200, 0.75);
--played-indicator-colour: rgba(32, 139, 36, 0.75);
}
.countIndicator {
display: var(--show-count-indicators);
}
.countIndicator,
.fullSyncIndicator,
.mediaSourceIndicator,
.playedIndicator {
background: var(--count-indicator-colour);
}
.playedIndicator {
background: var(--played-indicator-colour);
}

View File

@@ -0,0 +1,45 @@
/*
Этот модуль делает прогресс-бары плавающими от низа карточки.
Полезно для большей видимости прогресс-бара.
Может использоваться как отдельный модуль.
*/
:root {
--floating-progress-roundness: .75rem;
--floating-progress-height: 10px;
}
.sessionNowPlayingDetails {
padding-bottom: 10px;
}
.fullInnerCardFooter,
.activeSession .backgroundProgress,
.activeSession .playbackProgress,
.activeSession .transcodingProgress {
width: 95%;
bottom: 10px;
margin: 0 auto;
height: var(--floating-progress-height);
border-radius: var(--floating-progress-roundness) !important;
-webkit-border-radius: var(--floating-progress-roundness) !important;
-moz-border-radius: var(--floating-progress-roundness) !important;
}
.itemProgressBar {
height: var(--floating-progress-height);
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-webkit-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-moz-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
}
.playbackProgress > div,
.backgroundProgress > div,
.transcodingProgress > div {
box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-webkit-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
-moz-box-shadow: inset 0 1px var(--theme-menu-shadow-colour);
border-radius: var(--floating-progress-roundness);
-webkit-border-radius: var(--floating-progress-roundness);
-moz-border-radius: var(--floating-progress-roundness);
}

View File

@@ -0,0 +1,14 @@
/*
Этот модуль убирает кнопку "Забыли пароль" со страницы входа.
Полезно если используется сторонняя система управления пользователями.
Может использоваться как отдельный модуль.
*/
#btnResetPassword,
.btnForgotPassword {
display: none !important;
}
#loginPage {
max-height: 450px;
}

View File

@@ -0,0 +1,17 @@
/*
Этот модуль скрывает секцию "Мои медиа" с главной страницы Jellyfin.
Полезно для более минималистичного вида главной страницы.
Может использоваться как отдельный модуль.
*/
#indexPage .section0 .sectionTitle {
display: none;
}
#indexPage .section0 {
padding-top: 1em;
}
#indexPage .verticalSection.section0 {
padding-top: 3em;
}

View File

@@ -0,0 +1,13 @@
/*
Этот модуль делает карточки Jellyfin немного приподнимающимися при наведении.
Простой способ сделать Jellyfin более современным.
Может использоваться как отдельный модуль.
*/
.cardBox:hover {
transform: translateY(-2.5px);
-webkit-transform: translateY(-2.5px);
-moz-transform: translateY(-2.5px);
-ms-transform: translateY(-2.5px);
-o-transform: translateY(-2.5px);
}

View File

@@ -0,0 +1,77 @@
/*
Этот модуль делает карточки актёров меньше при просмотре деталей контента.
Полезно для более компактного отображения актёрского состава.
Может использоваться как отдельный модуль.
Оригинальный код: https://jellyfin.org/docs/general/clients/css-customization/#stylized-and-smaller-cast--crew-info
*/
#castContent .card.overflowPortraitCard.personCard.card-hoverable.card-withuserdata {
width: 4.2cm;
font-size: 90%;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.cardContent.cardContent-shadow.itemAction.lazy {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground1.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground2.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground3.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground4.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardContent-button.cardImageContainer.coveredImage.defaultCardBackground.defaultCardBackground5.cardContent.cardContent-shadow.itemAction {
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#castContent .cardScalable {
width: 3.8cm;
height: 3.8cm;
}
#castContent .cardOverlayButton-br {
bottom: 4%;
right: 15%;
width: 70%;
}
#castContent .cardOverlayButton.cardOverlayButton-hover.itemAction.paper-icon-button-light {
margin: auto;
}
#castContent .cardBox:not(.visualCardBox) .cardPadder {
background-color: unset;
}
#castContent .cardBox:not(.visualCardBox) .cardPadder,
#castContent .cardContent-shadow {
box-shadow: unset;
}

View File

@@ -0,0 +1,34 @@
/*
Этот модуль делает боковую панель статичной (не прокручивается вместе со страницей).
Простой способ сделать Jellyfin более современным.
Может использоваться как отдельный модуль.
*/
.layout-desktop .mainDrawer,
.MuiDrawer-paperAnchorLeft {
left: 0 !important;
top: 0;
width: 250px !important;
background-color: var(--theme-sidebar-background-colour) !important;
z-index: 100;
}
.layout-desktop .mainDrawerButton,
.layout-desktop .headerHomeButton {
display: none;
}
.layout-desktop .libraryPage:not(#editItemMetadataPage) {
margin-left: 250px;
width: calc(100% - 250px);
}
.layout-desktop #slides-container {
margin-left: 320px;
width: calc(100% - 385px);
}
.layout-desktop .hide-scroll .mainDrawer,
.layout-desktop .hideMainDrawer .mainDrawer {
display: none;
}