f
This commit is contained in:
@@ -10,7 +10,8 @@
|
|||||||
"start": "next start",
|
"start": "next start",
|
||||||
"test": "pnpm build && playwright test",
|
"test": "pnpm build && playwright test",
|
||||||
"test:e2e": "playwright test",
|
"test:e2e": "playwright test",
|
||||||
"test:e2e:ui": "playwright test --ui"
|
"test:e2e:ui": "playwright test --ui",
|
||||||
|
"optimize:banner": "node scripts/optimize-hero-banner.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "2.1.2",
|
"@headlessui/react": "2.1.2",
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"babel-plugin-react-compiler": "1.0.0",
|
"babel-plugin-react-compiler": "1.0.0",
|
||||||
|
"ffmpeg-static": "^5.3.0",
|
||||||
"pagefind": "^1.5.2",
|
"pagefind": "^1.5.2",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
|
|||||||
135
pnpm-lock.yaml
generated
135
pnpm-lock.yaml
generated
@@ -57,6 +57,9 @@ importers:
|
|||||||
babel-plugin-react-compiler:
|
babel-plugin-react-compiler:
|
||||||
specifier: 1.0.0
|
specifier: 1.0.0
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
ffmpeg-static:
|
||||||
|
specifier: ^5.3.0
|
||||||
|
version: 5.3.0
|
||||||
pagefind:
|
pagefind:
|
||||||
specifier: ^1.5.2
|
specifier: ^1.5.2
|
||||||
version: 1.5.2
|
version: 1.5.2
|
||||||
@@ -94,6 +97,10 @@ packages:
|
|||||||
'@chevrotain/types@11.1.2':
|
'@chevrotain/types@11.1.2':
|
||||||
resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==}
|
resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==}
|
||||||
|
|
||||||
|
'@derhuerst/http-basic@8.2.4':
|
||||||
|
resolution: {integrity: sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
'@emnapi/runtime@1.10.0':
|
'@emnapi/runtime@1.10.0':
|
||||||
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
|
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
|
||||||
|
|
||||||
@@ -1017,6 +1024,9 @@ packages:
|
|||||||
'@types/nlcst@2.0.3':
|
'@types/nlcst@2.0.3':
|
||||||
resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==}
|
resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==}
|
||||||
|
|
||||||
|
'@types/node@10.17.60':
|
||||||
|
resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==}
|
||||||
|
|
||||||
'@types/node@20.19.41':
|
'@types/node@20.19.41':
|
||||||
resolution: {integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==}
|
resolution: {integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==}
|
||||||
|
|
||||||
@@ -1062,6 +1072,10 @@ packages:
|
|||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
agent-base@6.0.2:
|
||||||
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
|
engines: {node: '>= 6.0.0'}
|
||||||
|
|
||||||
arg@5.0.2:
|
arg@5.0.2:
|
||||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||||
|
|
||||||
@@ -1104,9 +1118,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
buffer-from@1.1.2:
|
||||||
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001793:
|
caniuse-lite@1.0.30001793:
|
||||||
resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==}
|
resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==}
|
||||||
|
|
||||||
|
caseless@0.12.0:
|
||||||
|
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
|
||||||
|
|
||||||
ccount@2.0.1:
|
ccount@2.0.1:
|
||||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||||
|
|
||||||
@@ -1161,6 +1181,10 @@ packages:
|
|||||||
compute-scroll-into-view@3.1.1:
|
compute-scroll-into-view@3.1.1:
|
||||||
resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
|
resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
|
||||||
|
|
||||||
|
concat-stream@2.0.0:
|
||||||
|
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
|
||||||
|
engines: {'0': node >= 6.0}
|
||||||
|
|
||||||
cose-base@1.0.3:
|
cose-base@1.0.3:
|
||||||
resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==}
|
resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==}
|
||||||
|
|
||||||
@@ -1370,6 +1394,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
|
env-paths@2.2.1:
|
||||||
|
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
es-toolkit@1.46.1:
|
es-toolkit@1.46.1:
|
||||||
resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==}
|
resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==}
|
||||||
|
|
||||||
@@ -1437,6 +1465,10 @@ packages:
|
|||||||
picomatch:
|
picomatch:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
ffmpeg-static@5.3.0:
|
||||||
|
resolution: {integrity: sha512-H+K6sW6TiIX6VGend0KQwthe+kaceeH/luE8dIZyOP35ik7ahYojDuqlTV1bOrtEwl01sy2HFNGQfi5IDJvotg==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
fill-range@7.1.1:
|
fill-range@7.1.1:
|
||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1529,6 +1561,13 @@ packages:
|
|||||||
html-void-elements@3.0.0:
|
html-void-elements@3.0.0:
|
||||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||||
|
|
||||||
|
http-response-object@3.0.2:
|
||||||
|
resolution: {integrity: sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==}
|
||||||
|
|
||||||
|
https-proxy-agent@5.0.1:
|
||||||
|
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
human-signals@5.0.0:
|
human-signals@5.0.0:
|
||||||
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
||||||
engines: {node: '>=16.17.0'}
|
engines: {node: '>=16.17.0'}
|
||||||
@@ -1540,6 +1579,9 @@ packages:
|
|||||||
import-meta-resolve@4.2.0:
|
import-meta-resolve@4.2.0:
|
||||||
resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
|
resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
|
||||||
|
|
||||||
|
inherits@2.0.4:
|
||||||
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
inline-style-parser@0.2.7:
|
inline-style-parser@0.2.7:
|
||||||
resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
|
resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
|
||||||
|
|
||||||
@@ -2015,6 +2057,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==}
|
resolution: {integrity: sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
parse-cache-control@1.0.1:
|
||||||
|
resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==}
|
||||||
|
|
||||||
parse-entities@4.0.2:
|
parse-entities@4.0.2:
|
||||||
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
||||||
|
|
||||||
@@ -2076,6 +2121,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
progress@2.0.3:
|
||||||
|
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
property-information@7.1.0:
|
property-information@7.1.0:
|
||||||
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
|
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
|
||||||
|
|
||||||
@@ -2113,6 +2162,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
|
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
readable-stream@3.6.2:
|
||||||
|
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
reading-time@1.5.0:
|
reading-time@1.5.0:
|
||||||
resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==}
|
resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==}
|
||||||
|
|
||||||
@@ -2213,6 +2266,9 @@ packages:
|
|||||||
rw@1.3.3:
|
rw@1.3.3:
|
||||||
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
|
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
|
||||||
|
|
||||||
|
safe-buffer@5.2.1:
|
||||||
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
safer-buffer@2.1.2:
|
safer-buffer@2.1.2:
|
||||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
|
||||||
@@ -2268,6 +2324,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-i/VCLG1fvRc95pMHRqG4aQNscv+9aIsqA2oI7ZQS51sTdUcDHYX6cpT8/tqZ+enjs1tKVwbRBWgxut9SWn+f9g==}
|
resolution: {integrity: sha512-i/VCLG1fvRc95pMHRqG4aQNscv+9aIsqA2oI7ZQS51sTdUcDHYX6cpT8/tqZ+enjs1tKVwbRBWgxut9SWn+f9g==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
string_decoder@1.3.0:
|
||||||
|
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||||
|
|
||||||
stringify-entities@4.0.4:
|
stringify-entities@4.0.4:
|
||||||
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
|
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
|
||||||
|
|
||||||
@@ -2351,6 +2410,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: ^5.5.0 || ^6.0.0
|
typescript: ^5.5.0 || ^6.0.0
|
||||||
|
|
||||||
|
typedarray@0.0.6:
|
||||||
|
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||||
|
|
||||||
typescript@5.9.3:
|
typescript@5.9.3:
|
||||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
@@ -2400,6 +2462,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
util-deprecate@1.0.2:
|
||||||
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
uuid@14.0.0:
|
uuid@14.0.0:
|
||||||
resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==}
|
resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -2475,6 +2540,13 @@ snapshots:
|
|||||||
|
|
||||||
'@chevrotain/types@11.1.2': {}
|
'@chevrotain/types@11.1.2': {}
|
||||||
|
|
||||||
|
'@derhuerst/http-basic@8.2.4':
|
||||||
|
dependencies:
|
||||||
|
caseless: 0.12.0
|
||||||
|
concat-stream: 2.0.0
|
||||||
|
http-response-object: 3.0.2
|
||||||
|
parse-cache-control: 1.0.1
|
||||||
|
|
||||||
'@emnapi/runtime@1.10.0':
|
'@emnapi/runtime@1.10.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@@ -3336,6 +3408,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 3.0.3
|
'@types/unist': 3.0.3
|
||||||
|
|
||||||
|
'@types/node@10.17.60': {}
|
||||||
|
|
||||||
'@types/node@20.19.41':
|
'@types/node@20.19.41':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.21.0
|
undici-types: 6.21.0
|
||||||
@@ -3377,6 +3451,12 @@ snapshots:
|
|||||||
|
|
||||||
acorn@8.16.0: {}
|
acorn@8.16.0: {}
|
||||||
|
|
||||||
|
agent-base@6.0.2:
|
||||||
|
dependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
arg@5.0.2: {}
|
arg@5.0.2: {}
|
||||||
|
|
||||||
aria-hidden@1.2.6:
|
aria-hidden@1.2.6:
|
||||||
@@ -3410,8 +3490,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
||||||
|
buffer-from@1.1.2: {}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001793: {}
|
caniuse-lite@1.0.30001793: {}
|
||||||
|
|
||||||
|
caseless@0.12.0: {}
|
||||||
|
|
||||||
ccount@2.0.1: {}
|
ccount@2.0.1: {}
|
||||||
|
|
||||||
chalk@5.6.2: {}
|
chalk@5.6.2: {}
|
||||||
@@ -3448,6 +3532,13 @@ snapshots:
|
|||||||
|
|
||||||
compute-scroll-into-view@3.1.1: {}
|
compute-scroll-into-view@3.1.1: {}
|
||||||
|
|
||||||
|
concat-stream@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
buffer-from: 1.1.2
|
||||||
|
inherits: 2.0.4
|
||||||
|
readable-stream: 3.6.2
|
||||||
|
typedarray: 0.0.6
|
||||||
|
|
||||||
cose-base@1.0.3:
|
cose-base@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
layout-base: 1.0.2
|
layout-base: 1.0.2
|
||||||
@@ -3681,6 +3772,8 @@ snapshots:
|
|||||||
|
|
||||||
entities@6.0.1: {}
|
entities@6.0.1: {}
|
||||||
|
|
||||||
|
env-paths@2.2.1: {}
|
||||||
|
|
||||||
es-toolkit@1.46.1: {}
|
es-toolkit@1.46.1: {}
|
||||||
|
|
||||||
esast-util-from-estree@2.0.0:
|
esast-util-from-estree@2.0.0:
|
||||||
@@ -3772,6 +3865,15 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
|
|
||||||
|
ffmpeg-static@5.3.0:
|
||||||
|
dependencies:
|
||||||
|
'@derhuerst/http-basic': 8.2.4
|
||||||
|
env-paths: 2.2.1
|
||||||
|
https-proxy-agent: 5.0.1
|
||||||
|
progress: 2.0.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
fill-range@7.1.1:
|
fill-range@7.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
@@ -3949,6 +4051,17 @@ snapshots:
|
|||||||
|
|
||||||
html-void-elements@3.0.0: {}
|
html-void-elements@3.0.0: {}
|
||||||
|
|
||||||
|
http-response-object@3.0.2:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 10.17.60
|
||||||
|
|
||||||
|
https-proxy-agent@5.0.1:
|
||||||
|
dependencies:
|
||||||
|
agent-base: 6.0.2
|
||||||
|
debug: 4.4.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
human-signals@5.0.0: {}
|
human-signals@5.0.0: {}
|
||||||
|
|
||||||
iconv-lite@0.6.3:
|
iconv-lite@0.6.3:
|
||||||
@@ -3957,6 +4070,8 @@ snapshots:
|
|||||||
|
|
||||||
import-meta-resolve@4.2.0: {}
|
import-meta-resolve@4.2.0: {}
|
||||||
|
|
||||||
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
inline-style-parser@0.2.7: {}
|
inline-style-parser@0.2.7: {}
|
||||||
|
|
||||||
internmap@1.0.1: {}
|
internmap@1.0.1: {}
|
||||||
@@ -4745,6 +4860,8 @@ snapshots:
|
|||||||
'@pagefind/windows-arm64': 1.5.2
|
'@pagefind/windows-arm64': 1.5.2
|
||||||
'@pagefind/windows-x64': 1.5.2
|
'@pagefind/windows-x64': 1.5.2
|
||||||
|
|
||||||
|
parse-cache-control@1.0.1: {}
|
||||||
|
|
||||||
parse-entities@4.0.2:
|
parse-entities@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 2.0.11
|
'@types/unist': 2.0.11
|
||||||
@@ -4811,6 +4928,8 @@ snapshots:
|
|||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
progress@2.0.3: {}
|
||||||
|
|
||||||
property-information@7.1.0: {}
|
property-information@7.1.0: {}
|
||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
@@ -4855,6 +4974,12 @@ snapshots:
|
|||||||
|
|
||||||
react@19.2.4: {}
|
react@19.2.4: {}
|
||||||
|
|
||||||
|
readable-stream@3.6.2:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
string_decoder: 1.3.0
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
|
||||||
reading-time@1.5.0: {}
|
reading-time@1.5.0: {}
|
||||||
|
|
||||||
recma-build-jsx@1.0.0:
|
recma-build-jsx@1.0.0:
|
||||||
@@ -5051,6 +5176,8 @@ snapshots:
|
|||||||
|
|
||||||
rw@1.3.3: {}
|
rw@1.3.3: {}
|
||||||
|
|
||||||
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
scheduler@0.27.0: {}
|
scheduler@0.27.0: {}
|
||||||
@@ -5129,6 +5256,10 @@ snapshots:
|
|||||||
commander: 13.1.0
|
commander: 13.1.0
|
||||||
wicked-good-xpath: 1.3.0
|
wicked-good-xpath: 1.3.0
|
||||||
|
|
||||||
|
string_decoder@1.3.0:
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
stringify-entities@4.0.4:
|
stringify-entities@4.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
character-entities-html4: 2.1.0
|
character-entities-html4: 2.1.0
|
||||||
@@ -5199,6 +5330,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
typedarray@0.0.6: {}
|
||||||
|
|
||||||
typescript@5.9.3: {}
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
undici-types@6.21.0: {}
|
undici-types@6.21.0: {}
|
||||||
@@ -5269,6 +5402,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
|
|
||||||
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
uuid@14.0.0: {}
|
uuid@14.0.0: {}
|
||||||
|
|
||||||
vfile-location@5.0.3:
|
vfile-location@5.0.3:
|
||||||
|
|||||||
BIN
public/banner.mp4
Normal file
BIN
public/banner.mp4
Normal file
Binary file not shown.
BIN
public/banner.webm
Normal file
BIN
public/banner.webm
Normal file
Binary file not shown.
74
scripts/optimize-hero-banner.mjs
Normal file
74
scripts/optimize-hero-banner.mjs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* 将 public/banner.mp4(或 banner.source.mp4)压成首屏 Hero 尺寸。
|
||||||
|
* 用法:pnpm run optimize:banner
|
||||||
|
* 可选:把未压缩母带重命名为 banner.source.mp4,脚本会优先读取它并写回 banner.mp4。
|
||||||
|
*/
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import ffmpegPath from "ffmpeg-static";
|
||||||
|
|
||||||
|
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
const publicDir = path.join(root, "public");
|
||||||
|
const sourceCandidates = [
|
||||||
|
path.join(publicDir, "banner.source.mp4"),
|
||||||
|
path.join(publicDir, "banner.mp4"),
|
||||||
|
];
|
||||||
|
const input = sourceCandidates.find((p) => fs.existsSync(p));
|
||||||
|
|
||||||
|
if (!input || !ffmpegPath) {
|
||||||
|
console.error("缺少 banner.mp4 / banner.source.mp4 或 ffmpeg 二进制。");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const outMp4 = path.join(publicDir, "banner.mp4");
|
||||||
|
const outWebm = path.join(publicDir, "banner.webm");
|
||||||
|
const tmpMp4 = path.join(publicDir, "banner.opt.mp4");
|
||||||
|
|
||||||
|
const scale = "scale=1920:-2";
|
||||||
|
const common = ["-y", "-i", input, "-an", "-vf", scale, "-pix_fmt", "yuv420p"];
|
||||||
|
|
||||||
|
console.log(`输入: ${input}`);
|
||||||
|
|
||||||
|
execFileSync(
|
||||||
|
ffmpegPath,
|
||||||
|
[
|
||||||
|
...common,
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-preset",
|
||||||
|
"slow",
|
||||||
|
"-crf",
|
||||||
|
"28",
|
||||||
|
"-movflags",
|
||||||
|
"+faststart",
|
||||||
|
tmpMp4,
|
||||||
|
],
|
||||||
|
{ stdio: "inherit" },
|
||||||
|
);
|
||||||
|
|
||||||
|
execFileSync(
|
||||||
|
ffmpegPath,
|
||||||
|
[
|
||||||
|
...common,
|
||||||
|
"-c:v",
|
||||||
|
"libvpx-vp9",
|
||||||
|
"-crf",
|
||||||
|
"35",
|
||||||
|
"-b:v",
|
||||||
|
"0",
|
||||||
|
"-row-mt",
|
||||||
|
"1",
|
||||||
|
outWebm,
|
||||||
|
],
|
||||||
|
{ stdio: "inherit" },
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.copyFileSync(tmpMp4, outMp4);
|
||||||
|
fs.unlinkSync(tmpMp4);
|
||||||
|
|
||||||
|
for (const f of [outMp4, outWebm]) {
|
||||||
|
const kb = (fs.statSync(f).size / 1024).toFixed(1);
|
||||||
|
console.log(`${path.basename(f)}: ${kb} KiB`);
|
||||||
|
}
|
||||||
163
src/components/hero-banner-video.tsx
Normal file
163
src/components/hero-banner-video.tsx
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useReducedMotion } from "motion/react";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
const POSTER = "/banner.png";
|
||||||
|
const WEBM = "/banner.webm";
|
||||||
|
const MP4 = "/banner.mp4";
|
||||||
|
|
||||||
|
const videoClassName =
|
||||||
|
"pointer-events-none absolute inset-0 h-full w-full object-cover object-center";
|
||||||
|
|
||||||
|
function HeroBannerSources() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<source src={WEBM} type="video/webm" />
|
||||||
|
<source src={MP4} type="video/mp4" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function seekToStart(video: HTMLVideoElement) {
|
||||||
|
if (typeof video.fastSeek === "function") {
|
||||||
|
try {
|
||||||
|
video.fastSeek(0);
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
video.currentTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function primeVideo(el: HTMLVideoElement, preload: "auto" | "none") {
|
||||||
|
el.muted = true;
|
||||||
|
el.playsInline = true;
|
||||||
|
el.preload = preload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 双轨在 ended 时刻精确切换:不提前截断,保证末帧与首帧对齐。
|
||||||
|
* 副轨 preload=none,仅在接力前加载,减少首屏带宽与解码占用。
|
||||||
|
*/
|
||||||
|
export function HeroBannerVideo() {
|
||||||
|
const reduceMotion = useReducedMotion();
|
||||||
|
const refA = useRef<HTMLVideoElement>(null);
|
||||||
|
const refB = useRef<HTMLVideoElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (reduceMotion) return;
|
||||||
|
|
||||||
|
const videoA = refA.current;
|
||||||
|
const videoB = refB.current;
|
||||||
|
if (!videoA || !videoB) return;
|
||||||
|
|
||||||
|
primeVideo(videoA, "auto");
|
||||||
|
primeVideo(videoB, "none");
|
||||||
|
|
||||||
|
let active: HTMLVideoElement = videoA;
|
||||||
|
let idle: HTMLVideoElement = videoB;
|
||||||
|
let idlePrimed = false;
|
||||||
|
|
||||||
|
const show = (el: HTMLVideoElement, visible: boolean) => {
|
||||||
|
el.style.opacity = visible ? "1" : "0";
|
||||||
|
};
|
||||||
|
|
||||||
|
show(videoA, true);
|
||||||
|
show(videoB, false);
|
||||||
|
|
||||||
|
const primeIdle = () => {
|
||||||
|
if (idlePrimed) return;
|
||||||
|
idlePrimed = true;
|
||||||
|
idle.preload = "auto";
|
||||||
|
idle.load();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEnded = (endedVideo: HTMLVideoElement) => {
|
||||||
|
if (endedVideo !== active) return;
|
||||||
|
|
||||||
|
seekToStart(endedVideo);
|
||||||
|
endedVideo.pause();
|
||||||
|
show(endedVideo, false);
|
||||||
|
|
||||||
|
active = idle;
|
||||||
|
idle = endedVideo;
|
||||||
|
|
||||||
|
primeIdle();
|
||||||
|
seekToStart(active);
|
||||||
|
show(active, true);
|
||||||
|
void active.play().catch(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEndedA = () => onEnded(videoA);
|
||||||
|
const handleEndedB = () => onEnded(videoB);
|
||||||
|
|
||||||
|
const warmIdleBeforeHandoff = (ev: Event) => {
|
||||||
|
const current = ev.currentTarget as HTMLVideoElement;
|
||||||
|
if (current !== active) return;
|
||||||
|
const duration = current.duration;
|
||||||
|
if (!Number.isFinite(duration) || duration <= 0) return;
|
||||||
|
if (duration - current.currentTime <= 1.5) {
|
||||||
|
primeIdle();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
videoA.addEventListener("ended", handleEndedA);
|
||||||
|
videoB.addEventListener("ended", handleEndedB);
|
||||||
|
videoA.addEventListener("timeupdate", warmIdleBeforeHandoff);
|
||||||
|
videoB.addEventListener("timeupdate", warmIdleBeforeHandoff);
|
||||||
|
|
||||||
|
void videoA.play().catch(() => {});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
videoA.removeEventListener("ended", handleEndedA);
|
||||||
|
videoB.removeEventListener("ended", handleEndedB);
|
||||||
|
videoA.removeEventListener("timeupdate", warmIdleBeforeHandoff);
|
||||||
|
videoB.removeEventListener("timeupdate", warmIdleBeforeHandoff);
|
||||||
|
};
|
||||||
|
}, [reduceMotion]);
|
||||||
|
|
||||||
|
if (reduceMotion === true) {
|
||||||
|
return (
|
||||||
|
<Image
|
||||||
|
src={POSTER}
|
||||||
|
alt=""
|
||||||
|
fill
|
||||||
|
priority
|
||||||
|
className={videoClassName}
|
||||||
|
sizes="100vw"
|
||||||
|
aria-hidden
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<video
|
||||||
|
ref={refA}
|
||||||
|
autoPlay
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
preload="auto"
|
||||||
|
poster={POSTER}
|
||||||
|
className={videoClassName}
|
||||||
|
aria-hidden
|
||||||
|
>
|
||||||
|
<HeroBannerSources />
|
||||||
|
</video>
|
||||||
|
<video
|
||||||
|
ref={refB}
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
preload="none"
|
||||||
|
poster={POSTER}
|
||||||
|
className={videoClassName}
|
||||||
|
aria-hidden
|
||||||
|
>
|
||||||
|
<HeroBannerSources />
|
||||||
|
</video>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import { HeroBannerVideo } from "@/components/hero-banner-video";
|
||||||
import { site } from "@/content/site";
|
import { site } from "@/content/site";
|
||||||
|
|
||||||
export function HeroSection() {
|
export function HeroSection() {
|
||||||
@@ -8,14 +8,7 @@ export function HeroSection() {
|
|||||||
className="hero-section relative isolate z-0 overflow-hidden"
|
className="hero-section relative isolate z-0 overflow-hidden"
|
||||||
id="top"
|
id="top"
|
||||||
>
|
>
|
||||||
<Image
|
<HeroBannerVideo />
|
||||||
src="/banner.png"
|
|
||||||
alt="海宇数科品牌视觉"
|
|
||||||
fill
|
|
||||||
priority
|
|
||||||
className="pointer-events-none object-cover object-center"
|
|
||||||
sizes="100vw"
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
className="hero-section__shade hero-section__shade--mobile pointer-events-none absolute inset-0"
|
className="hero-section__shade hero-section__shade--mobile pointer-events-none absolute inset-0"
|
||||||
aria-hidden
|
aria-hidden
|
||||||
|
|||||||
Reference in New Issue
Block a user