diff --git a/package-lock.json b/package-lock.json
index 761e22009..b33d3b7ce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"@fontsource/noto-sans-tc": "5.2.5",
"@jellyfin/libass-wasm": "4.2.3",
"@jellyfin/sdk": "0.0.0-unstable.202504100501",
+ "@jellyfin/ux-web": "1.0.0",
"@mui/icons-material": "6.4.10",
"@mui/material": "6.4.10",
"@mui/x-date-pickers": "7.28.2",
@@ -4097,6 +4098,11 @@
"axios": "^1.3.4"
}
},
+ "node_modules/@jellyfin/ux-web": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@jellyfin/ux-web/-/ux-web-1.0.0.tgz",
+ "integrity": "sha512-3uBl/CMkWBsL2aD5xmg5qEQcN57ZJE/d5JktbwxXgWPrfa9A6KltivvcEltY4zVyT6btGgLy7sKmtFyu6gQ7dw=="
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -24604,9 +24610,9 @@
}
},
"node_modules/tslib": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
- "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==",
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"devOptional": true
},
"node_modules/tunnel-agent": {
@@ -28558,6 +28564,11 @@
"integrity": "sha512-Qpmn8+TQz//EJjkhcXmhq5cytcIsQhxRQz943udlKoRXbz9UdnnMq/VUngMg+F+FHbDM1TTpb3h1Ki3tCH/HFw==",
"requires": {}
},
+ "@jellyfin/ux-web": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@jellyfin/ux-web/-/ux-web-1.0.0.tgz",
+ "integrity": "sha512-3uBl/CMkWBsL2aD5xmg5qEQcN57ZJE/d5JktbwxXgWPrfa9A6KltivvcEltY4zVyT6btGgLy7sKmtFyu6gQ7dw=="
+ },
"@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -42679,9 +42690,9 @@
}
},
"tslib": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
- "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==",
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"devOptional": true
},
"tunnel-agent": {
diff --git a/package.json b/package.json
index 6863ada04..78335b2f2 100644
--- a/package.json
+++ b/package.json
@@ -85,6 +85,7 @@
"@fontsource/noto-sans-tc": "5.2.5",
"@jellyfin/libass-wasm": "4.2.3",
"@jellyfin/sdk": "0.0.0-unstable.202504100501",
+ "@jellyfin/ux-web": "1.0.0",
"@mui/icons-material": "6.4.10",
"@mui/material": "6.4.10",
"@mui/x-date-pickers": "7.28.2",
diff --git a/src/apps/experimental/components/drawers/DrawerHeaderLink.tsx b/src/apps/experimental/components/drawers/DrawerHeaderLink.tsx
index 7f9b14206..f60a87fef 100644
--- a/src/apps/experimental/components/drawers/DrawerHeaderLink.tsx
+++ b/src/apps/experimental/components/drawers/DrawerHeaderLink.tsx
@@ -6,7 +6,7 @@ import React from 'react';
import { useSystemInfo } from 'hooks/useSystemInfo';
import ListItemLink from 'components/ListItemLink';
-import appIcon from 'assets/img/icon-transparent.png';
+import appIcon from '@jellyfin/ux-web/icon-transparent.png';
const DrawerHeaderLink = () => {
const { data: systemInfo } = useSystemInfo();
diff --git a/src/assets/img/banner-dark.png b/src/assets/img/banner-dark.png
deleted file mode 100644
index 7189aac21..000000000
Binary files a/src/assets/img/banner-dark.png and /dev/null differ
diff --git a/src/assets/img/banner-light.png b/src/assets/img/banner-light.png
deleted file mode 100644
index 769801160..000000000
Binary files a/src/assets/img/banner-light.png and /dev/null differ
diff --git a/src/assets/img/icon-transparent.png b/src/assets/img/icon-transparent.png
deleted file mode 100644
index 76ef75baf..000000000
Binary files a/src/assets/img/icon-transparent.png and /dev/null differ
diff --git a/src/favicon.ico b/src/favicon.ico
deleted file mode 100644
index a127e27d4..000000000
Binary files a/src/favicon.ico and /dev/null differ
diff --git a/src/favicon.png b/src/favicon.png
deleted file mode 100644
index 7300170d9..000000000
Binary files a/src/favicon.png and /dev/null differ
diff --git a/src/index.html b/src/index.html
index 550cec1ec..fca71a44a 100644
--- a/src/index.html
+++ b/src/index.html
@@ -15,9 +15,9 @@
-
-
-
+
+
+
Jellyfin
@@ -80,37 +80,6 @@
[dir="rtl"] .mainDrawerHandle {
left: 0;
}
-
- @keyframes fadein {
- from {
- opacity: 0;
- }
-
- to {
- opacity: 1;
- }
- }
-
- .splashLogo {
- animation: fadein 0.5s;
- width: 30%;
- height: 30%;
- background-image: url(assets/img/icon-transparent.png);
- background-position: center center;
- background-repeat: no-repeat;
- background-size: contain;
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- }
-
- @media screen
- and (min-device-width: 992px) {
- .splashLogo {
- background-image: url(assets/img/banner-light.png);
- }
- }
diff --git a/src/manifest.json b/src/manifest.json
index 1e8f9dd71..144f32840 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -10,22 +10,22 @@
"icons": [
{
"sizes": "72x72",
- "src": "touchicon72.png",
+ "src": "favicons/touchicon72.png",
"type": "image/png"
},
{
"sizes": "114x114",
- "src": "touchicon114.png",
+ "src": "favicons/touchicon114.png",
"type": "image/png"
},
{
"sizes": "144x144",
- "src": "touchicon144.png",
+ "src": "favicons/touchicon144.png",
"type": "image/png"
},
{
"sizes": "512x512",
- "src": "touchicon512.png",
+ "src": "favicons/touchicon512.png",
"type": "image/png"
}
]
diff --git a/src/plugins/logoScreensaver/plugin.js b/src/plugins/logoScreensaver/plugin.js
index 06d643d77..37535d0ff 100644
--- a/src/plugins/logoScreensaver/plugin.js
+++ b/src/plugins/logoScreensaver/plugin.js
@@ -1,3 +1,5 @@
+import icon from '@jellyfin/ux-web/icon-transparent.png';
+
import { PluginType } from '../../types/plugin.ts';
import { randomInt } from '../../utils/number.ts';
@@ -133,7 +135,7 @@ export default function () {
elem.classList.add('logoScreenSaver');
document.body.appendChild(elem);
- elem.innerHTML = '
';
+ elem.innerHTML = `
`;
}
stopInterval();
diff --git a/src/styles/site.scss b/src/styles/site.scss
index 429305b7d..3cb2d1fe7 100644
--- a/src/styles/site.scss
+++ b/src/styles/site.scss
@@ -4,6 +4,37 @@
height: 100%;
}
+@keyframes fadein {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+
+.splashLogo {
+ animation: fadein 0.5s;
+ width: 30%;
+ height: 30%;
+ background-image: url(@jellyfin/ux-web/icon-transparent.png);
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: contain;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+@media screen
+ and (min-device-width: 992px) {
+ .splashLogo {
+ background-image: url(@jellyfin/ux-web/banner-light.png);
+ }
+}
+
html {
@include fullpage;
line-height: 1.35;
diff --git a/src/themes/appletv/theme.scss b/src/themes/appletv/theme.scss
index bee10ed5f..71cbabcd9 100644
--- a/src/themes/appletv/theme.scss
+++ b/src/themes/appletv/theme.scss
@@ -35,11 +35,11 @@ html {
}
.pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/banner-dark.png);
+ background-image: url(@jellyfin/ux-web/banner-dark.png);
}
.layout-tv .pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/icon-transparent.png);
+ background-image: url(@jellyfin/ux-web/icon-transparent.png);
}
html {
diff --git a/src/themes/blueradiance/theme.scss b/src/themes/blueradiance/theme.scss
index aabfaba6b..c6d0d7c68 100644
--- a/src/themes/blueradiance/theme.scss
+++ b/src/themes/blueradiance/theme.scss
@@ -35,11 +35,11 @@ html {
}
.pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/banner-light.png);
+ background-image: url(@jellyfin/ux-web/banner-light.png);
}
.layout-tv .pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/icon-transparent.png);
+ background-image: url(@jellyfin/ux-web/icon-transparent.png);
}
.dialog,
diff --git a/src/themes/dark/theme.scss b/src/themes/dark/theme.scss
index f7447c4c8..f055a4cfc 100644
--- a/src/themes/dark/theme.scss
+++ b/src/themes/dark/theme.scss
@@ -34,11 +34,11 @@ html {
}
.pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/banner-light.png);
+ background-image: url(@jellyfin/ux-web/banner-light.png);
}
.layout-tv .pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/icon-transparent.png);
+ background-image: url(@jellyfin/ux-web/icon-transparent.png);
}
.backgroundContainer,
diff --git a/src/themes/light/theme.scss b/src/themes/light/theme.scss
index feedf23a1..f0235dc97 100644
--- a/src/themes/light/theme.scss
+++ b/src/themes/light/theme.scss
@@ -44,11 +44,11 @@ html {
}
.pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/banner-light.png);
+ background-image: url(@jellyfin/ux-web/banner-light.png);
}
.layout-tv .pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/icon-transparent.png);
+ background-image: url(@jellyfin/ux-web/icon-transparent.png);
}
.backgroundContainer,
diff --git a/src/themes/purplehaze/theme.scss b/src/themes/purplehaze/theme.scss
index 87e4f7cc3..5e47b2353 100644
--- a/src/themes/purplehaze/theme.scss
+++ b/src/themes/purplehaze/theme.scss
@@ -31,11 +31,11 @@ html {
}
.pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/banner-light.png);
+ background-image: url(@jellyfin/ux-web/banner-light.png);
}
.layout-tv .pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/icon-transparent.png);
+ background-image: url(@jellyfin/ux-web/icon-transparent.png);
}
.dialog,
diff --git a/src/themes/wmc/theme.scss b/src/themes/wmc/theme.scss
index 5d62369a8..2749ca1cf 100644
--- a/src/themes/wmc/theme.scss
+++ b/src/themes/wmc/theme.scss
@@ -41,11 +41,11 @@ html {
}
.pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/banner-light.png);
+ background-image: url(@jellyfin/ux-web/banner-light.png);
}
.layout-tv .pageTitleWithDefaultLogo {
- background-image: url(../../assets/img/icon-transparent.png);
+ background-image: url(@jellyfin/ux-web/icon-transparent.png);
}
.backgroundContainer,
diff --git a/src/touchicon.png b/src/touchicon.png
deleted file mode 100644
index 8ad4ee0af..000000000
Binary files a/src/touchicon.png and /dev/null differ
diff --git a/src/touchicon114.png b/src/touchicon114.png
deleted file mode 100644
index 1a04cfa87..000000000
Binary files a/src/touchicon114.png and /dev/null differ
diff --git a/src/touchicon144.png b/src/touchicon144.png
deleted file mode 100644
index 87081ec3f..000000000
Binary files a/src/touchicon144.png and /dev/null differ
diff --git a/src/touchicon512.png b/src/touchicon512.png
deleted file mode 100644
index a253b46e1..000000000
Binary files a/src/touchicon512.png and /dev/null differ
diff --git a/src/touchicon72.png b/src/touchicon72.png
deleted file mode 100644
index dfefc075f..000000000
Binary files a/src/touchicon72.png and /dev/null differ
diff --git a/webpack.common.js b/webpack.common.js
index b66f0b761..4fa50976f 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -80,35 +80,24 @@ const config = {
new CopyPlugin({
patterns: [
{
- from: 'assets/**',
- globOptions: {
- dot: true,
- ignore: ['**/css/*']
- }
+ from: 'assets',
+ to: 'assets'
},
+ 'config.json',
+ 'robots.txt',
{
- from: '*.*',
- globOptions: {
- dot: true,
- ignore: [
- '**.js',
- '**.jsx',
- '**.html',
- '**.ts',
- '**.tsx'
- ]
- }
- }
+ from: 'touchicon*.png',
+ context: path.resolve(__dirname, 'node_modules/@jellyfin/ux-web/favicons'),
+ to: 'favicons'
+ },
+ ...Assets.map(asset => {
+ return {
+ from: path.resolve(__dirname, `node_modules/${asset}`),
+ to: 'libraries'
+ };
+ })
]
}),
- new CopyPlugin({
- patterns: Assets.map(asset => {
- return {
- from: path.resolve(__dirname, `./node_modules/${asset}`),
- to: path.resolve(__dirname, './dist/libraries')
- };
- })
- }),
// The libarchive.js worker-bundle is copied manually.
// If it is automatically bundled, escheck will fail since it uses import.meta.url.
new IgnorePlugin({
@@ -139,7 +128,7 @@ const config = {
if (pathData.filename.startsWith('assets/') || pathData.filename.startsWith('themes/')) {
return '[path][base][query]';
}
- return '[hash][ext][query]';
+ return '[name].[hash][ext][query]';
},
path: path.resolve(__dirname, 'dist'),
publicPath: ''
@@ -359,7 +348,7 @@ const config = {
]
},
{
- test: /\.(png|jpg|gif|svg)$/i,
+ test: /\.(ico|png|jpg|gif|svg)$/i,
type: 'asset/resource'
},
{