Compare commits
39 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa2b47ace4 | ||
|
|
3a96d38a77 | ||
|
|
7e8f23f5fa | ||
|
|
d0160763ee | ||
|
|
b921629ee3 | ||
|
|
ee139150f5 | ||
|
|
04c52962c3 | ||
|
|
97ca030534 | ||
|
|
e160d26677 | ||
|
|
642a551226 | ||
|
|
6ac65c1948 | ||
|
|
50687c97ca | ||
|
|
95b641a88f | ||
|
|
d11a6ab062 | ||
|
|
a071ba04c7 | ||
|
|
a179c09d0c | ||
|
|
066af9e2f3 | ||
|
|
1e5bda707c | ||
|
|
e2bb4dd55f | ||
|
|
d9df0d4b2c | ||
|
|
3feb9c1a09 | ||
|
|
b191e6067d | ||
|
|
81d9d7ca03 | ||
|
|
1e24cbc6eb | ||
|
|
78fb8cd76f | ||
|
|
4c8d577527 | ||
|
|
fcbe50c78c | ||
|
|
af096077ae | ||
|
|
4996cc893c | ||
|
|
d6484103a7 | ||
|
|
374de8b0d2 | ||
|
|
b171793040 | ||
|
|
dcc91e038d | ||
|
|
348fc1e8c4 | ||
|
|
a0a7f94c33 | ||
|
|
2f994c6094 | ||
|
|
fb82117742 | ||
|
|
7951e9829a | ||
|
|
755c442263 |
68
CHANGELOG.md
|
|
@ -2,6 +2,74 @@
|
|||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [2.4.0](https://github.com/remvze/moodist/compare/v2.3.0...v2.4.0) (2025-11-25)
|
||||
|
||||
|
||||
### ✨ Features
|
||||
|
||||
* add audio session type ([3a96d38](https://github.com/remvze/moodist/commit/3a96d38a774c7675811d5a3ea323a49d9d129bbc))
|
||||
|
||||
## [2.3.0](https://github.com/remvze/moodist/compare/v2.2.0...v2.3.0) (2025-11-24)
|
||||
|
||||
|
||||
### 🚚 Chores
|
||||
|
||||
* change silence ([b921629](https://github.com/remvze/moodist/commit/b921629ee33c4a18a86258ba204921f732f404ff))
|
||||
|
||||
|
||||
### ✨ Features
|
||||
|
||||
* turn links into buttons ([d016076](https://github.com/remvze/moodist/commit/d0160763eeb66ba47dd06098b1f2a84e234fca36))
|
||||
|
||||
## [2.2.0](https://github.com/remvze/moodist/compare/v2.1.0...v2.2.0) (2025-11-24)
|
||||
|
||||
|
||||
### ✨ Features
|
||||
|
||||
* add category icons ([642a551](https://github.com/remvze/moodist/commit/642a5512267ce66492cf86f222fa01714960162a))
|
||||
* add shine effect ([d9df0d4](https://github.com/remvze/moodist/commit/d9df0d4b2c5071c12cecc6452acc0f160c57deb5))
|
||||
* change lofi icon ([066af9e](https://github.com/remvze/moodist/commit/066af9e2f31bc9201d349d888c6dc19cd5ad7750))
|
||||
* extract the provider for the tooltip ([95b641a](https://github.com/remvze/moodist/commit/95b641a88f2eee264b59b5bd62206bb84119da57))
|
||||
* make sound file addresses relative ([81d9d7c](https://github.com/remvze/moodist/commit/81d9d7ca03f6c7410ca750e069c9c8b935114950))
|
||||
* migrate to motion and fix some animations ([b191e60](https://github.com/remvze/moodist/commit/b191e6067ddc3233689a34946c602db36d6133ba))
|
||||
* replace the silence file ([e160d26](https://github.com/remvze/moodist/commit/e160d2667737b47c18b08887735be26f21bf52ae))
|
||||
|
||||
|
||||
### 💄 Styling
|
||||
|
||||
* add animation on active ([50687c9](https://github.com/remvze/moodist/commit/50687c97ca483f4de3ee7633d333dfcb4def0c4d))
|
||||
* change cursor ([6ac65c1](https://github.com/remvze/moodist/commit/6ac65c1948ad93fed012a8203fc8c6c2b2898b5b))
|
||||
* change snackbar styles ([1e5bda7](https://github.com/remvze/moodist/commit/1e5bda707cc202407b179e2d1b95dec34bfe9420))
|
||||
* decrease background opacity ([a071ba0](https://github.com/remvze/moodist/commit/a071ba04c7e86b3056049492386516b58c4210c0))
|
||||
* increase border radius ([e2bb4dd](https://github.com/remvze/moodist/commit/e2bb4dd55fbf17e777ddbb6825e400bd023da328))
|
||||
* increase line height ([a179c09](https://github.com/remvze/moodist/commit/a179c09d0c637d33d310960dbf3e92af4b5c526b))
|
||||
* increase text color ([d11a6ab](https://github.com/remvze/moodist/commit/d11a6ab062061da5809ebddd6eb39b17c2cd3862))
|
||||
* minor changes ([04c5296](https://github.com/remvze/moodist/commit/04c52962c3b65ebb7875ebadf20132846a5c020b))
|
||||
* remove cipher animation ([3feb9c1](https://github.com/remvze/moodist/commit/3feb9c1a09b52a35d79cebb7ece54989e9faf481))
|
||||
|
||||
## [2.1.0](https://github.com/remvze/moodist/compare/v2.0.1...v2.1.0) (2025-07-19)
|
||||
|
||||
|
||||
### 🚚 Chores
|
||||
|
||||
* add banner ([fb82117](https://github.com/remvze/moodist/commit/fb82117742c2a0beb8937a76fcd5f313230cd418))
|
||||
* refine logo ([755c442](https://github.com/remvze/moodist/commit/755c4422635e475b8d3b0f26e3cf493a59ff3065))
|
||||
* update banner ([a0a7f94](https://github.com/remvze/moodist/commit/a0a7f94c3328c65d4fc756ca52455461a05657ab))
|
||||
* update banner ([2f994c6](https://github.com/remvze/moodist/commit/2f994c6094ad1948c14346badbc4462ae7782904))
|
||||
* update the logo ([348fc1e](https://github.com/remvze/moodist/commit/348fc1e8c4561481e5ad1d4528e8ee480d0e2fb4))
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **component:** update oscillators frequency on preset change ([dcc91e0](https://github.com/remvze/moodist/commit/dcc91e038d806994382baa19b3d238da4a8ecaae))
|
||||
* fixate the binary pattern ([4996cc8](https://github.com/remvze/moodist/commit/4996cc893c480ab77cf27a27801dba96771eadc5))
|
||||
* replace generator with static silent audio ([af09607](https://github.com/remvze/moodist/commit/af096077aed6c42d4ff77303e6f3c1d39cd87209))
|
||||
|
||||
|
||||
### ✨ Features
|
||||
|
||||
* add lofi music play ([fcbe50c](https://github.com/remvze/moodist/commit/fcbe50c78c30e4422aea2ed698fff777fcaea1c4))
|
||||
|
||||
### [2.0.1](https://github.com/remvze/moodist/compare/v2.0.0...v2.0.1) (2025-03-25)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<div align="center">
|
||||
<!-- <img src="/assets/banner.svg" alt="Moodist Logo Banner" /> -->
|
||||
<img src="/assets/banner.png" alt="Moodist Logo Banner" />
|
||||
<h2>Moodist 🌲</h2>
|
||||
<p>Ambient sounds for focus and calm.</p>
|
||||
<a href="https://moodist.mvze.net">Visit <strong>Moodist</strong></a> | <a href="https://buymeacoffee.com/remvze">Buy Me a Coffee</a>
|
||||
|
|
|
|||
BIN
assets/banner.png
Normal file
|
After Width: | Height: | Size: 193 KiB |
|
|
@ -1,40 +0,0 @@
|
|||
<svg width="1200" height="400" viewBox="0 0 1200 400" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1200" height="400" rx="25" fill="#09090B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M600 237.5C620.711 237.5 637.5 220.711 637.5 200C637.5 179.289 620.711 162.5 600 162.5C579.289 162.5 562.5 179.289 562.5 200C562.5 220.711 579.289 237.5 600 237.5ZM600 218.75C610.355 218.75 618.75 210.355 618.75 200C618.75 189.645 610.355 181.25 600 181.25C589.645 181.25 581.25 189.645 581.25 200C581.25 210.355 589.645 218.75 600 218.75Z" fill="#FAFAFA"/>
|
||||
<path d="M562.5 162.5C541.789 162.5 525 179.289 525 200C525 220.711 541.789 237.5 562.5 237.5L562.5 218.75C552.145 218.75 543.75 210.355 543.75 200C543.75 189.645 552.145 181.25 562.5 181.25L562.5 162.5Z" fill="#D4D4D8"/>
|
||||
<path d="M637.5 162.5C637.5 141.789 620.711 125 600 125C579.289 125 562.5 141.789 562.5 162.5L581.25 162.5C581.25 152.145 589.645 143.75 600 143.75C610.355 143.75 618.75 152.145 618.75 162.5L637.5 162.5Z" fill="#D4D4D8"/>
|
||||
<path d="M637.5 237.5C658.211 237.5 675 220.711 675 200C675 179.289 658.211 162.5 637.5 162.5L637.5 181.25C647.855 181.25 656.25 189.645 656.25 200C656.25 210.355 647.855 218.75 637.5 218.75L637.5 237.5Z" fill="#D4D4D8"/>
|
||||
<path d="M562.5 237.5C562.5 258.211 579.289 275 600 275C620.711 275 637.5 258.211 637.5 237.5H618.75C618.75 247.855 610.355 256.25 600 256.25C589.645 256.25 581.25 247.855 581.25 237.5H562.5Z" fill="#D4D4D8"/>
|
||||
<path d="M543.75 162.5C543.75 152.145 552.145 143.75 562.5 143.75L562.5 125C541.789 125 525 141.789 525 162.5L543.75 162.5Z" fill="#A1A1AA"/>
|
||||
<path d="M637.5 143.75C647.855 143.75 656.25 152.145 656.25 162.5L675 162.5C675 141.789 658.211 125 637.5 125L637.5 143.75Z" fill="#A1A1AA"/>
|
||||
<path d="M656.25 237.5C656.25 247.855 647.855 256.25 637.5 256.25L637.5 275C658.211 275 675 258.211 675 237.5L656.25 237.5Z" fill="#A1A1AA"/>
|
||||
<path d="M562.5 256.25C552.145 256.25 543.75 247.855 543.75 237.5H525C525 258.211 541.789 275 562.5 275V256.25Z" fill="#A1A1AA"/>
|
||||
<path d="M693.75 237.5C693.75 247.855 685.355 256.25 675 256.25L675 275C695.711 275 712.5 258.211 712.5 237.5L693.75 237.5Z" fill="#18181B"/>
|
||||
<path d="M656.25 275C656.25 285.355 647.855 293.75 637.5 293.75L637.5 312.5C658.211 312.5 675 295.711 675 275L656.25 275Z" fill="#18181B"/>
|
||||
<path d="M525 256.25C514.645 256.25 506.25 247.855 506.25 237.5H487.5C487.5 258.211 504.289 275 525 275V256.25Z" fill="#18181B"/>
|
||||
<path d="M562.5 293.75C552.145 293.75 543.75 285.355 543.75 275H525C525 295.711 541.789 312.5 562.5 312.5V293.75Z" fill="#18181B"/>
|
||||
<path d="M562.5 331.25C552.145 331.25 543.75 322.855 543.75 312.5H525C525 333.211 541.789 350 562.5 350V331.25Z" fill="#18181B"/>
|
||||
<path d="M525 293.75C514.645 293.75 506.25 285.355 506.25 275H487.5C487.5 295.711 504.289 312.5 525 312.5V293.75Z" fill="#18181B"/>
|
||||
<path d="M487.5 256.25C477.145 256.25 468.75 247.855 468.75 237.5H450C450 258.211 466.789 275 487.5 275V256.25Z" fill="#18181B"/>
|
||||
<path d="M543.75 125C543.75 114.645 552.145 106.25 562.5 106.25L562.5 87.5C541.789 87.5 525 104.289 525 125L543.75 125Z" fill="#18181B"/>
|
||||
<path d="M506.25 162.5C506.25 152.145 514.645 143.75 525 143.75L525 125C504.289 125 487.5 141.789 487.5 162.5L506.25 162.5Z" fill="#18181B"/>
|
||||
<path d="M468.75 162.5C468.75 152.145 477.145 143.75 487.5 143.75L487.5 125C466.789 125 450 141.789 450 162.5L468.75 162.5Z" fill="#18181B"/>
|
||||
<path d="M506.25 125C506.25 114.645 514.645 106.25 525 106.25L525 87.5C504.289 87.5 487.5 104.289 487.5 125L506.25 125Z" fill="#18181B"/>
|
||||
<path d="M543.75 87.5C543.75 77.1447 552.145 68.75 562.5 68.75L562.5 50C541.789 50 525 66.7893 525 87.5L543.75 87.5Z" fill="#18181B"/>
|
||||
<path d="M675 143.75C685.355 143.75 693.75 152.145 693.75 162.5L712.5 162.5C712.5 141.789 695.711 125 675 125L675 143.75Z" fill="#18181B"/>
|
||||
<path d="M637.5 106.25C647.855 106.25 656.25 114.645 656.25 125L675 125C675 104.289 658.211 87.5 637.5 87.5L637.5 106.25Z" fill="#18181B"/>
|
||||
<path d="M637.5 68.75C647.855 68.75 656.25 77.1447 656.25 87.5L675 87.5C675 66.7893 658.211 50 637.5 50L637.5 68.75Z" fill="#18181B"/>
|
||||
<path d="M675 106.25C685.355 106.25 693.75 114.645 693.75 125L712.5 125C712.5 104.289 695.711 87.5 675 87.5L675 106.25Z" fill="#18181B"/>
|
||||
<path d="M712.5 143.75C722.855 143.75 731.25 152.145 731.25 162.5L750 162.5C750 141.789 733.211 125 712.5 125L712.5 143.75Z" fill="#18181B"/>
|
||||
<path d="M693.75 275C693.75 285.355 685.355 293.75 675 293.75L675 312.5C695.711 312.5 712.5 295.711 712.5 275L693.75 275Z" fill="#18181B"/>
|
||||
<path d="M731.25 237.5C731.25 247.855 722.855 256.25 712.5 256.25L712.5 275C733.211 275 750 258.211 750 237.5L731.25 237.5Z" fill="#18181B"/>
|
||||
<path d="M656.25 312.5C656.25 322.855 647.855 331.25 637.5 331.25L637.5 350C658.211 350 675 333.211 675 312.5L656.25 312.5Z" fill="#18181B"/>
|
||||
<path d="M525 162.5C504.289 162.5 487.5 179.289 487.5 200C487.5 220.711 504.289 237.5 525 237.5L525 218.75C514.645 218.75 506.25 210.355 506.25 200C506.25 189.645 514.645 181.25 525 181.25L525 162.5Z" fill="#18181B"/>
|
||||
<path d="M487.5 162.5C466.789 162.5 450 179.289 450 200C450 220.711 466.789 237.5 487.5 237.5L487.5 218.75C477.145 218.75 468.75 210.355 468.75 200C468.75 189.645 477.145 181.25 487.5 181.25L487.5 162.5Z" fill="#18181B"/>
|
||||
<path d="M637.5 125C637.5 104.289 620.711 87.5 600 87.5C579.289 87.5 562.5 104.289 562.5 125L581.25 125C581.25 114.645 589.645 106.25 600 106.25C610.355 106.25 618.75 114.645 618.75 125L637.5 125Z" fill="#18181B"/>
|
||||
<path d="M637.5 87.5C637.5 66.7893 620.711 50 600 50C579.289 50 562.5 66.7893 562.5 87.5L581.25 87.5C581.25 77.1447 589.645 68.75 600 68.75C610.355 68.75 618.75 77.1447 618.75 87.5L637.5 87.5Z" fill="#18181B"/>
|
||||
<path d="M675 237.5C695.711 237.5 712.5 220.711 712.5 200C712.5 179.289 695.711 162.5 675 162.5L675 181.25C685.355 181.25 693.75 189.645 693.75 200C693.75 210.355 685.355 218.75 675 218.75L675 237.5Z" fill="#18181B"/>
|
||||
<path d="M712.5 237.5C733.211 237.5 750 220.711 750 200C750 179.289 733.211 162.5 712.5 162.5L712.5 181.25C722.855 181.25 731.25 189.645 731.25 200C731.25 210.355 722.855 218.75 712.5 218.75L712.5 237.5Z" fill="#18181B"/>
|
||||
<path d="M562.5 275C562.5 295.711 579.289 312.5 600 312.5C620.711 312.5 637.5 295.711 637.5 275H618.75C618.75 285.355 610.355 293.75 600 293.75C589.645 293.75 581.25 285.355 581.25 275H562.5Z" fill="#18181B"/>
|
||||
<path d="M562.5 312.5C562.5 333.211 579.289 350 600 350C620.711 350 637.5 333.211 637.5 312.5H618.75C618.75 322.855 610.355 331.25 600 331.25C589.645 331.25 581.25 322.855 581.25 312.5H562.5Z" fill="#18181B"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.3 KiB |
604
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "moodist",
|
||||
"version": "2.0.1",
|
||||
"version": "2.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "moodist",
|
||||
"version": "2.0.1",
|
||||
"version": "2.4.0",
|
||||
"dependencies": {
|
||||
"@astrojs/react": "3.6.0",
|
||||
"@floating-ui/react": "0.26.0",
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"@radix-ui/react-checkbox": "1.1.4",
|
||||
"@radix-ui/react-dropdown-menu": "2.0.6",
|
||||
"@radix-ui/react-slider": "1.2.3",
|
||||
"@radix-ui/react-tooltip": "1.0.7",
|
||||
"@radix-ui/react-tooltip": "1.2.8",
|
||||
"@types/howler": "2.2.10",
|
||||
"@types/react": "^18.2.25",
|
||||
"@types/react-dom": "^18.2.10",
|
||||
|
|
@ -25,11 +25,13 @@
|
|||
"framer-motion": "10.16.4",
|
||||
"howler": "2.2.4",
|
||||
"js-confetti": "0.12.0",
|
||||
"motion": "12.23.24",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hotkeys-hook": "3.2.1",
|
||||
"react-icons": "4.11.0",
|
||||
"react-wrap-balancer": "1.1.0",
|
||||
"react-youtube": "10.1.0",
|
||||
"uuid": "10.0.0",
|
||||
"zustand": "4.4.3"
|
||||
},
|
||||
|
|
@ -5122,29 +5124,29 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",
|
||||
"integrity": "sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==",
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
|
||||
"integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@radix-ui/primitive": "1.0.1",
|
||||
"@radix-ui/react-compose-refs": "1.0.1",
|
||||
"@radix-ui/react-context": "1.0.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.0.5",
|
||||
"@radix-ui/react-id": "1.0.1",
|
||||
"@radix-ui/react-popper": "1.1.3",
|
||||
"@radix-ui/react-portal": "1.0.4",
|
||||
"@radix-ui/react-presence": "1.0.1",
|
||||
"@radix-ui/react-primitive": "1.0.3",
|
||||
"@radix-ui/react-slot": "1.0.2",
|
||||
"@radix-ui/react-use-controllable-state": "1.0.1",
|
||||
"@radix-ui/react-visually-hidden": "1.0.3"
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.11",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-popper": "1.2.8",
|
||||
"@radix-ui/react-portal": "1.1.9",
|
||||
"@radix-ui/react-presence": "1.1.5",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||
"@radix-ui/react-visually-hidden": "1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
|
|
@ -5155,6 +5157,340 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
||||
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
|
||||
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
|
||||
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"@radix-ui/react-use-escape-keydown": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-id": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
|
||||
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||
"integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@radix-ui/react-arrow": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1",
|
||||
"@radix-ui/react-use-rect": "1.1.1",
|
||||
"@radix-ui/react-use-size": "1.1.1",
|
||||
"@radix-ui/rect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
|
||||
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
||||
"license": "MIT",
|
||||
"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"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-callback-ref": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
||||
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-controllable-state": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
|
||||
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-effect-event": "0.0.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-escape-keydown": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
|
||||
"integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-layout-effect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
||||
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-rect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
|
||||
"integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/rect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-size": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
|
||||
"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/rect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
|
||||
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-callback-ref": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
|
||||
|
|
@ -5190,6 +5526,39 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-effect-event": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
|
||||
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
||||
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-escape-keydown": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz",
|
||||
|
|
@ -5277,18 +5646,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-visually-hidden": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz",
|
||||
"integrity": "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==",
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
|
||||
"integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@radix-ui/react-primitive": "1.0.3"
|
||||
"@radix-ui/react-primitive": "2.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
|
|
@ -5299,6 +5668,62 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
||||
"license": "MIT",
|
||||
"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"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/rect": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz",
|
||||
|
|
@ -19285,6 +19710,12 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/load-script": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
|
||||
"integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/load-yaml-file": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz",
|
||||
|
|
@ -20725,6 +21156,74 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/motion": {
|
||||
"version": "12.23.24",
|
||||
"resolved": "https://registry.npmjs.org/motion/-/motion-12.23.24.tgz",
|
||||
"integrity": "sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"framer-motion": "^12.23.24",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/motion-dom": {
|
||||
"version": "12.23.23",
|
||||
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
|
||||
"integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"motion-utils": "^12.23.6"
|
||||
}
|
||||
},
|
||||
"node_modules/motion-utils": {
|
||||
"version": "12.23.6",
|
||||
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
|
||||
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/motion/node_modules/framer-motion": {
|
||||
"version": "12.23.24",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz",
|
||||
"integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"motion-dom": "^12.23.23",
|
||||
"motion-utils": "^12.23.6",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||
|
|
@ -22343,6 +22842,23 @@
|
|||
"react": ">=16.8.0 || ^17.0.0 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-10.1.0.tgz",
|
||||
"integrity": "sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"prop-types": "15.8.1",
|
||||
"youtube-player": "5.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.x"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.14.1"
|
||||
}
|
||||
},
|
||||
"node_modules/read-pkg": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz",
|
||||
|
|
@ -23844,6 +24360,12 @@
|
|||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sister": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz",
|
||||
"integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
|
|
@ -27593,6 +28115,32 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/youtube-player": {
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz",
|
||||
"integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"debug": "^2.6.6",
|
||||
"load-script": "^1.0.0",
|
||||
"sister": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/youtube-player/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/youtube-player/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.23.8",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "moodist",
|
||||
"type": "module",
|
||||
"version": "2.0.1",
|
||||
"version": "2.4.0",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
"@radix-ui/react-checkbox": "1.1.4",
|
||||
"@radix-ui/react-dropdown-menu": "2.0.6",
|
||||
"@radix-ui/react-slider": "1.2.3",
|
||||
"@radix-ui/react-tooltip": "1.0.7",
|
||||
"@radix-ui/react-tooltip": "1.2.8",
|
||||
"@types/howler": "2.2.10",
|
||||
"@types/react": "^18.2.25",
|
||||
"@types/react-dom": "^18.2.10",
|
||||
|
|
@ -41,11 +41,13 @@
|
|||
"framer-motion": "10.16.4",
|
||||
"howler": "2.2.4",
|
||||
"js-confetti": "0.12.0",
|
||||
"motion": "12.23.24",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hotkeys-hook": "3.2.1",
|
||||
"react-icons": "4.11.0",
|
||||
"react-wrap-balancer": "1.1.0",
|
||||
"react-youtube": "10.1.0",
|
||||
"uuid": "10.0.0",
|
||||
"zustand": "4.4.3"
|
||||
},
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 10 KiB |
BIN
public/og.png
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
BIN
public/sounds/silence.wav
Normal file
7
src/components/binary.astro
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
import { generateRandomBinaryString } from '@/helpers/binary';
|
||||
|
||||
const binary = generateRandomBinaryString(1000);
|
||||
---
|
||||
|
||||
<span>{binary}</span>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { generateRandomBinaryString } from '@/helpers/binary';
|
||||
|
||||
export function Binary() {
|
||||
const [binary, setBinary] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
setBinary(generateRandomBinaryString(1000));
|
||||
|
||||
setInterval(() => {
|
||||
setBinary(generateRandomBinaryString(1000));
|
||||
}, 200);
|
||||
}, []);
|
||||
|
||||
return <span>{binary}</span>;
|
||||
}
|
||||
|
|
@ -18,6 +18,10 @@
|
|||
background-color: var(--color-neutral-800);
|
||||
}
|
||||
|
||||
&:not(.disabled):active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
background-color: var(--color-neutral-200);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useCallback } from 'react';
|
||||
import { BiUndo, BiTrash } from 'react-icons/bi/index';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
import { Tooltip } from '@/components/tooltip';
|
||||
|
|
@ -41,30 +41,31 @@ export function UnselectButton() {
|
|||
initial="hidden"
|
||||
variants={variants}
|
||||
>
|
||||
<Tooltip
|
||||
showDelay={0}
|
||||
content={
|
||||
hasHistory
|
||||
? 'Restore unselected sounds.'
|
||||
: 'Unselect all sounds.'
|
||||
}
|
||||
>
|
||||
<button
|
||||
disabled={noSelected && !hasHistory}
|
||||
aria-label={
|
||||
<Tooltip.Provider delayDuration={0}>
|
||||
<Tooltip
|
||||
content={
|
||||
hasHistory
|
||||
? 'Restore Unselected Sounds'
|
||||
: 'Unselect All Sounds'
|
||||
? 'Restore unselected sounds.'
|
||||
: 'Unselect all sounds.'
|
||||
}
|
||||
className={cn(
|
||||
styles.unselectButton,
|
||||
noSelected && !hasHistory && styles.disabled,
|
||||
)}
|
||||
onClick={handleToggle}
|
||||
>
|
||||
{hasHistory ? <BiUndo /> : <BiTrash />}
|
||||
</button>
|
||||
</Tooltip>
|
||||
<button
|
||||
disabled={noSelected && !hasHistory}
|
||||
aria-label={
|
||||
hasHistory
|
||||
? 'Restore Unselected Sounds'
|
||||
: 'Unselect All Sounds'
|
||||
}
|
||||
className={cn(
|
||||
styles.unselectButton,
|
||||
noSelected && !hasHistory && styles.disabled,
|
||||
)}
|
||||
onClick={handleToggle}
|
||||
>
|
||||
{hasHistory ? <BiUndo /> : <BiTrash />}
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Tooltip.Provider>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { AnimatePresence } from 'framer-motion';
|
||||
import { AnimatePresence } from 'motion/react';
|
||||
|
||||
import { Category } from './category';
|
||||
import { Donate } from './donate';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
padding-bottom: 80px;
|
||||
|
||||
& .title {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--font-lg);
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& .categoryIconsWrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& .icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
font-size: var(--font-md);
|
||||
color: var(--color-foreground);
|
||||
cursor: pointer;
|
||||
background: linear-gradient(
|
||||
var(--color-neutral-50),
|
||||
var(--color-neutral-100)
|
||||
);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 50%;
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(
|
||||
var(--color-neutral-100),
|
||||
var(--color-neutral-200)
|
||||
);
|
||||
transform: scale(1.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/components/categories/category-icons/category-icons.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { sounds } from '@/data/sounds';
|
||||
import { useMemo } from 'react';
|
||||
import styles from './category-icons.module.css';
|
||||
import { Container } from '@/components/container';
|
||||
import { Tooltip } from '@/components/tooltip';
|
||||
|
||||
export default function CategoryIcons() {
|
||||
const categories = useMemo(() => sounds.categories, []);
|
||||
|
||||
const goto = (id: string) => {
|
||||
const category = document.getElementById(`category-${id}`);
|
||||
category?.scrollIntoView();
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className={styles.wrapper}>
|
||||
<h3 className={styles.title}>Categories</h3>
|
||||
<div className={styles.categoryIconsWrapper}>
|
||||
<Tooltip.Provider delayDuration={0}>
|
||||
{categories.map(category => {
|
||||
return (
|
||||
<Tooltip
|
||||
content={category.title}
|
||||
key={category.id}
|
||||
placement="bottom"
|
||||
>
|
||||
<button
|
||||
className={styles.icon}
|
||||
onClick={() => goto(category.id)}
|
||||
>
|
||||
{category.icon}
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Tooltip.Provider>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ import { Container } from './container';
|
|||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
var(--color-neutral-200),
|
||||
var(--color-neutral-400),
|
||||
transparent
|
||||
);
|
||||
transform: translateX(-50%);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
import { BsSoundwave } from 'react-icons/bs/index';
|
||||
|
||||
import { Container } from './container';
|
||||
import { CipherText } from './cipher';
|
||||
|
||||
import { count as soundCount } from '@/lib/sounds';
|
||||
|
||||
|
|
@ -27,9 +26,7 @@ const count = soundCount();
|
|||
<h1 class="title">
|
||||
Ambient Sounds<span class="line">For Focus and Calm</span>
|
||||
</h1>
|
||||
<h2 class="desc">
|
||||
Free and <CipherText client:load text="Open-Source" />.
|
||||
</h2>
|
||||
<h2 class="desc">Free and Open-Source.</h2>
|
||||
|
||||
<p class="sounds">
|
||||
<span aria-hidden="true" class="icon">
|
||||
|
|
@ -64,6 +61,20 @@ const count = soundCount();
|
|||
background-size: 21px 21px;
|
||||
opacity: 0.8;
|
||||
mask-image: linear-gradient(#fff, transparent, transparent);
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
height: 100px;
|
||||
content: '';
|
||||
background: var(--color-neutral-200);
|
||||
filter: blur(50px);
|
||||
border-radius: 100%;
|
||||
opacity: 0.8;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,17 +97,7 @@ const count = soundCount();
|
|||
font-family: var(--font-display);
|
||||
font-size: var(--font-xlg);
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
|
||||
/* & .gradient {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
var(--color-foreground),
|
||||
var(--color-foreground-subtle)
|
||||
);
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
} */
|
||||
line-height: 1.1;
|
||||
|
||||
& .line {
|
||||
display: block;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
import { getSilenceDataURL } from '@/helpers/sound';
|
||||
import { BrowserDetect } from '@/helpers/browser-detect';
|
||||
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
|
@ -16,21 +15,14 @@ const metadata: MediaMetadataInit = {
|
|||
export function MediaSessionTrack() {
|
||||
const { isBrowser } = useSSR();
|
||||
const isDarkTheme = useDarkTheme();
|
||||
const [isGenerated, setIsGenerated] = useState(false);
|
||||
const isPlaying = useSoundStore(state => state.isPlaying);
|
||||
const play = useSoundStore(state => state.play);
|
||||
const pause = useSoundStore(state => state.pause);
|
||||
const masterAudioSoundRef = useRef<HTMLAudioElement>(null);
|
||||
const artworkURL = isDarkTheme ? '/logo-dark.png' : '/logo-light.png';
|
||||
|
||||
const generateSilence = useCallback(async () => {
|
||||
if (!masterAudioSoundRef.current) return;
|
||||
masterAudioSoundRef.current.src = await getSilenceDataURL();
|
||||
setIsGenerated(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isBrowser || !isPlaying || !isGenerated) return;
|
||||
if (!isBrowser || !isPlaying) return;
|
||||
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
...metadata,
|
||||
|
|
@ -42,11 +34,7 @@ export function MediaSessionTrack() {
|
|||
},
|
||||
],
|
||||
});
|
||||
}, [artworkURL, isBrowser, isDarkTheme, isGenerated, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
generateSilence();
|
||||
}, [generateSilence]);
|
||||
}, [artworkURL, isBrowser, isDarkTheme, isPlaying]);
|
||||
|
||||
const startMasterAudio = useCallback(async () => {
|
||||
if (!masterAudioSoundRef.current) return;
|
||||
|
|
@ -78,7 +66,6 @@ export function MediaSessionTrack() {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isGenerated) return;
|
||||
if (!masterAudioSoundRef.current) return;
|
||||
|
||||
if (isPlaying) {
|
||||
|
|
@ -86,7 +73,7 @@ export function MediaSessionTrack() {
|
|||
} else {
|
||||
stopMasterAudio();
|
||||
}
|
||||
}, [isGenerated, isPlaying, startMasterAudio, stopMasterAudio]);
|
||||
}, [isPlaying, startMasterAudio, stopMasterAudio]);
|
||||
|
||||
useEffect(() => {
|
||||
const masterAudioSound = masterAudioSoundRef.current;
|
||||
|
|
@ -100,5 +87,12 @@ export function MediaSessionTrack() {
|
|||
};
|
||||
}, []);
|
||||
|
||||
return <audio id="media-session-track" loop ref={masterAudioSoundRef} />;
|
||||
return (
|
||||
<audio
|
||||
id="media-session-track"
|
||||
loop
|
||||
ref={masterAudioSoundRef}
|
||||
src="/sounds/silence.wav"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect } from 'react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
import { IoClose } from 'react-icons/io5/index';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,16 @@ const presets: Preset[] = [
|
|||
{ baseFrequency: 440, beatFrequency: 10, name: 'Custom' },
|
||||
];
|
||||
|
||||
function computeBinauralBeatOscillatorFrequencies(
|
||||
baseFrequency: number,
|
||||
beatFrequency: number,
|
||||
) {
|
||||
return {
|
||||
leftFrequency: baseFrequency - beatFrequency / 2,
|
||||
rightFrequency: baseFrequency + beatFrequency / 2,
|
||||
};
|
||||
}
|
||||
|
||||
export function BinauralModal({ onClose, show }: BinauralProps) {
|
||||
const [baseFrequency, setBaseFrequency] = useState<number>(440); // Default to A4 note
|
||||
const [beatFrequency, setBeatFrequency] = useState<number>(10); // Default to 10 Hz difference
|
||||
|
|
@ -61,10 +71,10 @@ export function BinauralModal({ onClose, show }: BinauralProps) {
|
|||
)
|
||||
return;
|
||||
|
||||
leftOscillatorRef.current.frequency.value =
|
||||
baseFrequency - beatFrequency / 2;
|
||||
rightOscillatorRef.current.frequency.value =
|
||||
baseFrequency + beatFrequency / 2;
|
||||
const { leftFrequency, rightFrequency } =
|
||||
computeBinauralBeatOscillatorFrequencies(baseFrequency, beatFrequency);
|
||||
leftOscillatorRef.current.frequency.value = leftFrequency;
|
||||
rightOscillatorRef.current.frequency.value = rightFrequency;
|
||||
|
||||
// Pan oscillators to left and right
|
||||
const leftPanner = audioContext.createStereoPanner();
|
||||
|
|
@ -104,6 +114,16 @@ export function BinauralModal({ onClose, show }: BinauralProps) {
|
|||
}
|
||||
}, [volume]);
|
||||
|
||||
useEffect(() => {
|
||||
// Update base frequency for both left and right oscillators when it changes
|
||||
if (leftOscillatorRef.current && rightOscillatorRef.current) {
|
||||
const { leftFrequency, rightFrequency } =
|
||||
computeBinauralBeatOscillatorFrequencies(baseFrequency, beatFrequency);
|
||||
leftOscillatorRef.current.frequency.value = leftFrequency;
|
||||
rightOscillatorRef.current.frequency.value = rightFrequency;
|
||||
}
|
||||
}, [baseFrequency, beatFrequency]);
|
||||
|
||||
useEffect(() => {
|
||||
// Cleanup when component unmounts
|
||||
return () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect, useMemo, useCallback } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { motion } from 'motion/react';
|
||||
|
||||
import { padNumber } from '@/helpers/number';
|
||||
|
||||
|
|
|
|||
1
src/components/modals/lofi/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { LofiModal } from './lofi';
|
||||
86
src/components/modals/lofi/lofi.module.css
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
.title {
|
||||
margin-bottom: 12px;
|
||||
font-family: var(--font-heading);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.notice {
|
||||
& p {
|
||||
line-height: 1.4;
|
||||
color: var(--color-foreground-subtle);
|
||||
}
|
||||
|
||||
& .buttons {
|
||||
display: flex;
|
||||
column-gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-top: 12px;
|
||||
|
||||
& button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
cursor: pointer;
|
||||
background: var(--color-neutral-200);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
|
||||
&.primary {
|
||||
color: var(--color-neutral-50);
|
||||
background: var(--color-neutral-950);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.videos {
|
||||
margin-top: 20px;
|
||||
|
||||
& .video {
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
& h2 {
|
||||
margin-bottom: 8px;
|
||||
font-size: var(--font-sm);
|
||||
color: var(--color-foreground-subtle);
|
||||
|
||||
& span {
|
||||
display: inline-block;
|
||||
color: var(--color-foreground-subtler);
|
||||
|
||||
&.index {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
& strong {
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
& .container {
|
||||
padding: 8px;
|
||||
background-color: var(--color-neutral-50);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 12px;
|
||||
|
||||
& .iframe {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 560 / 315;
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
src/components/modals/lofi/lofi.tsx
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { useState } from 'react';
|
||||
import YouTube from 'react-youtube';
|
||||
|
||||
import { Modal } from '@/components/modal/modal';
|
||||
|
||||
import styles from './lofi.module.css';
|
||||
import { padNumber } from '@/helpers/number';
|
||||
|
||||
interface LofiProps {
|
||||
onClose: () => void;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
const videos = [
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'jfKfPfyJRdk',
|
||||
title: 'lofi hip hop radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: '4xDzrJKXOOY',
|
||||
title: 'synthwave radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'P6Segk8cr-c',
|
||||
title: 'sad lofi radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'S_MOd40zlYU',
|
||||
title: 'dark ambient radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'TtkFsfOP9QI',
|
||||
title: 'peaceful piano radio',
|
||||
},
|
||||
];
|
||||
|
||||
export function LofiModal({ onClose, show }: LofiProps) {
|
||||
const [isAccepted, setIsAccepted] = useState(false);
|
||||
|
||||
return (
|
||||
<Modal persist show={show} onClose={onClose}>
|
||||
<h1 className={styles.title}>Lofi Music Player</h1>
|
||||
|
||||
{!isAccepted ? (
|
||||
<div className={styles.notice}>
|
||||
<p>
|
||||
This feature plays music using embedded YouTube videos. By
|
||||
continuing, you agree to connect to YouTube, which may collect data
|
||||
in accordance with their privacy policy. We do not control or track
|
||||
this data.
|
||||
</p>
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<button onClick={onClose}>Cancel</button>
|
||||
<button
|
||||
className={styles.primary}
|
||||
onClick={() => setIsAccepted(true)}
|
||||
>
|
||||
Continue
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.videos}>
|
||||
{videos.map((video, index) => (
|
||||
<div className={styles.video} key={video.id}>
|
||||
<h2>
|
||||
<span className={styles.index}>{padNumber(index + 1, 2)}</span>{' '}
|
||||
<strong>{video.channel}</strong> <span>/</span> {video.title}
|
||||
</h2>
|
||||
<div className={styles.container}>
|
||||
<YouTube iframeClassName={styles.iframe} videoId={video.id} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
@ -9,14 +9,16 @@ export function Shuffle() {
|
|||
const shuffle = useSoundStore(state => state.shuffle);
|
||||
|
||||
return (
|
||||
<Tooltip content="Shuffle sounds" showDelay={0}>
|
||||
<button
|
||||
aria-label="Shuffle sounds"
|
||||
className={styles.button}
|
||||
onClick={shuffle}
|
||||
>
|
||||
<BiShuffle />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip.Provider delayDuration={0}>
|
||||
<Tooltip content="Shuffle sounds">
|
||||
<button
|
||||
aria-label="Shuffle sounds"
|
||||
className={styles.button}
|
||||
onClick={shuffle}
|
||||
>
|
||||
<BiShuffle />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Tooltip.Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
margin: 0 auto;
|
||||
font-size: var(--font-sm);
|
||||
pointer-events: fill;
|
||||
background-color: var(--color-neutral-200);
|
||||
background-color: var(--color-neutral-100);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { motion } from 'framer-motion';
|
||||
import { motion } from 'motion/react';
|
||||
|
||||
import { mix, fade, slideY } from '@/lib/motion';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { BiHeart, BiSolidHeart } from 'react-icons/bi/index';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
justify-content: center;
|
||||
padding: 25px 20px;
|
||||
text-align: center;
|
||||
background: linear-gradient(var(--color-neutral-100), transparent);
|
||||
cursor: pointer;
|
||||
background: linear-gradient(rgb(24 24 27 / 50%), transparent);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 8px;
|
||||
border-radius: 12px;
|
||||
transition: 0.2s;
|
||||
|
||||
&:focus-visible {
|
||||
|
|
@ -107,7 +108,6 @@
|
|||
font-size: var(--font-sm);
|
||||
font-weight: 600;
|
||||
line-height: 1.6;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
|
||||
import { Sound } from './sound';
|
||||
import { useLocalStorage } from '@/hooks/use-local-storage';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { FaGithub } from 'react-icons/fa/index';
|
|||
|
||||
import { SpecialButton } from './special-button';
|
||||
import { Container } from './container';
|
||||
import { Binary } from './binary';
|
||||
import Binary from './binary.astro';
|
||||
---
|
||||
|
||||
<div class="source">
|
||||
|
|
@ -25,7 +25,7 @@ import { Binary } from './binary';
|
|||
</SpecialButton>
|
||||
</div>
|
||||
|
||||
<div class="binary"><Binary client:load /></div>
|
||||
<div class="binary"><Binary /></div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ export { Todo as TodoItem } from './todo';
|
|||
export { Countdown as CountdownItem } from './countdown';
|
||||
export { Binaural as BinauralItem } from './binaural';
|
||||
export { Isochronic as IsochronicItem } from './isochronic';
|
||||
export { Lofi as LofiItem } from './lofi';
|
||||
|
|
|
|||
17
src/components/toolbar/menu/items/lofi.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { IoIosMusicalNote } from 'react-icons/io/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
interface LofiProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function Lofi({ open }: LofiProps) {
|
||||
return (
|
||||
<Item
|
||||
icon={<IoIosMusicalNote />}
|
||||
label="Lofi Music Player"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ import { useState, useMemo, useCallback } from 'react';
|
|||
import { IoMenu, IoClose } from 'react-icons/io5/index';
|
||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
|
||||
import {
|
||||
ShuffleItem,
|
||||
|
|
@ -19,6 +19,7 @@ import {
|
|||
CountdownItem,
|
||||
BinauralItem,
|
||||
IsochronicItem,
|
||||
LofiItem,
|
||||
} from './items';
|
||||
import { Divider } from './divider';
|
||||
import { ShareLinkModal } from '@/components/modals/share-link';
|
||||
|
|
@ -28,6 +29,7 @@ import { SleepTimerModal } from '@/components/modals/sleep-timer';
|
|||
import { BreathingExerciseModal } from '@/components/modals/breathing';
|
||||
import { BinauralModal } from '@/components/modals/binaural';
|
||||
import { IsochronicModal } from '@/components/modals/isochronic';
|
||||
import { LofiModal } from '@/components/modals/lofi';
|
||||
import { Pomodoro, Notepad, Todo, Countdown } from '@/components/toolbox';
|
||||
import { Slider } from '@/components/slider';
|
||||
|
||||
|
|
@ -51,6 +53,7 @@ export function Menu() {
|
|||
breathing: false,
|
||||
countdown: false,
|
||||
isochronic: false,
|
||||
lofi: false,
|
||||
notepad: false,
|
||||
pomodoro: false,
|
||||
presets: false,
|
||||
|
|
@ -137,6 +140,7 @@ export function Menu() {
|
|||
<Divider />
|
||||
<BinauralItem open={() => open('binaural')} />
|
||||
<IsochronicItem open={() => open('isochronic')} />
|
||||
<LofiItem open={() => open('lofi')} />
|
||||
|
||||
<Divider />
|
||||
<ShortcutsItem open={() => open('shortcuts')} />
|
||||
|
|
@ -193,6 +197,7 @@ export function Menu() {
|
|||
show={modals.isochronic}
|
||||
onClose={() => close('isochronic')}
|
||||
/>
|
||||
<LofiModal show={modals.lofi} onClose={() => close('lofi')} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { BiUpArrowAlt } from 'react-icons/bi/index';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { motion } from 'motion/react';
|
||||
|
||||
import { mix, fade, slideY } from '@/lib/motion';
|
||||
|
||||
|
|
@ -30,22 +30,20 @@ export function ScrollToTop() {
|
|||
const variants = mix(fade(), slideY(10, 0));
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isVisible ? (
|
||||
<motion.button
|
||||
animate="show"
|
||||
aria-label="Scroll to top"
|
||||
className={styles.button}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
variants={variants}
|
||||
onClick={scrollToTop}
|
||||
>
|
||||
<BiUpArrowAlt />
|
||||
</motion.button>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<motion.button
|
||||
animate={isVisible ? 'show' : 'hidden'}
|
||||
aria-label="Scroll to top"
|
||||
className={styles.button}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
variants={variants}
|
||||
style={{
|
||||
pointerEvents: isVisible ? 'auto' : 'none',
|
||||
visibility: isVisible ? 'visible' : 'hidden',
|
||||
}}
|
||||
onClick={scrollToTop}
|
||||
>
|
||||
<BiUpArrowAlt />
|
||||
</motion.button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,16 @@ export function Button({
|
|||
tooltip,
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<Tooltip content={tooltip} placement="bottom" showDelay={0}>
|
||||
<button
|
||||
className={cn(styles.button, smallIcon && styles.smallIcon)}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
>
|
||||
{icon}
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip.Provider delayDuration={0}>
|
||||
<Tooltip content={tooltip} placement="bottom">
|
||||
<button
|
||||
className={cn(styles.button, smallIcon && styles.smallIcon)}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
>
|
||||
{icon}
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Tooltip.Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export function Button({
|
|||
tooltip,
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<Tooltip content={tooltip} placement="bottom" showDelay={0}>
|
||||
<Tooltip content={tooltip} placement="bottom">
|
||||
<button
|
||||
className={cn(
|
||||
styles.button,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
height: 350px;
|
||||
padding: 12px;
|
||||
line-height: 1.6;
|
||||
color: var(--color-foreground-subtle);
|
||||
color: var(--color-foreground);
|
||||
resize: none;
|
||||
background-color: var(--color-neutral-50);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { useCopy } from '@/hooks/use-copy';
|
|||
import { download } from '@/helpers/download';
|
||||
|
||||
import styles from './notepad.module.css';
|
||||
import { Tooltip } from '@/components/tooltip';
|
||||
|
||||
interface NotepadProps {
|
||||
onClose: () => void;
|
||||
|
|
@ -50,23 +51,25 @@ export function Notepad({ onClose, show }: NotepadProps) {
|
|||
<header className={styles.header}>
|
||||
<h2 className={styles.label}>Your Note</h2>
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
icon={copying ? <FaCheck /> : <LuCopy />}
|
||||
tooltip="Copy Note"
|
||||
onClick={() => copy(note)}
|
||||
/>
|
||||
<Button
|
||||
icon={<LuDownload />}
|
||||
tooltip="Download Note"
|
||||
onClick={() => download('Moodit Note.txt', note)}
|
||||
/>
|
||||
<Button
|
||||
critical={!history}
|
||||
icon={history ? <FaUndo /> : <BiTrash />}
|
||||
recommended={!!history}
|
||||
tooltip={history ? 'Restore Note' : 'Clear Note'}
|
||||
onClick={() => (history ? restore() : clear())}
|
||||
/>
|
||||
<Tooltip.Provider delayDuration={0}>
|
||||
<Button
|
||||
icon={copying ? <FaCheck /> : <LuCopy />}
|
||||
tooltip="Copy Note"
|
||||
onClick={() => copy(note)}
|
||||
/>
|
||||
<Button
|
||||
icon={<LuDownload />}
|
||||
tooltip="Download Note"
|
||||
onClick={() => download('Moodit Note.txt', note)}
|
||||
/>
|
||||
<Button
|
||||
critical={!history}
|
||||
icon={history ? <FaUndo /> : <BiTrash />}
|
||||
recommended={!!history}
|
||||
tooltip={history ? 'Restore Note' : 'Clear Note'}
|
||||
onClick={() => (history ? restore() : clear())}
|
||||
/>
|
||||
</Tooltip.Provider>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
||||
|
||||
import { slideX, slideY, mix, fade } from '@/lib/motion';
|
||||
|
|
@ -24,14 +24,12 @@ interface TooltipProps {
|
|||
children: JSX.Element;
|
||||
content: string;
|
||||
placement?: Placement;
|
||||
showDelay?: number;
|
||||
}
|
||||
|
||||
export function Tooltip({
|
||||
children,
|
||||
content,
|
||||
placement = 'top',
|
||||
showDelay = 500,
|
||||
}: TooltipProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
|
|
@ -52,35 +50,56 @@ export function Tooltip({
|
|||
const variants = mix(fade(), slide!);
|
||||
|
||||
return (
|
||||
<TooltipPrimitive.Provider delayDuration={showDelay}>
|
||||
<TooltipPrimitive.Root open={isOpen} onOpenChange={o => setIsOpen(o)}>
|
||||
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
|
||||
<TooltipPrimitive.Root open={isOpen} onOpenChange={o => setIsOpen(o)}>
|
||||
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
|
||||
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<TooltipPrimitive.Portal forceMount>
|
||||
<TooltipPrimitive.Content
|
||||
align={align}
|
||||
asChild
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<TooltipPrimitive.Portal forceMount>
|
||||
<TooltipPrimitive.Content
|
||||
align={align}
|
||||
asChild
|
||||
className={styles.tooltip}
|
||||
collisionPadding={8}
|
||||
side={side}
|
||||
sideOffset={12}
|
||||
>
|
||||
<motion.div
|
||||
animate="show"
|
||||
className={styles.tooltip}
|
||||
collisionPadding={8}
|
||||
side={side}
|
||||
sideOffset={12}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
variants={variants}
|
||||
>
|
||||
<motion.div
|
||||
animate="show"
|
||||
className={styles.tooltip}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
variants={variants}
|
||||
>
|
||||
{content}
|
||||
</motion.div>
|
||||
</TooltipPrimitive.Content>
|
||||
</TooltipPrimitive.Portal>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</TooltipPrimitive.Root>
|
||||
{content}
|
||||
</motion.div>
|
||||
</TooltipPrimitive.Content>
|
||||
</TooltipPrimitive.Portal>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</TooltipPrimitive.Root>
|
||||
);
|
||||
}
|
||||
|
||||
interface TooltipProviderProps {
|
||||
children: React.ReactNode;
|
||||
delayDuration?: number;
|
||||
skipDelayDuration?: number;
|
||||
}
|
||||
|
||||
function Provider({
|
||||
children,
|
||||
delayDuration = 500,
|
||||
skipDelayDuration = 0,
|
||||
}: TooltipProviderProps) {
|
||||
return (
|
||||
<TooltipPrimitive.Provider
|
||||
delayDuration={delayDuration}
|
||||
skipDelayDuration={skipDelayDuration}
|
||||
>
|
||||
{children}
|
||||
</TooltipPrimitive.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
Tooltip.Provider = Provider;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
useRef,
|
||||
useContext,
|
||||
} from 'react';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import { AnimatePresence } from 'motion/react';
|
||||
|
||||
import { Snackbar } from '@/components/snackbar';
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import { PiBirdFill, PiDogBold } from 'react-icons/pi/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const animals: Category = {
|
||||
icon: <FaDog />,
|
||||
id: 'animals',
|
||||
|
|
@ -29,97 +31,97 @@ export const animals: Category = {
|
|||
icon: <PiBirdFill />,
|
||||
id: 'birds',
|
||||
label: 'Birds',
|
||||
src: '/sounds/animals/birds.mp3',
|
||||
src: getAssetPath('/sounds/animals/birds.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiSeagull />,
|
||||
id: 'seagulls',
|
||||
label: 'Seagulls',
|
||||
src: '/sounds/animals/seagulls.mp3',
|
||||
src: getAssetPath('/sounds/animals/seagulls.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiCricket />,
|
||||
id: 'crickets',
|
||||
label: 'Crickets',
|
||||
src: '/sounds/animals/crickets.mp3',
|
||||
src: getAssetPath('/sounds/animals/crickets.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiWolfHead />,
|
||||
id: 'wolf',
|
||||
label: 'Wolf',
|
||||
src: '/sounds/animals/wolf.mp3',
|
||||
src: getAssetPath('/sounds/animals/wolf.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiOwl />,
|
||||
id: 'owl',
|
||||
label: 'Owl',
|
||||
src: '/sounds/animals/owl.mp3',
|
||||
src: getAssetPath('/sounds/animals/owl.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaFrog />,
|
||||
id: 'frog',
|
||||
label: 'Frog',
|
||||
src: '/sounds/animals/frog.mp3',
|
||||
src: getAssetPath('/sounds/animals/frog.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <PiDogBold />,
|
||||
id: 'dog-barking',
|
||||
label: 'Dog Barking',
|
||||
src: '/sounds/animals/dog-barking.mp3',
|
||||
src: getAssetPath('/sounds/animals/dog-barking.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaHorseHead />,
|
||||
id: 'horse-galopp',
|
||||
label: 'Horse Galopp',
|
||||
src: '/sounds/animals/horse-galopp.mp3',
|
||||
id: 'horse-gallop',
|
||||
label: 'Horse Gallop',
|
||||
src: getAssetPath('/sounds/animals/horse-gallop.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaCat />,
|
||||
id: 'cat-purring',
|
||||
label: 'Cat Purring',
|
||||
src: '/sounds/animals/cat-purring.mp3',
|
||||
src: getAssetPath('/sounds/animals/cat-purring.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaCrow />,
|
||||
id: 'crows',
|
||||
label: 'Crows',
|
||||
src: '/sounds/animals/crows.mp3',
|
||||
src: getAssetPath('/sounds/animals/crows.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiWhaleTail />,
|
||||
id: 'whale',
|
||||
label: 'Whale',
|
||||
src: '/sounds/animals/whale.mp3',
|
||||
src: getAssetPath('/sounds/animals/whale.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiTreeBeehive />,
|
||||
id: 'beehive',
|
||||
label: 'Beehive',
|
||||
src: '/sounds/animals/beehive.mp3',
|
||||
src: getAssetPath('/sounds/animals/beehive.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiEgyptianBird />,
|
||||
id: 'woodpecker',
|
||||
label: 'Woodpecker',
|
||||
src: '/sounds/animals/woodpecker.mp3',
|
||||
src: getAssetPath('/sounds/animals/woodpecker.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiChicken />,
|
||||
id: 'chickens',
|
||||
label: 'Chickens',
|
||||
src: '/sounds/animals/chickens.mp3',
|
||||
src: getAssetPath('/sounds/animals/chickens.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiCow />,
|
||||
id: 'cows',
|
||||
label: 'Cows',
|
||||
src: '/sounds/animals/cows.mp3',
|
||||
src: getAssetPath('/sounds/animals/cows.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiSheep />,
|
||||
id: 'sheep',
|
||||
label: 'Sheep',
|
||||
src: '/sounds/animals/sheep.mp3',
|
||||
src: getAssetPath('/sounds/animals/sheep.mp3'),
|
||||
},
|
||||
],
|
||||
title: 'Animals',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { BsSoundwave } from 'react-icons/bs/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const binaural: Category = {
|
||||
icon: <TbWaveSine />,
|
||||
id: 'binaural',
|
||||
|
|
@ -11,31 +13,31 @@ export const binaural: Category = {
|
|||
icon: <BsSoundwave />,
|
||||
id: 'binaural-delta',
|
||||
label: 'Delta',
|
||||
src: '/sounds/binaural/binaural-delta.wav',
|
||||
src: getAssetPath('/sounds/binaural/binaural-delta.wav'),
|
||||
},
|
||||
{
|
||||
icon: <BsSoundwave />,
|
||||
id: 'binaural-theta',
|
||||
label: 'Theta',
|
||||
src: '/sounds/binaural/binaural-theta.wav',
|
||||
src: getAssetPath('/sounds/binaural/binaural-theta.wav'),
|
||||
},
|
||||
{
|
||||
icon: <BsSoundwave />,
|
||||
id: 'binaural-alpha',
|
||||
label: 'Alpha',
|
||||
src: '/sounds/binaural/binaural-alpha.wav',
|
||||
src: getAssetPath('/sounds/binaural/binaural-alpha.wav'),
|
||||
},
|
||||
{
|
||||
icon: <BsSoundwave />,
|
||||
id: 'binaural-beta',
|
||||
label: 'Beta',
|
||||
src: '/sounds/binaural/binaural-beta.wav',
|
||||
src: getAssetPath('/sounds/binaural/binaural-beta.wav'),
|
||||
},
|
||||
{
|
||||
icon: <BsSoundwave />,
|
||||
id: 'binaural-gamma',
|
||||
label: 'Gamma',
|
||||
src: '/sounds/binaural/binaural-gamma.wav',
|
||||
src: getAssetPath('/sounds/binaural/binaural-gamma.wav'),
|
||||
},
|
||||
],
|
||||
title: 'Binaural Beats',
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import {
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const nature: Category = {
|
||||
icon: <BiSolidTree />,
|
||||
id: 'nature',
|
||||
|
|
@ -19,73 +21,73 @@ export const nature: Category = {
|
|||
icon: <BiWater />,
|
||||
id: 'river',
|
||||
label: 'River',
|
||||
src: '/sounds/nature/river.mp3',
|
||||
src: getAssetPath('/sounds/nature/river.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaWater />,
|
||||
id: 'waves',
|
||||
label: 'Waves',
|
||||
src: '/sounds/nature/waves.mp3',
|
||||
src: getAssetPath('/sounds/nature/waves.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BsFire />,
|
||||
id: 'campfire',
|
||||
label: 'Campfire',
|
||||
src: '/sounds/nature/campfire.mp3',
|
||||
src: getAssetPath('/sounds/nature/campfire.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaWind />,
|
||||
id: 'wind',
|
||||
label: 'Wind',
|
||||
src: '/sounds/nature/wind.mp3',
|
||||
src: getAssetPath('/sounds/nature/wind.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaWind />,
|
||||
id: 'howling-wind',
|
||||
label: 'Howling Wind',
|
||||
src: '/sounds/nature/howling-wind.mp3',
|
||||
src: getAssetPath('/sounds/nature/howling-wind.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BiSolidTree />,
|
||||
id: 'wind-in-trees',
|
||||
label: 'Wind in Trees',
|
||||
src: '/sounds/nature/wind-in-trees.mp3',
|
||||
src: getAssetPath('/sounds/nature/wind-in-trees.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiWaterfall />,
|
||||
id: 'waterfall',
|
||||
label: 'Waterfall',
|
||||
src: '/sounds/nature/waterfall.mp3',
|
||||
src: getAssetPath('/sounds/nature/waterfall.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaRegSnowflake />,
|
||||
id: 'walk-in-snow',
|
||||
label: 'Walk in Snow',
|
||||
src: '/sounds/nature/walk-in-snow.mp3',
|
||||
src: getAssetPath('/sounds/nature/walk-in-snow.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaLeaf />,
|
||||
id: 'walk-on-leaves',
|
||||
label: 'Walk on Leaves',
|
||||
src: '/sounds/nature/walk-on-leaves.mp3',
|
||||
src: getAssetPath('/sounds/nature/walk-on-leaves.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiStonePile />,
|
||||
id: 'walk-on-gravel',
|
||||
label: 'Walk on Gravel',
|
||||
src: '/sounds/nature/walk-on-gravel.mp3',
|
||||
src: getAssetPath('/sounds/nature/walk-on-gravel.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BsFillDropletFill />,
|
||||
id: 'droplets',
|
||||
label: 'Droplets',
|
||||
src: '/sounds/nature/droplets.mp3',
|
||||
src: getAssetPath('/sounds/nature/droplets.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaTree />,
|
||||
id: 'jungle',
|
||||
label: 'Jungle',
|
||||
src: '/sounds/nature/jungle.mp3',
|
||||
src: getAssetPath('/sounds/nature/jungle.mp3'),
|
||||
},
|
||||
],
|
||||
title: 'Nature',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { BsSoundwave } from 'react-icons/bs/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const noise: Category = {
|
||||
icon: <BsSoundwave />,
|
||||
id: 'noise',
|
||||
|
|
@ -11,19 +13,19 @@ export const noise: Category = {
|
|||
icon: <GiSoundWaves />,
|
||||
id: 'white-noise',
|
||||
label: 'White Noise',
|
||||
src: '/sounds/noise/white-noise.wav',
|
||||
src: getAssetPath('/sounds/noise/white-noise.wav'),
|
||||
},
|
||||
{
|
||||
icon: <GiSoundWaves />,
|
||||
id: 'pink-noise',
|
||||
label: 'Pink Noise',
|
||||
src: '/sounds/noise/pink-noise.wav',
|
||||
src: getAssetPath('/sounds/noise/pink-noise.wav'),
|
||||
},
|
||||
{
|
||||
icon: <GiSoundWaves />,
|
||||
id: 'brown-noise',
|
||||
label: 'Brown Noise',
|
||||
src: '/sounds/noise/brown-noise.wav',
|
||||
src: getAssetPath('/sounds/noise/brown-noise.wav'),
|
||||
},
|
||||
],
|
||||
title: 'Noise',
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import { FaBookOpen } from 'react-icons/fa6/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const places: Category = {
|
||||
icon: <MdLocationPin />,
|
||||
id: 'places',
|
||||
|
|
@ -26,97 +28,97 @@ export const places: Category = {
|
|||
icon: <BiSolidCoffeeAlt />,
|
||||
id: 'cafe',
|
||||
label: 'Cafe',
|
||||
src: '/sounds/places/cafe.mp3',
|
||||
src: getAssetPath('/sounds/places/cafe.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BiSolidPlaneAlt />,
|
||||
id: 'airport',
|
||||
label: 'Airport',
|
||||
src: '/sounds/places/airport.mp3',
|
||||
src: getAssetPath('/sounds/places/airport.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaChurch />,
|
||||
id: 'church',
|
||||
label: 'Church',
|
||||
src: '/sounds/places/church.mp3',
|
||||
src: getAssetPath('/sounds/places/church.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <MdTempleBuddhist />,
|
||||
id: 'temple',
|
||||
label: 'Temple',
|
||||
src: '/sounds/places/temple.mp3',
|
||||
src: getAssetPath('/sounds/places/temple.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <MdConstruction />,
|
||||
id: 'construction-site',
|
||||
label: 'Construction Site',
|
||||
src: '/sounds/places/construction-site.mp3',
|
||||
src: getAssetPath('/sounds/places/construction-site.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <TbScubaMask />,
|
||||
id: 'underwater',
|
||||
label: 'Underwater',
|
||||
src: '/sounds/places/underwater.mp3',
|
||||
src: getAssetPath('/sounds/places/underwater.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <TbBeerFilled />,
|
||||
id: 'crowded-bar',
|
||||
label: 'Crowded Bar',
|
||||
src: '/sounds/places/crowded-bar.mp3',
|
||||
src: getAssetPath('/sounds/places/crowded-bar.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiVillage />,
|
||||
id: 'night-village',
|
||||
label: 'Night Village',
|
||||
src: '/sounds/places/night-village.mp3',
|
||||
src: getAssetPath('/sounds/places/night-village.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaSubway />,
|
||||
id: 'subway-station',
|
||||
label: 'Subway Station',
|
||||
src: '/sounds/places/subway-station.mp3',
|
||||
src: getAssetPath('/sounds/places/subway-station.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <HiOfficeBuilding />,
|
||||
id: 'office',
|
||||
label: 'Office',
|
||||
src: '/sounds/places/office.mp3',
|
||||
src: getAssetPath('/sounds/places/office.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaShoppingBasket />,
|
||||
id: 'supermarket',
|
||||
label: 'Supermarket',
|
||||
src: '/sounds/places/supermarket.mp3',
|
||||
src: getAssetPath('/sounds/places/supermarket.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiCarousel />,
|
||||
id: 'carousel',
|
||||
label: 'Carousel',
|
||||
src: '/sounds/places/carousel.mp3',
|
||||
src: getAssetPath('/sounds/places/carousel.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <AiFillExperiment />,
|
||||
id: 'laboratory',
|
||||
label: 'Laboratory',
|
||||
src: '/sounds/places/laboratory.mp3',
|
||||
src: getAssetPath('/sounds/places/laboratory.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BiSolidDryer />,
|
||||
id: 'laundry-room',
|
||||
label: 'Laundry Room',
|
||||
src: '/sounds/places/laundry-room.mp3',
|
||||
src: getAssetPath('/sounds/places/laundry-room.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <IoRestaurant />,
|
||||
id: 'restaurant',
|
||||
label: 'Restaurant',
|
||||
src: '/sounds/places/restaurant.mp3',
|
||||
src: getAssetPath('/sounds/places/restaurant.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaBookOpen />,
|
||||
id: 'library',
|
||||
label: 'Library',
|
||||
src: '/sounds/places/library.mp3',
|
||||
src: getAssetPath('/sounds/places/library.mp3'),
|
||||
},
|
||||
],
|
||||
title: 'Places',
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import { MdOutlineThunderstorm } from 'react-icons/md/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const rain: Category = {
|
||||
icon: <BsFillCloudRainFill />,
|
||||
id: 'rain',
|
||||
|
|
@ -18,49 +20,49 @@ export const rain: Category = {
|
|||
icon: <BsFillCloudRainFill />,
|
||||
id: 'light-rain',
|
||||
label: 'Light Rain',
|
||||
src: '/sounds/rain/light-rain.mp3',
|
||||
src: getAssetPath('/sounds/rain/light-rain.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BsFillCloudRainHeavyFill />,
|
||||
id: 'heavy-rain',
|
||||
label: 'Heavy Rain',
|
||||
src: '/sounds/rain/heavy-rain.mp3',
|
||||
src: getAssetPath('/sounds/rain/heavy-rain.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <MdOutlineThunderstorm />,
|
||||
id: 'thunder',
|
||||
label: 'Thunder',
|
||||
src: '/sounds/rain/thunder.mp3',
|
||||
src: getAssetPath('/sounds/rain/thunder.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiWindow />,
|
||||
id: 'rain-on-window',
|
||||
label: 'Rain on Window',
|
||||
src: '/sounds/rain/rain-on-window.mp3',
|
||||
src: getAssetPath('/sounds/rain/rain-on-window.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaCarSide />,
|
||||
id: 'rain-on-car-roof',
|
||||
label: 'Rain on Car Roof',
|
||||
src: '/sounds/rain/rain-on-car-roof.mp3',
|
||||
src: getAssetPath('/sounds/rain/rain-on-car-roof.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BsUmbrellaFill />,
|
||||
id: 'rain-on-umbrella',
|
||||
label: 'Rain on Umbrella',
|
||||
src: '/sounds/rain/rain-on-umbrella.mp3',
|
||||
src: getAssetPath('/sounds/rain/rain-on-umbrella.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <PiTentFill />,
|
||||
id: 'rain-on-tent',
|
||||
label: 'Rain on Tent',
|
||||
src: '/sounds/rain/rain-on-tent.mp3',
|
||||
src: getAssetPath('/sounds/rain/rain-on-tent.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaLeaf />,
|
||||
id: 'rain-on-leaves',
|
||||
label: 'Rain on Leaves',
|
||||
src: '/sounds/rain/rain-on-leaves.mp3',
|
||||
src: getAssetPath('/sounds/rain/rain-on-leaves.mp3'),
|
||||
},
|
||||
],
|
||||
title: 'Rain',
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import { PiVinylRecord } from 'react-icons/pi/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const things: Category = {
|
||||
icon: <MdSmartToy />,
|
||||
id: 'things',
|
||||
|
|
@ -22,97 +24,97 @@ export const things: Category = {
|
|||
icon: <BsFillKeyboardFill />,
|
||||
id: 'keyboard',
|
||||
label: 'Keyboard',
|
||||
src: '/sounds/things/keyboard.mp3',
|
||||
src: getAssetPath('/sounds/things/keyboard.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaKeyboard />,
|
||||
id: 'typewriter',
|
||||
label: 'Typewriter',
|
||||
src: '/sounds/things/typewriter.mp3',
|
||||
src: getAssetPath('/sounds/things/typewriter.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <RiFilePaper2Fill />,
|
||||
id: 'paper',
|
||||
label: 'Paper',
|
||||
src: '/sounds/things/paper.mp3',
|
||||
src: getAssetPath('/sounds/things/paper.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaClock />,
|
||||
id: 'clock',
|
||||
label: 'Clock',
|
||||
src: '/sounds/things/clock.mp3',
|
||||
src: getAssetPath('/sounds/things/clock.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiWindchimes />,
|
||||
id: 'wind-chimes',
|
||||
label: 'Wind Chimes',
|
||||
src: '/sounds/things/wind-chimes.mp3',
|
||||
src: getAssetPath('/sounds/things/wind-chimes.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <TbBowlFilled />,
|
||||
id: 'singing-bowl',
|
||||
label: 'Singing Bowl',
|
||||
src: '/sounds/things/singing-bowl.mp3',
|
||||
src: getAssetPath('/sounds/things/singing-bowl.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaFan />,
|
||||
id: 'ceiling-fan',
|
||||
label: 'Ceiling Fan',
|
||||
src: '/sounds/things/ceiling-fan.mp3',
|
||||
src: getAssetPath('/sounds/things/ceiling-fan.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BiSolidDryer />,
|
||||
id: 'dryer',
|
||||
label: 'Dryer',
|
||||
src: '/sounds/things/dryer.mp3',
|
||||
src: getAssetPath('/sounds/things/dryer.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiFilmProjector />,
|
||||
id: 'slide-projector',
|
||||
label: 'Slide Projector',
|
||||
src: '/sounds/things/slide-projector.mp3',
|
||||
src: getAssetPath('/sounds/things/slide-projector.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <MdWaterDrop />,
|
||||
id: 'boiling-water',
|
||||
label: 'Boiling Water',
|
||||
src: '/sounds/things/boiling-water.mp3',
|
||||
src: getAssetPath('/sounds/things/boiling-water.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <RiBubbleChartFill />,
|
||||
id: 'bubbles',
|
||||
label: 'Bubbles',
|
||||
src: '/sounds/things/bubbles.mp3',
|
||||
src: getAssetPath('/sounds/things/bubbles.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <MdRadio />,
|
||||
id: 'tuning-radio',
|
||||
label: 'Tuning Radio',
|
||||
src: '/sounds/things/tuning-radio.mp3',
|
||||
src: getAssetPath('/sounds/things/tuning-radio.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <IoIosRadio />,
|
||||
id: 'morse-code',
|
||||
label: 'Morse Code',
|
||||
src: '/sounds/things/morse-code.mp3',
|
||||
src: getAssetPath('/sounds/things/morse-code.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiWashingMachine />,
|
||||
id: 'washing-machine',
|
||||
label: 'Washing Machine',
|
||||
src: '/sounds/things/washing-machine.mp3',
|
||||
src: getAssetPath('/sounds/things/washing-machine.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <PiVinylRecord />,
|
||||
id: 'vinyl-effect',
|
||||
label: 'Vinyl Effect',
|
||||
src: '/sounds/things/vinyl-effect.mp3',
|
||||
src: getAssetPath('/sounds/things/vinyl-effect.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <TbWiper />,
|
||||
id: 'windshield-wipers',
|
||||
label: 'Windshield Wipers',
|
||||
src: '/sounds/things/windshield-wipers.mp3',
|
||||
src: getAssetPath('/sounds/things/windshield-wipers.mp3'),
|
||||
},
|
||||
],
|
||||
title: 'Things',
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import { TbSailboat } from 'react-icons/tb/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const transport: Category = {
|
||||
icon: <FaCarSide />,
|
||||
id: 'transport',
|
||||
|
|
@ -13,37 +15,37 @@ export const transport: Category = {
|
|||
icon: <BiSolidTrain />,
|
||||
id: 'train',
|
||||
label: 'Train',
|
||||
src: '/sounds/transport/train.mp3',
|
||||
src: getAssetPath('/sounds/transport/train.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BiSolidTrain />,
|
||||
id: 'inside-a-train',
|
||||
label: 'Inside a Train',
|
||||
src: '/sounds/transport/inside-a-train.mp3',
|
||||
src: getAssetPath('/sounds/transport/inside-a-train.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BiSolidPlaneAlt />,
|
||||
id: 'airplane',
|
||||
label: 'Airplane',
|
||||
src: '/sounds/transport/airplane.mp3',
|
||||
src: getAssetPath('/sounds/transport/airplane.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiSubmarine />,
|
||||
id: 'submarine',
|
||||
label: 'Submarine',
|
||||
src: '/sounds/transport/submarine.mp3',
|
||||
src: getAssetPath('/sounds/transport/submarine.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <GiSailboat />,
|
||||
id: 'sailboat',
|
||||
label: 'Sailboat',
|
||||
src: '/sounds/transport/sailboat.mp3',
|
||||
src: getAssetPath('/sounds/transport/sailboat.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <TbSailboat />,
|
||||
id: 'rowing-boat',
|
||||
label: 'Rowing Boat',
|
||||
src: '/sounds/transport/rowing-boat.mp3',
|
||||
src: getAssetPath('/sounds/transport/rowing-boat.mp3'),
|
||||
},
|
||||
],
|
||||
title: 'Transport',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { RiSparkling2Fill } from 'react-icons/ri/index';
|
|||
|
||||
import type { Category } from '../types';
|
||||
|
||||
import { getAssetPath } from '@/helpers/path';
|
||||
|
||||
export const urban: Category = {
|
||||
icon: <FaCity />,
|
||||
id: 'urban',
|
||||
|
|
@ -14,43 +16,43 @@ export const urban: Category = {
|
|||
icon: <PiRoadHorizonFill />,
|
||||
id: 'highway',
|
||||
label: 'Highway',
|
||||
src: '/sounds/urban/highway.mp3',
|
||||
src: getAssetPath('/sounds/urban/highway.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <FaRoad />,
|
||||
id: 'road',
|
||||
label: 'Road',
|
||||
src: '/sounds/urban/road.mp3',
|
||||
src: getAssetPath('/sounds/urban/road.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <PiSirenBold />,
|
||||
id: 'ambulance-siren',
|
||||
label: 'Ambulance Siren',
|
||||
src: '/sounds/urban/ambulance-siren.mp3',
|
||||
src: getAssetPath('/sounds/urban/ambulance-siren.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BsSoundwave />,
|
||||
id: 'busy-street',
|
||||
label: 'Busy Street',
|
||||
src: '/sounds/urban/busy-street.mp3',
|
||||
src: getAssetPath('/sounds/urban/busy-street.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BsPeopleFill />,
|
||||
id: 'crowd',
|
||||
label: 'Crowd',
|
||||
src: '/sounds/urban/crowd.mp3',
|
||||
src: getAssetPath('/sounds/urban/crowd.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <BiSolidTraffic />,
|
||||
id: 'traffic',
|
||||
label: 'Traffic',
|
||||
src: '/sounds/urban/traffic.mp3',
|
||||
src: getAssetPath('/sounds/urban/traffic.mp3'),
|
||||
},
|
||||
{
|
||||
icon: <RiSparkling2Fill />,
|
||||
id: 'fireworks',
|
||||
label: 'Fireworks',
|
||||
src: '/sounds/urban/fireworks.mp3',
|
||||
src: getAssetPath('/sounds/urban/fireworks.mp3'),
|
||||
},
|
||||
],
|
||||
title: 'Urban',
|
||||
|
|
|
|||
7
src/helpers/path.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export function getAssetPath(relativePath: string): string {
|
||||
const baseURL = import.meta.env.BASE_URL;
|
||||
const withoutTrailingSlash = baseURL.replace(/\/+$/, '');
|
||||
const withoutLeadingSlash = relativePath.replace(/^\/+/, '');
|
||||
|
||||
return `${withoutTrailingSlash}/${withoutLeadingSlash}`;
|
||||
}
|
||||
|
|
@ -47,6 +47,10 @@ export function useSound(
|
|||
preload: options.preload ?? false,
|
||||
src: src,
|
||||
});
|
||||
|
||||
if (window.navigator.audioSession) {
|
||||
window.navigator.audioSession.type = 'playback';
|
||||
}
|
||||
}
|
||||
|
||||
return sound;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ import Source from '@/components/source.astro';
|
|||
import Footer from '@/components/footer.astro';
|
||||
|
||||
import { App } from '@/components/app';
|
||||
import CategoryIcons from '@/components/categories/category-icons/category-icons';
|
||||
---
|
||||
|
||||
<Layout title="Moodist: Ambient Sounds for Focus and Calm">
|
||||
<Donate />
|
||||
<Hero />
|
||||
<CategoryIcons client:load />
|
||||
<App client:load />
|
||||
<About />
|
||||
<Source />
|
||||
|
|
|
|||