feat: animated icons

This commit is contained in:
ThaUnknown 2025-08-31 21:19:24 +02:00
parent 0f0f06d6aa
commit 8dd43a635b
No known key found for this signature in database
36 changed files with 1295 additions and 90 deletions

View file

@ -52,6 +52,7 @@
"@cloudflare/speedtest": "^1.4.1",
"@fontsource-variable/nunito": "^5.2.5",
"@fontsource/geist-mono": "^5.2.6",
"@jis3r/icons": "^1.1.5",
"@prgm/sveltekit-progress-bar": "2.0.0",
"@thaunknown/web-irc": "^1.0.3",
"@urql/core": "^5.2.0",

View file

@ -17,6 +17,9 @@ importers:
'@fontsource/geist-mono':
specifier: ^5.2.6
version: 5.2.6
'@jis3r/icons':
specifier: ^1.1.5
version: 1.1.5(react@19.0.0)
'@prgm/sveltekit-progress-bar':
specifier: 2.0.0
version: 2.0.0(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(terser@5.43.1)))(svelte@4.2.19)(vite@5.4.19(terser@5.43.1)))(svelte@4.2.19)
@ -176,7 +179,7 @@ importers:
version: 1.8.10(@gql.tada/svelte-support@1.0.1(svelte@4.2.19)(typescript@5.8.3))(graphql@16.10.0)(typescript@5.8.3)
hayase-extensions:
specifier: github:hayase-app/extensions
version: https://codeload.github.com/hayase-app/extensions/tar.gz/675c4a7cfa1e2b4e88c2d11c4c195c33c68116e0
version: https://codeload.github.com/hayase-app/extensions/tar.gz/785940de1833af9b5eb0f41dc3a537c881cb6276
jassub:
specifier: ^1.8.6
version: 1.8.6
@ -491,6 +494,9 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@jis3r/icons@1.1.5':
resolution: {integrity: sha512-A3W+SEI/EST0+UM9G/a7e5hwFpr6BTbEgJ74MeIfpH2pdUdNWR7AWzzBPCG8k36XSi2qqqg3kI1kxFj3i5kYOQ==}
'@jridgewell/gen-mapping@0.3.12':
resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
@ -498,6 +504,9 @@ packages:
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
engines: {node: '>=6.0.0'}
'@jridgewell/remapping@2.3.5':
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
@ -518,6 +527,11 @@ packages:
'@jridgewell/trace-mapping@0.3.29':
resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
'@lucide/svelte@0.535.0':
resolution: {integrity: sha512-LSVs0G+IXSHHxMl/U6bHTnDP/pbmwpS7/mkCDXmWD9Wi0oQlZihKFoFLjDFhC+6mdfRE6ZgBasXTusvrOYv0lA==}
peerDependencies:
svelte: ^5
'@melt-ui/svelte@0.76.2':
resolution: {integrity: sha512-7SbOa11tXUS95T3fReL+dwDs5FyJtCEqrqG3inRziDws346SYLsxOQ6HmX+4BkIsQh1R8U3XNa+EMmdMt38lMA==}
peerDependencies:
@ -535,6 +549,11 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
'@number-flow/svelte@0.3.9':
resolution: {integrity: sha512-CTw1+e0074GzbPX2IHcNCaK8nqxGNCOIUnQUjEjhcmBwBxOAhN3GYLQ6cJHvhQnWwplVe4eQ3z+c25Vttr2stQ==}
peerDependencies:
svelte: ^4 || ^5
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@ -542,6 +561,9 @@ packages:
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
'@posthog/core@1.0.2':
resolution: {integrity: sha512-hWk3rUtJl2crQK0WNmwg13n82hnTwB99BT99/XI5gZSvIlYZ1TPmMZE8H2dhJJ98J/rm9vYJ/UXNzw3RV5HTpQ==}
'@prgm/sveltekit-progress-bar@2.0.0':
resolution: {integrity: sha512-N9SlYDfpqaY9MyG85Wk38R9/BipIUdTJ4U7LVPY5cFn5cwGZrVA1lsXC3I2kmGtwz+DF6v/DvySkYOWCPmJV4A==}
engines: {node: '>=18'}
@ -1060,6 +1082,10 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
commander@14.0.0:
resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
engines: {node: '>=20'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@ -1080,6 +1106,9 @@ packages:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
core-js@3.45.1:
resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@ -1378,6 +1407,9 @@ packages:
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
engines: {node: '>=0.10'}
esrap@2.1.0:
resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==}
esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
@ -1424,6 +1456,9 @@ packages:
picomatch:
optional: true
fflate@0.4.8:
resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
@ -1457,6 +1492,20 @@ packages:
fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
framer-motion@12.23.12:
resolution: {integrity: sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==}
peerDependencies:
'@emotion/is-prop-valid': '*'
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
peerDependenciesMeta:
'@emotion/is-prop-valid':
optional: true
react:
optional: true
react-dom:
optional: true
fs-extra@11.3.0:
resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
engines: {node: '>=14.14'}
@ -1583,13 +1632,16 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/675c4a7cfa1e2b4e88c2d11c4c195c33c68116e0:
resolution: {tarball: https://codeload.github.com/hayase-app/extensions/tar.gz/675c4a7cfa1e2b4e88c2d11c4c195c33c68116e0}
hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/785940de1833af9b5eb0f41dc3a537c881cb6276:
resolution: {tarball: https://codeload.github.com/hayase-app/extensions/tar.gz/785940de1833af9b5eb0f41dc3a537c881cb6276}
version: 1.0.6
idb-keyval@6.2.2:
resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==}
iflog@0.3.0:
resolution: {integrity: sha512-H66Mn4YfPG+GdTLniaV0Fa+Op19nNdXbWEIgSlq6ZuEr8M0znKEoWmKkg5XpEAaPQBK/IgPkl23PxB9HtBRa9Q==}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@ -1882,9 +1934,34 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
mode-watcher@0.5.1:
resolution: {integrity: sha512-adEC6T7TMX/kzQlaO/MtiQOSFekZfQu4MC+lXyoceQG+U5sKpJWZ4yKXqw846ExIuWJgedkOIPqAYYRk/xHm+w==}
peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.1
moment@2.30.1:
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
motion-dom@12.23.12:
resolution: {integrity: sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==}
motion-utils@12.23.6:
resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==}
motion@12.23.12:
resolution: {integrity: sha512-8jCD8uW5GD1csOoqh1WhH1A6j5APHVE15nuBkFeRiMzYBdRwyAHmSP/oXSuW0WJPZRXTFdBoG4hY9TFWNhhwng==}
peerDependencies:
'@emotion/is-prop-valid': '*'
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
peerDependenciesMeta:
'@emotion/is-prop-valid':
optional: true
react:
optional: true
react-dom:
optional: true
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@ -1919,6 +1996,9 @@ packages:
no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
node-fetch-native@1.6.7:
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
@ -1943,6 +2023,9 @@ packages:
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
engines: {node: '>=0.10.0'}
number-flow@0.5.8:
resolution: {integrity: sha512-FPr1DumWyGi5Nucoug14bC6xEz70A1TnhgSHhKyfqjgji2SOTz+iLJxKtv37N5JyJbteGYCm6NQ9p1O4KZ7iiA==}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@ -2133,6 +2216,24 @@ packages:
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
posthog-js@1.261.0:
resolution: {integrity: sha512-jyiXqyrCU+VlpbNNVRA6OQYAVut0XZMYNELCZH+XvTd981VqbE4jXn4XCBreo7XCL2gdPgDVxUVOuzNvEuKcmw==}
peerDependencies:
'@rrweb/types': 2.0.0-alpha.17
rrweb-snapshot: 2.0.0-alpha.17
peerDependenciesMeta:
'@rrweb/types':
optional: true
rrweb-snapshot:
optional: true
preact@10.27.1:
resolution: {integrity: sha512-V79raXEWch/rbqoNc7nT9E4ep7lu+mI3+sBmfRD4i1M73R3WLYcCtdI0ibxGVf4eQL8ZIz2nFacqEC+rmnOORQ==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -2246,6 +2347,10 @@ packages:
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
engines: {node: '>= 0.4'}
shadcn-svelte@1.0.7:
resolution: {integrity: sha512-WM012JGATJpEqCaSNd9eAscFr/HKwLmRD5TplBXvhuMgbAVUNsjKiOSyvvjrZDx9L2FEqoEu9Ld5JpKr3xe2yQ==}
hasBin: true
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@ -2467,6 +2572,10 @@ packages:
resolution: {integrity: sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==}
engines: {node: '>=16'}
svelte@5.38.6:
resolution: {integrity: sha512-ltBPlkvqk3bgCK7/N323atUpP3O3Y+DrGV4dcULrsSn4fZaaNnOmdplNznwfdWclAgvSr5rxjtzn/zJhRm6TKg==}
engines: {node: '>=18'}
tabbable@6.2.0:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
@ -2667,6 +2776,9 @@ packages:
vscode-languageserver-textdocument@1.0.12:
resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==}
web-vitals@4.2.4:
resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==}
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
@ -2761,6 +2873,9 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
zimmerframe@1.1.2:
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
snapshots:
'@0no-co/graphql.web@1.1.2(graphql@16.10.0)':
@ -2966,11 +3081,27 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@jis3r/icons@1.1.5(react@19.0.0)':
dependencies:
'@lucide/svelte': 0.535.0(svelte@5.38.6)
'@number-flow/svelte': 0.3.9(svelte@5.38.6)
iflog: 0.3.0
mode-watcher: 0.5.1(svelte@5.38.6)
motion: 12.23.12(react@19.0.0)
posthog-js: 1.261.0
shadcn-svelte: 1.0.7
svelte: 5.38.6
transitivePeerDependencies:
- '@emotion/is-prop-valid'
- '@rrweb/types'
- react
- react-dom
- rrweb-snapshot
'@jridgewell/gen-mapping@0.3.12':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.29
optional: true
'@jridgewell/gen-mapping@0.3.8':
dependencies:
@ -2978,6 +3109,11 @@ snapshots:
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25
'@jridgewell/remapping@2.3.5':
dependencies:
'@jridgewell/gen-mapping': 0.3.12
'@jridgewell/trace-mapping': 0.3.29
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/set-array@1.2.1': {}
@ -2999,7 +3135,10 @@ snapshots:
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
optional: true
'@lucide/svelte@0.535.0(svelte@5.38.6)':
dependencies:
svelte: 5.38.6
'@melt-ui/svelte@0.76.2(svelte@4.2.19)':
dependencies:
@ -3023,11 +3162,19 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
'@number-flow/svelte@0.3.9(svelte@5.38.6)':
dependencies:
esm-env: 1.2.2
number-flow: 0.5.8
svelte: 5.38.6
'@pkgjs/parseargs@0.11.0':
optional: true
'@polka/url@1.0.0-next.29': {}
'@posthog/core@1.0.2': {}
'@prgm/sveltekit-progress-bar@2.0.0(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(terser@5.43.1)))(svelte@4.2.19)(vite@5.4.19(terser@5.43.1)))(svelte@4.2.19)':
dependencies:
'@sveltejs/kit': 2.21.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.19(terser@5.43.1)))(svelte@4.2.19)(vite@5.4.19(terser@5.43.1))
@ -3624,6 +3771,8 @@ snapshots:
color-name@1.1.4: {}
commander@14.0.0: {}
commander@2.20.3: {}
commander@4.1.1: {}
@ -3638,6 +3787,8 @@ snapshots:
cookie@0.6.0: {}
core-js@3.45.1: {}
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@ -4066,6 +4217,10 @@ snapshots:
dependencies:
estraverse: 5.3.0
esrap@2.1.0:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
esrecurse@4.3.0:
dependencies:
estraverse: 5.3.0
@ -4104,6 +4259,8 @@ snapshots:
optionalDependencies:
picomatch: 4.0.2
fflate@0.4.8: {}
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
@ -4139,6 +4296,14 @@ snapshots:
fraction.js@4.3.7: {}
framer-motion@12.23.12(react@19.0.0):
dependencies:
motion-dom: 12.23.12
motion-utils: 12.23.6
tslib: 2.8.1
optionalDependencies:
react: 19.0.0
fs-extra@11.3.0:
dependencies:
graceful-fs: 4.2.11
@ -4276,10 +4441,12 @@ snapshots:
dependencies:
function-bind: 1.1.2
hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/675c4a7cfa1e2b4e88c2d11c4c195c33c68116e0: {}
hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/785940de1833af9b5eb0f41dc3a537c881cb6276: {}
idb-keyval@6.2.2: {}
iflog@0.3.0: {}
ignore@5.3.2: {}
ignore@7.0.4: {}
@ -4553,8 +4720,25 @@ snapshots:
minipass@7.1.2: {}
mode-watcher@0.5.1(svelte@5.38.6):
dependencies:
svelte: 5.38.6
moment@2.30.1: {}
motion-dom@12.23.12:
dependencies:
motion-utils: 12.23.6
motion-utils@12.23.6: {}
motion@12.23.12(react@19.0.0):
dependencies:
framer-motion: 12.23.12(react@19.0.0)
tslib: 2.8.1
optionalDependencies:
react: 19.0.0
mri@1.2.0: {}
mrmime@2.0.1: {}
@ -4580,6 +4764,8 @@ snapshots:
lower-case: 2.0.2
tslib: 2.8.1
node-fetch-native@1.6.7: {}
node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
@ -4593,6 +4779,10 @@ snapshots:
normalize-range@0.1.2: {}
number-flow@0.5.8:
dependencies:
esm-env: 1.2.2
object-assign@4.1.1: {}
object-hash@3.0.0: {}
@ -4771,6 +4961,22 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
postcss@8.5.6:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
posthog-js@1.261.0:
dependencies:
'@posthog/core': 1.0.2
core-js: 3.45.1
fflate: 0.4.8
preact: 10.27.1
web-vitals: 4.2.4
preact@10.27.1: {}
prelude-ls@1.2.1: {}
punycode@2.3.1: {}
@ -4922,6 +5128,12 @@ snapshots:
es-errors: 1.3.0
es-object-atoms: 1.1.1
shadcn-svelte@1.0.7:
dependencies:
commander: 14.0.0
node-fetch-native: 1.6.7
postcss: 8.5.6
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
@ -5192,6 +5404,23 @@ snapshots:
magic-string: 0.30.17
periscopic: 3.1.0
svelte@5.38.6:
dependencies:
'@jridgewell/remapping': 2.3.5
'@jridgewell/sourcemap-codec': 1.5.0
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.14.1)
'@types/estree': 1.0.7
acorn: 8.14.1
aria-query: 5.3.2
axobject-query: 4.1.0
clsx: 2.1.1
esm-env: 1.2.2
esrap: 2.1.0
is-reference: 3.0.3
locate-character: 3.0.0
magic-string: 0.30.17
zimmerframe: 1.1.2
tabbable@6.2.0: {}
tailwind-merge@3.0.2: {}
@ -5405,6 +5634,8 @@ snapshots:
vscode-languageserver-textdocument@1.0.12: {}
web-vitals@4.2.4: {}
webidl-conversions@3.0.1: {}
webidl-conversions@4.0.2:
@ -5511,3 +5742,5 @@ snapshots:
yaml@2.6.0: {}
yocto-queue@0.1.0: {}
zimmerframe@1.1.2: {}

