Compare commits

...

39 commits
v2.0.1 ... main

Author SHA1 Message Date
MAZE
aa2b47ace4 chore(release): 2.4.0 2025-11-25 20:09:52 +03:30
MAZE
3a96d38a77 feat: add audio session type 2025-11-25 19:45:54 +03:30
MAZE
7e8f23f5fa chore(release): 2.3.0 2025-11-25 00:27:03 +03:30
MAZE
d0160763ee feat: turn links into buttons 2025-11-25 00:26:47 +03:30
MAZE
b921629ee3 chore: change silence 2025-11-25 00:17:52 +03:30
MAZE
ee139150f5 chore(release): 2.2.0 2025-11-25 00:10:46 +03:30
MAZE
04c52962c3 style: minor changes 2025-11-25 00:10:07 +03:30
maze
97ca030534
Merge pull request #84 from amir-rahmanii/feat/add-category-icons
feat: add category icons
2025-11-25 00:06:52 +03:30
MAZE
e160d26677 feat: replace the silence file 2025-11-24 23:56:07 +03:30
Amirreza
642a551226 feat: add category icons 2025-10-30 13:03:58 +03:30
MAZE
6ac65c1948 style: change cursor 2025-10-26 12:48:55 +03:30
MAZE
50687c97ca style: add animation on active 2025-10-26 12:43:14 +03:30
MAZE
95b641a88f feat: extract the provider for the tooltip 2025-10-25 13:11:04 +03:30
MAZE
d11a6ab062 style: increase text color 2025-08-13 12:12:27 +03:30
MAZE
a071ba04c7 style: decrease background opacity 2025-08-13 12:01:38 +03:30
MAZE
a179c09d0c style: increase line height 2025-08-13 11:59:45 +03:30
MAZE
066af9e2f3 feat: change lofi icon 2025-08-13 11:57:08 +03:30
MAZE
1e5bda707c style: change snackbar styles 2025-08-06 13:23:41 +03:30
MAZE
e2bb4dd55f style: increase border radius 2025-08-06 13:21:44 +03:30
MAZE
d9df0d4b2c feat: add shine effect 2025-08-06 13:13:14 +03:30
MAZE
3feb9c1a09 style: remove cipher animation 2025-08-06 13:08:57 +03:30
MAZE
b191e6067d feat: migrate to motion and fix some animations 2025-08-06 13:07:03 +03:30
MAZE
81d9d7ca03 feat: make sound file addresses relative 2025-07-19 22:07:06 +03:30
MAZE ✧
1e24cbc6eb
Merge pull request #69 from ncguk/patch-2
Update animals.tsx
2025-07-19 21:48:24 +03:30
MAZE ✧
78fb8cd76f
Merge pull request #68 from ncguk/patch-1
Rename horse-galopp.mp3 to horse-gallop.mp3
2025-07-19 21:47:50 +03:30
MAZE
4c8d577527 chore(release): 2.1.0 2025-07-19 21:16:54 +03:30
MAZE
fcbe50c78c feat: add lofi music play 2025-07-12 12:32:49 +03:30
MAZE
af096077ae fix: replace generator with static silent audio 2025-07-12 00:50:47 +03:30
MAZE
4996cc893c fix: fixate the binary pattern 2025-07-12 00:06:59 +03:30
ncguk
d6484103a7
Update animals.tsx
Change instances of "galopp" to "gallop"
2025-06-18 10:51:10 +01:00
ncguk
374de8b0d2
Rename horse-galopp.mp3 to horse-gallop.mp3
Fixes typo in filename.
2025-06-18 10:43:55 +01:00
MAZE ✧
b171793040
Merge pull request #63 from LBRDan/make-binaural-popup-preset-change-reactive
fix(component): update oscillators frequency on preset change
2025-04-05 15:36:23 +03:30
Daniele Lubrano
dcc91e038d fix(component): update oscillators frequency on preset change
Update oscillators frequency on preset change
2025-03-26 14:48:47 +01:00
MAZE
348fc1e8c4 chore: update the logo 2025-03-26 01:17:15 +03:30
MAZE
a0a7f94c33 chore: update banner 2025-03-25 23:10:51 +03:30
MAZE
2f994c6094 chore: update banner 2025-03-25 23:07:52 +03:30
MAZE
fb82117742 chore: add banner 2025-03-25 23:06:55 +03:30
MAZE
7951e9829a Merge branch 'develop' 2025-03-25 23:00:57 +03:30
MAZE
755c442263 chore: refine logo 2025-03-25 22:54:23 +03:30
66 changed files with 1271 additions and 340 deletions

View file

@ -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)

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

View file

@ -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
View file

@ -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",

View file

@ -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"
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

BIN
public/sounds/silence.wav Normal file

Binary file not shown.

View file

@ -0,0 +1,7 @@
---
import { generateRandomBinaryString } from '@/helpers/binary';
const binary = generateRandomBinaryString(1000);
---
<span>{binary}</span>

View file

@ -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>;
}

View file

@ -18,6 +18,10 @@
background-color: var(--color-neutral-800);
}
&:not(.disabled):active {
transform: scale(0.97);
}
&:disabled,
&.disabled {
cursor: not-allowed;

View file

@ -19,6 +19,10 @@
cursor: not-allowed;
}
&:active {
transform: scale(0.97);
}
&:hover,
&:focus-visible {
background-color: var(--color-neutral-200);

View file

@ -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>

View file

@ -1,4 +1,4 @@
import { AnimatePresence } from 'framer-motion';
import { AnimatePresence } from 'motion/react';
import { Category } from './category';
import { Donate } from './donate';

View file

@ -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);
}
}
}
}

View 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>
);
}

View file

@ -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%);

View file

@ -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;

View file

@ -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"
/>
);
}

View file

@ -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';

View file

@ -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 () => {

View file

@ -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';

View file

@ -0,0 +1 @@
export { LofiModal } from './lofi';

View 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;
}
}
}
}

View 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>
);
}

View file

@ -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>
);
}

View file

@ -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;
}
}

View file

@ -1,4 +1,4 @@
import { motion } from 'framer-motion';
import { motion } from 'motion/react';
import { mix, fade, slideY } from '@/lib/motion';

View file

@ -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';

View file

@ -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;
}
}

View file

@ -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';

View file

@ -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>

View file

@ -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';

View 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}
/>
);
}

View file

@ -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')} />
</>
);
}

View file

@ -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>
);
}

View file

@ -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>
);
}

View file

@ -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,

View file

@ -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);

View file

@ -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>

View file

@ -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;

View file

@ -5,7 +5,7 @@ import {
useRef,
useContext,
} from 'react';
import { AnimatePresence } from 'framer-motion';
import { AnimatePresence } from 'motion/react';
import { Snackbar } from '@/components/snackbar';

View file

@ -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',

View file

@ -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',

View file

@ -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',

View file

@ -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',

View file

@ -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',

View file

@ -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',

View file

@ -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',

View file

@ -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',

View file

@ -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
View 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}`;
}

View file

@ -47,6 +47,10 @@ export function useSound(
preload: options.preload ?? false,
src: src,
});
if (window.navigator.audioSession) {
window.navigator.audioSession.type = 'playback';
}
}
return sound;

View file

@ -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 />