Merge pull request #1624 from Materialious/update/1.16.24
Update/1.16.24
This commit is contained in:
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "us.materialio.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 240
|
||||
versionName "1.16.23"
|
||||
versionCode 241
|
||||
versionName "1.16.24"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
||||
@@ -82,7 +82,11 @@
|
||||
|
||||
|
||||
|
||||
<release version="1.16.23" date="2026-3-25">
|
||||
|
||||
<release version="1.16.24" date="2026-4-07">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.16.24</url>
|
||||
</release>
|
||||
<release version="1.16.23" date="2026-3-25">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.16.23</url>
|
||||
</release>
|
||||
<release version="1.16.22" date="2026-3-17">
|
||||
|
||||
Generated
+30
-30
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "Materialious",
|
||||
"version": "1.16.22",
|
||||
"version": "1.16.23",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "Materialious",
|
||||
"version": "1.16.22",
|
||||
"version": "1.16.23",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@capacitor-community/electron": "^5.0.0",
|
||||
@@ -22,7 +22,7 @@
|
||||
"youtubei.js": "^17.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^41.0.3",
|
||||
"electron": "^41.1.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
"typescript": "^5.9.3"
|
||||
@@ -401,9 +401,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/asar/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1652,9 +1652,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
|
||||
"version": "0.8.12",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz",
|
||||
"integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
@@ -2183,9 +2183,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2390,9 +2390,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cacache/node_modules/rimraf/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2956,9 +2956,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dir-compare/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3105,9 +3105,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "41.0.3",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-41.0.3.tgz",
|
||||
"integrity": "sha512-IDjx8liW1q+r7+MOip5W1Eo1eMwJzVObmYrd9yz2dPCkS7XlgLq3qPVMR80TpiROFp73iY30kTzMdpA6fEVs3A==",
|
||||
"version": "41.1.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-41.1.0.tgz",
|
||||
"integrity": "sha512-0XRFyxRqetmqtkkBvV++wGbHYJ7bD++f6EgJW8y9kX4pPRagwlmKDtzqXZhKiu0DIQppm3sXxzHWK9GYP91OKQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
@@ -3886,9 +3886,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -4856,9 +4856,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch/node_modules/brace-expansion": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz",
|
||||
"integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
@@ -5376,9 +5376,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Materialious",
|
||||
"version": "1.16.23",
|
||||
"version": "1.16.24",
|
||||
"description": "Modern material design for YouTube and Invidious.",
|
||||
"author": {
|
||||
"name": "Ward Pearce",
|
||||
@@ -35,7 +35,7 @@
|
||||
"youtubei.js": "^17.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^41.0.3",
|
||||
"electron": "^41.1.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
"typescript": "^5.9.3"
|
||||
|
||||
Generated
+50
-50
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "materialious",
|
||||
"version": "1.16.22",
|
||||
"version": "1.16.24",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "materialious",
|
||||
"version": "1.16.22",
|
||||
"version": "1.16.24",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@capacitor-community/electron": "^5.0.1",
|
||||
@@ -91,7 +91,7 @@
|
||||
"tslib": "^2.7.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.55.0",
|
||||
"vite": "^7.3.1"
|
||||
"vite": "^7.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@acemir/cssom": {
|
||||
@@ -1972,9 +1972,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/assets/node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3037,9 +3037,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array/node_modules/brace-expansion": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5002,9 +5002,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-commonjs/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -5107,9 +5107,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -6479,9 +6479,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz",
|
||||
"integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -7669,9 +7669,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -9792,9 +9792,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/brace-expansion": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10167,9 +10167,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/filelist/node_modules/brace-expansion": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz",
|
||||
"integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10877,15 +10877,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/brace-expansion": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz",
|
||||
"integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/minimatch": {
|
||||
@@ -11008,9 +11008,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/handlebars": {
|
||||
"version": "4.7.8",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
|
||||
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
|
||||
"version": "4.7.9",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
|
||||
"integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -14856,9 +14856,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -17660,9 +17660,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -18301,9 +18301,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz",
|
||||
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -18450,9 +18450,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -18929,16 +18929,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/workbox-build/node_modules/brace-expansion": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz",
|
||||
"integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/workbox-build/node_modules/estree-walker": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "materialious",
|
||||
"version": "1.16.23",
|
||||
"version": "1.16.24",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run patch:github && vite dev",
|
||||
@@ -44,7 +44,7 @@
|
||||
"tslib": "^2.7.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.55.0",
|
||||
"vite": "^7.3.1"
|
||||
"vite": "^7.3.2"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -58,16 +58,16 @@
|
||||
<nav>
|
||||
<a href={resolve(`/channel/[authorId]`, { authorId: channel.authorId })}>
|
||||
<nav style="gap: 0.5em;">
|
||||
<img class="circle large" {...avatar.image} alt="Channel profile" />
|
||||
<img class="circle" {...avatar.image} alt="Channel profile" />
|
||||
<button
|
||||
class="circle large secondary-container"
|
||||
class="circle small secondary-container"
|
||||
{...mergeAttrs(avatar.fallback, {
|
||||
style: 'text-transform: uppercase;border-radius: 2.5rem !important;'
|
||||
})}>{channel.author[0]}</button
|
||||
>
|
||||
<div>
|
||||
<p style="margin: 0;" class="bold">
|
||||
{$isAndroidTvStore ? channel.author : truncate(channel.author, 16)}
|
||||
{$isAndroidTvStore ? channel.author : truncate(channel.author, 14)}
|
||||
</p>
|
||||
<p style="margin: 0;">{channel.subCountText}</p>
|
||||
</div>
|
||||
|
||||
@@ -19,14 +19,20 @@
|
||||
if (src) avatarSrc = proxyGoogleImage(src);
|
||||
});
|
||||
});
|
||||
|
||||
function goToChannel() {
|
||||
goto(resolve('/channel/[authorId]', { authorId }));
|
||||
}
|
||||
</script>
|
||||
|
||||
<img class="circle small" {...avatar.image} alt="Channel profile" />
|
||||
<img
|
||||
class="circle small"
|
||||
{...mergeAttrs(avatar.image, { onclick: goToChannel })}
|
||||
alt="Channel profile"
|
||||
/>
|
||||
<button
|
||||
class="circle secondary-container"
|
||||
onclick={() => {
|
||||
goto(resolve('/channel/[authorId]', { authorId }));
|
||||
}}
|
||||
onclick={goToChannel}
|
||||
{...mergeAttrs(avatar.fallback, {
|
||||
style: 'text-transform: uppercase;border-radius: 2.5rem !important;'
|
||||
})}>{author[0]}</button
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
let fillColor = $state('');
|
||||
|
||||
async function setFill() {
|
||||
fillColor = (await getDynamicTheme())['--primary'];
|
||||
fillColor = (await getDynamicTheme())['--primary'] ?? '#fff';
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
|
||||
@@ -448,6 +448,8 @@
|
||||
transform: translateY(-50%);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-right-radius: var(--player-border-radius);
|
||||
border-bottom-right-radius: var(--player-border-radius);
|
||||
opacity: 0.5;
|
||||
|
||||
@@ -6,10 +6,21 @@
|
||||
import { importSubscriptions } from '$lib/importExport';
|
||||
import { postSubscribeInvidious } from '$lib/api/invidious/subscribe';
|
||||
import { getSubscriptionsInvidious } from '$lib/api/invidious/feed';
|
||||
import { backendInUseStore, invidiousAuthStore, invidiousInstanceStore } from '$lib/store';
|
||||
import {
|
||||
backendInUseStore,
|
||||
interfaceAdvancedThemingStore,
|
||||
interfaceBorderRadiusStore,
|
||||
invidiousAuthStore,
|
||||
invidiousInstanceStore
|
||||
} from '$lib/store';
|
||||
import { Clipboard } from '@capacitor/clipboard';
|
||||
import { loadSettingsFromFile, settingsToJson } from '$lib/externalSettings';
|
||||
import {
|
||||
bookmarkletSaveToUrl,
|
||||
loadSettingsFromFile,
|
||||
settingsToJson
|
||||
} from '$lib/externalSettings';
|
||||
import { downloadStringAsFile } from '$lib/misc';
|
||||
import { zNumber, zThemeColors } from '$lib/externalSettings/settings';
|
||||
|
||||
async function importInvidiousSubs() {
|
||||
const importedSubs = await getSubscriptionsInvidious();
|
||||
@@ -179,3 +190,79 @@
|
||||
type="file"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h3>{$_('layout.theme.theme')}</h3>
|
||||
<div class="space"></div>
|
||||
<button
|
||||
class="no-margin surface-container-highest"
|
||||
onclick={async () => {
|
||||
await Clipboard.write({
|
||||
string: bookmarkletSaveToUrl([
|
||||
{
|
||||
name: 'advancedTheming',
|
||||
store: interfaceAdvancedThemingStore,
|
||||
schema: zThemeColors,
|
||||
serialize: JSON.stringify
|
||||
},
|
||||
{
|
||||
name: 'borderRadius',
|
||||
store: interfaceBorderRadiusStore,
|
||||
schema: zNumber
|
||||
}
|
||||
])
|
||||
});
|
||||
|
||||
addToast({
|
||||
data: {
|
||||
text: $_('player.share.copiedSuccess')
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
<i>content_copy</i>
|
||||
<span>{$_('layout.export.exportToShareUrl')}</span>
|
||||
</button>
|
||||
|
||||
<div class="space"></div>
|
||||
<button
|
||||
class="no-margin surface-container-highest"
|
||||
onclick={async () => {
|
||||
downloadStringAsFile(
|
||||
settingsToJson([
|
||||
{
|
||||
name: 'advancedTheming',
|
||||
store: interfaceAdvancedThemingStore,
|
||||
schema: zThemeColors,
|
||||
serialize: JSON.stringify
|
||||
},
|
||||
{
|
||||
name: 'borderRadius',
|
||||
store: interfaceBorderRadiusStore,
|
||||
schema: zNumber
|
||||
}
|
||||
]),
|
||||
'materialious-theme.json'
|
||||
);
|
||||
}}
|
||||
>
|
||||
<i>file_export</i>
|
||||
<span>{$_('layout.export.exportToFile')}</span>
|
||||
</button>
|
||||
|
||||
<div class="space"></div>
|
||||
<div>
|
||||
<button class="surface-container-highest">
|
||||
<i>attach_file</i>
|
||||
<span>{$_('layout.export.importFromFile')}</span>
|
||||
</button>
|
||||
<input
|
||||
onchange={async (event: Event) => {
|
||||
const files = (event.target as HTMLInputElement).files;
|
||||
if (files?.length === 0 || !files) return;
|
||||
|
||||
await loadSettingsFromFile(files[0]);
|
||||
}}
|
||||
accept=".json"
|
||||
type="file"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { bookmarkletSaveToUrl } from '$lib/externalSettings/index';
|
||||
import { letterCase, titleCases, type TitleCase } from '$lib/letterCasing';
|
||||
import { setAmoledTheme } from '$lib/theme';
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import ui from 'beercss';
|
||||
import { iso31661 } from 'iso-3166';
|
||||
import type { RgbaColor, HsvaColor, Colord } from 'colord';
|
||||
import { _ } from '$lib/i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import { isUnrestrictedPlatform, timeout, shareURL } from '$lib/misc';
|
||||
import { getPages, type Pages } from '$lib/navPages';
|
||||
import { setInvidiousInstance, goToInvidiousLogin, invidiousLogout } from '$lib/auth';
|
||||
import ColorPicker from 'svelte-awesome-color-picker';
|
||||
import {
|
||||
invidiousAuthStore,
|
||||
backendInUseStore,
|
||||
darkModeStore,
|
||||
invidiousInstanceStore,
|
||||
interfaceAllowInsecureRequests,
|
||||
interfaceAmoledTheme,
|
||||
interfaceAndroidUseNativeShare,
|
||||
interfaceAutoExpandChapters,
|
||||
interfaceAutoExpandComments,
|
||||
@@ -30,46 +24,14 @@
|
||||
interfaceSearchHistoryEnabled,
|
||||
interfaceSearchSuggestionsStore,
|
||||
searchHistoryStore,
|
||||
themeColorStore,
|
||||
watchHistoryEnabledStore
|
||||
} from '../../store';
|
||||
import { tick } from 'svelte';
|
||||
import { isOwnBackend } from '$lib/shared';
|
||||
import ComboBox from '../ComboBox.svelte';
|
||||
|
||||
let invidiousInstance = $state(get(invidiousInstanceStore));
|
||||
|
||||
let invalidInstance = $state(false);
|
||||
let colorPickerOpen = $state(false);
|
||||
let colorPickerDebounce: ReturnType<typeof setTimeout>;
|
||||
|
||||
async function setColor(color: {
|
||||
hsv: HsvaColor | null;
|
||||
rgb: RgbaColor | null;
|
||||
hex: string | null;
|
||||
color: Colord | null;
|
||||
}) {
|
||||
if (!color.hex) return;
|
||||
if (colorPickerDebounce) clearTimeout(colorPickerDebounce);
|
||||
|
||||
colorPickerDebounce = setTimeout(async () => {
|
||||
themeColorStore.set(color.hex);
|
||||
await tick();
|
||||
setAmoledTheme();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function toggleDarkMode() {
|
||||
const isDark = get(darkModeStore);
|
||||
|
||||
if (isDark) {
|
||||
ui('mode', 'light');
|
||||
darkModeStore.set(false);
|
||||
} else {
|
||||
ui('mode', 'dark');
|
||||
darkModeStore.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
async function setInstance(event: Event) {
|
||||
event.preventDefault();
|
||||
@@ -130,7 +92,7 @@
|
||||
<form onsubmit={setInstance}>
|
||||
<nav>
|
||||
<div
|
||||
class="field prefix suffix label surface-container-highest max"
|
||||
class="field prefix label surface-container-highest max"
|
||||
class:invalid={invalidInstance}
|
||||
>
|
||||
<i>link</i>
|
||||
@@ -144,17 +106,6 @@
|
||||
{#if invalidInstance}
|
||||
<span class="error">{$_('invalidInstance')}</span>
|
||||
{/if}
|
||||
{#if $invidiousInstanceStore}
|
||||
<i
|
||||
role="presentation"
|
||||
class="front"
|
||||
onclick={() => {
|
||||
invidiousInstanceStore.set(undefined);
|
||||
invidiousInstance = undefined;
|
||||
invidiousLogout();
|
||||
}}>close</i
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<button class="circle">
|
||||
<i>done</i>
|
||||
@@ -199,57 +150,6 @@
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<button onclick={toggleDarkMode} class="no-margin surface-container-highest">
|
||||
{#if !$darkModeStore}
|
||||
<i>dark_mode</i>
|
||||
<span>{$_('layout.theme.darkMode')}</span>
|
||||
{:else}
|
||||
<i>light_mode</i>
|
||||
<span>{$_('layout.theme.lightMode')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
<button class="surface-container-highest" onclick={() => (colorPickerOpen = !colorPickerOpen)}>
|
||||
<i>palette</i>
|
||||
<span>{$_('layout.theme.color')}</span>
|
||||
</button>
|
||||
|
||||
{#if colorPickerOpen}
|
||||
<div class="space"></div>
|
||||
|
||||
<div class="color-picker">
|
||||
<ColorPicker
|
||||
isTextInput={false}
|
||||
isDialog={false}
|
||||
onInput={setColor}
|
||||
position="responsive"
|
||||
isAlpha={false}
|
||||
hex={get(themeColorStore)}
|
||||
sliderDirection="horizontal"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="space"></div>
|
||||
|
||||
{#if $darkModeStore}
|
||||
<div class="field no-margin">
|
||||
<nav class="no-padding">
|
||||
<div class="max">
|
||||
<div>{$_('layout.theme.AmoledTheme')}</div>
|
||||
</div>
|
||||
<label class="switch" tabindex="0">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={$interfaceAmoledTheme}
|
||||
onclick={() => interfaceAmoledTheme.set(!$interfaceAmoledTheme)}
|
||||
role="switch"
|
||||
/>
|
||||
<span></span>
|
||||
</label>
|
||||
</nav>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="field no-margin">
|
||||
<nav class="no-padding">
|
||||
<div class="max">
|
||||
@@ -447,22 +347,3 @@
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.color-picker {
|
||||
--cp-bg-color: var(--surface-container);
|
||||
--cp-border-color: transparent;
|
||||
--cp-text-color: var(--on-surface);
|
||||
--cp-input-color: var(--surface);
|
||||
--cp-button-hover-color: var(--surface-variant);
|
||||
--slider-width: 50px;
|
||||
--picker-width: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
.color-picker {
|
||||
--picker-width: 95vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import { mergeAttrs } from 'melt';
|
||||
import Filters from './Filters.svelte';
|
||||
import ExportImport from './ExportImport.svelte';
|
||||
import Theme from './Theme.svelte';
|
||||
|
||||
type TabCategories =
|
||||
| 'interface'
|
||||
@@ -27,7 +28,8 @@
|
||||
| 'engine'
|
||||
| 'account'
|
||||
| 'filters'
|
||||
| 'export';
|
||||
| 'export'
|
||||
| 'theme';
|
||||
|
||||
const tabCategories: Tabs<TabCategories> = new Tabs({
|
||||
value: 'interface',
|
||||
@@ -42,6 +44,7 @@
|
||||
|
||||
let tabs: { id: TabCategories; label: string; icon: string; component: Component }[] = $state([
|
||||
{ id: 'interface', label: $_('layout.interface'), icon: 'grid_view', component: Interface },
|
||||
{ id: 'theme', label: $_('layout.theme.theme'), icon: 'colors', component: Theme },
|
||||
{ id: 'player', label: $_('layout.player.title'), icon: 'smart_display', component: Player },
|
||||
{ id: 'filters', label: $_('layout.filter.title'), icon: 'filter_alt', component: Filters },
|
||||
{ id: 'ryd', label: 'Return YT Dislike', icon: 'thumb_down', component: Ryd },
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
{@const currentCategoryTrigger = $sponsorBlockCategoriesStore[sponsor.category]}
|
||||
|
||||
<div class="field middle-align">
|
||||
<nav class="no-padding">
|
||||
<nav class="no-padding combobox">
|
||||
<div class="max">
|
||||
<p>{sponsor.name}</p>
|
||||
</div>
|
||||
@@ -130,3 +130,12 @@
|
||||
</nav>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<style>
|
||||
@media screen and (max-width: 640px) {
|
||||
nav.combobox {
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
getDynamicTheme,
|
||||
setAmoledTheme,
|
||||
setThemeColor,
|
||||
type ThemeColors,
|
||||
type ThemeKey
|
||||
} from '$lib/theme';
|
||||
import ui from 'beercss';
|
||||
import type { RgbaColor, HsvaColor, Colord } from 'colord';
|
||||
import { _ } from '$lib/i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import ColorPicker from 'svelte-awesome-color-picker';
|
||||
import {
|
||||
darkModeStore,
|
||||
interfaceAdvancedThemingStore,
|
||||
interfaceAmoledTheme,
|
||||
interfaceBorderRadiusStore,
|
||||
themeColorStore
|
||||
} from '../../store';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { titleCase } from '$lib/letterCasing';
|
||||
|
||||
let colorPickerOpen = $state(false);
|
||||
let colorPickerDebounce: ReturnType<typeof setTimeout>;
|
||||
|
||||
let currentThemeColors: ThemeColors | undefined = $state();
|
||||
|
||||
onMount(async () => {
|
||||
currentThemeColors = await getDynamicTheme();
|
||||
});
|
||||
|
||||
async function setThemeColors() {
|
||||
await tick();
|
||||
|
||||
currentThemeColors = await getDynamicTheme();
|
||||
interfaceAdvancedThemingStore.set(currentThemeColors);
|
||||
}
|
||||
|
||||
async function colorOnInput(
|
||||
color: {
|
||||
hsv: HsvaColor | null;
|
||||
rgb: RgbaColor | null;
|
||||
hex: string | null;
|
||||
color: Colord | null;
|
||||
},
|
||||
propetyKey: ThemeKey
|
||||
) {
|
||||
if (colorPickerDebounce) clearTimeout(colorPickerDebounce);
|
||||
|
||||
colorPickerDebounce = setTimeout(async () => {
|
||||
if (!color.hex) return;
|
||||
setThemeColor(propetyKey, color.hex);
|
||||
await setThemeColors();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
async function themeColorOnInput(color: {
|
||||
hsv: HsvaColor | null;
|
||||
rgb: RgbaColor | null;
|
||||
hex: string | null;
|
||||
color: Colord | null;
|
||||
}) {
|
||||
if (!color.hex) return;
|
||||
if (colorPickerDebounce) clearTimeout(colorPickerDebounce);
|
||||
|
||||
colorPickerDebounce = setTimeout(async () => {
|
||||
interfaceAdvancedThemingStore.set({});
|
||||
|
||||
themeColorStore.set(color.hex);
|
||||
await tick();
|
||||
|
||||
setAmoledTheme();
|
||||
currentThemeColors = await getDynamicTheme();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
async function toggleDarkMode() {
|
||||
const isDark = get(darkModeStore);
|
||||
|
||||
interfaceAdvancedThemingStore.set({});
|
||||
|
||||
if (isDark) {
|
||||
ui('mode', 'light');
|
||||
darkModeStore.set(false);
|
||||
} else {
|
||||
ui('mode', 'dark');
|
||||
darkModeStore.set(true);
|
||||
}
|
||||
|
||||
currentThemeColors = await getDynamicTheme();
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={toggleDarkMode} class="no-margin surface-container-highest">
|
||||
{#if !$darkModeStore}
|
||||
<i>dark_mode</i>
|
||||
<span>{$_('layout.theme.darkMode')}</span>
|
||||
{:else}
|
||||
<i>light_mode</i>
|
||||
<span>{$_('layout.theme.lightMode')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
<button class="surface-container-highest" onclick={() => (colorPickerOpen = !colorPickerOpen)}>
|
||||
<i>palette</i>
|
||||
<span>{$_('layout.theme.color')}</span>
|
||||
</button>
|
||||
|
||||
{#if colorPickerOpen}
|
||||
<div class="space"></div>
|
||||
|
||||
<div class="color-picker global-color-picker">
|
||||
<ColorPicker
|
||||
isTextInput={false}
|
||||
isDialog={false}
|
||||
onInput={themeColorOnInput}
|
||||
position="responsive"
|
||||
isAlpha={false}
|
||||
hex={get(themeColorStore)}
|
||||
sliderDirection="horizontal"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="space"></div>
|
||||
|
||||
{#if $darkModeStore}
|
||||
<div class="field no-margin">
|
||||
<nav class="no-padding">
|
||||
<div class="max">
|
||||
<div>{$_('layout.theme.AmoledTheme')}</div>
|
||||
</div>
|
||||
<label class="switch" tabindex="0">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={$interfaceAmoledTheme}
|
||||
onclick={async () => {
|
||||
interfaceAdvancedThemingStore.set({});
|
||||
interfaceAmoledTheme.set(!$interfaceAmoledTheme);
|
||||
await setThemeColors();
|
||||
}}
|
||||
role="switch"
|
||||
/>
|
||||
<span></span>
|
||||
</label>
|
||||
</nav>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<h5>{$_('layout.theme.borderRadius.borderRadius')}</h5>
|
||||
<div class="grid">
|
||||
<div class="s6 m3 l3">
|
||||
<button
|
||||
onclick={() => {
|
||||
interfaceBorderRadiusStore.set(0);
|
||||
}}
|
||||
class="surface-container-highest"
|
||||
style="border-radius: 0 !important;width: 80%;"
|
||||
>
|
||||
<p>{$_('layout.theme.borderRadius.none')}</p>
|
||||
</button>
|
||||
</div>
|
||||
<div class="s6 m3 l3">
|
||||
<button
|
||||
onclick={() => {
|
||||
interfaceBorderRadiusStore.set(0.25);
|
||||
}}
|
||||
class="surface-container-highest"
|
||||
style="border-radius: 0.25rem !important;width: 80%;"
|
||||
>
|
||||
<p>{$_('layout.theme.borderRadius.slight')}</p>
|
||||
</button>
|
||||
</div>
|
||||
<div class="s6 m3 l3">
|
||||
<button
|
||||
onclick={() => {
|
||||
interfaceBorderRadiusStore.set(0.5);
|
||||
}}
|
||||
class="surface-container-highest"
|
||||
style="border-radius: 0.5rem !important;width: 80%;"
|
||||
>
|
||||
<p>{$_('layout.theme.borderRadius.modern')}</p>
|
||||
</button>
|
||||
</div>
|
||||
<div class="s6 m3 l3">
|
||||
<button
|
||||
onclick={() => {
|
||||
interfaceBorderRadiusStore.set(1);
|
||||
}}
|
||||
class="surface-container-highest"
|
||||
style="border-radius: 1rem !important;width: 80%;"
|
||||
>
|
||||
<p>{$_('layout.theme.borderRadius.rounded')}</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>{$_('layout.theme.advanced')}</h5>
|
||||
<div class="space"></div>
|
||||
|
||||
{#if currentThemeColors}
|
||||
{#each Object.entries(currentThemeColors) as [themeVar, themeColor] (themeVar)}
|
||||
<div class="color-picker">
|
||||
<ColorPicker
|
||||
hex={themeColor}
|
||||
label={titleCase(themeVar.replaceAll('--', '').replaceAll('-', ' '))}
|
||||
position="responsive"
|
||||
textInputModes={['hex']}
|
||||
sliderDirection="vertical"
|
||||
onInput={async (color) => await colorOnInput(color, themeVar as ThemeKey)}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.color-picker {
|
||||
--cp-bg-color: var(--surface-container);
|
||||
--cp-border-color: transparent;
|
||||
--cp-text-color: var(--on-surface);
|
||||
--cp-input-color: var(--surface);
|
||||
--cp-button-hover-color: var(--surface-variant);
|
||||
--slider-width: 30px;
|
||||
--picker-width: 350px;
|
||||
width: 100%;
|
||||
--input-size: 40px;
|
||||
}
|
||||
|
||||
.global-color-picker {
|
||||
--slider-width: 50px;
|
||||
--picker-width: 500px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
.global-color-picker {
|
||||
--picker-width: 95vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -43,6 +43,7 @@ body {
|
||||
|
||||
article {
|
||||
box-shadow: none !important;
|
||||
border-radius: var(--border-radius) !important;
|
||||
}
|
||||
|
||||
.primary-border {
|
||||
@@ -75,7 +76,17 @@ nav.bottom {
|
||||
}
|
||||
|
||||
dialog {
|
||||
border-radius: 0.25rem !important;
|
||||
border-radius: var(--border-radius) !important;
|
||||
}
|
||||
|
||||
:is(.button, button):not(.chip):active,
|
||||
:is(.button, button):not(.chip).active {
|
||||
border-radius: var(--border-radius) !important;
|
||||
}
|
||||
|
||||
nav:not(.max):is(.left, .right, .top, .bottom) > a:not(.button, .chip) > i,
|
||||
nav:not(.max):is(.left, .right, .top, .bottom) > :is(ol, ul) > li > a:not(.button, .chip) > i {
|
||||
border-radius: var(--border-radius) !important;
|
||||
}
|
||||
|
||||
main.root {
|
||||
@@ -103,7 +114,7 @@ menu {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.color-picker .picker {
|
||||
.global-color-picker .picker {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -183,7 +194,7 @@ menu.player-settings {
|
||||
|
||||
.player-slider [data-melt-slider-thumb] {
|
||||
position: absolute;
|
||||
border-radius: 1rem;
|
||||
border-radius: var(--player-border-radius);
|
||||
background: var(--primary);
|
||||
left: var(--percentage);
|
||||
top: 50%;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { page } from '$app/state';
|
||||
import { get } from 'svelte/store';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { persistedStores } from './settings';
|
||||
import { persistedStores, type PersistedStore } from './settings';
|
||||
|
||||
import { isOwnBackend } from '$lib/shared';
|
||||
import { addOrUpdateKeyValue, getKeyValue } from '$lib/api/backend/keyvalue';
|
||||
@@ -121,10 +121,10 @@ export function loadSettingsFromEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
export function bookmarkletSaveToUrl(): string {
|
||||
export function bookmarkletSaveToUrl(stores: PersistedStore<any>[] = persistedStores): string {
|
||||
const url = new URL(location.origin);
|
||||
|
||||
for (const { name, store, serialize, excludeFromBookmarklet } of persistedStores) {
|
||||
for (const { name, store, serialize, excludeFromBookmarklet } of stores) {
|
||||
const value = get(store);
|
||||
const encoded = serialize ? serialize(value) : value?.toString();
|
||||
|
||||
@@ -136,10 +136,10 @@ export function bookmarkletSaveToUrl(): string {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
export function settingsToJson(): string {
|
||||
export function settingsToJson(stores: PersistedStore<any>[] = persistedStores): string {
|
||||
const settings: Record<string, string> = {};
|
||||
|
||||
for (const { name, store, excludeFromBookmarklet } of persistedStores) {
|
||||
for (const { name, store, excludeFromBookmarklet } of stores) {
|
||||
const value = get(store);
|
||||
if (!excludeFromBookmarklet) {
|
||||
settings[name] = value;
|
||||
|
||||
@@ -53,11 +53,14 @@ import {
|
||||
playerPreferredVolumeStore,
|
||||
watchHistoryEnabledStore,
|
||||
filterContentUrlStore,
|
||||
filterContentUrlAutoUpdateStore
|
||||
filterContentUrlAutoUpdateStore,
|
||||
interfaceAdvancedThemingStore,
|
||||
interfaceBorderRadiusStore
|
||||
} from '$lib/store';
|
||||
import { isOwnBackend } from '$lib/shared';
|
||||
import { SUPPORTED_THEME_KEYS } from '$lib/shared/theme';
|
||||
|
||||
type PersistedStore<T> = {
|
||||
export type PersistedStore<T> = {
|
||||
name: string;
|
||||
store: Writable<T>;
|
||||
schema: z.ZodType<T>;
|
||||
@@ -66,17 +69,23 @@ type PersistedStore<T> = {
|
||||
excludeFromBackendSync?: boolean; // Won't be sync'd to account cloud
|
||||
};
|
||||
|
||||
const zBoolean = z.coerce.boolean();
|
||||
const zNumber = z.coerce.number();
|
||||
const zFloat = z.coerce.number().min(0).max(1);
|
||||
const zString = z.string();
|
||||
const zArray = z.array(z.string());
|
||||
const zChapterMode = z.enum(['automatic', 'manual', 'timeline']);
|
||||
const zChapterModeRecord = z.record(z.string(), zChapterMode.optional());
|
||||
const zAuth = z.object({
|
||||
export const zBoolean = z.coerce.boolean();
|
||||
export const zNumber = z.coerce.number();
|
||||
export const zFloat = z.coerce.number().min(0).max(1);
|
||||
export const zString = z.string();
|
||||
export const zArray = z.array(z.string());
|
||||
export const zChapterMode = z.enum(['automatic', 'manual', 'timeline']);
|
||||
export const zChapterModeRecord = z.record(z.string(), zChapterMode.optional());
|
||||
export const zAuth = z.object({
|
||||
username: z.string(),
|
||||
token: z.string()
|
||||
});
|
||||
export const zThemeColors = z.record(
|
||||
z.string().refine((val) => SUPPORTED_THEME_KEYS.includes(val), {
|
||||
message: 'CSS property not allowed'
|
||||
}),
|
||||
z.string().regex(/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)
|
||||
);
|
||||
|
||||
export const persistedStores: PersistedStore<any>[] = [
|
||||
{
|
||||
@@ -270,6 +279,17 @@ export const persistedStores: PersistedStore<any>[] = [
|
||||
name: 'filterContentUrlAutoUpdate',
|
||||
store: filterContentUrlAutoUpdateStore,
|
||||
schema: zBoolean
|
||||
},
|
||||
{
|
||||
name: 'advancedTheming',
|
||||
store: interfaceAdvancedThemingStore,
|
||||
schema: zThemeColors,
|
||||
serialize: JSON.stringify
|
||||
},
|
||||
{
|
||||
name: 'borderRadius',
|
||||
store: interfaceBorderRadiusStore,
|
||||
schema: zNumber
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ const zFilterRootSchema = z.object({
|
||||
});
|
||||
|
||||
export function isItemFiltered(item: FeedItem): boolean {
|
||||
console.log(item);
|
||||
const filteredContent = get(filterContentListStore);
|
||||
if (!filteredContent) return false;
|
||||
|
||||
|
||||
@@ -199,7 +199,15 @@
|
||||
"darkMode": "Dark mode",
|
||||
"lightMode": "Light mode",
|
||||
"AmoledTheme": "Amoled theme",
|
||||
"color": "Color"
|
||||
"color": "Color",
|
||||
"advanced": "Advanced theming",
|
||||
"borderRadius": {
|
||||
"none": "None",
|
||||
"slight": "Slight",
|
||||
"modern": "Modern",
|
||||
"rounded": "Rounded",
|
||||
"borderRadius": "Border radius"
|
||||
}
|
||||
},
|
||||
"searchSuggestions": "Search suggestions",
|
||||
"previewVideoOnHover": "Preview video on hover",
|
||||
@@ -287,7 +295,8 @@
|
||||
"exportSub": "Export subscriptions",
|
||||
"exportToClipboard": "Export to clipboard",
|
||||
"exportToFile": "Export to file",
|
||||
"importFromFile": "Import from file"
|
||||
"importFromFile": "Import from file",
|
||||
"exportToShareUrl": "Export to share URL"
|
||||
},
|
||||
"deArrow": {
|
||||
"title": "DeArrow",
|
||||
|
||||
@@ -221,7 +221,7 @@ export async function exportSubscriptionsAsFile(exportType: 'InvidiousJSON' | 'O
|
||||
if (data) {
|
||||
downloadStringAsFile(
|
||||
data,
|
||||
`materialious-export-${new Date().toDateString().replaceAll(' ', '')}.${exportType === 'InvidiousJSON' ? 'json' : 'opml'}`
|
||||
`materialious-export.${exportType === 'InvidiousJSON' ? 'json' : 'opml'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ export function downloadStringAsFile(content: string, filename: string) {
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.download = `${new Date().toDateString().replaceAll(' ', '')}-${filename}`;
|
||||
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
export const SUPPORTED_THEME_KEYS: string[] = [
|
||||
'--primary',
|
||||
'--on-primary',
|
||||
'--primary-container',
|
||||
'--on-primary-container',
|
||||
'--secondary',
|
||||
'--on-secondary',
|
||||
'--secondary-container',
|
||||
'--on-secondary-container',
|
||||
'--tertiary',
|
||||
'--on-tertiary',
|
||||
'--tertiary-container',
|
||||
'--on-tertiary-container',
|
||||
'--error',
|
||||
'--on-error',
|
||||
'--error-container',
|
||||
'--on-error-container',
|
||||
'--background',
|
||||
'--on-background',
|
||||
'--surface',
|
||||
'--on-surface',
|
||||
'--surface-variant',
|
||||
'--on-surface-variant',
|
||||
'--outline',
|
||||
'--outline-variant',
|
||||
'--shadow',
|
||||
'--scrim',
|
||||
'--inverse-surface',
|
||||
'--inverse-on-surface',
|
||||
'--inverse-primary',
|
||||
'--surface-dim',
|
||||
'--surface-bright',
|
||||
'--surface-container-lowest',
|
||||
'--surface-container-low',
|
||||
'--surface-container',
|
||||
'--surface-container-high',
|
||||
'--surface-container-highest'
|
||||
] as const;
|
||||
@@ -24,6 +24,7 @@ import { ensureNoTrailingSlash, getPublicEnv } from './misc';
|
||||
import type { EngineFallback } from './api/misc';
|
||||
import type z from 'zod';
|
||||
import type { zFilterSchema } from './filtering/index';
|
||||
import type { ThemeColors } from './theme';
|
||||
|
||||
function createListenerFunctions(): {
|
||||
callListeners: (eventKey: string, newValue: any) => void;
|
||||
@@ -260,6 +261,16 @@ export const interfaceAndroidUseNativeShare = persist(
|
||||
createStorage(),
|
||||
'androidUseNativeShare'
|
||||
);
|
||||
export const interfaceAdvancedThemingStore: Writable<ThemeColors> = persist(
|
||||
writable({}),
|
||||
createStorage(),
|
||||
'advancedTheming'
|
||||
);
|
||||
export const interfaceBorderRadiusStore: Writable<number> = persist(
|
||||
writable(0.5),
|
||||
createStorage(),
|
||||
'borderRadius'
|
||||
);
|
||||
|
||||
export const sponsorBlockStore = persist(writable(true), createStorage(), 'sponsorBlock');
|
||||
export const sponsorBlockUrlStore: Writable<string | null | undefined> = persist(
|
||||
|
||||
@@ -4,16 +4,61 @@ import { get } from 'svelte/store';
|
||||
import { SystemBars, SystemBarsStyle } from '@capacitor/core';
|
||||
import { darkModeStore, interfaceAmoledTheme } from './store';
|
||||
|
||||
export async function getDynamicTheme(mode?: string): Promise<Record<string, string>> {
|
||||
export type ThemeKey =
|
||||
| '--primary'
|
||||
| '--on-primary'
|
||||
| '--primary-container'
|
||||
| '--on-primary-container'
|
||||
| '--secondary'
|
||||
| '--on-secondary'
|
||||
| '--secondary-container'
|
||||
| '--on-secondary-container'
|
||||
| '--tertiary'
|
||||
| '--on-tertiary'
|
||||
| '--tertiary-container'
|
||||
| '--on-tertiary-container'
|
||||
| '--error'
|
||||
| '--on-error'
|
||||
| '--error-container'
|
||||
| '--on-error-container'
|
||||
| '--background'
|
||||
| '--on-background'
|
||||
| '--surface'
|
||||
| '--on-surface'
|
||||
| '--surface-variant'
|
||||
| '--on-surface-variant'
|
||||
| '--outline'
|
||||
| '--outline-variant'
|
||||
| '--shadow'
|
||||
| '--scrim'
|
||||
| '--inverse-surface'
|
||||
| '--inverse-on-surface'
|
||||
| '--inverse-primary'
|
||||
| '--surface-dim'
|
||||
| '--surface-bright'
|
||||
| '--surface-container-lowest'
|
||||
| '--surface-container-low'
|
||||
| '--surface-container'
|
||||
| '--surface-container-high'
|
||||
| '--surface-container-highest';
|
||||
|
||||
export type ThemeColors = Partial<Record<ThemeKey, string>>;
|
||||
|
||||
export async function getDynamicTheme(mode?: string): Promise<ThemeColors> {
|
||||
const givenSettings = await ui('theme');
|
||||
|
||||
if (typeof givenSettings !== 'object') return {};
|
||||
|
||||
// @ts-expect-error Works as expected
|
||||
const themes: string = givenSettings[mode ? mode : (ui('mode') as string)];
|
||||
const themeVars: Record<string, string> = {};
|
||||
themes.split(';').forEach((keyVar) => {
|
||||
for (const keyVar of themes.split(';')) {
|
||||
const [key, value] = keyVar.split(':');
|
||||
themeVars[key] = value;
|
||||
});
|
||||
themeVars[key] = window.getComputedStyle(document.body).getPropertyValue(key) ?? value;
|
||||
}
|
||||
|
||||
delete themeVars[''];
|
||||
|
||||
return themeVars;
|
||||
}
|
||||
|
||||
@@ -35,7 +80,7 @@ export function setAmoledTheme() {
|
||||
const isDark = get(darkModeStore);
|
||||
|
||||
if (isAmoled && isDark) {
|
||||
const rootVars = [
|
||||
const rootVars: ThemeKey[] = [
|
||||
'--surface-container',
|
||||
'--surface',
|
||||
'--surface-container-lowest',
|
||||
@@ -44,7 +89,7 @@ export function setAmoledTheme() {
|
||||
'--surface-container-highest'
|
||||
];
|
||||
rootVars.forEach((varName) => {
|
||||
document.body.style.setProperty(varName, '#000');
|
||||
setThemeColor(varName, '#000');
|
||||
});
|
||||
} else {
|
||||
setTheme();
|
||||
@@ -70,3 +115,14 @@ export function setTheme() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function setThemeColors(theme: ThemeColors) {
|
||||
for (const [themeKey, themeValue] of Object.entries(theme)) {
|
||||
setThemeColor(themeKey as ThemeKey, themeValue.trim());
|
||||
}
|
||||
}
|
||||
|
||||
export function setThemeColor(theme: ThemeKey, color: string) {
|
||||
document.documentElement.style.setProperty(theme, color.trim());
|
||||
document.body.style.setProperty(theme, color.trim());
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
playerState,
|
||||
playerTheatreModeIsActive,
|
||||
rawMasterKeyStore,
|
||||
themeColorStore,
|
||||
backendInUseStore,
|
||||
hideSearchStore
|
||||
} from '$lib/store';
|
||||
@@ -126,11 +125,6 @@
|
||||
notifications = feed.notifications;
|
||||
}
|
||||
|
||||
themeColorStore.subscribe(async (hex) => {
|
||||
if (!hex) return;
|
||||
await ui('theme', hex);
|
||||
});
|
||||
|
||||
function resetScroll() {
|
||||
const main = document.querySelector('main.root');
|
||||
if (main) main.scrollTop = 0;
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
playerTheatreModeByDefaultStore,
|
||||
playerTheatreModeIsActive,
|
||||
playlistCacheStore,
|
||||
type PlayerState
|
||||
type PlayerState,
|
||||
filterContentListStore
|
||||
} from '$lib/store';
|
||||
import ui from 'beercss';
|
||||
import { onDestroy, onMount, tick } from 'svelte';
|
||||
@@ -38,7 +39,7 @@
|
||||
import { page } from '$app/state';
|
||||
import Share from '$lib/components/Share.svelte';
|
||||
import Playlist from '$lib/components/watch/Playlist.svelte';
|
||||
import { isItemFiltered } from '$lib/filtering/index.js';
|
||||
import { isItemFiltered } from '$lib/filtering/index';
|
||||
|
||||
let { data = $bindable() } = $props();
|
||||
|
||||
@@ -398,26 +399,55 @@
|
||||
<div class="chapter-list" id="chapters">
|
||||
<ul class="list">
|
||||
{#each data.content.timestamps as timestamp (timestamp)}
|
||||
<li
|
||||
role="presentation"
|
||||
onclick={() => {
|
||||
if (playerElement) playerElement.currentTime = timestamp.time;
|
||||
}}
|
||||
>
|
||||
<li>
|
||||
<img
|
||||
class="round large"
|
||||
loading="lazy"
|
||||
src={getBestThumbnail(data.video.videoThumbnails) as string}
|
||||
alt="Thumbnail for current video"
|
||||
role="presentation"
|
||||
onclick={() => {
|
||||
if (playerElement) playerElement.currentTime = timestamp.time;
|
||||
}}
|
||||
/>
|
||||
<div class="max" style="white-space: pre-line; overflow-wrap: break-word;">
|
||||
<p style="no-margin no-padding">{timestamp.title}</p>
|
||||
<div
|
||||
role="presentation"
|
||||
onclick={() => {
|
||||
if (playerElement) playerElement.currentTime = timestamp.time;
|
||||
}}
|
||||
class="max"
|
||||
style="white-space: pre-line; overflow-wrap: break-word;"
|
||||
>
|
||||
<p style="margin: 0;">{timestamp.title}</p>
|
||||
<span
|
||||
class:primary={playerCurrentTime >= timestamp.time &&
|
||||
(playerCurrentTime <= timestamp.endTime || timestamp.endTime === -1)}
|
||||
class="chip no-margin">{timestamp.timePretty}</span
|
||||
>
|
||||
</div>
|
||||
<Share
|
||||
shares={[
|
||||
{
|
||||
type: 'materialious',
|
||||
path: resolve(`/watch/[videoId]?time=${Math.round(timestamp.time)}`, {
|
||||
videoId: data.video.videoId
|
||||
})
|
||||
},
|
||||
{
|
||||
type: 'invidious',
|
||||
path: `/watch?v=${data.video.videoId}&t=${Math.round(timestamp.time)}`
|
||||
},
|
||||
{
|
||||
type: 'invidious redirect',
|
||||
path: `/watch?v=${data.video.videoId}&t=${Math.round(timestamp.time)}`
|
||||
},
|
||||
{
|
||||
type: 'youtube',
|
||||
path: `/watch?v=${data.video.videoId}&t=${Math.round(timestamp.time)}`
|
||||
}
|
||||
]}
|
||||
iconOnly={true}
|
||||
/>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -461,15 +491,17 @@
|
||||
{#if data.playlistId && data.playlistId in $playlistCacheStore}
|
||||
<Playlist video={data.video} playlist={$playlistCacheStore[data.playlistId]} />
|
||||
{:else if data.video.recommendedVideos}
|
||||
{#each data.video.recommendedVideos as recommendedVideo (recommendedVideo.videoId)}
|
||||
{#if !isItemFiltered(recommendedVideo)}
|
||||
<article class="no-padding border">
|
||||
{#key recommendedVideo.videoId}
|
||||
<Thumbnail video={recommendedVideo} sideways={true} />
|
||||
{/key}
|
||||
</article>
|
||||
{/if}
|
||||
{/each}
|
||||
{#key $filterContentListStore?.length}
|
||||
{#each data.video.recommendedVideos as recommendedVideo (recommendedVideo.videoId)}
|
||||
{#if !isItemFiltered(recommendedVideo)}
|
||||
<article class="no-padding border">
|
||||
{#key recommendedVideo.videoId}
|
||||
<Thumbnail video={recommendedVideo} sideways={true} />
|
||||
{/key}
|
||||
</article>
|
||||
{/if}
|
||||
{/each}
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -557,6 +589,10 @@
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.video-actions button {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
.video-actions {
|
||||
align-items: flex-start;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
darkModeStore,
|
||||
interfaceAdvancedThemingStore,
|
||||
interfaceAmoledTheme,
|
||||
interfaceBorderRadiusStore,
|
||||
invidiousAuthStore,
|
||||
isAndroidTvStore,
|
||||
rawMasterKeyStore,
|
||||
@@ -15,7 +17,7 @@
|
||||
import 'beercss';
|
||||
import 'material-dynamic-colors';
|
||||
|
||||
import { setAmoledTheme, setStatusBarColor, setTheme } from '$lib/theme';
|
||||
import { setAmoledTheme, setStatusBarColor, setTheme, setThemeColors } from '$lib/theme';
|
||||
|
||||
import { pwaInfo } from 'virtual:pwa-info';
|
||||
import { onMount } from 'svelte';
|
||||
@@ -30,13 +32,30 @@
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
interfaceAmoledTheme.subscribe(async () => {
|
||||
setAmoledTheme();
|
||||
themeColorStore.subscribe(async (hex) => {
|
||||
if (!hex || Object.keys($interfaceAdvancedThemingStore).length > 0) return;
|
||||
await ui('theme', hex);
|
||||
});
|
||||
|
||||
interfaceAdvancedThemingStore.subscribe(async (colors) => {
|
||||
setThemeColors(colors);
|
||||
await setStatusBarColor();
|
||||
});
|
||||
|
||||
interfaceBorderRadiusStore.subscribe((radius) => {
|
||||
document.documentElement.style.setProperty('--border-radius', `${radius}rem`);
|
||||
});
|
||||
|
||||
interfaceAmoledTheme.subscribe(async () => {
|
||||
if (Object.keys($interfaceAdvancedThemingStore).length > 0) return;
|
||||
|
||||
setAmoledTheme();
|
||||
await setStatusBarColor();
|
||||
});
|
||||
|
||||
darkModeStore.subscribe(async () => {
|
||||
if (Object.keys($interfaceAdvancedThemingStore).length > 0) return;
|
||||
|
||||
setTheme();
|
||||
setAmoledTheme();
|
||||
|
||||
@@ -115,10 +134,7 @@
|
||||
// So user preferences overwrite instance preferences.
|
||||
bookmarkletLoadFromUrl();
|
||||
|
||||
await setStatusBarColor();
|
||||
|
||||
setTheme();
|
||||
setAmoledTheme();
|
||||
setThemeColors($interfaceAdvancedThemingStore);
|
||||
});
|
||||
|
||||
let syncToSettingsInitialized = false;
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function DELETE({ locals, params }) {
|
||||
}
|
||||
|
||||
const zUpdateKeyStore = z.object({
|
||||
valueCipher: z.string().max(1000),
|
||||
valueCipher: z.string().max(3000),
|
||||
valueNonce: z.string().max(255)
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -3,7 +3,7 @@ import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
LATEST_VERSION = "1.16.23"
|
||||
LATEST_VERSION = "1.16.24"
|
||||
RELEASE_DATE = datetime.now().strftime("%Y-%-m-%d") # Format: YYYY-M-D
|
||||
|
||||
WORKING_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "materialious")
|
||||
|
||||
Reference in New Issue
Block a user