View file

@ -282,6 +282,12 @@ details,
height: 4px !important;
}
/* animated SVG icons */
.animated-icon:not(:hover):not(:focus-visible):not(:active) .target-animated-icon {
animation: none !important;
transform: translateX(0) translateX(0) translateZ(0) translate(0, 0) !important;
}
/* Backplate related things */
body {

View file

@ -1,5 +1,5 @@
<script lang='ts'>
import PencilLine from 'lucide-svelte/icons/pencil-line'
import { PencilLine } from './icons/animated'
import { Button } from '$lib/components/ui/button'
import * as Dialog from '$lib/components/ui/dialog'
@ -37,7 +37,7 @@
<Dialog.Root portal='#root'>
<Dialog.Trigger let:builder asChild>
<Button size='icon' class='rounded-l-none bg-custom-400 select:!bg-custom-700 shrink-0 text-contrast' builders={[builder]}>
<Button size='icon' class='rounded-l-none bg-custom-400 select:!bg-custom-700 shrink-0 text-contrast animated-icon' builders={[builder]}>
<PencilLine class='size-4' />
</Button>
</Dialog.Trigger>

View file

@ -1,9 +1,8 @@
<script lang='ts'>
import ChevronLeft from 'lucide-svelte/icons/chevron-left'
import ChevronRight from 'lucide-svelte/icons/chevron-right'
import Play from 'lucide-svelte/icons/play'
import Pagination from './Pagination.svelte'
import { ChevronLeft, ChevronRight } from './icons/animated'
import { Button } from './ui/button'
import { Load } from './ui/img'
import { playEp } from './ui/player/mediahandler.svelte'
@ -115,8 +114,8 @@
Showing <span class='font-bold'>{range.start + 1}</span> to <span class='font-bold'>{range.end}</span> of <span class='font-bold'>{episodeCount}</span> episodes
</p>
<div class='w-full md:w-auto gap-2 flex items-center'>
<Button size='icon' variant='ghost' on:click={() => setPage(currentPage - 1)} disabled={!hasPrev}>
<ChevronLeft class='h-4 w-4' />
<Button size='icon' variant='ghost' class='animated-icon' on:click={() => setPage(currentPage - 1)} disabled={!hasPrev}>
<ChevronLeft class='size-4' />
</Button>
{#if $breakpoints.md}
{#each pages as { page, type } (page)}
@ -133,8 +132,8 @@
Showing <span class='font-bold'>{range.start + 1}</span> to <span class='font-bold'>{range.end}</span> of <span class='font-bold'>{episodeCount}</span> episodes
</p>
{/if}
<Button size='icon' variant='ghost' on:click={() => setPage(currentPage + 1)} disabled={!hasNext}>
<ChevronRight class='h-4 w-4' />
<Button size='icon' variant='ghost' class='animated-icon' on:click={() => setPage(currentPage + 1)} disabled={!hasNext}>
<ChevronRight class='size-4' />
</Button>
</div>
</div>

View file

@ -0,0 +1,43 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible [transform-origin:center] target-animated-icon')}
{...$$restProps}
>
<path
d='M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z'
/><circle cx='12' cy='12' r='4' />
</svg>
<style>
.target-animated-icon {
animation: screw-rotate 1s ease 3;
}
@keyframes screw-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(180deg);
}
}
</style>

View file

@ -0,0 +1,47 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size: number | string = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible target-animated-icon')}
{...$$restProps}
>
<path d='m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z' />
</svg>
<style>
.target-animated-icon {
animation: primaryAnimation 0.5s ease-in-out;
}
@keyframes primaryAnimation {
0% {
transform: scale(1) rotate(0deg);
}
20% {
transform: scale(1.05) rotate(-7deg);
}
40% {
transform: scale(1.05) rotate(7deg);
}
100% {
transform: scale(1) rotate(0deg);
}
}
</style>

View file

@ -0,0 +1,68 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
const DOTS = [
{ cx: 8, cy: 14 },
{ cx: 12, cy: 14 },
{ cx: 16, cy: 14 },
{ cx: 8, cy: 18 },
{ cx: 12, cy: 18 },
{ cx: 16, cy: 18 }
]
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='M8 2v4' />
<path d='M16 2v4' />
<rect width='18' height='18' x='3' y='4' rx='2' />
<path d='M3 10h18' />
{#each DOTS as dot, index (index)}
<circle
cx={dot.cx}
cy={dot.cy}
r='1'
fill={color}
stroke='none'
class='target-animated-icon'
style='animation-delay: {index * 0.17}s'
/>
{/each}
</svg>
<style>
.target-animated-icon {
animation: pulse 0.8s;
}
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
</style>

View file

@ -0,0 +1,33 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size: number | string = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='m15 18-6-6 6-6' class='target-animated-icon' />
</svg>
<style>
.target-animated-icon {
transition: transform 0.2s ease-in;
transform: translateX(-3px);
}
</style>

View file

@ -0,0 +1,33 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size: number | string = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='m9 18 6-6-6-6' class='target-animated-icon' />
</svg>
<style>
.target-animated-icon {
transition: transform 0.2s ease-in;
transform: translateX(3px);
}
</style>

View file

@ -0,0 +1,76 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<g class='target-animated-icon clapperboard-outer'>
<g class='target-animated-icon clapperboard-inner'>
<path d='M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3Z' />
<path d='m6.2 5.3 3.1 3.9' />
<path d='m12.4 3.4 3.1 4' />
</g>
<path d='M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z' />
</g>
</svg>
<style>
.clapperboard-outer {
transform-origin: 4px 20px;
}
.clapperboard-inner {
transform-origin: 3px 11px;
}
.target-animated-icon {
animation: clapperboardOuter 0.8s ease-in-out;
}
.target-animated-icon {
animation: clapperboardInner 0.4s ease-in-out;
}
@keyframes clapperboardOuter {
0%,
50% {
transform: rotate(-10deg);
}
100% {
transform: rotate(0deg);
}
}
@keyframes clapperboardInner {
0% {
transform: rotate(0deg);
}
30% {
transform: rotate(-10deg);
}
60% {
transform: rotate(16deg);
}
100% {
transform: rotate(0deg);
}
}
</style>

View file

@ -0,0 +1,37 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4' />
<g>
<polyline points='7 10 12 15 17 10' class='target-animated-icon' />
<line x1='12' x2='12' y1='15' y2='3' class='target-animated-icon' />
</g>
</svg>
<style>
.target-animated-icon {
transform: translateY(2px);
transition: transform 0.3s cubic-bezier(0.68, -0.6, 0.32, 1.6);
}
</style>

View file

@ -0,0 +1,50 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible target-animated-icon')}
{...$$restProps}
>
<path d='M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z' />
<path d='M14 2v4a2 2 0 0 0 2 2h4' />
<circle cx='10' cy='12' r='2' />
<path d='m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22' />
</svg>
<style>
.target-animated-icon {
animation: primaryAnimation 0.5s ease-in-out;
}
@keyframes primaryAnimation {
0% {
transform: scale(1) rotate(0deg);
}
20% {
transform: scale(1.05) rotate(-7deg);
}
40% {
transform: scale(1.05) rotate(7deg);
}
100% {
transform: scale(1) rotate(0deg);
}
}
</style>

View file

@ -0,0 +1,60 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size: number | string = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path
d='M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z'
class='target-animated-icon'
/>
</svg>
<style>
.target-animated-icon {
transform-origin: center;
animation: heartBeat 1.2s ease-in-out;
}
@keyframes heartBeat {
0% {
transform: scale(1);
}
16.67% {
transform: scale(1.1);
}
33.33% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
66.67% {
transform: scale(1);
}
83.33% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
</style>

View file

@ -0,0 +1,52 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path
d='M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'
/>
<path d='M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8' class='target-animated-icon' />
</svg>
<style>
.target-animated-icon {
stroke-dasharray: 22;
stroke-dashoffset: 0;
animation: doorAnimation 0.6s ease-out forwards;
}
@keyframes doorAnimation {
0% {
stroke-dashoffset: 22;
opacity: 0;
}
15% {
stroke-dashoffset: 22;
opacity: 0;
}
100% {
stroke-dashoffset: 0;
opacity: 1;
}
}
</style>

View file

@ -0,0 +1,18 @@
export { default as Home } from './home.svelte'
export { default as Search } from './search.svelte'
export { default as Calendar } from './calendar.svelte'
export { default as Users } from './users.svelte'
export { default as Download } from './download.svelte'
export { default as Bolt } from './bolt.svelte'
export { default as LogIn } from './login.svelte'
export { default as Messages } from './messages.svelte'
export { default as PencilLine } from './pencilline.svelte'
export { default as Heart } from './heart.svelte'
export { default as Bookmark } from './bookmark.svelte'
export { default as Clapperboard } from './clapperboard.svelte'
export { default as ChevronRight } from './chevronright.svelte'
export { default as ChevronLeft } from './chevronleft.svelte'
export { default as Trash } from './trash.svelte'
export { default as FileImage } from './fileimage.svelte'
export { default as Minimize } from './minimize.svelte'
export { default as Maximize } from './maximize.svelte'

View file

@ -0,0 +1,37 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible -rotate-90')}
{...$$restProps}
>
<path d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4' />
<g>
<polyline points='7 10 12 15 17 10' class='target-animated-icon' />
<line x1='12' x2='12' y1='15' y2='3' class='target-animated-icon' />
</g>
</svg>
<style>
.target-animated-icon {
transform: translateY(2px);
transition: transform 0.3s cubic-bezier(0.68, -0.6, 0.32, 1.6);
}
</style>

View file

@ -0,0 +1,55 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size: string | number = 24
export let strokeWidth: string | number = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='M8 3H5a2 2 0 0 0-2 2v3' class='top-left target-animated-icon' />
<path d='M21 8V5a2 2 0 0 0-2-2h-3' class='top-right target-animated-icon' />
<path d='M3 16v3a2 2 0 0 0 2 2h3' class='bottom-left target-animated-icon' />
<path d='M16 21h3a2 2 0 0 0 2-2v-3' class='bottom-right target-animated-icon' />
</svg>
<style>
path {
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.bottom-right {
transform: translate(2px, 2px);
}
.bottom-left {
transform: translate(-2px, 2px);
}
.top-right {
transform: translate(2px, -2px);
}
.top-left {
transform: translate(-2px, -2px);
}
svg {
overflow: visible;
}
</style>

View file

@ -0,0 +1,48 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible target-animated-icon')}
{...$$restProps}
>
<path d='M14 9a2 2 0 0 1-2 2H6l-4 4V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2z' />
<path d='M18 9h2a2 2 0 0 1 2 2v11l-4-4h-6a2 2 0 0 1-2-2v-1' />
</svg>
<style>
.target-animated-icon {
animation: primaryAnimation 0.5s ease-in-out;
}
@keyframes primaryAnimation {
0% {
transform: scale(1) rotate(0deg);
}
20% {
transform: scale(1.05) rotate(-7deg);
}
40% {
transform: scale(1.05) rotate(7deg);
}
100% {
transform: scale(1) rotate(0deg);
}
}
</style>

View file

@ -0,0 +1,51 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size: string | number = 24
export let strokeWidth: string | number = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='M8 3v3a2 2 0 0 1-2 2H3' class='top-left target-animated-icon' />
<path d='M21 8h-3a2 2 0 0 1-2-2V3' class='top-right target-animated-icon' />
<path d='M3 16h3a2 2 0 0 1 2 2v3' class='bottom-left target-animated-icon' />
<path d='M16 21v-3a2 2 0 0 1 2-2h3' class='bottom-right target-animated-icon' />
</svg>
<style>
path {
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.bottom-right {
transform: translate(-1px, -1px);
}
.top-left {
transform: translate(1px, 1px);
}
.bottom-left {
transform: translate(1px, -1px);
}
.top-right {
transform: translate(-1px, 1px);
}
</style>

View file

@ -0,0 +1,51 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='M12 20h9' />
<path
d='M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z'
class='target-animated-icon'
/>
<path d='m15 5 3 3' class='target-animated-icon' />
</svg>
<style>
.target-animated-icon {
transform-origin: 16.376px 3.622px;
animation: penWiggle 0.5s ease-in-out 2;
}
@keyframes penWiggle {
0%,
100% {
transform: rotate(0deg) translate(0px, 0px);
}
25% {
transform: rotate(-0.5deg) translate(-1px, 1.5px);
}
75% {
transform: rotate(0.5deg) translate(1.5px, -1px);
}
}
</style>

View file

@ -0,0 +1,46 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible target-animated-icon')}
{...$$restProps}
>
<circle cx='11' cy='11' r='8' />
<path d='m21 21-4.3-4.3' />
</svg>
<style>
.target-animated-icon {
animation: search-bounce 1s ease-in-out;
}
@keyframes search-bounce {
0%,
100% {
transform: translateX(0) translateY(0);
}
25% {
transform: translateX(0) translateY(-4px);
}
50% {
transform: translateX(-3px) translateY(0);
}
}
</style>

View file

@ -0,0 +1,41 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible [transform-origin:center]')}
{...$$restProps}
>
<g class='target-animated-icon'>
<path d='M3 6h18' />
<path d='M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2' />
</g>
<path d='M19 8v12c0 1-1 2-2 2H7c-1 0-2-1-2-2V8' class='target-animated-icon' />
</svg>
<style>
g.target-animated-icon {
transform: translateY(-1px);
transition: transform 0.2s ease-in;
}
path.target-animated-icon {
transform: translateY(1px);
transition: transform 0.2s ease-in;
}
</style>

View file

@ -0,0 +1,47 @@
<script lang='ts'>
import { cn } from '$lib/utils'
export let color = 'currentColor'
export let size = 24
export let strokeWidth = 2
let className = ''
export { className as class }
</script>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
viewBox='0 0 24 24'
fill='none'
stroke={color}
stroke-width={strokeWidth}
stroke-linecap='round'
stroke-linejoin='round'
class={cn(className, 'overflow-visible')}
{...$$restProps}
>
<path d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2' />
<circle cx='9' cy='7' r='4' />
<path d='M22 21v-2a4 4 0 0 0-3-3.87' class='target-animated-icon' />
<path d='M16 3.13a4 4 0 0 1 0 7.75' class='target-animated-icon' />
</svg>
<style>
.target-animated-icon {
animation: users-slide 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}
@keyframes users-slide {
0% {
transform: translateX(0);
}
50% {
transform: translateX(-6px);
}
100% {
transform: translateX(0);
}
}
</style>

View file

@ -1,11 +1,11 @@
<script lang='ts'>
import Bookmark from 'lucide-svelte/icons/bookmark'
import type { Media } from '$lib/modules/anilist'
import { Bookmark } from '$lib/components/icons/animated'
import { Button, iconSizes, type Props } from '$lib/components/ui/button'
import { list, authAggregator, lists } from '$lib/modules/auth'
import { clickwrap, keywrap } from '$lib/modules/navigate'
import { cn } from '$lib/utils'
type $$Props = Props & { media: Media }
@ -27,6 +27,6 @@
let key = 1
</script>
<Button {size} {variant} class={className} on:click={clickwrap(toggleBookmark)} on:keydown={keywrap(toggleBookmark)}>
<Button {size} {variant} class={cn(className, 'animated-icon')} on:click={clickwrap(toggleBookmark)} on:keydown={keywrap(toggleBookmark)}>
<Bookmark fill={key && list(media) ? 'currentColor' : 'transparent'} size={iconSizes[size]} />
</Button>

View file

@ -1,9 +1,11 @@
import Bookmark from './bookmark.svelte'
import Favorite from './favorite.svelte'
import Play from './play.svelte'
import Transition from './transition.svelte'
export {
Play as PlayButton,
Favorite as FavoriteButton,
Bookmark as BookmarkButton
Bookmark as BookmarkButton,
Transition as TransitionButton
}

View file

@ -1,11 +1,11 @@
<script lang='ts'>
import Heart from 'lucide-svelte/icons/heart'
import type { Media } from '$lib/modules/anilist'
import { Heart } from '$lib/components/icons/animated'
import { Button, iconSizes, type Props } from '$lib/components/ui/button'
import { authAggregator, fav } from '$lib/modules/auth'
import { clickwrap, keywrap } from '$lib/modules/navigate'
import { cn } from '$lib/utils'
type $$Props = Props & { media: Media }
@ -23,6 +23,6 @@
}
</script>
<Button {size} {variant} class={className} on:click={clickwrap(toggleFav)} on:keydown={keywrap(toggleFav)} on:click={() => ++key}>
<Button {size} {variant} class={cn(className, 'animated-icon')} on:click={clickwrap(toggleFav)} on:keydown={keywrap(toggleFav)} on:click={() => ++key}>
<Heart fill={key && fav(media) ? 'currentColor' : 'transparent'} size={iconSizes[size]} />
</Button>

View file

@ -0,0 +1,40 @@
<script lang='ts'>
import { Button, type Props } from '$lib/components/ui/button'
import { clickwrap, keywrap } from '$lib/modules/navigate'
import { cn, scaleBlurFade } from '$lib/utils'
type $$Props = Props & { duration?: number }
export let duration: $$Props['duration'] = 300
let className: $$Props['class'] = ''
export { className as class }
let toggled = false
let timeout: ReturnType<typeof setTimeout>
export let size: NonNullable<$$Props['size']> = 'icon-sm'
export let variant: NonNullable<$$Props['variant']> = 'ghost'
function handleClick () {
if (toggled) return
toggled = true
clearTimeout(timeout)
timeout = setTimeout(() => {
toggled = false
}, duration! + 500)
}
</script>
<Button {size} {variant} class={cn(className, 'relative')} on:click={clickwrap(handleClick)} on:click on:keydown={keywrap(handleClick)}>
{#if toggled}
<div class='absolute inset-0 flex items-center justify-center' transition:scaleBlurFade={{ duration }}>
<slot name='transition' />
</div>
{:else}
<div class='absolute inset-0 flex items-center justify-center' transition:scaleBlurFade={{ duration }}>
<slot name='base' />
</div>
{/if}
</Button>

View file

@ -8,8 +8,6 @@
import DecimalsArrowRight from 'lucide-svelte/icons/decimals-arrow-right'
import FastForward from 'lucide-svelte/icons/fast-forward'
import List from 'lucide-svelte/icons/list'
import Maximize from 'lucide-svelte/icons/maximize'
import Minimize from 'lucide-svelte/icons/minimize'
import Pause from 'lucide-svelte/icons/pause'
import PictureInPicture2 from 'lucide-svelte/icons/picture-in-picture-2'
import Proportions from 'lucide-svelte/icons/proportions'
@ -50,6 +48,7 @@
import PictureInPictureExit from '$lib/components/icons/PictureInPictureExit.svelte'
import Play from '$lib/components/icons/Play.svelte'
import Subtitles from '$lib/components/icons/Subtitles.svelte'
import { Maximize, Minimize } from '$lib/components/icons/animated'
import { Button, iconSizes } from '$lib/components/ui/button'
import * as Sheet from '$lib/components/ui/sheet'
import { client } from '$lib/modules/anilist'
@ -62,7 +61,7 @@
import { server } from '$lib/modules/torrent'
import { w2globby } from '$lib/modules/w2g/lobby'
import { getAnimeProgress, setAnimeProgress } from '$lib/modules/watchProgress'
import { toTS, fastPrettyBits } from '$lib/utils'
import { toTS, fastPrettyBits, scaleBlurFade } from '$lib/utils'
export let mediaInfo: MediaInfo
export let otherFiles: TorrentFile[]
@ -852,7 +851,7 @@
</div>
{/if}
<Options {wrapper} bind:openSubs {video} {seekTo} {selectAudio} {selectVideo} {fullscreen} {chapters} {subtitles} {videoFiles} {selectFile} {pip} bind:playbackRate={$playbackRate} bind:subtitleDelay id='player-options-button-top'
class='{($settings.minimalPlayerUI || SUPPORTS.isAndroid) ? 'inline-flex' : 'mobile:inline-flex hidden'} p-3 w-12 h-12 absolute z-[1] top-4 left-4 bg-black/20 pointer-events-auto transition-opacity select:opacity-100 delay-150 {immersed && 'opacity-0'}' />
class='{($settings.minimalPlayerUI || SUPPORTS.isAndroid) ? 'inline-flex' : 'mobile:inline-flex hidden'} p-3 size-12 absolute z-[1] top-4 left-4 bg-black/20 pointer-events-auto transition-opacity select:opacity-100 delay-150 {immersed && 'opacity-0'}' />
{#if fastForwarding}
<div class='absolute top-10 font-bold text-sm animate-[fade-in_.4s_ease] flex items-center leading-none bg-black/60 px-4 py-2 rounded-2xl'>x2 <FastForward class='ml-2' size='12' fill='currentColor' /></div>
{/if}
@ -928,20 +927,24 @@
<Seekbar {duration} {currentTime} buffer={buffer / duration * 100} {chapters} bind:seeking bind:seek={seekPercent} on:seeked={finishSeek} on:seeking={startSeek} {thumbnailer} on:keydown={seekBarKey} on:dblclick={fullscreen} />
<div class='justify-between gap-2 {($settings.minimalPlayerUI || SUPPORTS.isAndroid) ? 'hidden' : 'mobile:hidden flex'}'>
<div class='flex text-white gap-2'>
<Button class='p-3 w-12 h-12' variant='ghost' on:click={playPause} on:keydown={keywrap(playPause)} id='player-play-pause-button' data-up='#player-seekbar'>
<Button class='p-3 size-12 relative shrink-0' variant='ghost' on:click={playPause} on:keydown={keywrap(playPause)} id='player-play-pause-button' data-up='#player-seekbar'>
{#if paused}
<Play size='24px' fill='currentColor' class='p-0.5' />
<div transition:scaleBlurFade class='absolute'>
<Play size='24px' fill='currentColor' class='p-0.5' />
</div>
{:else}
<Pause size='24px' fill='currentColor' strokeWidth='1' />
<div transition:scaleBlurFade class='absolute'>
<Pause size='24px' fill='currentColor' strokeWidth='1' />
</div>
{/if}
</Button>
{#if prev}
<Button class='p-3 w-12 h-12' variant='ghost' on:click={prev} on:keydown={keywrap(prev)} id='player-prev-button' data-up='#player-seekbar' data-right='#player-next-button, #player-volume-button, #player-options-button'>
<Button class='p-3 size-12' variant='ghost' on:click={prev} on:keydown={keywrap(prev)} id='player-prev-button' data-up='#player-seekbar' data-right='#player-next-button, #player-volume-button, #player-options-button'>
<SkipBack size='24px' fill='currentColor' strokeWidth='1' />
</Button>
{/if}
{#if next}
<Button class='p-3 w-12 h-12' variant='ghost' on:click={next} on:keydown={keywrap(next)} id='player-next-button' data-up='#player-seekbar' data-right='#player-volume-button, #player-options-button'>
<Button class='p-3 size-12' variant='ghost' on:click={next} on:keydown={keywrap(next)} id='player-next-button' data-up='#player-seekbar' data-right='#player-volume-button, #player-options-button'>
<SkipForward size='24px' fill='currentColor' strokeWidth='1' />
</Button>
{/if}
@ -955,19 +958,23 @@
{/if}
<Options {fullscreen} {wrapper} {seekTo} bind:openSubs {video} {selectAudio} {selectVideo} {chapters} {subtitles} {videoFiles} {selectFile} {pip} bind:playbackRate={$playbackRate} bind:subtitleDelay id='player-options-button' />
{#if subtitles}
<Button class='p-3 w-12 h-12' variant='ghost' on:click={openSubs} on:keydown={keywrap(openSubs)} data-up='#player-seekbar'>
<Button class='p-3 size-12' variant='ghost' on:click={openSubs} on:keydown={keywrap(openSubs)} data-up='#player-seekbar'>
<Subtitles size='24px' fill='currentColor' strokeWidth='0' />
</Button>
{/if}
<Button class='p-3 w-12 h-12' variant='ghost' on:click={() => pip.pip()} on:keydown={keywrap(() => pip.pip())} data-up='#player-seekbar'>
<Button class='p-3 size-12 relative shrink-0' variant='ghost' on:click={() => pip.pip()} on:keydown={keywrap(() => pip.pip())} data-up='#player-seekbar'>
{#if pictureInPictureElement}
<PictureInPictureExit size='24px' strokeWidth='2' />
<div transition:scaleBlurFade class='absolute'>
<PictureInPictureExit size='24px' strokeWidth='2' />
</div>
{:else}
<PictureInPictureOff size='24px' strokeWidth='2' />
<div transition:scaleBlurFade class='absolute'>
<PictureInPictureOff size='24px' strokeWidth='2' />
</div>
{/if}
</Button>
{#if false}
<Button class='p-3 w-12 h-12' variant='ghost' on:click={toggleCast} on:keydown={keywrap(toggleCast)} data-up='#player-seekbar'>
<Button class='p-3 size-12' variant='ghost' on:click={toggleCast} on:keydown={keywrap(toggleCast)} data-up='#player-seekbar'>
{#if cast}
<Cast size='24px' fill='white' strokeWidth='2' />
{:else}
@ -975,11 +982,15 @@
{/if}
</Button>
{/if}
<Button class='p-3 w-12 h-12' variant='ghost' on:click={fullscreen} on:keydown={keywrap(fullscreen)} data-up='#player-seekbar'>
<Button class='p-3 size-12 relative animated-icon shrink-0' variant='ghost' on:click={fullscreen} on:keydown={keywrap(fullscreen)} data-up='#player-seekbar'>
{#if fullscreenElement}
<Minimize size='24px' class='p-0.5' strokeWidth='2.5' />
<div transition:scaleBlurFade class='absolute'>
<Minimize size='24px' class='p-0.5' strokeWidth='2.5' />
</div>
{:else}
<Maximize size='24px' class='p-0.5' strokeWidth='2.5' />
<div transition:scaleBlurFade class='absolute'>
<Maximize size='24px' class='p-0.5' strokeWidth='2.5' />
</div>
{/if}
</Button>
</div>
@ -987,11 +998,15 @@
</div>
{:else}
<div class='absolute w-full left-0 bottom-0 flex justify-center'>
<Button variant='ghost' class='drop-shadow-[0_0_7px_#000] mb-1' size='icon' on:pointerdown={e => { e.stopPropagation(); playPause() }}>
<Button variant='ghost' class='drop-shadow-[0_0_7px_#000] mb-1 relative' size='icon' on:pointerdown={e => { e.stopPropagation(); playPause() }}>
{#if paused}
<Play size={iconSizes.lg} fill='currentColor' class='px-0.5' />
<div transition:scaleBlurFade class='absolute'>
<Play size={iconSizes.lg} fill='currentColor' class='px-0.5' />
</div>
{:else}
<Pause size={iconSizes.lg} fill='currentColor' strokeWidth='1' />
<div transition:scaleBlurFade class='absolute'>
<Pause size={iconSizes.lg} fill='currentColor' strokeWidth='1' />
</div>
{/if}
</Button>
</div>

View file

@ -28,11 +28,9 @@
$: isActive = href && matchPath(href, $page)
</script>
<Button variant='ghost' {href} class={cn(className, 'px-2 w-10 relative md:pl-4 md:w-12 md:rounded-l-none group/sidebar')} {...$$restProps}>
<Button variant='ghost' {href} class={cn(className, 'px-2 w-10 relative md:pl-4 md:w-12 md:rounded-l-none group/sidebar transition-colors duration-300', isActive ? '!text-black' : 'text-white')} {...$$restProps}>
{#if isActive}
<div class='bg-white absolute inset-0 rounded-md md:rounded-l-none group-select/sidebar:bg-primary/70' in:send={{ key }} out:receive={{ key }} />
<div class='bg-white absolute inset-0 rounded-md md:rounded-l-none group-select/sidebar:bg-primary/70 -z-[1]' in:send={{ key }} out:receive={{ key }} />
{/if}
<div class='relative text-white transition-colors duration-300 pointer-events-none' class:!text-black={isActive}>
<slot />
</div>
<slot />
</Button>

View file

@ -1,14 +1,6 @@
<script lang='ts'>
import Calendar from 'lucide-svelte/icons/calendar'
import Heart from 'lucide-svelte/icons/heart'
import House from 'lucide-svelte/icons/house'
import LogIn from 'lucide-svelte/icons/log-in'
import MessagesSquare from 'lucide-svelte/icons/messages-square'
import Play from 'lucide-svelte/icons/play'
import Search from 'lucide-svelte/icons/search'
import Settings from 'lucide-svelte/icons/settings'
import Users from 'lucide-svelte/icons/users'
import Download from 'svelte-radix/Download.svelte'
import { BannerImage } from '../banner'
import { Button } from '../button'
@ -18,6 +10,7 @@
import { goto } from '$app/navigation'
import { page } from '$app/stores'
import Logo from '$lib/components/icons/Logo.svelte'
import { Home, Search, Calendar, Users, Download, Bolt, LogIn, Messages } from '$lib/components/icons/animated'
import * as Avatar from '$lib/components/ui/avatar'
import client from '$lib/modules/auth/client'
import { lockedState, idleState, activityState } from '$lib/modules/idle'
@ -47,32 +40,32 @@
<Play size={16} />
</SidebarButton>
{/if}
<SidebarButton href='/app/home/'>
<House size={18} />
<SidebarButton href='/app/home/' class='animated-icon'>
<Home size={18} />
</SidebarButton>
<SidebarButton href='/app/search/'>
<SidebarButton href='/app/search/' class='animated-icon'>
<Search size={18} />
</SidebarButton>
<SidebarButton href='/app/schedule/'>
<SidebarButton href='/app/schedule/' class='animated-icon'>
<Calendar size={18} />
</SidebarButton>
<SidebarButton href='/app/w2g/'>
<SidebarButton href='/app/w2g/' class='animated-icon'>
<Users size={18} />
</SidebarButton>
<SidebarButton href='/app/chat/'>
<MessagesSquare size={18} />
<SidebarButton href='/app/chat/' class='animated-icon'>
<Messages size={18} />
</SidebarButton>
<SidebarButton href='/app/client/' id='sidebar-client' data-down='#sidebar-donate'>
<SidebarButton href='/app/client/' id='sidebar-client' data-down='#sidebar-donate' class='animated-icon'>
<Download size={18} />
</SidebarButton>
<Button variant='ghost' id='sidebar-donate' data-up='#sidebar-client' on:click={() => native.openURL('https://github.com/sponsors/ThaUnknown/')} class='px-2 w-full relative mt-auto select:!bg-transparent text-[#fa68b6] select:text-[#fa68b6] md:pl-4 md:w-12 md:rounded-l-none'>
<Heart size={18} fill='currentColor' class={cn('drop-shadow-[0_0_1rem_#fa68b6]', active && 'animate-[hearbeat_1s_ease-in-out_infinite_alternate]')} />
</Button>
<SidebarButton href='/app/settings/'>
<Settings size={18} />
<SidebarButton href='/app/settings/' class='animated-icon'>
<Bolt size={18} />
</SidebarButton>
<!-- <SidebarButton href='/app/profile/'> -->
<SidebarButton href='/app/profile/' class='hidden md:flex py-0'>
<SidebarButton href='/app/profile/' class='hidden md:flex py-0 animated-icon'>
{#if hasAuth}
{@const viewer = client.profile()}
<Avatar.Root class='size-6 rounded-md'>

View file

@ -316,3 +316,16 @@ export function colors (hex = '#ffffff') {
const b = bigint & 255
return { r, g, b }
}
export function scaleBlurFade (node: Element, { duration = 300 } = {}) {
return {
delay: 0,
duration,
easing: cubicOut,
css: (t: number) => `
transform: scale(${t});
filter: blur(${(1 - t) * 4}px);
opacity: ${t};
`
}
}

View file

@ -1,6 +1,6 @@
<script lang='ts'>
// import Bell from 'lucide-svelte/icons/bell'
import Clapperboard from 'lucide-svelte/icons/clapperboard'
import Check from 'lucide-svelte/icons/check'
import Maximize2 from 'lucide-svelte/icons/maximize-2'
import Share2 from 'lucide-svelte/icons/share-2'
import { onDestroy } from 'svelte'
@ -11,9 +11,10 @@
import EntryEditor from '$lib/components/EntryEditor.svelte'
import Anilist from '$lib/components/icons/Anilist.svelte'
import MyAnimeList from '$lib/components/icons/MyAnimeList.svelte'
import { Clapperboard } from '$lib/components/icons/animated'
import { bannerSrc, hideBanner } from '$lib/components/ui/banner'
import { Button } from '$lib/components/ui/button'
import { PlayButton, BookmarkButton, FavoriteButton } from '$lib/components/ui/button/extra'
import { PlayButton, BookmarkButton, FavoriteButton, TransitionButton } from '$lib/components/ui/button/extra'
import * as Dialog from '$lib/components/ui/dialog'
import { Load } from '$lib/components/ui/img'
import { Profile } from '$lib/components/ui/profile'
@ -98,9 +99,11 @@
{of(media) ?? duration(media) ?? 'N/A'}
</div>
<Button class='rounded px-3.5 font-bold bg-custom select:!bg-custom-600 text-contrast h-6 py-0 text-base' on:click={() => goto('/app/search', { state: { search: { format: [media.format] } } })}>
{format(media)} </Button>
{format(media)}
</Button>
<Button class='rounded px-3.5 font-bold bg-custom select:!bg-custom-600 text-contrast h-6 py-0 text-base' on:click={() => goto('/app/search', { state: { search: { status: [media.status] } } })}>
{status(media)} </Button>
{status(media)}
</Button>
{#if season(media)}
<Button class='rounded px-3.5 font-bold bg-custom select:!bg-custom-600 text-contrast h-6 py-0 text-base capitalize' on:click={() => goto('/app/search', { state: { search: { season: media.season, seasonYear: media.seasonYear } } })}>
{season(media)}
@ -127,13 +130,18 @@
</div>
<FavoriteButton {media} variant='secondary' size='icon' class='min-[380px]:-order-1 md:order-none select:!text-custom' />
<BookmarkButton {media} variant='secondary' size='icon' class='min-[380px]:-order-2 md:order-none select:!text-custom' />
<Button size='icon' variant='secondary' on:click={share} class='select:!text-custom'>
<Share2 class='size-4' />
</Button>
<TransitionButton size='icon' variant='secondary' on:click={share} class='select:!text-custom'>
<div slot='base'>
<Share2 class='size-4' />
</div>
<div slot='transition'>
<Check class='size-4' />
</div>
</TransitionButton>
{#if media.trailer?.id}
<Dialog.Root portal='#root'>
<Dialog.Trigger let:builder asChild>
<Button size='icon' variant='secondary' class='select:!text-custom' builders={[builder]}>
<Button size='icon' variant='secondary' class='select:!text-custom animated-icon' builders={[builder]}>
<Clapperboard class='size-4' />
</Button>
</Dialog.Trigger>

View file

@ -1,8 +1,6 @@
<script lang='ts'>
import { Button as ButtonPrimitive } from 'bits-ui'
import { addMonths, endOfMonth, endOfWeek, format, isSameMonth, isToday, startOfMonth, startOfWeek, subMonths } from 'date-fns'
import ChevronLeftIcon from 'lucide-svelte/icons/chevron-left'
import ChevronRightIcon from 'lucide-svelte/icons/chevron-right'
import { persisted } from 'svelte-persisted-store'
import Cross2 from 'svelte-radix/Cross2.svelte'
@ -10,6 +8,7 @@
import type { ResultOf } from 'gql.tada'
import StatusDot from '$lib/components/StatusDot.svelte'
import { ChevronLeft, ChevronRight } from '$lib/components/icons/animated'
import { Button } from '$lib/components/ui/button'
import * as Drawer from '$lib/components/ui/drawer'
import { Label } from '$lib/components/ui/label'
@ -88,8 +87,8 @@
</div>
<div class='grid grid-cols-7 border rounded-lg [&>*:not(:nth-child(7n+1)):nth-child(n+8)]:border-r [&>*:nth-last-child(n+8)]:border-b [&>*:nth-child(-n+8)]:border-b w-full max-w-[1800px]'>
<div class='col-span-full flex justify-between items-center p-4'>
<Button size='icon' on:click={prevMonth} variant='outline' class='bg-transparent'>
<ChevronLeftIcon class='h-6 w-6' />
<Button size='icon' on:click={prevMonth} variant='outline' class='bg-transparent animated-icon'>
<ChevronLeft class='h-6 w-6' />
</Button>
<div class='text-center font-bold text-xl'>
{monthName}
@ -98,8 +97,8 @@
<Label for='schedule-on-list'>My list</Label>
</div>
</div>
<Button size='icon' on:click={nextMonth} variant='outline' class='bg-transparent'>
<ChevronRightIcon class='h-6 w-6' />
<Button size='icon' on:click={nextMonth} variant='outline' class='bg-transparent animated-icon'>
<ChevronRight class='h-6 w-6' />
</Button>
</div>
<div class='text-center py-2'>Mon</div>

View file

@ -1,7 +1,4 @@
<script lang='ts'>
import FileImage from 'lucide-svelte/icons/file-image'
import Settings from 'lucide-svelte/icons/settings'
import Trash from 'lucide-svelte/icons/trash'
import X from 'lucide-svelte/icons/x'
import { onDestroy, tick } from 'svelte'
import MagnifyingGlass from 'svelte-radix/MagnifyingGlass.svelte'
@ -14,6 +11,7 @@
import { replaceState } from '$app/navigation'
import { page } from '$app/stores'
import { Bolt, FileImage, Trash } from '$lib/components/icons/animated'
import { badgeVariants } from '$lib/components/ui/badge'
import { Button } from '$lib/components/ui/button'
import { QueryCard, TraceCards } from '$lib/components/ui/cards'
@ -297,17 +295,17 @@
{/if}
{/if}
<div class='w-auto p-2 gap-4 flex items-end'>
<Button variant='outline' size='icon' class='border-0'>
<Button variant='outline' size='icon' class='border-0 animated-icon'>
<label for='search-image' class='contents'>
<FileImage class='h-4 w-full cursor-pointer' />
</label>
<input type='file' class='hidden' id='search-image' accept='image/*' on:input|preventDefault|stopPropagation={imagePicker} />
</Button>
<Button variant='outline' size='icon' on:click={clear} class='border-0'>
<Trash class={cn('h-4 w-4', empty(search) ? 'text-muted-foreground opacity-50' : 'text-blue-400')} />
<Button variant='outline' size='icon' on:click={clear} class='border-0 animated-icon'>
<Trash class={cn('size-4', empty(search) ? 'text-muted-foreground opacity-50' : 'text-blue-400')} />
</Button>
<Toggle variant='outline' size='icon' class='border-0 md:hidden' bind:pressed>
<Settings size={18} />
<Toggle variant='outline' size='icon' class='border-0 md:hidden animated-icon' bind:pressed>
<Bolt size={18} />
</Toggle>
</div>
</div>

View file

@ -1,4 +1,5 @@
<script lang='ts' context='module'>
import Check from 'lucide-svelte/icons/check'
import DoorOpen from 'lucide-svelte/icons/door-open'
import SendHorizontal from 'lucide-svelte/icons/send-horizontal'
import UserPlus from 'lucide-svelte/icons/user-plus'
@ -12,6 +13,7 @@
import { onDestroy } from 'svelte'
import { goto } from '$app/navigation'
import { TransitionButton } from '$lib/components/ui/button/extra'
import { Separator } from '$lib/components/ui/separator'
import native from '$lib/modules/native'
import { w2globby } from '$lib/modules/w2g/lobby'
@ -73,9 +75,14 @@
<Button on:click={quit} size='icon' class='border-0 shrink-0' variant='outline'>
<DoorOpen size={18} />
</Button>
<Button on:click={invite} size='icon' class='border-0 shrink-0' variant='outline'>
<UserPlus size={18} />
</Button>
<TransitionButton on:click={invite} size='icon' class='border-0 shrink-0' variant='outline'>
<div slot='base'>
<UserPlus size={18} />
</div>
<div slot='transition'>
<Check class='size-4' />
</div>
</TransitionButton>
<Textarea
bind:value={message}
class='h-auto px-3 w-full resize-none min-h-0 border-0 bg-background select:bg-accent select:text-accent-foreground'