mirror of
https://github.com/zoriya/Kyoo.git
synced 2026-05-25 08:32:27 -04:00
Rework entry and item grids
This commit is contained in:
+11
-12
@@ -87,22 +87,21 @@ export const expo: ExpoConfig = {
|
||||
fontFamily: "Poppins",
|
||||
fontDefinitions: [
|
||||
{
|
||||
fontFamily: "Poppins",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "300",
|
||||
file: "./node_modules/@expo-google-fonts/poppins/300Light/Poppins_300Light.ttf",
|
||||
path: "./node_modules/@expo-google-fonts/poppins/300Light/Poppins_300Light.ttf",
|
||||
weight: "300",
|
||||
},
|
||||
{
|
||||
fontFamily: "Poppins",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "500",
|
||||
file: "./node_modules/@expo-google-fonts/poppins/500Medium/Poppins_500Medium.ttf",
|
||||
path: "./node_modules/@expo-google-fonts/poppins/500Medium/Poppins_500Medium.ttf",
|
||||
weight: "500",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fontFamily: "Sora",
|
||||
fontDefinitions: [
|
||||
{
|
||||
fontFamily: "Sora",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "800",
|
||||
file: "./node_modules/@expo-google-fonts/sora/800ExtraBold/Sora_800ExtraBold.ttf",
|
||||
path: "./node_modules/@expo-google-fonts/sora/800ExtraBold/Sora_800ExtraBold.ttf",
|
||||
weight: "800",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+9
-11
@@ -20,7 +20,7 @@
|
||||
"@tanstack/react-query-devtools": "^5.91.2",
|
||||
"@types/langmap": "^0.0.3",
|
||||
"clsx": "^2.1.1",
|
||||
"expo": "~54.0.31",
|
||||
"expo": "~54.0.33",
|
||||
"expo-build-properties": "~1.0.10",
|
||||
"expo-constants": "~18.0.13",
|
||||
"expo-dev-client": "~6.0.20",
|
||||
@@ -29,7 +29,7 @@
|
||||
"expo-linear-gradient": "~15.0.8",
|
||||
"expo-linking": "~8.0.11",
|
||||
"expo-localization": "~17.0.8",
|
||||
"expo-router": "~6.0.21",
|
||||
"expo-router": "~6.0.23",
|
||||
"expo-splash-screen": "~31.0.13",
|
||||
"expo-status-bar": "~3.0.9",
|
||||
"expo-updates": "~29.0.16",
|
||||
@@ -53,7 +53,7 @@
|
||||
"react-native-svg-transformer": "^1.5.2",
|
||||
"react-native-video": "zoriya/react-native-video#build",
|
||||
"react-native-web": "^0.21.2",
|
||||
"react-native-worklets": "^0.5.1",
|
||||
"react-native-worklets": "0.5.1",
|
||||
"react-tooltip": "^5.29.1",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"sweetalert2": "^11.26.17",
|
||||
@@ -344,7 +344,7 @@
|
||||
|
||||
"@expo-google-fonts/sora": ["@expo-google-fonts/sora@0.4.2", "", {}, "sha512-X86Kl1cfObcSUzTLIbtmrPCLRlIbCNh0uBOo8bjmXb8gWgVVhnI8CZJEK2btsdq85JPn5k4P6sbV9JLbAm7dqQ=="],
|
||||
|
||||
"@expo/cli": ["@expo/cli@54.0.21", "", { "dependencies": { "@0no-co/graphql.web": "^1.0.8", "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devcert": "^1.2.1", "@expo/env": "~2.0.8", "@expo/image-utils": "^0.8.8", "@expo/json-file": "^10.0.8", "@expo/metro": "~54.2.0", "@expo/metro-config": "~54.0.13", "@expo/osascript": "^2.3.8", "@expo/package-manager": "^1.9.9", "@expo/plist": "^0.4.8", "@expo/prebuild-config": "^54.0.8", "@expo/schema-utils": "^0.1.8", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.3.0", "@react-native/dev-middleware": "0.81.5", "@urql/core": "^5.0.6", "@urql/exchange-retry": "^1.3.0", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "env-editor": "^0.4.1", "expo-server": "^1.0.5", "freeport-async": "^2.0.0", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.1.6", "minimatch": "^9.0.0", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^3.0.1", "pretty-bytes": "^5.6.0", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "qrcode-terminal": "0.11.0", "require-from-string": "^2.0.2", "requireg": "^0.2.2", "resolve": "^1.22.2", "resolve-from": "^5.0.0", "resolve.exports": "^2.0.3", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "tar": "^7.5.2", "terminal-link": "^2.1.1", "undici": "^6.18.2", "wrap-ansi": "^7.0.0", "ws": "^8.12.1" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "build/bin/cli" } }, "sha512-L/FdpyZDsg/Nq6xW6kfiyF9DUzKfLZCKFXEVZcDqCNar6bXxQVotQyvgexRvtUF5nLinuT/UafLOdC3FUALUmA=="],
|
||||
"@expo/cli": ["@expo/cli@54.0.23", "", { "dependencies": { "@0no-co/graphql.web": "^1.0.8", "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devcert": "^1.2.1", "@expo/env": "~2.0.8", "@expo/image-utils": "^0.8.8", "@expo/json-file": "^10.0.8", "@expo/metro": "~54.2.0", "@expo/metro-config": "~54.0.14", "@expo/osascript": "^2.3.8", "@expo/package-manager": "^1.9.10", "@expo/plist": "^0.4.8", "@expo/prebuild-config": "^54.0.8", "@expo/schema-utils": "^0.1.8", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.3.0", "@react-native/dev-middleware": "0.81.5", "@urql/core": "^5.0.6", "@urql/exchange-retry": "^1.3.0", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "env-editor": "^0.4.1", "expo-server": "^1.0.5", "freeport-async": "^2.0.0", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.1.6", "minimatch": "^9.0.0", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^3.0.1", "pretty-bytes": "^5.6.0", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "qrcode-terminal": "0.11.0", "require-from-string": "^2.0.2", "requireg": "^0.2.2", "resolve": "^1.22.2", "resolve-from": "^5.0.0", "resolve.exports": "^2.0.3", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "tar": "^7.5.2", "terminal-link": "^2.1.1", "undici": "^6.18.2", "wrap-ansi": "^7.0.0", "ws": "^8.12.1" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "build/bin/cli" } }, "sha512-km0h72SFfQCmVycH/JtPFTVy69w6Lx1cHNDmfLfQqgKFYeeHTjx7LVDP4POHCtNxFP2UeRazrygJhlh4zz498g=="],
|
||||
|
||||
"@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.6", "", { "dependencies": { "node-forge": "^1.3.3" } }, "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w=="],
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
|
||||
"@expo/metro": ["@expo/metro@54.2.0", "", { "dependencies": { "metro": "0.83.3", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-config": "0.83.3", "metro-core": "0.83.3", "metro-file-map": "0.83.3", "metro-minify-terser": "0.83.3", "metro-resolver": "0.83.3", "metro-runtime": "0.83.3", "metro-source-map": "0.83.3", "metro-symbolicate": "0.83.3", "metro-transform-plugins": "0.83.3", "metro-transform-worker": "0.83.3" } }, "sha512-h68TNZPGsk6swMmLm9nRSnE2UXm48rWwgcbtAHVMikXvbxdS41NDHHeqg1rcQ9AbznDRp6SQVC2MVpDnsRKU1w=="],
|
||||
|
||||
"@expo/metro-config": ["@expo/metro-config@54.0.13", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@expo/config": "~12.0.13", "@expo/env": "~2.0.8", "@expo/json-file": "~10.0.8", "@expo/metro": "~54.2.0", "@expo/spawn-async": "^1.7.2", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0", "glob": "^13.0.0", "hermes-parser": "^0.29.1", "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", "minimatch": "^9.0.0", "postcss": "~8.4.32", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*" }, "optionalPeers": ["expo"] }, "sha512-RRufMCgLR2Za1WGsh02OatIJo5qZFt31yCnIOSfoubNc3Qqe92Z41pVsbrFnmw5CIaisv1NgdBy05DHe7pEyuw=="],
|
||||
"@expo/metro-config": ["@expo/metro-config@54.0.14", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@expo/config": "~12.0.13", "@expo/env": "~2.0.8", "@expo/json-file": "~10.0.8", "@expo/metro": "~54.2.0", "@expo/spawn-async": "^1.7.2", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0", "glob": "^13.0.0", "hermes-parser": "^0.29.1", "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", "minimatch": "^9.0.0", "postcss": "~8.4.32", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*" }, "optionalPeers": ["expo"] }, "sha512-hxpLyDfOR4L23tJ9W1IbJJsG7k4lv2sotohBm/kTYyiG+pe1SYCAWsRmgk+H42o/wWf/HQjE5k45S5TomGLxNA=="],
|
||||
|
||||
"@expo/metro-runtime": ["@expo/metro-runtime@6.1.2", "", { "dependencies": { "anser": "^1.4.9", "pretty-format": "^29.7.0", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-dom": "*", "react-native": "*" }, "optionalPeers": ["react-dom"] }, "sha512-nvM+Qv45QH7pmYvP8JB1G8JpScrWND3KrMA6ZKe62cwwNiX/BjHU28Ear0v/4bQWXlOY0mv6B8CDIm8JxXde9g=="],
|
||||
|
||||
@@ -720,7 +720,7 @@
|
||||
|
||||
"babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="],
|
||||
|
||||
"babel-preset-expo": ["babel-preset-expo@54.0.9", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-preset": "0.81.5", "babel-plugin-react-compiler": "^1.0.0", "babel-plugin-react-native-web": "~0.21.0", "babel-plugin-syntax-hermes-parser": "^0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "resolve-from": "^5.0.0" }, "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", "react-refresh": ">=0.14.0 <1.0.0" }, "optionalPeers": ["@babel/runtime", "expo"] }, "sha512-8J6hRdgEC2eJobjoft6mKJ294cLxmi3khCUy2JJQp4htOYYkllSLUq6vudWJkTJiIuGdVR4bR6xuz2EvJLWHNg=="],
|
||||
"babel-preset-expo": ["babel-preset-expo@54.0.10", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-preset": "0.81.5", "babel-plugin-react-compiler": "^1.0.0", "babel-plugin-react-native-web": "~0.21.0", "babel-plugin-syntax-hermes-parser": "^0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "resolve-from": "^5.0.0" }, "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", "react-refresh": ">=0.14.0 <1.0.0" }, "optionalPeers": ["@babel/runtime", "expo"] }, "sha512-wTt7POavLFypLcPW/uC5v8y+mtQKDJiyGLzYCjqr9tx0Qc3vCXcDKk1iCFIj/++Iy5CWhhTflEa7VvVPNWeCfw=="],
|
||||
|
||||
"babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="],
|
||||
|
||||
@@ -900,7 +900,7 @@
|
||||
|
||||
"exec-async": ["exec-async@2.2.0", "", {}, "sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw=="],
|
||||
|
||||
"expo": ["expo@54.0.31", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.21", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devtools": "0.1.8", "@expo/fingerprint": "0.15.4", "@expo/metro": "~54.2.0", "@expo/metro-config": "54.0.13", "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.9", "expo-asset": "~12.0.12", "expo-constants": "~18.0.13", "expo-file-system": "~19.0.21", "expo-font": "~14.0.10", "expo-keep-awake": "~15.0.8", "expo-modules-autolinking": "3.0.24", "expo-modules-core": "3.0.29", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-kQ3RDqA/a59I7y+oqQGyrPbbYlgPMUdKBOgvFLpoHbD2bCM+F75i4N0mUijy7dG5F/CUCu2qHmGGUCXBbMDkCg=="],
|
||||
"expo": ["expo@54.0.33", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.23", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devtools": "0.1.8", "@expo/fingerprint": "0.15.4", "@expo/metro": "~54.2.0", "@expo/metro-config": "54.0.14", "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.10", "expo-asset": "~12.0.12", "expo-constants": "~18.0.13", "expo-file-system": "~19.0.21", "expo-font": "~14.0.11", "expo-keep-awake": "~15.0.8", "expo-modules-autolinking": "3.0.24", "expo-modules-core": "3.0.29", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw=="],
|
||||
|
||||
"expo-asset": ["expo-asset@12.0.12", "", { "dependencies": { "@expo/image-utils": "^0.8.8", "expo-constants": "~18.0.12" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-CsXFCQbx2fElSMn0lyTdRIyKlSXOal6ilLJd+yeZ6xaC7I9AICQgscY5nj0QcwgA+KYYCCEQEBndMsmj7drOWQ=="],
|
||||
|
||||
@@ -940,7 +940,7 @@
|
||||
|
||||
"expo-modules-core": ["expo-modules-core@3.0.29", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-LzipcjGqk8gvkrOUf7O2mejNWugPkf3lmd9GkqL9WuNyeN2fRwU0Dn77e3ZUKI3k6sI+DNwjkq4Nu9fNN9WS7Q=="],
|
||||
|
||||
"expo-router": ["expo-router@6.0.21", "", { "dependencies": { "@expo/metro-runtime": "^6.1.2", "@expo/schema-utils": "^0.1.8", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/native": "^7.1.8", "@react-navigation/native-stack": "^7.3.16", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-server": "^1.0.5", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@react-navigation/drawer": "^7.5.0", "@testing-library/react-native": ">= 12.0.0", "expo": "*", "expo-constants": "^18.0.12", "expo-linking": "^8.0.11", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": "~19.0.3 || ~19.1.4 || ~19.2.3" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-wjTUjrnWj6gRYjaYl1kYfcRnNE4ZAQ0kz0+sQf6/mzBd/OU6pnOdD7WrdAW3pTTpm52Q8sMoeX98tNQEddg2uA=="],
|
||||
"expo-router": ["expo-router@6.0.23", "", { "dependencies": { "@expo/metro-runtime": "^6.1.2", "@expo/schema-utils": "^0.1.8", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/native": "^7.1.8", "@react-navigation/native-stack": "^7.3.16", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-server": "^1.0.5", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@react-navigation/drawer": "^7.5.0", "@testing-library/react-native": ">= 12.0.0", "expo": "*", "expo-constants": "^18.0.13", "expo-linking": "^8.0.11", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-qCxVAiCrCyu0npky6azEZ6dJDMt77OmCzEbpF6RbUTlfkaCA417LvY14SBkk0xyGruSxy/7pvJOI6tuThaUVCA=="],
|
||||
|
||||
"expo-server": ["expo-server@1.0.5", "", {}, "sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA=="],
|
||||
|
||||
@@ -1390,7 +1390,7 @@
|
||||
|
||||
"react-native-web": ["react-native-web@0.21.2", "", { "dependencies": { "@babel/runtime": "^7.18.6", "@react-native/normalize-colors": "^0.74.1", "fbjs": "^3.0.4", "inline-style-prefixer": "^7.0.1", "memoize-one": "^6.0.0", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", "styleq": "^0.1.3" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg=="],
|
||||
|
||||
"react-native-worklets": ["react-native-worklets@0.5.2", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", "@babel/plugin-transform-class-properties": "^7.0.0-0", "@babel/plugin-transform-classes": "^7.0.0-0", "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", "@babel/plugin-transform-optional-chaining": "^7.0.0-0", "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", "@babel/plugin-transform-template-literals": "^7.0.0-0", "@babel/plugin-transform-unicode-regex": "^7.0.0-0", "@babel/preset-typescript": "^7.16.7", "convert-source-map": "^2.0.0", "semver": "7.7.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*" } }, "sha512-lCzmuIPAK/UaOJYEPgYpVqrsxby1I54f7PyyZUMEO04nwc00CDrCvv9lCTY1daLHYTF8lS3f9zlzErfVsIKqkA=="],
|
||||
"react-native-worklets": ["react-native-worklets@0.5.1", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", "@babel/plugin-transform-class-properties": "^7.0.0-0", "@babel/plugin-transform-classes": "^7.0.0-0", "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", "@babel/plugin-transform-optional-chaining": "^7.0.0-0", "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", "@babel/plugin-transform-template-literals": "^7.0.0-0", "@babel/plugin-transform-unicode-regex": "^7.0.0-0", "@babel/preset-typescript": "^7.16.7", "convert-source-map": "^2.0.0", "semver": "7.7.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*" } }, "sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
|
||||
|
||||
@@ -1748,8 +1748,6 @@
|
||||
|
||||
"error-ex/is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
|
||||
|
||||
"expo/expo-font": ["expo-font@14.0.10", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-UqyNaaLKRpj4pKAP4HZSLnuDQqueaO5tB1c/NWu5vh1/LF9ulItyyg2kF/IpeOp0DeOLk0GY0HrIXaKUMrwB+Q=="],
|
||||
|
||||
"expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
|
||||
|
||||
"expo-router/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="],
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@
|
||||
"@tanstack/react-query-devtools": "^5.91.2",
|
||||
"@types/langmap": "^0.0.3",
|
||||
"clsx": "^2.1.1",
|
||||
"expo": "~54.0.31",
|
||||
"expo": "~54.0.33",
|
||||
"expo-build-properties": "~1.0.10",
|
||||
"expo-constants": "~18.0.13",
|
||||
"expo-dev-client": "~6.0.20",
|
||||
@@ -39,7 +39,7 @@
|
||||
"expo-linear-gradient": "~15.0.8",
|
||||
"expo-linking": "~8.0.11",
|
||||
"expo-localization": "~17.0.8",
|
||||
"expo-router": "~6.0.21",
|
||||
"expo-router": "~6.0.23",
|
||||
"expo-splash-screen": "~31.0.13",
|
||||
"expo-status-bar": "~3.0.9",
|
||||
"expo-updates": "~29.0.16",
|
||||
@@ -63,7 +63,7 @@
|
||||
"react-native-svg-transformer": "^1.5.2",
|
||||
"react-native-video": "zoriya/react-native-video#build",
|
||||
"react-native-web": "^0.21.2",
|
||||
"react-native-worklets": "^0.5.1",
|
||||
"react-native-worklets": "0.5.1",
|
||||
"react-tooltip": "^5.29.1",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"sweetalert2": "^11.26.17",
|
||||
|
||||
@@ -4,6 +4,7 @@ import Home from "@material-symbols/svg-400/rounded/home-fill.svg";
|
||||
import { Tabs } from "expo-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Icon } from "~/primitives";
|
||||
import { cn } from "~/utils";
|
||||
|
||||
export default function TabsLayout() {
|
||||
const { t } = useTranslation();
|
||||
@@ -18,29 +19,28 @@ export default function TabsLayout() {
|
||||
name="index"
|
||||
options={{
|
||||
tabBarLabel: t("navbar.home"),
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<Icon icon={Home} color={color} size={size} />
|
||||
),
|
||||
tabBarIcon: ({ focused }) => {
|
||||
return (
|
||||
<Icon
|
||||
icon={Home}
|
||||
className={cn(focused && "fill-accent dark:fill-accent")}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="browse"
|
||||
options={{
|
||||
tabBarLabel: t("navbar.browse"),
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<Icon icon={Browse} color={color} size={size} />
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<Icon
|
||||
icon={Browse}
|
||||
className={cn(focused && "fill-accent dark:fill-accent")}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
{/* <Tabs.Screen */}
|
||||
{/* name="downloads" */}
|
||||
{/* options={{ */}
|
||||
{/* tabBarLabel: t("navbar.download"), */}
|
||||
{/* tabBarIcon: ({ color, size }) => ( */}
|
||||
{/* <Icon icon={Downloading} color={color} size={size} /> */}
|
||||
{/* ), */}
|
||||
{/* }} */}
|
||||
{/* /> */}
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Stack } from "expo-router";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { useTheme } from "yoshiki/native";
|
||||
import { useCSSVariable } from "uniwind";
|
||||
import { ErrorConsumer } from "~/providers/error-consumer";
|
||||
import { NavbarProfile, NavbarTitle } from "~/ui/navbar";
|
||||
|
||||
export default function Layout() {
|
||||
const insets = useSafeAreaInsets();
|
||||
const theme = useTheme();
|
||||
const accent = useCSSVariable("--color-accent");
|
||||
|
||||
return (
|
||||
<ErrorConsumer scope="login">
|
||||
@@ -19,7 +19,7 @@ export default function Layout() {
|
||||
paddingRight: insets.right,
|
||||
},
|
||||
headerStyle: {
|
||||
backgroundColor: theme.accent,
|
||||
backgroundColor: accent as string,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { View } from "react-native";
|
||||
import type { KImage, WatchStatusV } from "~/models";
|
||||
import {
|
||||
percent,
|
||||
rem,
|
||||
type Stylable,
|
||||
type Theme,
|
||||
useYoshiki,
|
||||
} from "yoshiki/native";
|
||||
import type { KImage } from "~/models";
|
||||
import {
|
||||
focusReset,
|
||||
Image,
|
||||
ImageBackground,
|
||||
Link,
|
||||
@@ -20,6 +12,9 @@ import {
|
||||
ts,
|
||||
} from "~/primitives";
|
||||
import type { Layout } from "~/query";
|
||||
import { cn } from "~/utils";
|
||||
import { EntryContext } from "../items/context-menus";
|
||||
import { ItemProgress } from "../items/item-grid";
|
||||
|
||||
export const EntryBox = ({
|
||||
slug,
|
||||
@@ -29,9 +24,10 @@ export const EntryBox = ({
|
||||
thumbnail,
|
||||
href,
|
||||
watchedPercent,
|
||||
// watchedStatus,
|
||||
watchedStatus,
|
||||
className,
|
||||
...props
|
||||
}: Stylable & {
|
||||
}: {
|
||||
slug: string;
|
||||
// if serie slug is null, disable "Go to serie" in the context menu
|
||||
serieSlug: string | null;
|
||||
@@ -40,107 +36,60 @@ export const EntryBox = ({
|
||||
href: string;
|
||||
thumbnail: KImage | null;
|
||||
watchedPercent: number | null;
|
||||
// watchedStatus: WatchStatusV | null;
|
||||
watchedStatus: WatchStatusV | null;
|
||||
className?: string;
|
||||
}) => {
|
||||
const [moreOpened, setMoreOpened] = useState(false);
|
||||
const { css } = useYoshiki("episodebox");
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={moreOpened ? undefined : href}
|
||||
onLongPress={() => setMoreOpened(true)}
|
||||
{...css(
|
||||
{
|
||||
alignItems: "center",
|
||||
width: EntryBox.layout.size,
|
||||
child: {
|
||||
poster: {
|
||||
borderColor: (theme) => theme.background,
|
||||
borderWidth: ts(0.5),
|
||||
borderStyle: "solid",
|
||||
borderRadius: 6,
|
||||
},
|
||||
more: {
|
||||
opacity: 0,
|
||||
},
|
||||
},
|
||||
fover: {
|
||||
self: focusReset,
|
||||
poster: {
|
||||
borderColor: (theme: Theme) => theme.accent,
|
||||
},
|
||||
title: {
|
||||
textDecorationLine: "underline",
|
||||
},
|
||||
more: {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
props,
|
||||
)}
|
||||
className={cn("group w-[350px] items-center outline-0", className)}
|
||||
{...props}
|
||||
>
|
||||
<ImageBackground
|
||||
src={thumbnail}
|
||||
quality="low"
|
||||
alt=""
|
||||
layout={{ width: percent(100), aspectRatio: 16 / 9 }}
|
||||
{...(css("poster") as any)}
|
||||
className={cn(
|
||||
"aspect-video w-full rounded",
|
||||
"ring-accent group-hover:ring-3 group-focus-visible:ring-3",
|
||||
)}
|
||||
>
|
||||
{/* {(watchedPercent || watchedStatus === "completed") && ( */}
|
||||
{/* <ItemProgress watchPercent={watchedPercent ?? 100} /> */}
|
||||
{/* )} */}
|
||||
{/* <EntryContext */}
|
||||
{/* slug={slug} */}
|
||||
{/* serieSlug={serieSlug} */}
|
||||
{/* status={watchedStatus} */}
|
||||
{/* isOpen={moreOpened} */}
|
||||
{/* setOpen={(v) => setMoreOpened(v)} */}
|
||||
{/* {...css([ */}
|
||||
{/* { */}
|
||||
{/* position: "absolute", */}
|
||||
{/* top: 0, */}
|
||||
{/* right: 0, */}
|
||||
{/* bg: (theme) => theme.darkOverlay, */}
|
||||
{/* }, */}
|
||||
{/* "more", */}
|
||||
{/* Platform.OS === "web" && */}
|
||||
{/* moreOpened && { display: important("flex") }, */}
|
||||
{/* ])} */}
|
||||
{/* /> */}
|
||||
{(watchedPercent || watchedStatus === "completed") && (
|
||||
<ItemProgress watchPercent={watchedPercent ?? 100} />
|
||||
)}
|
||||
<EntryContext
|
||||
slug={slug}
|
||||
serieSlug={serieSlug}
|
||||
isOpen={moreOpened}
|
||||
setOpen={(v) => setMoreOpened(v)}
|
||||
className={cn(
|
||||
"absolute top-0 right-0 bg-gray-800/70 hover:bg-gray-800 focus-visible:bg-gray-800",
|
||||
"native:hidden opacity-0 focus-visible:opacity-100 group-focus-within:opacity-100 group-hover:opacity-100",
|
||||
moreOpened && "opacity-100",
|
||||
)}
|
||||
iconClassName="fill-slate-200 dark:fill-slate-200"
|
||||
/>
|
||||
</ImageBackground>
|
||||
<P {...css([{ marginY: 0, textAlign: "center" }, "title"])}>
|
||||
<P className="text-center group-focus-within:underline group-hover:underline">
|
||||
{name ?? t("show.episodeNoMetadata")}
|
||||
</P>
|
||||
<SubP
|
||||
numberOfLines={3}
|
||||
{...css({
|
||||
marginTop: 0,
|
||||
textAlign: "center",
|
||||
})}
|
||||
>
|
||||
<SubP numberOfLines={3} className="text-center">
|
||||
{description}
|
||||
</SubP>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
EntryBox.Loader = (props: Stylable) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
EntryBox.Loader = ({ className, ...props }: { className?: string }) => {
|
||||
return (
|
||||
<View
|
||||
{...css(
|
||||
{
|
||||
alignItems: "center",
|
||||
},
|
||||
props,
|
||||
)}
|
||||
>
|
||||
<Image.Loader layout={{ width: percent(100), aspectRatio: 16 / 9 }} />
|
||||
<Skeleton {...css({ width: percent(50) })} />
|
||||
<Skeleton {...css({ width: percent(75), height: rem(0.8) })} />
|
||||
<View className={cn("items-center", className)} {...props}>
|
||||
<Image.Loader className="aspect-video w-full" />
|
||||
<Skeleton className="w-1/2" />
|
||||
<Skeleton className="h-3 w-4/5" />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ export const EntryLine = ({
|
||||
className={cn(
|
||||
"mr-1 w-1/5 shrink-0 rounded",
|
||||
poster ? "aspect-2/3" : "aspect-video",
|
||||
"group-hover:ring-3 group-hover:ring-accent group-focus-visible:ring-3 group-focus-visible:ring-accent",
|
||||
"ring-accent group-hover:ring-3 group-focus-visible:ring-3",
|
||||
)}
|
||||
>
|
||||
{(watchedPercent ?? 0) > 0 && (
|
||||
|
||||
@@ -4,8 +4,6 @@ import MoreVert from "@material-symbols/svg-400/rounded/more_vert.svg";
|
||||
import MovieInfo from "@material-symbols/svg-400/rounded/movie_info.svg";
|
||||
import type { ComponentProps } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform } from "react-native";
|
||||
import { useYoshiki } from "yoshiki/native";
|
||||
import { WatchStatusV } from "~/models";
|
||||
import { IconButton, Menu, tooltip } from "~/primitives";
|
||||
import { useAccount } from "~/providers/account-context";
|
||||
@@ -23,7 +21,8 @@ export const EntryContext = ({
|
||||
serieSlug: string | null;
|
||||
slug: string;
|
||||
className?: string;
|
||||
} & Partial<ComponentProps<typeof Menu<typeof IconButton>>>) => {
|
||||
} & Partial<ComponentProps<typeof Menu>> &
|
||||
Partial<ComponentProps<typeof IconButton>>) => {
|
||||
// const downloader = useDownloader();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -60,15 +59,17 @@ export const ItemContext = ({
|
||||
kind,
|
||||
slug,
|
||||
status,
|
||||
className,
|
||||
...props
|
||||
}: {
|
||||
kind: "movie" | "serie";
|
||||
slug: string;
|
||||
status: WatchStatusV | null;
|
||||
} & Partial<ComponentProps<typeof Menu<typeof IconButton>>>) => {
|
||||
className?: string;
|
||||
} & Partial<ComponentProps<typeof Menu>> &
|
||||
Partial<ComponentProps<typeof IconButton>>) => {
|
||||
const account = useAccount();
|
||||
// const downloader = useDownloader();
|
||||
const { css } = useYoshiki();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const mutation = useMutation({
|
||||
@@ -90,8 +91,9 @@ export const ItemContext = ({
|
||||
<Menu
|
||||
Trigger={IconButton}
|
||||
icon={MoreVert}
|
||||
className={cn("not:web:hidden", className)}
|
||||
{...tooltip(t("misc.more"))}
|
||||
{...(css([Platform.OS !== "web" && { display: "none" }], props) as any)}
|
||||
{...(props as any)}
|
||||
>
|
||||
<Menu.Sub
|
||||
label={account ? t("show.watchlistEdit") : t("show.watchlistLogin")}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { type ImageStyle, Platform, View } from "react-native";
|
||||
import { percent, type Stylable, type Theme, useYoshiki } from "yoshiki/native";
|
||||
import { View } from "react-native";
|
||||
import type { KImage, WatchStatusV } from "~/models";
|
||||
import {
|
||||
focusReset,
|
||||
important,
|
||||
Link,
|
||||
P,
|
||||
Poster,
|
||||
@@ -14,31 +11,17 @@ import {
|
||||
ts,
|
||||
} from "~/primitives";
|
||||
import type { Layout } from "~/query";
|
||||
import { cn } from "~/utils";
|
||||
import { ItemContext } from "./context-menus";
|
||||
import { ItemWatchStatus } from "./item-helpers";
|
||||
|
||||
export const ItemProgress = ({ watchPercent }: { watchPercent: number }) => {
|
||||
const { css } = useYoshiki("episodebox");
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className="absolute bottom-0 h-1 w-full bg-slate-400" />
|
||||
<View
|
||||
{...css({
|
||||
backgroundColor: (theme) => theme.user.overlay0,
|
||||
width: percent(100),
|
||||
height: ts(0.5),
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
})}
|
||||
/>
|
||||
<View
|
||||
{...css({
|
||||
backgroundColor: (theme) => theme.user.accent,
|
||||
width: percent(watchPercent),
|
||||
height: ts(0.5),
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
})}
|
||||
className="absolute bottom-0 h-1 bg-accent"
|
||||
style={{ width: `${watchPercent}%` }}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -55,6 +38,7 @@ export const ItemGrid = ({
|
||||
watchPercent,
|
||||
unseenEpisodesCount,
|
||||
horizontal = false,
|
||||
className,
|
||||
...props
|
||||
}: {
|
||||
href: string;
|
||||
@@ -67,52 +51,29 @@ export const ItemGrid = ({
|
||||
kind: "movie" | "serie" | "collection";
|
||||
unseenEpisodesCount: number | null;
|
||||
horizontal: boolean;
|
||||
} & Stylable<"text">) => {
|
||||
className?: string;
|
||||
}) => {
|
||||
const [moreOpened, setMoreOpened] = useState(false);
|
||||
const { css } = useYoshiki("grid");
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={moreOpened ? undefined : href}
|
||||
onLongPress={() => setMoreOpened(true)}
|
||||
{...css(
|
||||
{
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
width: horizontal ? ItemGrid.layout.size : percent(100),
|
||||
height: horizontal ? percent(100) : undefined,
|
||||
child: {
|
||||
poster: {
|
||||
borderColor: (theme) => theme.background,
|
||||
borderWidth: ts(0.5),
|
||||
borderStyle: "solid",
|
||||
},
|
||||
more: {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
fover: {
|
||||
self: focusReset,
|
||||
poster: {
|
||||
borderColor: (theme: Theme) => theme.accent,
|
||||
},
|
||||
title: {
|
||||
textDecorationLine: "underline",
|
||||
},
|
||||
more: {
|
||||
display: "flex",
|
||||
},
|
||||
},
|
||||
},
|
||||
props,
|
||||
className={cn(
|
||||
"group items-center outline-0",
|
||||
horizontal && "h-full w-[200px]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<PosterBackground
|
||||
src={poster}
|
||||
alt={name}
|
||||
quality="low"
|
||||
layout={{ width: percent(100) }}
|
||||
{...(css("poster") as { style: ImageStyle })}
|
||||
className={cn(
|
||||
"w-full",
|
||||
"ring-accent group-hover:ring-3 group-focus-visible:ring-3",
|
||||
)}
|
||||
>
|
||||
<ItemWatchStatus
|
||||
watchStatus={watchStatus}
|
||||
@@ -128,64 +89,38 @@ export const ItemGrid = ({
|
||||
status={watchStatus}
|
||||
isOpen={moreOpened}
|
||||
setOpen={(v) => setMoreOpened(v)}
|
||||
{...css([
|
||||
{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bg: (theme) => theme.dark.background,
|
||||
},
|
||||
"more",
|
||||
Platform.OS === "web" &&
|
||||
moreOpened && { display: important("flex") },
|
||||
])}
|
||||
className={cn(
|
||||
"absolute top-0 right-0 bg-gray-800/70 hover:bg-gray-800 focus-visible:bg-gray-800",
|
||||
"native:hidden opacity-0 focus-visible:opacity-100 group-focus-within:opacity-100 group-hover:opacity-100",
|
||||
moreOpened && "opacity-100",
|
||||
)}
|
||||
iconClassName="fill-slate-200 dark:fill-slate-200"
|
||||
/>
|
||||
)}
|
||||
</PosterBackground>
|
||||
<P
|
||||
numberOfLines={subtitle ? 1 : 2}
|
||||
{...css([{ marginY: 0, textAlign: "center" }, "title"])}
|
||||
className="text-center group-focus-within:underline group-hover:underline"
|
||||
>
|
||||
{name}
|
||||
</P>
|
||||
{subtitle && (
|
||||
<SubP
|
||||
{...css({
|
||||
marginTop: 0,
|
||||
textAlign: "center",
|
||||
})}
|
||||
>
|
||||
{subtitle}
|
||||
</SubP>
|
||||
)}
|
||||
{subtitle && <SubP className="text-center">{subtitle}</SubP>}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
ItemGrid.Loader = (props: object) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<View
|
||||
{...css(
|
||||
{
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
width: percent(100),
|
||||
},
|
||||
props,
|
||||
)}
|
||||
>
|
||||
<Poster.Loader layout={{ width: percent(100) }} />
|
||||
<View className="w-full items-center" {...props}>
|
||||
<Poster.Loader className="w-full" />
|
||||
<Skeleton />
|
||||
<Skeleton {...css({ width: percent(50) })} />
|
||||
<Skeleton className="w-1/2" />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
ItemGrid.layout = {
|
||||
size: 200,
|
||||
// size: { xs: 150, md: 200, xl: 210 },
|
||||
numColumns: { xs: 3, sm: 4, md: 5, lg: 6, xl: 8 },
|
||||
gap: { xs: ts(1), sm: ts(2), md: ts(4) },
|
||||
layout: "grid",
|
||||
|
||||
@@ -69,12 +69,12 @@ export const IconButton = <AsProps = PressableProps>({
|
||||
icon,
|
||||
as,
|
||||
className,
|
||||
iconProps,
|
||||
iconClassName,
|
||||
...asProps
|
||||
}: {
|
||||
as?: ComponentType<AsProps>;
|
||||
icon: Icon;
|
||||
iconProps?: Omit<ComponentProps<typeof Icon>, "icon">;
|
||||
iconClassName?: string;
|
||||
className?: string;
|
||||
} & AsProps) => {
|
||||
const Container = as ?? PressableFeedback;
|
||||
@@ -89,7 +89,7 @@ export const IconButton = <AsProps = PressableProps>({
|
||||
)}
|
||||
{...(asProps as AsProps)}
|
||||
>
|
||||
<Icon icon={icon} {...iconProps} />
|
||||
<Icon icon={icon} className={iconClassName} />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -99,7 +99,7 @@ const Pressable = Animated.createAnimatedComponent(PressableFeedback);
|
||||
export const IconFab = <AsProps = PressableProps>({
|
||||
icon,
|
||||
className,
|
||||
iconProps,
|
||||
iconClassName,
|
||||
...props
|
||||
}: ComponentProps<typeof IconButton<AsProps>>) => {
|
||||
const [hover, setHover] = useState(false);
|
||||
@@ -123,11 +123,10 @@ export const IconFab = <AsProps = PressableProps>({
|
||||
>
|
||||
<Icon
|
||||
icon={icon}
|
||||
{...iconProps}
|
||||
className={cn(
|
||||
"fill-slate-300",
|
||||
(hover || focus) && "fill-slate-200",
|
||||
iconProps?.className,
|
||||
iconClassName,
|
||||
)}
|
||||
/>
|
||||
</Pressable>
|
||||
|
||||
@@ -74,7 +74,6 @@ const RnTheme = ({ children }: { children: ReactNode }) => {
|
||||
Uniwind.updateInsets(insets);
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{children}
|
||||
</SafeAreaListener>
|
||||
</RNThemeProvider>
|
||||
|
||||
@@ -18,7 +18,7 @@ const LegendList = withUniwind(RLegendList) as typeof RLegendList;
|
||||
|
||||
export const InfiniteFetch = <Data, Type extends string = string>({
|
||||
query,
|
||||
placeholderCount = 2,
|
||||
placeholderCount = 4,
|
||||
incremental = false,
|
||||
getItemType,
|
||||
getItemSizeMult,
|
||||
|
||||
@@ -10,7 +10,6 @@ import All from "@material-symbols/svg-400/rounded/view_headline.svg";
|
||||
import ViewList from "@material-symbols/svg-400/rounded/view_list.svg";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type PressableProps, View } from "react-native";
|
||||
import { useYoshiki } from "yoshiki/native";
|
||||
import {
|
||||
HR,
|
||||
Icon,
|
||||
@@ -19,23 +18,24 @@ import {
|
||||
P,
|
||||
PressableFeedback,
|
||||
tooltip,
|
||||
ts,
|
||||
} from "~/primitives";
|
||||
import { cn } from "~/utils";
|
||||
import { availableSorts, type SortBy, type SortOrd } from "./types";
|
||||
|
||||
const SortTrigger = ({
|
||||
sortBy,
|
||||
className,
|
||||
...props
|
||||
}: { sortBy: SortBy } & PressableProps) => {
|
||||
const { css } = useYoshiki();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<PressableFeedback
|
||||
{...css({ flexDirection: "row", alignItems: "center" }, props as any)}
|
||||
className={cn("flex-row items-center", className)}
|
||||
{...tooltip(t("browse.sortby-tt"))}
|
||||
{...props}
|
||||
>
|
||||
<Icon icon={Sort} {...css({ paddingX: ts(0.5) })} />
|
||||
<Icon icon={Sort} className="mx-1" />
|
||||
<P>{t(`browse.sortkey.${sortBy}`)}</P>
|
||||
</PressableFeedback>
|
||||
);
|
||||
@@ -50,20 +50,18 @@ const MediaTypeIcons = {
|
||||
|
||||
const MediaTypeTrigger = ({
|
||||
mediaType,
|
||||
className,
|
||||
...props
|
||||
}: PressableProps & { mediaType: keyof typeof MediaTypeIcons }) => {
|
||||
const { css } = useYoshiki();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<PressableFeedback
|
||||
{...css({ flexDirection: "row", alignItems: "center" }, props as any)}
|
||||
className={cn("flex-row items-center", className)}
|
||||
{...tooltip(t("browse.mediatype-tt"))}
|
||||
{...props}
|
||||
>
|
||||
<Icon
|
||||
icon={MediaTypeIcons[mediaType] ?? FilterList}
|
||||
{...css({ paddingX: ts(0.5) })}
|
||||
/>
|
||||
<Icon icon={MediaTypeIcons[mediaType] ?? FilterList} className="mx-1" />
|
||||
<P>
|
||||
{t(
|
||||
mediaType !== "all"
|
||||
@@ -92,7 +90,6 @@ export const BrowseSettings = ({
|
||||
layout: "grid" | "list";
|
||||
setLayout: (layout: "grid" | "list") => void;
|
||||
}) => {
|
||||
const { css, theme } = useYoshiki();
|
||||
const { t } = useTranslation();
|
||||
|
||||
// TODO: have a proper filter frontend
|
||||
@@ -101,15 +98,22 @@ export const BrowseSettings = ({
|
||||
setFilter(kind !== "all" ? `kind eq ${kind}` : "");
|
||||
|
||||
return (
|
||||
<View
|
||||
{...css({
|
||||
flexDirection: "row-reverse",
|
||||
alignItems: "center",
|
||||
marginX: ts(4),
|
||||
marginY: ts(1),
|
||||
})}
|
||||
>
|
||||
<View {...css({ flexDirection: "row" })}>
|
||||
<View className="mx-8 my-2 flex-row items-center justify-between">
|
||||
<Menu
|
||||
Trigger={MediaTypeTrigger}
|
||||
mediaType={mediaType as keyof typeof MediaTypeIcons}
|
||||
>
|
||||
{Object.keys(MediaTypeIcons).map((x) => (
|
||||
<Menu.Item
|
||||
key={x}
|
||||
label={t(`browse.mediatypekey.${x as keyof typeof MediaTypeIcons}`)}
|
||||
selected={mediaType === x}
|
||||
icon={MediaTypeIcons[x as keyof typeof MediaTypeIcons]}
|
||||
onSelect={() => setMediaType(x)}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
<View className="flex-row">
|
||||
<Menu Trigger={SortTrigger} sortBy={sortBy}>
|
||||
{availableSorts.map((x) => (
|
||||
<Menu.Item
|
||||
@@ -127,38 +131,22 @@ export const BrowseSettings = ({
|
||||
<IconButton
|
||||
icon={GridView}
|
||||
onPress={() => setLayout("grid")}
|
||||
color={layout === "grid" ? theme.accent : undefined}
|
||||
className="m-1"
|
||||
iconClassName={cn(
|
||||
layout === "grid" && "fill-accent dark:fill-accent",
|
||||
)}
|
||||
{...tooltip(t("browse.switchToGrid"))}
|
||||
{...css({ padding: ts(0.5), marginY: "auto" })}
|
||||
/>
|
||||
<IconButton
|
||||
icon={ViewList}
|
||||
onPress={() => setLayout("list")}
|
||||
color={layout === "list" ? theme.accent : undefined}
|
||||
className="m-1"
|
||||
iconClassName={cn(
|
||||
layout === "list" && "fill-accent dark:fill-accent",
|
||||
)}
|
||||
{...tooltip(t("browse.switchToList"))}
|
||||
{...css({ padding: ts(0.5), marginY: "auto" })}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
{...css({ flexGrow: 1, flexDirection: "row", alignItems: "center" })}
|
||||
>
|
||||
<Menu
|
||||
Trigger={MediaTypeTrigger}
|
||||
mediaType={mediaType as keyof typeof MediaTypeIcons}
|
||||
>
|
||||
{Object.keys(MediaTypeIcons).map((x) => (
|
||||
<Menu.Item
|
||||
key={x}
|
||||
label={t(
|
||||
`browse.mediatypekey.${x as keyof typeof MediaTypeIcons}`,
|
||||
)}
|
||||
selected={mediaType === x}
|
||||
icon={MediaTypeIcons[x as keyof typeof MediaTypeIcons]}
|
||||
onSelect={() => setMediaType(x)}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -82,7 +82,7 @@ const ButtonList = ({
|
||||
icon={PlayArrow}
|
||||
as={Link}
|
||||
href={playHref}
|
||||
iconProps={{ className: "dark:fill-slate-200" }}
|
||||
iconClassName="dark:fill-slate-200"
|
||||
{...tooltip(t("show.play"))}
|
||||
/>
|
||||
)}
|
||||
@@ -92,7 +92,7 @@ const ButtonList = ({
|
||||
as={Link}
|
||||
href={trailerUrl}
|
||||
target="_blank"
|
||||
iconProps={{ className: iconsClassName }}
|
||||
iconClassName={iconsClassName}
|
||||
{...tooltip(t("show.trailer"))}
|
||||
/>
|
||||
)}
|
||||
@@ -101,14 +101,14 @@ const ButtonList = ({
|
||||
kind={kind}
|
||||
slug={slug}
|
||||
status={watchStatus}
|
||||
iconProps={{ className: iconsClassName }}
|
||||
iconClassName={iconsClassName}
|
||||
/>
|
||||
)}
|
||||
{(kind === "movie" || account?.isAdmin === true) && (
|
||||
<Menu
|
||||
Trigger={IconButton}
|
||||
icon={MoreHoriz}
|
||||
iconProps={{ className: iconsClassName }}
|
||||
iconClassName={iconsClassName}
|
||||
{...tooltip(t("misc.more"))}
|
||||
>
|
||||
{kind === "movie" && (
|
||||
@@ -241,19 +241,10 @@ TitleLine.Loader = ({
|
||||
<Skeleton variant="custom" className="h-10 w-2/5 max-sm:text-center" />
|
||||
<Skeleton className="h-6 w-4/5 max-sm:text-center" />
|
||||
<View className="flex-warp flex-row items-center max-sm:justify-center sm:mt-8">
|
||||
<IconFab
|
||||
icon={PlayArrow}
|
||||
iconProps={{ className: "lg:fill-slate-200" }}
|
||||
/>
|
||||
<IconButton
|
||||
icon={Theaters}
|
||||
iconProps={{ className: "lg:fill-slate-200" }}
|
||||
/>
|
||||
<IconFab icon={PlayArrow} iconClassName="lg:fill-slate-200" />
|
||||
<IconButton icon={Theaters} iconClassName="lg:fill-slate-200" />
|
||||
{kind !== "collection" && (
|
||||
<IconButton
|
||||
icon={BookmarkAdd}
|
||||
iconProps={{ className: "lg:fill-slate-200" }}
|
||||
/>
|
||||
<IconButton icon={BookmarkAdd} iconClassName="lg:fill-slate-200" />
|
||||
)}
|
||||
{kind === "movie" && <IconButton icon={MoreHoriz} />}
|
||||
<DottedSeparator className="lg:text-slate-200" />
|
||||
@@ -326,12 +317,12 @@ const Description = ({
|
||||
<P className="my-5 flex-row flex-wrap items-center">
|
||||
<P className="mr-1">{t("show.studios")}:</P>
|
||||
{studios.map((x, i) => (
|
||||
<>
|
||||
<Fragment key={x.id}>
|
||||
{i !== 0 && ","}
|
||||
<A key={x.id} href={x.slug} className="ml-2">
|
||||
<A href={x.slug} className="ml-2">
|
||||
{x.name}
|
||||
</A>
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</P>
|
||||
<View className="flex-row flex-wrap items-center">
|
||||
|
||||
@@ -39,7 +39,7 @@ import { KyooLongLogo } from "./icon";
|
||||
export const NavbarTitle = ({
|
||||
className,
|
||||
...props
|
||||
}: ComponentProps<typeof A>) => {
|
||||
}: Partial<ComponentProps<typeof A>>) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user