112 Commits

Author SHA1 Message Date
MAZE
78656bb61f chore(release): 1.5.0 2024-05-19 17:25:10 +03:30
MAZE
629f0a514e chore: update README file 2024-05-18 23:31:49 +03:30
MAZE
9338b1d30a fix: remove media session 2024-05-11 16:48:44 +03:30
MAZE
34d3f07581 feat: add media session (wip) 2024-05-11 16:44:22 +03:30
MAZE
cf4870b0d6 feat: add media session (wip) 2024-05-11 16:38:26 +03:30
MAZE
9f0a28d930 feat: add media session (wip) 2024-05-11 16:35:07 +03:30
MAZE
56b0e9bf1a feat: add media session (wip) 2024-05-11 16:31:32 +03:30
MAZE
4f752bb6d0 feat: add media session (wip) 2024-05-11 16:25:14 +03:30
MAZE
1547b0a436 feat: add media session (wip) 2024-05-11 16:20:48 +03:30
MAZE
9ad16306cf chore: remove extra sound 2024-05-11 16:49:55 +04:30
MAZE
4b73e45dd4 Merge branch 'main' of https://github.com/remvze/moodist into main 2024-05-11 16:46:43 +04:30
MAZE
05b298f51e Merge branch 'main' into develop 2024-05-11 16:45:58 +04:30
MAZE
8d01d74bd3 fix: remove media session 2024-05-11 16:45:13 +04:30
MAZE
f311ec114e feat: add media session (wip) 2024-05-11 16:26:25 +04:30
MAZE
df1b05f7ce feat: add media session (wip) 2024-05-11 16:20:26 +04:30
MAZE
ea0dfff9c1 feat: add media session (wip) 2024-05-11 15:57:20 +04:30
MAZE
fc1bd07b7d feat: add media session (wip) 2024-05-11 15:53:30 +04:30
MAZE
f79e941527 feat: add media session (wip) 2024-05-11 15:30:49 +04:30
MAZE
11a4514a0f feat: add media session (wip) 2024-05-11 15:20:41 +04:30
MAZE
e41f901041 Merge branch 'main' of https://github.com/remvze/moodist 2024-05-09 20:53:01 +03:30
MAZE
de49d37f08 chore: update README file 2024-05-09 20:52:32 +03:30
MAZE
5f066a4eff feat: add countdown timer button 2024-05-09 20:51:57 +03:30
MAZE
b925a2e04f Merge branch 'develop' into main 2024-05-03 16:00:36 +04:30
MAZE
c66cddc4c9 fix: turn off spell check 2024-05-03 15:59:19 +04:30
MAZE
7cb0f1c752 chore: update README file 2024-05-03 00:02:17 +03:30
MAZE
d09e598297 chore: add emojis 2024-05-01 16:28:32 +04:30
MAZE
5899d1bbbb chore: add contributing guide 2024-05-01 16:25:22 +04:30
MAZE
81678ea384 refactor: add constants 2024-05-01 15:50:07 +04:30
MAZE
d9246b692b feat: add lock while fading 2024-04-30 18:13:00 +03:30
MAZE
c893e2a6ad refactor: reduce dependency 2024-04-30 18:00:19 +03:30
MAZE
f025213ef2 fix: close all modals 2024-04-30 17:50:53 +03:30
MAZE
6ce766af47 feat: add basic fading effect 2024-04-30 17:47:49 +03:30
MAZE
7c57fb686b refactor: rewrite timer logic 2024-04-30 16:53:49 +03:30
MAZE
dc139e41e6 chore: update README file 2024-04-30 16:36:42 +03:30
MAZE
b990778142 chore: add contribution section to README file 2024-04-30 15:58:16 +03:30
MAZE
672988c36e chore: add support section 2024-04-30 15:51:10 +03:30
MAZE
06d0dfbe7e fix: typo in README file 2024-04-30 15:48:29 +03:30
MAZE
954a1b1ce2 chore: update README file 2024-04-30 15:47:54 +03:30
MAZE
383f898125 chore: update README file 2024-04-30 15:46:53 +03:30
MAZE
8d90344b26 chore: add npm commands to README file 2024-04-29 18:10:57 +03:30
MAZE
c614e3d4f5 chore: add features to README file 2024-04-29 18:01:54 +03:30
MAZE
781adcf17e chore: add emojis 2024-04-29 17:52:29 +03:30
MAZE
3e44516509 chore: add divider 2024-04-29 17:48:48 +03:30
MAZE
aeccf2dabd chore: complete tech stack 2024-04-29 17:47:30 +03:30
MAZE
8e6e690006 chore: add tech stack to README file 2024-04-29 17:41:10 +03:30
MAZE
75e7c48b21 Merge branch 'main' into develop 2024-04-29 15:50:26 +03:30
MAZE
dcef777295 chore: add licenses to README file 2024-04-29 15:48:53 +03:30
MAZE
cc77f9e9c0 fix: make inputs full width 2024-04-29 15:57:07 +04:30
MAZE
8fe90daf1e style: change input styles 2024-04-29 15:46:06 +04:30
MAZE
34d3c72f35 fix: change default values 2024-04-29 15:34:00 +04:30
MAZE
9d458fb60e feat: add form to sleep timer 2024-04-29 15:21:50 +04:30
MAZE
e674738ce7 style: change button styles 2024-04-29 15:06:09 +04:30
MAZE
77e2ec5e79 feat: add description for sleep timer 2024-04-29 00:43:35 +03:30
MAZE
4adfb3ddc9 refactor: relocate generic components 2024-04-29 00:38:15 +03:30
MAZE
ae0cbf1aa3 refactor: reorder menu items 2024-04-29 00:35:53 +03:30
MAZE ✧
dbbd68b73d Merge pull request #32 from SuperMeepBoy/add-sleep-timer
feat: add sleep timer
2024-04-29 00:32:09 +03:30
Jef Roelandt
2e375ad40a fix: play sounds when starting timer if not already playing 2024-04-28 20:40:08 +02:00
Jef Roelandt
58bf28bb24 fix: fix button disabled and reset to 0 2024-04-28 20:40:08 +02:00
Jef Roelandt
0517c31fc1 fix: take remvze comments into account 2024-04-28 18:47:24 +02:00
Jef Roelandt
71b62ed3dd feat: add sleep timer 2024-04-28 16:11:38 +02:00
MAZE
0300df3852 chore: add accessibility addon 2024-04-27 22:49:48 +03:30
MAZE
3f3bcdda21 chore: add autodocs for button 2024-04-27 22:47:23 +03:30
MAZE
f19d151f4a chore: add story for snackbar provider 2024-04-27 22:45:32 +03:30
MAZE
43f6245227 feat: add story for snackbar 2024-04-27 22:41:59 +03:30
MAZE
9b7d3c645b feat: add story for modal 2024-04-27 22:38:45 +03:30
MAZE
f8fb1ed61e chore: add link to story 2024-04-27 22:22:16 +03:30
MAZE
6fe9ce8915 chore: add link to issue 2024-04-27 22:21:07 +03:30
MAZE
603d318e68 chore: write story for button 2024-04-27 21:03:54 +03:30
MAZE
65ca7e1c94 chore: install Storybook 2024-04-27 20:07:39 +03:30
MAZE
583578b315 feat: close notepad on escape 2024-04-27 19:53:59 +03:30
MAZE
60f167c4d7 feat: add shortcuts list 2024-04-26 15:30:27 +03:30
MAZE
99f3a41598 feat: add keyboard shortcut for unselect button 2024-04-26 15:03:02 +03:30
MAZE
d3a2a12e1f feat: add keyboard shortcut for play button 2024-04-26 14:41:57 +03:30
MAZE
ebb35deaf9 style: add hover state to button 2024-04-26 14:24:35 +03:30
MAZE
9ad49d021a fix: make share hotkey conditional 2024-04-26 14:22:39 +03:30
MAZE
8307657628 fix: replace the animation on button 2024-04-26 12:40:04 +03:30
MAZE
3b0c22968e fix: remove auto focus on load 2024-04-25 23:48:27 +03:30
MAZE
e490a1da84 refactor: remove extra types 2024-04-25 21:21:21 +03:30
MAZE
7c6f068d15 fix: remove console log 2024-04-25 20:23:39 +03:30
MAZE
a46a4cdc96 Merge branch 'develop' 2024-04-25 20:00:22 +03:30
MAZE
b955fc93f4 fix: refocus on show more button 2024-04-25 19:59:41 +03:30
MAZE
54c777276d fix: focus on the first new sound 2024-04-25 19:48:09 +03:30
MAZE
136a009379 Merge branch 'develop' 2024-04-25 15:38:41 +03:30
MAZE
601ba6def7 fix: allow empty inputs 2024-04-25 15:35:07 +03:30
MAZE
89a83089c5 fix: reset values on cancel 2024-04-25 14:39:13 +03:30
MAZE
2192335238 refactor: better name 2024-04-24 19:50:44 +03:30
MAZE
af92b1ed90 feat: add close event for modals 2024-04-24 19:13:29 +03:30
MAZE
f81ea9e7bd refactor: better shortcut handling 2024-04-24 16:59:27 +03:30
MAZE
98e5021f56 feat: add better aria labels 2024-04-24 16:04:18 +03:30
MAZE
9774532308 feat: add better aria labels 2024-04-24 15:55:42 +03:30
MAZE
837826fbc1 feat: change shortcuts to shift 2024-04-24 13:29:28 +03:30
MAZE
2f84268017 refactor: rename hook file 2024-04-23 23:22:39 +03:30
MAZE
24a53c81df feat: add autofocus for note 2024-04-23 23:20:58 +03:30
MAZE ✧
ab9d47befb Merge pull request #26 from SuperMeepBoy/improve-accessibility-2
Allow using spacebar or enter to trigger buttons
2024-04-23 23:08:53 +03:30
Jef Roelandt
60cc2e9369 feat: allow using spacebar or enter to trigger buttons
It is a good practice for accessibility.
Cf https://webaim.org/techniques/keyboard/ or
any other resource on the Internet talking about buttons accessibiltiy.
2024-04-23 21:15:32 +02:00
MAZE
42f82ab95d feat: add shortcuts to items 2024-04-23 17:51:51 +03:30
MAZE
669df1f082 feat: add keyboard shortcuts 2024-04-23 17:24:32 +03:30
MAZE
a3cfbb98db style: add outlines to toolbar buttons 2024-04-23 17:08:15 +03:30
MAZE
3c8d75b018 style: better outlines for accessibility 2024-04-23 17:06:35 +03:30
MAZE
e7d7a37a12 style: add outline for better accessibility 2024-04-23 00:02:27 +03:30
MAZE
6f9c941a87 style: change outline color 2024-04-22 23:52:18 +03:30
MAZE
8596a0014c fix: relocate focus trap 2024-04-22 23:47:57 +03:30
MAZE
908fe01c5e Merge branch 'main' into develop 2024-04-22 23:44:09 +03:30
MAZE ✧
8009e1519f Merge pull request #24 from SuperMeepBoy/add-accessibility
Improve accessibility
2024-04-22 20:51:17 +03:30
MAZE
0252fa96ab feat: make the modal more accessible 2024-04-22 18:46:51 +03:30
MAZE
48291a6457 refactor: remove hide delay for tooltips 2024-04-22 18:40:25 +03:30
MAZE
ddae0b660f refactor: add Radix 2024-04-22 18:39:30 +03:30
Jef Roelandt
8669489747 Fix keyboard focus on Sound cards 2024-04-21 16:28:42 +02:00
Jef Roelandt
4f4ffe3e3a Add visibility on buttons focus 2024-04-21 16:28:36 +02:00
Jef Roelandt
42d3bd9e8c Make Dockerfile compatible with podman 2024-04-19 20:41:29 +02:00
MAZE
4b5456a51d chore(release): 1.4.3 2024-04-11 16:19:31 +03:30
MAZE
fa9711a1e0 chore: remove arm/v7 2024-04-11 16:19:04 +03:30
83 changed files with 11190 additions and 849 deletions

View File

@@ -1,15 +1,12 @@
{
"root": true,
"env": {
"browser": true,
"amd": true,
"node": true,
"es2022": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
@@ -17,7 +14,6 @@
"jsx": true
}
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
@@ -28,9 +24,9 @@
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended",
"plugin:astro/recommended",
"prettier"
"prettier",
"plugin:storybook/recommended"
],
"plugins": [
"@typescript-eslint",
"typescript-sort-keys",
@@ -38,7 +34,6 @@
"sort-destructure-keys",
"prettier"
],
"rules": {
"@typescript-eslint/ban-ts-comment": "off",
"prettier/prettier": "error",
@@ -54,48 +49,39 @@
}
]
},
"settings": {
"react": {
"version": "detect"
},
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx", ".js", ".jsx"]
},
"import/resolver": {
"typescript": true,
"node": true,
"alias": {
"extensions": [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
"map": [["@", "./src"]]
}
}
},
"overrides": [
{
"files": ["**/*.astro"],
"parser": "astro-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser",
"extraFileExtensions": [".astro"]
},
"rules": {
"prettier/prettier": "error",
"react/no-unknown-property": "off",
"react/jsx-key": "off"
},
"globals": {
"Astro": "readonly"
}
},
{
"files": ["**/*.astro/*.js"],
"rules": {

View File

@@ -34,7 +34,7 @@ jobs:
GIT_TAG=${GIT_TAG#refs/tags/}
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
--platform linux/amd64,linux/arm64 \
-t $IMAGE_NAME:latest \
-t $IMAGE_NAME:$GIT_TAG \
--push .

2
.gitignore vendored
View File

@@ -19,3 +19,5 @@ pnpm-debug.log*
# macOS-specific files
.DS_Store
*storybook.log

46
.storybook/main.ts Normal file
View File

@@ -0,0 +1,46 @@
import path from 'node:path';
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-onboarding',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
viteFinal(config) {
return {
...config,
define: {
'process.env.NODE_DEBUG': false, // https://github.com/storybookjs/storybook/issues/18920
},
resolve: {
alias: [
{
find: '@',
replacement: path.resolve(__dirname, '../src'),
},
],
},
}
}
};
export default config;

16
.storybook/preview.ts Normal file
View File

@@ -0,0 +1,16 @@
import '../src/styles/global.css';
import type { Preview } from '@storybook/react';
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview;

View File

@@ -2,432 +2,524 @@
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.
### [1.4.2](https://github.com/remvze/moodist/compare/v1.4.1...v1.4.2) (2024-04-11)
## [1.5.0](https://github.com/remvze/moodist/compare/v1.4.3...v1.5.0) (2024-05-19)
### 💄 Styling
* change font path ([43ba975](https://github.com/remvze/moodist/commit/43ba9754085d7a710d3d629e70f873b16f267507))
* add hover state to button ([ebb35de](https://github.com/remvze/moodist/commit/ebb35deaf982348ccea49e3830af77521fbed207))
* add outline for better accessibility ([e7d7a37](https://github.com/remvze/moodist/commit/e7d7a37a12dd79f12933b3ffa91fe6e0557c4f9e))
* add outlines to toolbar buttons ([a3cfbb9](https://github.com/remvze/moodist/commit/a3cfbb98db8a70d8055e86071a4dab4d2b7ab952))
* better outlines for accessibility ([3c8d75b](https://github.com/remvze/moodist/commit/3c8d75b018e657b2c2e13d967b90b635360225fe))
* change button styles ([e674738](https://github.com/remvze/moodist/commit/e674738ce70d1c240c57433824a0b509f24deb88))
* change input styles ([8fe90da](https://github.com/remvze/moodist/commit/8fe90daf1e96def534c62f3241438cf62ea00b18))
* change outline color ([6f9c941](https://github.com/remvze/moodist/commit/6f9c941a8749f2b006c3f352e0a047c5dc1d3d21))
### ♻️ Code Refactoring
* add constants ([81678ea](https://github.com/remvze/moodist/commit/81678ea384bfdc00925e674c988fad85710d705a))
* add Radix ([ddae0b6](https://github.com/remvze/moodist/commit/ddae0b660ff2bb0bc33400ad59159f4525d80429))
* better name ([2192335](https://github.com/remvze/moodist/commit/219233523827ed47a8ebea88a4ce73bb3c027e0c))
* better shortcut handling ([f81ea9e](https://github.com/remvze/moodist/commit/f81ea9e7bdf7c7253587da9312e6fb6caaf14590))
* reduce dependency ([c893e2a](https://github.com/remvze/moodist/commit/c893e2a6adc68bdd40f8e5dd1e2b3ab6642a0145))
* relocate generic components ([4adfb3d](https://github.com/remvze/moodist/commit/4adfb3ddc938a2720c26b9107c8cccdf66c0b913))
* remove extra types ([e490a1d](https://github.com/remvze/moodist/commit/e490a1da84d948c9db2e689414f432aaf53bc0b2))
* remove hide delay for tooltips ([48291a6](https://github.com/remvze/moodist/commit/48291a645776b235918485b737b9272113f838a0))
* rename hook file ([2f84268](https://github.com/remvze/moodist/commit/2f84268017aa4592684c8e3ac47399d0f100669d))
* reorder menu items ([ae0cbf1](https://github.com/remvze/moodist/commit/ae0cbf1aa3392ae775bfee9404c21ed7c145166e))
* rewrite timer logic ([7c57fb6](https://github.com/remvze/moodist/commit/7c57fb686b50fa106ad0663a44f4831295d235c3))
### ✨ Features
* add autofocus for note ([24a53c8](https://github.com/remvze/moodist/commit/24a53c81dffc1a4ba0b46244a87fb49bf562e755))
* add basic fading effect ([6ce766a](https://github.com/remvze/moodist/commit/6ce766af47389e9e3e57226b956b8593a4af06d4))
* add better aria labels ([98e5021](https://github.com/remvze/moodist/commit/98e5021f561458465a544e2b86194e7f52a62169))
* add better aria labels ([9774532](https://github.com/remvze/moodist/commit/977453230847790de86aa7721c059d4fe3ec7eeb))
* add close event for modals ([af92b1e](https://github.com/remvze/moodist/commit/af92b1ed902b4bf221e53315ba431f834915d7c2))
* add countdown timer button ([5f066a4](https://github.com/remvze/moodist/commit/5f066a4eff91996b165de3b86549fffe93800d38))
* add description for sleep timer ([77e2ec5](https://github.com/remvze/moodist/commit/77e2ec5e798771b7719b36882bc68c10265c06f6))
* add form to sleep timer ([9d458fb](https://github.com/remvze/moodist/commit/9d458fb60e8b84210f492541bab2c5dc94adcc8b))
* add keyboard shortcut for play button ([d3a2a12](https://github.com/remvze/moodist/commit/d3a2a12e1fdcca502c0d3d6dc60d3e4c577165f2))
* add keyboard shortcut for unselect button ([99f3a41](https://github.com/remvze/moodist/commit/99f3a41598ea237d2f509825d0b3c0ee27e789d7))
* add keyboard shortcuts ([669df1f](https://github.com/remvze/moodist/commit/669df1f08264e63c0892e7d4fdd2ee7dbcb96b2e))
* add lock while fading ([d9246b6](https://github.com/remvze/moodist/commit/d9246b692bcb75018653cb6f437b1f46af1f925d))
* add media session (wip) ([34d3f07](https://github.com/remvze/moodist/commit/34d3f075816eb821979f1d51a1177ecfa03920f3))
* add media session (wip) ([cf4870b](https://github.com/remvze/moodist/commit/cf4870b0d6b172bd4e6b79ff517af06b2aeac7a5))
* add media session (wip) ([9f0a28d](https://github.com/remvze/moodist/commit/9f0a28d9305954486d4f609f85811982df9710f3))
* add media session (wip) ([56b0e9b](https://github.com/remvze/moodist/commit/56b0e9bf1a16d4e7e2c8d7a552b652f8d30dd800))
* add media session (wip) ([4f752bb](https://github.com/remvze/moodist/commit/4f752bb6d048c0260ff6b2aada59c227624b2d17))
* add media session (wip) ([1547b0a](https://github.com/remvze/moodist/commit/1547b0a436bd9a77c19fc5d37be3cb3e123e6117))
* add media session (wip) ([f311ec1](https://github.com/remvze/moodist/commit/f311ec114e3a8ca61954819334e43195d0980219))
* add media session (wip) ([df1b05f](https://github.com/remvze/moodist/commit/df1b05f7ce3e26128d0bc4a9a022b5300ea88f85))
* add media session (wip) ([ea0dfff](https://github.com/remvze/moodist/commit/ea0dfff9c1e7d8e6e03bccdc0ab15d098b31a10d))
* add media session (wip) ([fc1bd07](https://github.com/remvze/moodist/commit/fc1bd07b7de9532383c66d7e59cc13bbe41f415a))
* add media session (wip) ([f79e941](https://github.com/remvze/moodist/commit/f79e941527e09e96b5eba6ca8c4e2e3df583c071))
* add media session (wip) ([11a4514](https://github.com/remvze/moodist/commit/11a4514a0f63f09954361fdef8145869d369fd29))
* add shortcuts list ([60f167c](https://github.com/remvze/moodist/commit/60f167c4d734bc6238f7c2bb7b39c89ed45ed9eb))
* add shortcuts to items ([42f82ab](https://github.com/remvze/moodist/commit/42f82ab95d684163826e76231fb1dd554f773d68))
* add sleep timer ([71b62ed](https://github.com/remvze/moodist/commit/71b62ed3dd365744435dc4499b9c53684f72849c))
* add story for modal ([9b7d3c6](https://github.com/remvze/moodist/commit/9b7d3c645b8c3469231641e6ec8bbdef88732bbc))
* add story for snackbar ([43f6245](https://github.com/remvze/moodist/commit/43f62452275573f948449190dcfcef89faa4ec51))
* allow using spacebar or enter to trigger buttons ([60cc2e9](https://github.com/remvze/moodist/commit/60cc2e9369aff3a374458cf1c3234eec8cd0530e))
* change shortcuts to shift ([837826f](https://github.com/remvze/moodist/commit/837826fbc13599e51bb7b65cf8b7bdcb1f1fc503))
* close notepad on escape ([583578b](https://github.com/remvze/moodist/commit/583578b31592b3c0e7f5ae6ad3f83e99e64fb6ff))
* make the modal more accessible ([0252fa9](https://github.com/remvze/moodist/commit/0252fa96abed18de71472ffc671b13c263754ed9))
### 🐛 Bug Fixes
* allow empty inputs ([601ba6d](https://github.com/remvze/moodist/commit/601ba6def7954ca8f961c461abacfb076863ae18))
* change default values ([34d3c72](https://github.com/remvze/moodist/commit/34d3c72f3512664ac8f26a637b0d0be86b5499df))
* close all modals ([f025213](https://github.com/remvze/moodist/commit/f025213ef2e8ddbc5e6603d045c8bd4d08ad8b7b))
* fix button disabled and reset to 0 ([58bf28b](https://github.com/remvze/moodist/commit/58bf28bb24fd12bc28f4f5e3e79058df60095fd4))
* focus on the first new sound ([54c7772](https://github.com/remvze/moodist/commit/54c777276deccfda20bb7f027cef40d141a445b1))
* make inputs full width ([cc77f9e](https://github.com/remvze/moodist/commit/cc77f9e9c0b0a0d7734353486c93b4ca1509bf36))
* make share hotkey conditional ([9ad49d0](https://github.com/remvze/moodist/commit/9ad49d021a34d47160575ae1349f866ecb26c077))
* play sounds when starting timer if not already playing ([2e375ad](https://github.com/remvze/moodist/commit/2e375ad40a8001ee00c9553ba46d70f3bbe6636c))
* refocus on show more button ([b955fc9](https://github.com/remvze/moodist/commit/b955fc93f42c1bd71d5fb5ff46f9e3a039c7fe83))
* relocate focus trap ([8596a00](https://github.com/remvze/moodist/commit/8596a0014cbbac25ec93b1bb9136219a096cb21f))
* remove auto focus on load ([3b0c229](https://github.com/remvze/moodist/commit/3b0c22968e4209fa5a37a88b69f55492615ec389))
* remove console log ([7c6f068](https://github.com/remvze/moodist/commit/7c6f068d158cda0f8b0fe6bd6352a65002db0e25))
* remove media session ([9338b1d](https://github.com/remvze/moodist/commit/9338b1d30a4ae4602b339bc5c5a391a462a03de2))
* remove media session ([8d01d74](https://github.com/remvze/moodist/commit/8d01d74bd356adce782b95065fadad332ed99e48))
* replace the animation on button ([8307657](https://github.com/remvze/moodist/commit/8307657628c0afc7ef11c3a829344a64777dc1d3))
* reset values on cancel ([89a8308](https://github.com/remvze/moodist/commit/89a83089c568c619fd76a28c268ad9af9913babc))
* take remvze comments into account ([0517c31](https://github.com/remvze/moodist/commit/0517c31fc13e0b82391e18a7d16341421488f1c2))
* turn off spell check ([c66cddc](https://github.com/remvze/moodist/commit/c66cddc4c98c19a8c0ef46ed0ee7555a30fd5059))
* typo in README file ([06d0dfb](https://github.com/remvze/moodist/commit/06d0dfbe7eb0660a97c84627b1751b9a43d2e033))
### 🚚 Chores
* remove arm/v6 ([017c27f](https://github.com/remvze/moodist/commit/017c27fb2b20402553011db8f417717dcca6d447))
* add accessibility addon ([0300df3](https://github.com/remvze/moodist/commit/0300df3852838135245882a8aa1c59dd1a3f8af7))
* add autodocs for button ([3f3bcdd](https://github.com/remvze/moodist/commit/3f3bcdda21b631683028ea1c65e674973c78291d))
* add contributing guide ([5899d1b](https://github.com/remvze/moodist/commit/5899d1bbbb8eb621882e2cbacc1bc1dc9ae2ee06))
* add contribution section to README file ([b990778](https://github.com/remvze/moodist/commit/b9907781424ccd43babd31dd1d939d2e78ba4a11))
* add divider ([3e44516](https://github.com/remvze/moodist/commit/3e445165090472859573e69fad0fdeec87ca858f))
* add emojis ([d09e598](https://github.com/remvze/moodist/commit/d09e598297fb29f005873eb5e1cfad62774fc7f0))
* add emojis ([781adcf](https://github.com/remvze/moodist/commit/781adcf17eecea61bc03b832d8c81f3aac304848))
* add features to README file ([c614e3d](https://github.com/remvze/moodist/commit/c614e3d4f54f814fe3813bc8788a23ecba5e38c8))
* add licenses to README file ([dcef777](https://github.com/remvze/moodist/commit/dcef77729579391706047ad68afd73a07acf5122))
* add link to issue ([6fe9ce8](https://github.com/remvze/moodist/commit/6fe9ce8915600e5ec0140b5bb635ac1a2b092339))
* add link to story ([f8fb1ed](https://github.com/remvze/moodist/commit/f8fb1ed61e071baeba7981773e4dbd1e345c29b1))
* add npm commands to README file ([8d90344](https://github.com/remvze/moodist/commit/8d90344b26d3d52d1649074486d10c7b0bc68b66))
* add story for snackbar provider ([f19d151](https://github.com/remvze/moodist/commit/f19d151f4a5292668e87abb04111e142482baf1e))
* add support section ([672988c](https://github.com/remvze/moodist/commit/672988c36e8630fe775fdf0707bfa3e1a8956231))
* add tech stack to README file ([8e6e690](https://github.com/remvze/moodist/commit/8e6e6900069775df5c29c53b2d2b9a00457ad8f8))
* complete tech stack ([aeccf2d](https://github.com/remvze/moodist/commit/aeccf2dabd7528ff7984b50b7e7c7b8f46d4cef7))
* install Storybook ([65ca7e1](https://github.com/remvze/moodist/commit/65ca7e1c942455a41f8af794861a1875bd6190be))
* remove extra sound ([9ad1630](https://github.com/remvze/moodist/commit/9ad16306cf534ff27e99a537589c0d3c2c483d81))
* update README file ([629f0a5](https://github.com/remvze/moodist/commit/629f0a514ec1ac96f1874b8d6a466bf05577cd4d))
* update README file ([de49d37](https://github.com/remvze/moodist/commit/de49d37f08a90523e9b9b298189b10103e833e15))
* update README file ([7cb0f1c](https://github.com/remvze/moodist/commit/7cb0f1c7521775578bb6d794f43d04aa0da2fcba))
* update README file ([dc139e4](https://github.com/remvze/moodist/commit/dc139e41e628a75756cea99bdca0252267541014))
* update README file ([954a1b1](https://github.com/remvze/moodist/commit/954a1b1ce2c9f334d349fcd140ec18a5c78b7dd7))
* update README file ([383f898](https://github.com/remvze/moodist/commit/383f8981250d2fe646b4f642b36b28b3dbdd178f))
* write story for button ([603d318](https://github.com/remvze/moodist/commit/603d318e68ec786cfbeaad57835a812ca8918fb9))
### [1.4.3](https://github.com/remvze/moodist/compare/v1.4.2...v1.4.3) (2024-04-11)
### 🚚 Chores
- remove arm/v7 ([fa9711a](https://github.com/remvze/moodist/commit/fa9711a1e09e6e979b420556160c3cd69a8c3775))
### [1.4.2](https://github.com/remvze/moodist/compare/v1.4.1...v1.4.2) (2024-04-11)
### 💄 Styling
- change font path ([43ba975](https://github.com/remvze/moodist/commit/43ba9754085d7a710d3d629e70f873b16f267507))
### 🚚 Chores
- remove arm/v6 ([017c27f](https://github.com/remvze/moodist/commit/017c27fb2b20402553011db8f417717dcca6d447))
### [1.4.1](https://github.com/remvze/moodist/compare/v1.4.0...v1.4.1) (2024-04-11)
### ✨ Features
* add toolbar and portal ([ede4801](https://github.com/remvze/moodist/commit/ede480186c4b3f187c82e1d64e4d521ee59da31a))
- add toolbar and portal ([ede4801](https://github.com/remvze/moodist/commit/ede480186c4b3f187c82e1d64e4d521ee59da31a))
### 💄 Styling
* widen the container ([7ec7ea7](https://github.com/remvze/moodist/commit/7ec7ea74d53db85cffa3af646c03270793453009))
- widen the container ([7ec7ea7](https://github.com/remvze/moodist/commit/7ec7ea74d53db85cffa3af646c03270793453009))
### 🚚 Chores
* change GitHub workflow ([faf7f78](https://github.com/remvze/moodist/commit/faf7f78b8c10cd7b3688ed5bba3d0c077c020ad2))
- change GitHub workflow ([faf7f78](https://github.com/remvze/moodist/commit/faf7f78b8c10cd7b3688ed5bba3d0c077c020ad2))
## [1.4.0](https://github.com/remvze/moodist/compare/v1.3.1...v1.4.0) (2024-02-29)
### ♻️ Code Refactoring
* add variant to container ([831a9c8](https://github.com/remvze/moodist/commit/831a9c8ea019a3d86e994ff0e060dd4337a84d1f))
* move donation to React ([c505c57](https://github.com/remvze/moodist/commit/c505c574a885004e071da63d8255062befc29921))
* move footer to React ([52176bc](https://github.com/remvze/moodist/commit/52176bc3f9eac43d701de0e7f0ca103eeca46858))
* remove sections ([3f45be3](https://github.com/remvze/moodist/commit/3f45be3942bfeff74f3f0126de5e61037a749e61))
- add variant to container ([831a9c8](https://github.com/remvze/moodist/commit/831a9c8ea019a3d86e994ff0e060dd4337a84d1f))
- move donation to React ([c505c57](https://github.com/remvze/moodist/commit/c505c574a885004e071da63d8255062befc29921))
- move footer to React ([52176bc](https://github.com/remvze/moodist/commit/52176bc3f9eac43d701de0e7f0ca103eeca46858))
- remove sections ([3f45be3](https://github.com/remvze/moodist/commit/3f45be3942bfeff74f3f0126de5e61037a749e61))
### 💄 Styling
* add effect to about ([1a499be](https://github.com/remvze/moodist/commit/1a499be2446730d5333dd0d0d6a06bbd47564979))
* add margin to donate section ([6d30a01](https://github.com/remvze/moodist/commit/6d30a0123e0feb509b6c560f405b98d20a89467a))
* add polka dot pattern ([dc22b51](https://github.com/remvze/moodist/commit/dc22b51548f0d6830fcee79eebd75650f3f19dc1))
* add scroll lock in modals ([def69de](https://github.com/remvze/moodist/commit/def69de6e4e11e373280c90f93af0b0369b85ac8))
* add shine to donation button ([ac24da2](https://github.com/remvze/moodist/commit/ac24da294008a34c49dc3502374f1fcf55db5be8))
* change description ([8930e7b](https://github.com/remvze/moodist/commit/8930e7b76abffafd0ace5926de6c1d3f7629febd))
* change dividers ([8471a3c](https://github.com/remvze/moodist/commit/8471a3ca493b0c738ed7de900e82403f0b1ce2b7))
* change pattern ([f3e7224](https://github.com/remvze/moodist/commit/f3e72242670317d938cc8d9619729be95df0f4f0))
* change position for toolbar ([e7fd84b](https://github.com/remvze/moodist/commit/e7fd84bd4e8637e34eb0a59e97fd9c49875f8776))
* change sound counter ([e1b9a17](https://github.com/remvze/moodist/commit/e1b9a1736c1d11827faf900838769194364afbd3))
* change the about style ([4515aa8](https://github.com/remvze/moodist/commit/4515aa8e7a7f6d0fbc839625f74f0583e1a20d18))
* change the pattern slightly ([5fc3e7e](https://github.com/remvze/moodist/commit/5fc3e7e5d048cb4aa189683d147b181fdf2a94b6))
* change unselected style ([586e502](https://github.com/remvze/moodist/commit/586e502c3cc81314bc1e83f4e088a0d9289390fc))
* decorate paragraphs ([1a6ecd8](https://github.com/remvze/moodist/commit/1a6ecd82abe89e1686538c42b31826ccc8a43b2d))
* decrease dots ([182a8c7](https://github.com/remvze/moodist/commit/182a8c7aadc9a253261c56ae7faf8ac5c3c82707))
* decrease dots ([0ad4bb7](https://github.com/remvze/moodist/commit/0ad4bb72e15e8f7d52e7d4b036b71fdb837e3554))
* decrease dots ([2b84374](https://github.com/remvze/moodist/commit/2b843747b41111908bbe5fb8f5abc407114e4f15))
* decrease font size ([69cb45b](https://github.com/remvze/moodist/commit/69cb45bff74d36f654d521e9e7f6b2149b01d630))
* decrease opacity ([56802b6](https://github.com/remvze/moodist/commit/56802b67f2db751dbede9aa58b2158dd250a1420))
* decrease opacity ([2078648](https://github.com/remvze/moodist/commit/2078648c6687aab79a725490335b8ae751f3d4ee))
* decrease opacity ([82e4ea7](https://github.com/remvze/moodist/commit/82e4ea72f4ddb8658824813a64e14970400b1820))
* decrease padding ([98d2f76](https://github.com/remvze/moodist/commit/98d2f764383eaba0dd6163b93826459b614b67d2))
* decrease shine ([0f32de3](https://github.com/remvze/moodist/commit/0f32de3c0ca9f553c8917b786ddcdfb6feccf0c8))
* hide about and features ([400ea0a](https://github.com/remvze/moodist/commit/400ea0aeafe48587fe8596d1b5fe90755995d1c3))
* hide features ([9028675](https://github.com/remvze/moodist/commit/902867505743dd1dcd3f1e2afef010a186586615))
* increase dots ([405fccc](https://github.com/remvze/moodist/commit/405fcccd95d9ce720f0731e8040006bd1d9b8bd2))
* increase opacity ([882d440](https://github.com/remvze/moodist/commit/882d44079cfba8c7536c3713f0abeaa075ecb069))
* increase padding ([8e50013](https://github.com/remvze/moodist/commit/8e500136cec6ba5580146306f25a5956aa3a2a4b))
* increase pattern opacity ([5b83710](https://github.com/remvze/moodist/commit/5b83710c75515352b88c7bd361694d3067cb08fb))
* lower opacity ([d4cc24e](https://github.com/remvze/moodist/commit/d4cc24e468230df51e5676abbd828b2f2edd97f3))
* remove hero pattern ([8f36c86](https://github.com/remvze/moodist/commit/8f36c863d7f7489979691475947dbc8f29f26b39))
* revert changes ([341a896](https://github.com/remvze/moodist/commit/341a896924a6ace70114ad2ae3349f8934a329ba))
* revert pattern ([5916e86](https://github.com/remvze/moodist/commit/5916e86d3c6de9912b2c9bd490fa04cd9a0958dd))
* show about and features ([37505a6](https://github.com/remvze/moodist/commit/37505a6b3f86919ac04b69519e56ddbaf5234843))
- add effect to about ([1a499be](https://github.com/remvze/moodist/commit/1a499be2446730d5333dd0d0d6a06bbd47564979))
- add margin to donate section ([6d30a01](https://github.com/remvze/moodist/commit/6d30a0123e0feb509b6c560f405b98d20a89467a))
- add polka dot pattern ([dc22b51](https://github.com/remvze/moodist/commit/dc22b51548f0d6830fcee79eebd75650f3f19dc1))
- add scroll lock in modals ([def69de](https://github.com/remvze/moodist/commit/def69de6e4e11e373280c90f93af0b0369b85ac8))
- add shine to donation button ([ac24da2](https://github.com/remvze/moodist/commit/ac24da294008a34c49dc3502374f1fcf55db5be8))
- change description ([8930e7b](https://github.com/remvze/moodist/commit/8930e7b76abffafd0ace5926de6c1d3f7629febd))
- change dividers ([8471a3c](https://github.com/remvze/moodist/commit/8471a3ca493b0c738ed7de900e82403f0b1ce2b7))
- change pattern ([f3e7224](https://github.com/remvze/moodist/commit/f3e72242670317d938cc8d9619729be95df0f4f0))
- change position for toolbar ([e7fd84b](https://github.com/remvze/moodist/commit/e7fd84bd4e8637e34eb0a59e97fd9c49875f8776))
- change sound counter ([e1b9a17](https://github.com/remvze/moodist/commit/e1b9a1736c1d11827faf900838769194364afbd3))
- change the about style ([4515aa8](https://github.com/remvze/moodist/commit/4515aa8e7a7f6d0fbc839625f74f0583e1a20d18))
- change the pattern slightly ([5fc3e7e](https://github.com/remvze/moodist/commit/5fc3e7e5d048cb4aa189683d147b181fdf2a94b6))
- change unselected style ([586e502](https://github.com/remvze/moodist/commit/586e502c3cc81314bc1e83f4e088a0d9289390fc))
- decorate paragraphs ([1a6ecd8](https://github.com/remvze/moodist/commit/1a6ecd82abe89e1686538c42b31826ccc8a43b2d))
- decrease dots ([182a8c7](https://github.com/remvze/moodist/commit/182a8c7aadc9a253261c56ae7faf8ac5c3c82707))
- decrease dots ([0ad4bb7](https://github.com/remvze/moodist/commit/0ad4bb72e15e8f7d52e7d4b036b71fdb837e3554))
- decrease dots ([2b84374](https://github.com/remvze/moodist/commit/2b843747b41111908bbe5fb8f5abc407114e4f15))
- decrease font size ([69cb45b](https://github.com/remvze/moodist/commit/69cb45bff74d36f654d521e9e7f6b2149b01d630))
- decrease opacity ([56802b6](https://github.com/remvze/moodist/commit/56802b67f2db751dbede9aa58b2158dd250a1420))
- decrease opacity ([2078648](https://github.com/remvze/moodist/commit/2078648c6687aab79a725490335b8ae751f3d4ee))
- decrease opacity ([82e4ea7](https://github.com/remvze/moodist/commit/82e4ea72f4ddb8658824813a64e14970400b1820))
- decrease padding ([98d2f76](https://github.com/remvze/moodist/commit/98d2f764383eaba0dd6163b93826459b614b67d2))
- decrease shine ([0f32de3](https://github.com/remvze/moodist/commit/0f32de3c0ca9f553c8917b786ddcdfb6feccf0c8))
- hide about and features ([400ea0a](https://github.com/remvze/moodist/commit/400ea0aeafe48587fe8596d1b5fe90755995d1c3))
- hide features ([9028675](https://github.com/remvze/moodist/commit/902867505743dd1dcd3f1e2afef010a186586615))
- increase dots ([405fccc](https://github.com/remvze/moodist/commit/405fcccd95d9ce720f0731e8040006bd1d9b8bd2))
- increase opacity ([882d440](https://github.com/remvze/moodist/commit/882d44079cfba8c7536c3713f0abeaa075ecb069))
- increase padding ([8e50013](https://github.com/remvze/moodist/commit/8e500136cec6ba5580146306f25a5956aa3a2a4b))
- increase pattern opacity ([5b83710](https://github.com/remvze/moodist/commit/5b83710c75515352b88c7bd361694d3067cb08fb))
- lower opacity ([d4cc24e](https://github.com/remvze/moodist/commit/d4cc24e468230df51e5676abbd828b2f2edd97f3))
- remove hero pattern ([8f36c86](https://github.com/remvze/moodist/commit/8f36c863d7f7489979691475947dbc8f29f26b39))
- revert changes ([341a896](https://github.com/remvze/moodist/commit/341a896924a6ace70114ad2ae3349f8934a329ba))
- revert pattern ([5916e86](https://github.com/remvze/moodist/commit/5916e86d3c6de9912b2c9bd490fa04cd9a0958dd))
- show about and features ([37505a6](https://github.com/remvze/moodist/commit/37505a6b3f86919ac04b69519e56ddbaf5234843))
### ✨ Features
* add about section ([d725d59](https://github.com/remvze/moodist/commit/d725d597034ead0bb63c5f0667b64ce459477662))
* add active indicators ([240fd9c](https://github.com/remvze/moodist/commit/240fd9c6e05c7385c0de92b8b57776988b902fae))
* add alarm for pomodoro timer ([0eb47ba](https://github.com/remvze/moodist/commit/0eb47ba2e1accaee7dd7d6114ca9a69cbc0656c4))
* add basic pomodoro structure ([9f7de33](https://github.com/remvze/moodist/commit/9f7de336e5add254b40c5694fc4c619ee00602ba))
* add controls to pomodoro ([7ed016d](https://github.com/remvze/moodist/commit/7ed016d8558a73d8d2bf05823cf80633882c1d69))
* add copy for productivity toolbox ([3205145](https://github.com/remvze/moodist/commit/3205145d5425c7a7a8660b46aa9de0b273a04ff0))
* add counter to notepad ([2424523](https://github.com/remvze/moodist/commit/24245235b14f9d59f86d2e988657a45a8a6d1eb7))
* add CTA button ([0e12a52](https://github.com/remvze/moodist/commit/0e12a5203ef836bd262b3d4cc02aaeb9048f461e))
* add custom presets ([2484e01](https://github.com/remvze/moodist/commit/2484e01273cf5e7ef5b44395cab26095891118fd))
* add dividers to menu items ([408734d](https://github.com/remvze/moodist/commit/408734d49fd89fbd47d29527c03927e49c834f30))
* add fade in/out ([663cb92](https://github.com/remvze/moodist/commit/663cb921350c083f1991665d147a3820bcdd9321))
* add features section ([e4e332a](https://github.com/remvze/moodist/commit/e4e332ad75aad1a58fd97acb71660b8dec9dfa09))
* add open-source section ([f7302de](https://github.com/remvze/moodist/commit/f7302dec5b7e182ad465bc30b63457a6e629a5b3))
* add scroll for lower heights ([758f2f4](https://github.com/remvze/moodist/commit/758f2f48dc6a4e520b7a1e937f96eed28c8e8c20))
* add simple notepad ([e923559](https://github.com/remvze/moodist/commit/e923559709796698257772cced4e20de584c6c80))
* add source code item ([d055e66](https://github.com/remvze/moodist/commit/d055e66dd9dd5789c88d1a002686457ea89db073))
* add special button ([a514a36](https://github.com/remvze/moodist/commit/a514a364ec5b6e2e34e7901ad51219d7be2aee86))
* add titles ([5f40435](https://github.com/remvze/moodist/commit/5f40435c0ccfec0cb87d9ac0c14723fb8265fa8d))
* add toolbar to notepad ([7463334](https://github.com/remvze/moodist/commit/7463334053ecd35a53cae535674169f5b50c81c2))
* change alignments ([1a01a00](https://github.com/remvze/moodist/commit/1a01a0086648c7564ecab30b79df0d67e93eb392))
* change the copy for features ([38da02a](https://github.com/remvze/moodist/commit/38da02a0d3b08e8f8802d6cf76a04ae656e10b76))
* change tooltip content ([941e1f0](https://github.com/remvze/moodist/commit/941e1f024189143340d663a0c117c08a0b315599))
* implement time setting ([f3cb2a1](https://github.com/remvze/moodist/commit/f3cb2a1b63e40f4f742ee2591b9353aa373f9783))
* persist pomodoro setting ([665e217](https://github.com/remvze/moodist/commit/665e2173f4083128687a6302a6f2fd82674f07c1))
* persist presets ([38a9a23](https://github.com/remvze/moodist/commit/38a9a23790248d5af522fc0d3cf6e99970e59637))
- add about section ([d725d59](https://github.com/remvze/moodist/commit/d725d597034ead0bb63c5f0667b64ce459477662))
- add active indicators ([240fd9c](https://github.com/remvze/moodist/commit/240fd9c6e05c7385c0de92b8b57776988b902fae))
- add alarm for pomodoro timer ([0eb47ba](https://github.com/remvze/moodist/commit/0eb47ba2e1accaee7dd7d6114ca9a69cbc0656c4))
- add basic pomodoro structure ([9f7de33](https://github.com/remvze/moodist/commit/9f7de336e5add254b40c5694fc4c619ee00602ba))
- add controls to pomodoro ([7ed016d](https://github.com/remvze/moodist/commit/7ed016d8558a73d8d2bf05823cf80633882c1d69))
- add copy for productivity toolbox ([3205145](https://github.com/remvze/moodist/commit/3205145d5425c7a7a8660b46aa9de0b273a04ff0))
- add counter to notepad ([2424523](https://github.com/remvze/moodist/commit/24245235b14f9d59f86d2e988657a45a8a6d1eb7))
- add CTA button ([0e12a52](https://github.com/remvze/moodist/commit/0e12a5203ef836bd262b3d4cc02aaeb9048f461e))
- add custom presets ([2484e01](https://github.com/remvze/moodist/commit/2484e01273cf5e7ef5b44395cab26095891118fd))
- add dividers to menu items ([408734d](https://github.com/remvze/moodist/commit/408734d49fd89fbd47d29527c03927e49c834f30))
- add fade in/out ([663cb92](https://github.com/remvze/moodist/commit/663cb921350c083f1991665d147a3820bcdd9321))
- add features section ([e4e332a](https://github.com/remvze/moodist/commit/e4e332ad75aad1a58fd97acb71660b8dec9dfa09))
- add open-source section ([f7302de](https://github.com/remvze/moodist/commit/f7302dec5b7e182ad465bc30b63457a6e629a5b3))
- add scroll for lower heights ([758f2f4](https://github.com/remvze/moodist/commit/758f2f48dc6a4e520b7a1e937f96eed28c8e8c20))
- add simple notepad ([e923559](https://github.com/remvze/moodist/commit/e923559709796698257772cced4e20de584c6c80))
- add source code item ([d055e66](https://github.com/remvze/moodist/commit/d055e66dd9dd5789c88d1a002686457ea89db073))
- add special button ([a514a36](https://github.com/remvze/moodist/commit/a514a364ec5b6e2e34e7901ad51219d7be2aee86))
- add titles ([5f40435](https://github.com/remvze/moodist/commit/5f40435c0ccfec0cb87d9ac0c14723fb8265fa8d))
- add toolbar to notepad ([7463334](https://github.com/remvze/moodist/commit/7463334053ecd35a53cae535674169f5b50c81c2))
- change alignments ([1a01a00](https://github.com/remvze/moodist/commit/1a01a0086648c7564ecab30b79df0d67e93eb392))
- change the copy for features ([38da02a](https://github.com/remvze/moodist/commit/38da02a0d3b08e8f8802d6cf76a04ae656e10b76))
- change tooltip content ([941e1f0](https://github.com/remvze/moodist/commit/941e1f024189143340d663a0c117c08a0b315599))
- implement time setting ([f3cb2a1](https://github.com/remvze/moodist/commit/f3cb2a1b63e40f4f742ee2591b9353aa373f9783))
- persist pomodoro setting ([665e217](https://github.com/remvze/moodist/commit/665e2173f4083128687a6302a6f2fd82674f07c1))
- persist presets ([38a9a23](https://github.com/remvze/moodist/commit/38a9a23790248d5af522fc0d3cf6e99970e59637))
### 🐛 Bug Fixes
* add correct count to description ([81e6666](https://github.com/remvze/moodist/commit/81e66667765879da624544c5d915c1562f2ab34c))
* add key to categories ([38c11f1](https://github.com/remvze/moodist/commit/38c11f124e2235bc32de1e469b00ccaa22467a7e))
* add min-width to inputs ([dfd6c1f](https://github.com/remvze/moodist/commit/dfd6c1fc4a41845e686fc6ee96f71b696213fe69))
* change completion condition ([1ac5286](https://github.com/remvze/moodist/commit/1ac52861d1de651f8245d1e343307c6cf7a13dde))
* change default times ([158cffc](https://github.com/remvze/moodist/commit/158cffca8c4b138f33e2df03e046706d2b122478))
* change initial value ([a7e5368](https://github.com/remvze/moodist/commit/a7e53685918187c47d4fc2935418786b772c189e))
* change z-index values ([79afb8d](https://github.com/remvze/moodist/commit/79afb8d92f9cb8e551bf101267018af1ab58815d))
* comment out toolbox section ([a8a8c36](https://github.com/remvze/moodist/commit/a8a8c3643478d3da531e1da6c3640eb327acad3b))
* make sound count dynamic ([f66a6ff](https://github.com/remvze/moodist/commit/f66a6ffde770992353a5b21fe65c20fe50ab4328))
* remove extra headings ([7390a9b](https://github.com/remvze/moodist/commit/7390a9b3de0c52163d63b42ad48a882087886b65))
* remove fading ([653d309](https://github.com/remvze/moodist/commit/653d309e64b770c2b270d2435bcd02345b686fec))
* remove time from tabs array ([110356b](https://github.com/remvze/moodist/commit/110356b2da82e0f1e971ee9dc486664027d886ff))
* remove word counter dependency ([ae3ea8c](https://github.com/remvze/moodist/commit/ae3ea8c74f9a94ae56a0eb4b165bc36d990dea7b))
- add correct count to description ([81e6666](https://github.com/remvze/moodist/commit/81e66667765879da624544c5d915c1562f2ab34c))
- add key to categories ([38c11f1](https://github.com/remvze/moodist/commit/38c11f124e2235bc32de1e469b00ccaa22467a7e))
- add min-width to inputs ([dfd6c1f](https://github.com/remvze/moodist/commit/dfd6c1fc4a41845e686fc6ee96f71b696213fe69))
- change completion condition ([1ac5286](https://github.com/remvze/moodist/commit/1ac52861d1de651f8245d1e343307c6cf7a13dde))
- change default times ([158cffc](https://github.com/remvze/moodist/commit/158cffca8c4b138f33e2df03e046706d2b122478))
- change initial value ([a7e5368](https://github.com/remvze/moodist/commit/a7e53685918187c47d4fc2935418786b772c189e))
- change z-index values ([79afb8d](https://github.com/remvze/moodist/commit/79afb8d92f9cb8e551bf101267018af1ab58815d))
- comment out toolbox section ([a8a8c36](https://github.com/remvze/moodist/commit/a8a8c3643478d3da531e1da6c3640eb327acad3b))
- make sound count dynamic ([f66a6ff](https://github.com/remvze/moodist/commit/f66a6ffde770992353a5b21fe65c20fe50ab4328))
- remove extra headings ([7390a9b](https://github.com/remvze/moodist/commit/7390a9b3de0c52163d63b42ad48a882087886b65))
- remove fading ([653d309](https://github.com/remvze/moodist/commit/653d309e64b770c2b270d2435bcd02345b686fec))
- remove time from tabs array ([110356b](https://github.com/remvze/moodist/commit/110356b2da82e0f1e971ee9dc486664027d886ff))
- remove word counter dependency ([ae3ea8c](https://github.com/remvze/moodist/commit/ae3ea8c74f9a94ae56a0eb4b165bc36d990dea7b))
### [1.3.1](https://github.com/remvze/moodist/compare/v1.3.0...v1.3.1) (2024-02-01)
### ✨ Features
* add donate item ([f12ca48](https://github.com/remvze/moodist/commit/f12ca4806c9279f69f298bef770f8cac69a0860a))
* add donate section ([d449c29](https://github.com/remvze/moodist/commit/d449c29321024a43517e92cc59223b4b22fe2e82))
* add donation header ([17b4f25](https://github.com/remvze/moodist/commit/17b4f25ff10e09a917203e67cf963cac8358de1a))
- add donate item ([f12ca48](https://github.com/remvze/moodist/commit/f12ca4806c9279f69f298bef770f8cac69a0860a))
- add donate section ([d449c29](https://github.com/remvze/moodist/commit/d449c29321024a43517e92cc59223b4b22fe2e82))
- add donation header ([17b4f25](https://github.com/remvze/moodist/commit/17b4f25ff10e09a917203e67cf963cac8358de1a))
### 🐛 Bug Fixes
* coffee typo ([8e02910](https://github.com/remvze/moodist/commit/8e0291004a90e55b67a921b9ffb483b409109ae4))
* complete donation links ([e6f768a](https://github.com/remvze/moodist/commit/e6f768a5e6dc983ae04b70f6c434fd4c13aeb506))
- coffee typo ([8e02910](https://github.com/remvze/moodist/commit/8e0291004a90e55b67a921b9ffb483b409109ae4))
- complete donation links ([e6f768a](https://github.com/remvze/moodist/commit/e6f768a5e6dc983ae04b70f6c434fd4c13aeb506))
### 🚚 Chores
* add donation link to README file ([1f806c4](https://github.com/remvze/moodist/commit/1f806c4e561d79a00850130eda09376299d85ed2))
- add donation link to README file ([1f806c4](https://github.com/remvze/moodist/commit/1f806c4e561d79a00850130eda09376299d85ed2))
## [1.3.0](https://github.com/remvze/moodist/compare/v1.2.0...v1.3.0) (2024-02-01)
### ♻️ Code Refactoring
* remove media session ([1f63534](https://github.com/remvze/moodist/commit/1f635348e3e5cf73ee76e1c5fac7b5f5b7f7ea6a))
* remove unmute and media session ([b77c817](https://github.com/remvze/moodist/commit/b77c817db25e1a738b6770b1ae86d792e0d42240))
- remove media session ([1f63534](https://github.com/remvze/moodist/commit/1f635348e3e5cf73ee76e1c5fac7b5f5b7f7ea6a))
- remove unmute and media session ([b77c817](https://github.com/remvze/moodist/commit/b77c817db25e1a738b6770b1ae86d792e0d42240))
### ✨ Features
* add fading to intro and outro ([5467bbb](https://github.com/remvze/moodist/commit/5467bbbc2437a5504e157122a995ad7a565ff0b8))
* add loader for favorites ([f682a91](https://github.com/remvze/moodist/commit/f682a910da97eb53cfb90ce955e953f05088e686))
* add media session ([5e0a842](https://github.com/remvze/moodist/commit/5e0a84259ff5586700c4e10087485d905be7ccee))
- add fading to intro and outro ([5467bbb](https://github.com/remvze/moodist/commit/5467bbbc2437a5504e157122a995ad7a565ff0b8))
- add loader for favorites ([f682a91](https://github.com/remvze/moodist/commit/f682a910da97eb53cfb90ce955e953f05088e686))
- add media session ([5e0a842](https://github.com/remvze/moodist/commit/5e0a84259ff5586700c4e10087485d905be7ccee))
### 🐛 Bug Fixes
* add audio element ([889962b](https://github.com/remvze/moodist/commit/889962babe6e940ff283a41b145620d2a0477c70))
* add media session ([81f33d9](https://github.com/remvze/moodist/commit/81f33d9d375f63b4dd0bf58ad28a72354d85706e))
* add media session ([216b913](https://github.com/remvze/moodist/commit/216b913ccd0a7dfe0d03575f842aac9711ef0216))
* add unmute for iOS ([e422b52](https://github.com/remvze/moodist/commit/e422b52436c7dfc0b6cf866afa2b74dc219dcf2f))
* connect audio context to audio element ([463667c](https://github.com/remvze/moodist/commit/463667c868371540c46c9007e686961f9a4be7e5))
* increase decimal ([a33ae45](https://github.com/remvze/moodist/commit/a33ae450cf2c883228c76d04df8df75839c12753))
* remove fading ([d96461d](https://github.com/remvze/moodist/commit/d96461d1ea83c72bfe651d84cf34fabc029c200e))
* resume audio ([8e4d053](https://github.com/remvze/moodist/commit/8e4d0531e0e9aaf4e52b3b3a8666b74ff0c0222e))
* undo changes ([32da26c](https://github.com/remvze/moodist/commit/32da26ccfc0c5bdbe031e26ea48363ea0d8a7b23))
- add audio element ([889962b](https://github.com/remvze/moodist/commit/889962babe6e940ff283a41b145620d2a0477c70))
- add media session ([81f33d9](https://github.com/remvze/moodist/commit/81f33d9d375f63b4dd0bf58ad28a72354d85706e))
- add media session ([216b913](https://github.com/remvze/moodist/commit/216b913ccd0a7dfe0d03575f842aac9711ef0216))
- add unmute for iOS ([e422b52](https://github.com/remvze/moodist/commit/e422b52436c7dfc0b6cf866afa2b74dc219dcf2f))
- connect audio context to audio element ([463667c](https://github.com/remvze/moodist/commit/463667c868371540c46c9007e686961f9a4be7e5))
- increase decimal ([a33ae45](https://github.com/remvze/moodist/commit/a33ae450cf2c883228c76d04df8df75839c12753))
- remove fading ([d96461d](https://github.com/remvze/moodist/commit/d96461d1ea83c72bfe651d84cf34fabc029c200e))
- resume audio ([8e4d053](https://github.com/remvze/moodist/commit/8e4d0531e0e9aaf4e52b3b3a8666b74ff0c0222e))
- undo changes ([32da26c](https://github.com/remvze/moodist/commit/32da26ccfc0c5bdbe031e26ea48363ea0d8a7b23))
### 🚚 Chores
* add binaural beats ([f1d212a](https://github.com/remvze/moodist/commit/f1d212abc8b69a614bbdc4a23876e2eab7cbb574))
* add more sounds ([38f6f7d](https://github.com/remvze/moodist/commit/38f6f7dbe6898ed78e51eb3f0c7936f003ddca08))
* add more sounds ([937bf29](https://github.com/remvze/moodist/commit/937bf29d09cbce20ea0b6b0c87879f3a7dd1d497))
* add more sounds ([e2172fd](https://github.com/remvze/moodist/commit/e2172fd2bbd0e12a705c9efc98c72ad99d86d006))
* add more sounds ([1f12afa](https://github.com/remvze/moodist/commit/1f12afa3943154d70145ef6adc6aeee79f7a7af3))
* add more sounds ([cd05704](https://github.com/remvze/moodist/commit/cd05704a73ffb33aa0ccf5d789328a4cefc320f1))
* add more sounds ([01b4bdb](https://github.com/remvze/moodist/commit/01b4bdbb572285984bcdc9bb94c1a1b6dd2630c5))
- add binaural beats ([f1d212a](https://github.com/remvze/moodist/commit/f1d212abc8b69a614bbdc4a23876e2eab7cbb574))
- add more sounds ([38f6f7d](https://github.com/remvze/moodist/commit/38f6f7dbe6898ed78e51eb3f0c7936f003ddca08))
- add more sounds ([937bf29](https://github.com/remvze/moodist/commit/937bf29d09cbce20ea0b6b0c87879f3a7dd1d497))
- add more sounds ([e2172fd](https://github.com/remvze/moodist/commit/e2172fd2bbd0e12a705c9efc98c72ad99d86d006))
- add more sounds ([1f12afa](https://github.com/remvze/moodist/commit/1f12afa3943154d70145ef6adc6aeee79f7a7af3))
- add more sounds ([cd05704](https://github.com/remvze/moodist/commit/cd05704a73ffb33aa0ccf5d789328a4cefc320f1))
- add more sounds ([01b4bdb](https://github.com/remvze/moodist/commit/01b4bdbb572285984bcdc9bb94c1a1b6dd2630c5))
## [1.2.0](https://github.com/remvze/moodist/compare/v1.1.0...v1.2.0) (2024-01-04)
### ♻️ Code Refactoring
* better item structure for menu ([26bf016](https://github.com/remvze/moodist/commit/26bf01690cfcc105b661951bcb2347394a67fb68))
* rewrite menu with floating ui ([8beb42c](https://github.com/remvze/moodist/commit/8beb42cb1b92c99aa9656b35cd7d82094e5baf72))
- better item structure for menu ([26bf016](https://github.com/remvze/moodist/commit/26bf01690cfcc105b661951bcb2347394a67fb68))
- rewrite menu with floating ui ([8beb42c](https://github.com/remvze/moodist/commit/8beb42cb1b92c99aa9656b35cd7d82094e5baf72))
### 🐛 Bug Fixes
* stringify dependency ([1a23e00](https://github.com/remvze/moodist/commit/1a23e004a65960ce169990211f150db25762fead))
- stringify dependency ([1a23e00](https://github.com/remvze/moodist/commit/1a23e004a65960ce169990211f150db25762fead))
### ✨ Features
* add animation to menu box ([17027e2](https://github.com/remvze/moodist/commit/17027e299bb9bf958aebaf735c40e7664ad71e8b))
* add disabled state ([ff26597](https://github.com/remvze/moodist/commit/ff26597d22d444d18d2874a5c278eccc288972de))
* add menu button ([184bb09](https://github.com/remvze/moodist/commit/184bb09f5ab09fcf877e6a904023d9de72be9a89))
* add share modal ([35e3215](https://github.com/remvze/moodist/commit/35e32152b153f4dfaf9e071f526f6d7602ea97fc))
* add share placeholder ([fe2357c](https://github.com/remvze/moodist/commit/fe2357c995713cd0fb8335b325266859dc47a769))
* basic structure for share link ([ef81f19](https://github.com/remvze/moodist/commit/ef81f198baeb927e3b1768570f75e6638a7bd0b6))
* **docker:** add dockerfile ([a234bc1](https://github.com/remvze/moodist/commit/a234bc17a66331acbbc1d980cd1f53d58646f534))
* implement override feature ([0f62f07](https://github.com/remvze/moodist/commit/0f62f0795c5a9e06fa4e62b6b7b1e6c0774dfe0f))
* implement sharing URL ([93ff72a](https://github.com/remvze/moodist/commit/93ff72a052484b36c9ac821b94b632865b4a3550))
- add animation to menu box ([17027e2](https://github.com/remvze/moodist/commit/17027e299bb9bf958aebaf735c40e7664ad71e8b))
- add disabled state ([ff26597](https://github.com/remvze/moodist/commit/ff26597d22d444d18d2874a5c278eccc288972de))
- add menu button ([184bb09](https://github.com/remvze/moodist/commit/184bb09f5ab09fcf877e6a904023d9de72be9a89))
- add share modal ([35e3215](https://github.com/remvze/moodist/commit/35e32152b153f4dfaf9e071f526f6d7602ea97fc))
- add share placeholder ([fe2357c](https://github.com/remvze/moodist/commit/fe2357c995713cd0fb8335b325266859dc47a769))
- basic structure for share link ([ef81f19](https://github.com/remvze/moodist/commit/ef81f198baeb927e3b1768570f75e6638a7bd0b6))
- **docker:** add dockerfile ([a234bc1](https://github.com/remvze/moodist/commit/a234bc17a66331acbbc1d980cd1f53d58646f534))
- implement override feature ([0f62f07](https://github.com/remvze/moodist/commit/0f62f0795c5a9e06fa4e62b6b7b1e6c0774dfe0f))
- implement sharing URL ([93ff72a](https://github.com/remvze/moodist/commit/93ff72a052484b36c9ac821b94b632865b4a3550))
### 💄 Styling
* add animation to modal ([7823dc7](https://github.com/remvze/moodist/commit/7823dc7ff473278ef8ee401e69796c17b33da794))
* add icon to menu items ([131ab29](https://github.com/remvze/moodist/commit/131ab296215812e45a0c60486d75683f3de25d16))
* change border color ([85b627e](https://github.com/remvze/moodist/commit/85b627ecb96a4f52ecacdb53ed4484c050adba5e))
* change copy ([c51acd6](https://github.com/remvze/moodist/commit/c51acd62618cc705902dc01f0574a2c9124264c5))
* change to primary color ([c8e5122](https://github.com/remvze/moodist/commit/c8e51226e57bfa72ad91318de25fc5f9b5751634))
* widen the menu ([37a0736](https://github.com/remvze/moodist/commit/37a0736a0e7edd09c33940099c884e5b48afbbf1))
- add animation to modal ([7823dc7](https://github.com/remvze/moodist/commit/7823dc7ff473278ef8ee401e69796c17b33da794))
- add icon to menu items ([131ab29](https://github.com/remvze/moodist/commit/131ab296215812e45a0c60486d75683f3de25d16))
- change border color ([85b627e](https://github.com/remvze/moodist/commit/85b627ecb96a4f52ecacdb53ed4484c050adba5e))
- change copy ([c51acd6](https://github.com/remvze/moodist/commit/c51acd62618cc705902dc01f0574a2c9124264c5))
- change to primary color ([c8e5122](https://github.com/remvze/moodist/commit/c8e51226e57bfa72ad91318de25fc5f9b5751634))
- widen the menu ([37a0736](https://github.com/remvze/moodist/commit/37a0736a0e7edd09c33940099c884e5b48afbbf1))
### 🚚 Chores
* change docker workflow ([cb4bfea](https://github.com/remvze/moodist/commit/cb4bfea5ab4326dee17c78554f12a08ffcb9dd0e))
* change docker-compose file ([660ee07](https://github.com/remvze/moodist/commit/660ee07a2359ec77c9d56bbe552541246e0f79c5))
* update GitHub action ([ee60613](https://github.com/remvze/moodist/commit/ee606139a80121fd6ee1b8233f82af994c4e1178))
- change docker workflow ([cb4bfea](https://github.com/remvze/moodist/commit/cb4bfea5ab4326dee17c78554f12a08ffcb9dd0e))
- change docker-compose file ([660ee07](https://github.com/remvze/moodist/commit/660ee07a2359ec77c9d56bbe552541246e0f79c5))
- update GitHub action ([ee60613](https://github.com/remvze/moodist/commit/ee606139a80121fd6ee1b8233f82af994c4e1178))
## [1.1.0](https://github.com/remvze/moodist/compare/v1.0.0...v1.1.0) (2023-12-29)
### ♻️ Code Refactoring
* change ordering config ([a43c679](https://github.com/remvze/moodist/commit/a43c679e214b24c7f547e182aea6e2fbf826228f))
- change ordering config ([a43c679](https://github.com/remvze/moodist/commit/a43c679e214b24c7f547e182aea6e2fbf826228f))
### 🐛 Bug Fixes
* change icon path ([28c3c40](https://github.com/remvze/moodist/commit/28c3c404ad790869b13731e4c3622abe33f1dda2))
- change icon path ([28c3c40](https://github.com/remvze/moodist/commit/28c3c404ad790869b13731e4c3622abe33f1dda2))
### 🚚 Chores
* add more sounds ([e3864be](https://github.com/remvze/moodist/commit/e3864bede129c102ef5b7258b4688d9177dd284c))
* add more sounds ([55e7f05](https://github.com/remvze/moodist/commit/55e7f05892f6d3200b56a7e06b371bed4b4c4554))
* add more sounds ([318e87c](https://github.com/remvze/moodist/commit/318e87c9f1f3e2509c2b8eeb3a7f6875dd1c02fd))
* add places category ([5970012](https://github.com/remvze/moodist/commit/5970012fa6cbd8222c2be8ce426065f928d81b2b))
* add transport category ([c1c3945](https://github.com/remvze/moodist/commit/c1c3945d43e84e3011de52bffa5116d58283c473))
* change heartbeat audio ([f43a378](https://github.com/remvze/moodist/commit/f43a378697437f671c0c33122b1c9ec5a1e173ff))
* relocate underwater audio ([37bad81](https://github.com/remvze/moodist/commit/37bad8149e1f5170426dc745322c0e65cb9a41ff))
* remove heartbeat audio ([121a8f2](https://github.com/remvze/moodist/commit/121a8f204c6b61490a7ab0e732779031278e6e8c))
- add more sounds ([e3864be](https://github.com/remvze/moodist/commit/e3864bede129c102ef5b7258b4688d9177dd284c))
- add more sounds ([55e7f05](https://github.com/remvze/moodist/commit/55e7f05892f6d3200b56a7e06b371bed4b4c4554))
- add more sounds ([318e87c](https://github.com/remvze/moodist/commit/318e87c9f1f3e2509c2b8eeb3a7f6875dd1c02fd))
- add places category ([5970012](https://github.com/remvze/moodist/commit/5970012fa6cbd8222c2be8ce426065f928d81b2b))
- add transport category ([c1c3945](https://github.com/remvze/moodist/commit/c1c3945d43e84e3011de52bffa5116d58283c473))
- change heartbeat audio ([f43a378](https://github.com/remvze/moodist/commit/f43a378697437f671c0c33122b1c9ec5a1e173ff))
- relocate underwater audio ([37bad81](https://github.com/remvze/moodist/commit/37bad8149e1f5170426dc745322c0e65cb9a41ff))
- remove heartbeat audio ([121a8f2](https://github.com/remvze/moodist/commit/121a8f204c6b61490a7ab0e732779031278e6e8c))
### 💄 Styling
* add hover states ([2c74dd0](https://github.com/remvze/moodist/commit/2c74dd0d604af86f99edcba2eb573641ac2010fd))
* change button style ([8efb1ce](https://github.com/remvze/moodist/commit/8efb1cee00ec0e0dcd9677729d9136ca8d69073f))
* change sound counter ([00fc5f3](https://github.com/remvze/moodist/commit/00fc5f3a872be51eb875744e254c75ea58e93281))
* change theme ([bd517f8](https://github.com/remvze/moodist/commit/bd517f88c01202eb7e7e5acf70bf4af2e6f91d75))
- add hover states ([2c74dd0](https://github.com/remvze/moodist/commit/2c74dd0d604af86f99edcba2eb573641ac2010fd))
- change button style ([8efb1ce](https://github.com/remvze/moodist/commit/8efb1cee00ec0e0dcd9677729d9136ca8d69073f))
- change sound counter ([00fc5f3](https://github.com/remvze/moodist/commit/00fc5f3a872be51eb875744e254c75ea58e93281))
- change theme ([bd517f8](https://github.com/remvze/moodist/commit/bd517f88c01202eb7e7e5acf70bf4af2e6f91d75))
## [1.0.0](https://github.com/remvze/moodist/compare/v0.0.1...v1.0.0) (2023-12-09)
### ✨ Features
* add about section ([4e84419](https://github.com/remvze/moodist/commit/4e84419ab19f4f0c129a76a91be194bbab7f6b11))
* add aria-disabled to play button ([f390f38](https://github.com/remvze/moodist/commit/f390f3801604c49799078298637ea63a06eb9721))
* add auto pause to play button ([7c901b2](https://github.com/remvze/moodist/commit/7c901b2bdc525d02b80a0c42eb2f81f766947ca3))
* add auto play on select ([17d1b23](https://github.com/remvze/moodist/commit/17d1b23c8f1a6c717d846c12d38945e7d3b47be1))
* add basic animations with Framer Motion ([fa7b90e](https://github.com/remvze/moodist/commit/fa7b90eeec5b697446fa5871f8b499a85d0d150f))
* add basic audio player ([5a7a58e](https://github.com/remvze/moodist/commit/5a7a58e883fbb0122d8d6e2c777049a8fc0d9609))
* add basic categories ([8d7e4d2](https://github.com/remvze/moodist/commit/8d7e4d26fd7b53a16f7ce39551b31484eefbe461))
* add basic sound components ([4adb8bf](https://github.com/remvze/moodist/commit/4adb8bfdbc86a475d59e1d636927539592ec4b6c))
* add basic sounds for prototyping ([5791346](https://github.com/remvze/moodist/commit/5791346a881a9f451b967f782257317d8fb04d63))
* add color noise ([7363e8d](https://github.com/remvze/moodist/commit/7363e8d51a347adf3c53cbef9ec3e181912ecc6b))
* add deep merge to Zustand Persist ([01f4031](https://github.com/remvze/moodist/commit/01f40318124ad1e6e09b1f0572f623900192ba9d))
* add footer component ([262bb1a](https://github.com/remvze/moodist/commit/262bb1a9c6153a53e259e5bd9123b8035bd6b6d1))
* add gradient line decoration ([5559152](https://github.com/remvze/moodist/commit/5559152a8492dac335f0e6620ca4ca2d9233c889))
* add help text ([c3521a7](https://github.com/remvze/moodist/commit/c3521a798611aa0ad7297493aa5a790a27bbc991))
* add hero section ([dc33c2c](https://github.com/remvze/moodist/commit/dc33c2cf9cdcb251b7a0cc4dabdd7aafae154aa9))
* add hidden selection indicator ([e2cd75a](https://github.com/remvze/moodist/commit/e2cd75a332fab318a529f4f6e04ecf1867be7fd1))
* add Howler for sounds ([735d9eb](https://github.com/remvze/moodist/commit/735d9ebebfa36dd3e7596e70a0549b24b7b9fc4d))
* add icon for sounds ([1994004](https://github.com/remvze/moodist/commit/199400446cc241fb66722c79e74f882a7ef6a26c))
* add link to reasons ([e2b6eaf](https://github.com/remvze/moodist/commit/e2b6eaf8f3278768ce142ed58594958dcc7821ad))
* add loading state for sounds ([aaccbee](https://github.com/remvze/moodist/commit/aaccbee3d7dd1d4469ee26cea14df7132e8e9e0d))
* add local storage support ([856b3e6](https://github.com/remvze/moodist/commit/856b3e668ed6f24c8aefe532ac673af5e99141d1))
* add more and less button for sounds ([13cd72a](https://github.com/remvze/moodist/commit/13cd72a0655d90f0a6b7658b3357d1e8902f8fb7))
* add more sounds ([0888aaa](https://github.com/remvze/moodist/commit/0888aaa0f09ed549afdb21166ad6d2f048604275))
* add more sounds ([63ed396](https://github.com/remvze/moodist/commit/63ed396a5a74ed2b6e25882a72511ee93935fe04))
* add new sounds ([759e6b0](https://github.com/remvze/moodist/commit/759e6b0ce8f0acc3eb0eed508f7c587804097748))
* add play button ([31c087e](https://github.com/remvze/moodist/commit/31c087ebc8e66220d488226029dcc1435667ce04))
* add ready section ([e372d2f](https://github.com/remvze/moodist/commit/e372d2f398dbdcfad1069b50911ba840f0c9a1fe))
* add scroll to top component ([3c1c27b](https://github.com/remvze/moodist/commit/3c1c27b2fd378eb0f7351a3f511375cbc62f2a7b))
* add simple tooltip ([f2efe3c](https://github.com/remvze/moodist/commit/f2efe3c490ab5429824d10e97979694a4de11dd4))
* add singing bowl sound ([0b49f66](https://github.com/remvze/moodist/commit/0b49f66e5879642da10054046700a160411448a3))
* add sound count to hero ([42ccc7a](https://github.com/remvze/moodist/commit/42ccc7ada780fd5db5c038fa9210ec0e3e75be6e))
* add tooltip to scroll button ([d4401fa](https://github.com/remvze/moodist/commit/d4401faaffcb4351be1a152b89f94c9db63ca213))
* add why section ([3ed610b](https://github.com/remvze/moodist/commit/3ed610bb468293f6b08c2b2444bc47cd570383eb))
* change sound count from round to exact ([8c49453](https://github.com/remvze/moodist/commit/8c49453011d127669774f46720ce6e98ca01aa13))
* complete meta tags ([1cfbf0d](https://github.com/remvze/moodist/commit/1cfbf0dd092d35d2f098c29baf6d6adbc1107cc0))
* create reusable tooltip ([c637e2d](https://github.com/remvze/moodist/commit/c637e2d63109e12886b6f688c643146707967c7a))
* implement basic snackbar ([8090599](https://github.com/remvze/moodist/commit/8090599f2bc9ce58cdb36a6a04555afdb7af2bb2))
* implement basic Zustand store ([22bb65d](https://github.com/remvze/moodist/commit/22bb65de0d4ea9f485e4923b9c8715233df3114e))
* implement favorite sounds functionality ([cb34b59](https://github.com/remvze/moodist/commit/cb34b59d864fb80b930c0c9e1c1269bb7e9c2b18))
* implement shuffle functionality ([26ba017](https://github.com/remvze/moodist/commit/26ba017815d7338f49d2017eda75f86f493bf050))
* implement shuffling functionality ([3ac211e](https://github.com/remvze/moodist/commit/3ac211e3554d26c48fb8e0a588a67f1a4901e9b9))
* implement unselect all functionality ([8966d59](https://github.com/remvze/moodist/commit/8966d59d758496cc94247364833788dcc555ce8b))
* reorder sounds in favorites ([dc9da85](https://github.com/remvze/moodist/commit/dc9da85e6825b3cb70e2e6ad4f35c0db3aeb26c2))
- add about section ([4e84419](https://github.com/remvze/moodist/commit/4e84419ab19f4f0c129a76a91be194bbab7f6b11))
- add aria-disabled to play button ([f390f38](https://github.com/remvze/moodist/commit/f390f3801604c49799078298637ea63a06eb9721))
- add auto pause to play button ([7c901b2](https://github.com/remvze/moodist/commit/7c901b2bdc525d02b80a0c42eb2f81f766947ca3))
- add auto play on select ([17d1b23](https://github.com/remvze/moodist/commit/17d1b23c8f1a6c717d846c12d38945e7d3b47be1))
- add basic animations with Framer Motion ([fa7b90e](https://github.com/remvze/moodist/commit/fa7b90eeec5b697446fa5871f8b499a85d0d150f))
- add basic audio player ([5a7a58e](https://github.com/remvze/moodist/commit/5a7a58e883fbb0122d8d6e2c777049a8fc0d9609))
- add basic categories ([8d7e4d2](https://github.com/remvze/moodist/commit/8d7e4d26fd7b53a16f7ce39551b31484eefbe461))
- add basic sound components ([4adb8bf](https://github.com/remvze/moodist/commit/4adb8bfdbc86a475d59e1d636927539592ec4b6c))
- add basic sounds for prototyping ([5791346](https://github.com/remvze/moodist/commit/5791346a881a9f451b967f782257317d8fb04d63))
- add color noise ([7363e8d](https://github.com/remvze/moodist/commit/7363e8d51a347adf3c53cbef9ec3e181912ecc6b))
- add deep merge to Zustand Persist ([01f4031](https://github.com/remvze/moodist/commit/01f40318124ad1e6e09b1f0572f623900192ba9d))
- add footer component ([262bb1a](https://github.com/remvze/moodist/commit/262bb1a9c6153a53e259e5bd9123b8035bd6b6d1))
- add gradient line decoration ([5559152](https://github.com/remvze/moodist/commit/5559152a8492dac335f0e6620ca4ca2d9233c889))
- add help text ([c3521a7](https://github.com/remvze/moodist/commit/c3521a798611aa0ad7297493aa5a790a27bbc991))
- add hero section ([dc33c2c](https://github.com/remvze/moodist/commit/dc33c2cf9cdcb251b7a0cc4dabdd7aafae154aa9))
- add hidden selection indicator ([e2cd75a](https://github.com/remvze/moodist/commit/e2cd75a332fab318a529f4f6e04ecf1867be7fd1))
- add Howler for sounds ([735d9eb](https://github.com/remvze/moodist/commit/735d9ebebfa36dd3e7596e70a0549b24b7b9fc4d))
- add icon for sounds ([1994004](https://github.com/remvze/moodist/commit/199400446cc241fb66722c79e74f882a7ef6a26c))
- add link to reasons ([e2b6eaf](https://github.com/remvze/moodist/commit/e2b6eaf8f3278768ce142ed58594958dcc7821ad))
- add loading state for sounds ([aaccbee](https://github.com/remvze/moodist/commit/aaccbee3d7dd1d4469ee26cea14df7132e8e9e0d))
- add local storage support ([856b3e6](https://github.com/remvze/moodist/commit/856b3e668ed6f24c8aefe532ac673af5e99141d1))
- add more and less button for sounds ([13cd72a](https://github.com/remvze/moodist/commit/13cd72a0655d90f0a6b7658b3357d1e8902f8fb7))
- add more sounds ([0888aaa](https://github.com/remvze/moodist/commit/0888aaa0f09ed549afdb21166ad6d2f048604275))
- add more sounds ([63ed396](https://github.com/remvze/moodist/commit/63ed396a5a74ed2b6e25882a72511ee93935fe04))
- add new sounds ([759e6b0](https://github.com/remvze/moodist/commit/759e6b0ce8f0acc3eb0eed508f7c587804097748))
- add play button ([31c087e](https://github.com/remvze/moodist/commit/31c087ebc8e66220d488226029dcc1435667ce04))
- add ready section ([e372d2f](https://github.com/remvze/moodist/commit/e372d2f398dbdcfad1069b50911ba840f0c9a1fe))
- add scroll to top component ([3c1c27b](https://github.com/remvze/moodist/commit/3c1c27b2fd378eb0f7351a3f511375cbc62f2a7b))
- add simple tooltip ([f2efe3c](https://github.com/remvze/moodist/commit/f2efe3c490ab5429824d10e97979694a4de11dd4))
- add singing bowl sound ([0b49f66](https://github.com/remvze/moodist/commit/0b49f66e5879642da10054046700a160411448a3))
- add sound count to hero ([42ccc7a](https://github.com/remvze/moodist/commit/42ccc7ada780fd5db5c038fa9210ec0e3e75be6e))
- add tooltip to scroll button ([d4401fa](https://github.com/remvze/moodist/commit/d4401faaffcb4351be1a152b89f94c9db63ca213))
- add why section ([3ed610b](https://github.com/remvze/moodist/commit/3ed610bb468293f6b08c2b2444bc47cd570383eb))
- change sound count from round to exact ([8c49453](https://github.com/remvze/moodist/commit/8c49453011d127669774f46720ce6e98ca01aa13))
- complete meta tags ([1cfbf0d](https://github.com/remvze/moodist/commit/1cfbf0dd092d35d2f098c29baf6d6adbc1107cc0))
- create reusable tooltip ([c637e2d](https://github.com/remvze/moodist/commit/c637e2d63109e12886b6f688c643146707967c7a))
- implement basic snackbar ([8090599](https://github.com/remvze/moodist/commit/8090599f2bc9ce58cdb36a6a04555afdb7af2bb2))
- implement basic Zustand store ([22bb65d](https://github.com/remvze/moodist/commit/22bb65de0d4ea9f485e4923b9c8715233df3114e))
- implement favorite sounds functionality ([cb34b59](https://github.com/remvze/moodist/commit/cb34b59d864fb80b930c0c9e1c1269bb7e9c2b18))
- implement shuffle functionality ([26ba017](https://github.com/remvze/moodist/commit/26ba017815d7338f49d2017eda75f86f493bf050))
- implement shuffling functionality ([3ac211e](https://github.com/remvze/moodist/commit/3ac211e3554d26c48fb8e0a588a67f1a4901e9b9))
- implement unselect all functionality ([8966d59](https://github.com/remvze/moodist/commit/8966d59d758496cc94247364833788dcc555ce8b))
- reorder sounds in favorites ([dc9da85](https://github.com/remvze/moodist/commit/dc9da85e6825b3cb70e2e6ad4f35c0db3aeb26c2))
### 💄 Styling
* add animation to more/less button ([b849b3a](https://github.com/remvze/moodist/commit/b849b3aecd6178114b3b27a2daa014b0795ddf42))
* add base and global styles ([05d68e4](https://github.com/remvze/moodist/commit/05d68e4de6f55ebbc08817ed553f7760f570208b))
* add gradient background ([77fed03](https://github.com/remvze/moodist/commit/77fed0308ad55ca32f07b4f30e7a7936063d842a))
* add gradient line ([ea722ea](https://github.com/remvze/moodist/commit/ea722eabd24cb966c65fa45d41f55e1e1a049939))
* add line to titles ([ec1def0](https://github.com/remvze/moodist/commit/ec1def041934d8a9f98084299a0606c5690ef23d))
* add more icons ([41c5ae5](https://github.com/remvze/moodist/commit/41c5ae5db8e72f15f5cc1b7501f397239ba9368a))
* add new font weight for links ([287d7b3](https://github.com/remvze/moodist/commit/287d7b33fb107e81034a17a60e1cd6cd5d40d935))
* add smooth transition ([3b33e09](https://github.com/remvze/moodist/commit/3b33e095479340496a7a11b057daef029f40b70a))
* add smooth transition ([e7fc951](https://github.com/remvze/moodist/commit/e7fc9513109ae48ce407745549085c9449cf3324))
* add text animation ([7810d21](https://github.com/remvze/moodist/commit/7810d212259cfe19befafab33d51110126089a83))
* add theme color ([6de1394](https://github.com/remvze/moodist/commit/6de1394628ccb6b58aec02bcd164e56e9ca0f30a))
* add wrap balancer to desc ([276639b](https://github.com/remvze/moodist/commit/276639b0d3a70ead87dc61e2c8cb7cd621261c3e))
* better line alignment ([1f24812](https://github.com/remvze/moodist/commit/1f24812efa3b64fdbfc794bcb546226cc2ef07d4))
* change border to shadow ([a53800c](https://github.com/remvze/moodist/commit/a53800c6b194e7520d2e7ee13c5e00f77db9f5f7))
* change button animation ([6983559](https://github.com/remvze/moodist/commit/6983559032d731ad6264ad56f0786b1a84f7cf4e))
* change button animation ([c44a863](https://github.com/remvze/moodist/commit/c44a86361ebf3a77d68148564a2983e60b522c29))
* change copy ([6242308](https://github.com/remvze/moodist/commit/624230843c3328fdfb42e0e2f23084cef4dec614))
* change favicon ([a82dc3f](https://github.com/remvze/moodist/commit/a82dc3f36af098071b6be09491e9e25bda190b74))
* change icon backgrounds ([ef825ca](https://github.com/remvze/moodist/commit/ef825cae68f3cd4ef58016212a45820d3b272f96))
* change icon color on selection ([e6abca6](https://github.com/remvze/moodist/commit/e6abca61fe9eb36ca6968339a4cb67beeb5f8fdc))
* change label cursor ([15953ef](https://github.com/remvze/moodist/commit/15953ef8565a27da2b41330753fbc40931987aa7))
* change like color ([d8c9806](https://github.com/remvze/moodist/commit/d8c9806a1964042b787baabf43e2852bab23dcfa))
* change logo ([9f702db](https://github.com/remvze/moodist/commit/9f702dbfa74b524b4553bd1686532bc7d35d9985))
* change primary color ([ed9a027](https://github.com/remvze/moodist/commit/ed9a0271f7c49b499ab07487072cfd7bab5277db))
* change reason copy ([69c4ec1](https://github.com/remvze/moodist/commit/69c4ec150849a15e2aa222ac4b6f2982cc9536df))
* change spacing ([cc26f68](https://github.com/remvze/moodist/commit/cc26f68097bd137bea1f62a9eba566844b1cb069))
* change tagline ([f3603e8](https://github.com/remvze/moodist/commit/f3603e84318a9b69145ae69d3aa02447ed1235e6))
* decrease gradient shine ([8f58794](https://github.com/remvze/moodist/commit/8f587944fd1ad5e11bb6bc3afc7e9380afa43a6c))
* decrease margin ([d700195](https://github.com/remvze/moodist/commit/d7001952f9ce323d746118583e0b34e001a8a517))
* decrease scale animation ([7e668e5](https://github.com/remvze/moodist/commit/7e668e5b393c7df71bec8bf11696acbae22d70e4))
* fix margins ([99775b7](https://github.com/remvze/moodist/commit/99775b7c6487b009bbf87fbd834ed8730508d1ce))
* fix snackbar pointer ([14c9e88](https://github.com/remvze/moodist/commit/14c9e88bfbef4b68dce0a1a8e570c1a9d9894dfd))
* fix tooltip z-index ([fb061c3](https://github.com/remvze/moodist/commit/fb061c3d66d3fa7c3fce63bae1e04e502fcbb891))
* fix z-index ([fa71709](https://github.com/remvze/moodist/commit/fa71709f897cc2b7a5ba03dbc1cb60a3198bf9f4))
* increase padding ([eedbf53](https://github.com/remvze/moodist/commit/eedbf53e0e07ba75161e9f397dc0554204bc004a))
* increase sounds per row ([cd8ec5e](https://github.com/remvze/moodist/commit/cd8ec5e8649f8808d0a89a74c1426b92628efbc7))
* relocate the play button ([403a755](https://github.com/remvze/moodist/commit/403a755ca7a9d93ef6940d1954fcde058505c1b8))
* remove extra colors ([38f05a3](https://github.com/remvze/moodist/commit/38f05a3e757ab0c8d91b1f84938bfb8443450769))
* remove gradient line ([de03cac](https://github.com/remvze/moodist/commit/de03cac6b374e836da65d00b7fe732bf17600554))
* remove gradient line ([6720e86](https://github.com/remvze/moodist/commit/6720e86a0af14c8c05d73f305ee12664f3b264b7))
* remove layout animation ([ef952d0](https://github.com/remvze/moodist/commit/ef952d0a03b2cc3490b65535f1c5707b6578836d))
* remove layout animation ([efd6f99](https://github.com/remvze/moodist/commit/efd6f9941d1483e6a6df8db861ba221084a1f298))
* remove opacity effect on disabled ([4266557](https://github.com/remvze/moodist/commit/4266557366977534a4fba24922904ac51aaae74d))
* reverse gradient line ([87f3a2b](https://github.com/remvze/moodist/commit/87f3a2b51104d635dcaf6e48281b99193a7d931a))
* widen the container ([e7c786f](https://github.com/remvze/moodist/commit/e7c786f25986436606fa723441338588a84b00b3))
- add animation to more/less button ([b849b3a](https://github.com/remvze/moodist/commit/b849b3aecd6178114b3b27a2daa014b0795ddf42))
- add base and global styles ([05d68e4](https://github.com/remvze/moodist/commit/05d68e4de6f55ebbc08817ed553f7760f570208b))
- add gradient background ([77fed03](https://github.com/remvze/moodist/commit/77fed0308ad55ca32f07b4f30e7a7936063d842a))
- add gradient line ([ea722ea](https://github.com/remvze/moodist/commit/ea722eabd24cb966c65fa45d41f55e1e1a049939))
- add line to titles ([ec1def0](https://github.com/remvze/moodist/commit/ec1def041934d8a9f98084299a0606c5690ef23d))
- add more icons ([41c5ae5](https://github.com/remvze/moodist/commit/41c5ae5db8e72f15f5cc1b7501f397239ba9368a))
- add new font weight for links ([287d7b3](https://github.com/remvze/moodist/commit/287d7b33fb107e81034a17a60e1cd6cd5d40d935))
- add smooth transition ([3b33e09](https://github.com/remvze/moodist/commit/3b33e095479340496a7a11b057daef029f40b70a))
- add smooth transition ([e7fc951](https://github.com/remvze/moodist/commit/e7fc9513109ae48ce407745549085c9449cf3324))
- add text animation ([7810d21](https://github.com/remvze/moodist/commit/7810d212259cfe19befafab33d51110126089a83))
- add theme color ([6de1394](https://github.com/remvze/moodist/commit/6de1394628ccb6b58aec02bcd164e56e9ca0f30a))
- add wrap balancer to desc ([276639b](https://github.com/remvze/moodist/commit/276639b0d3a70ead87dc61e2c8cb7cd621261c3e))
- better line alignment ([1f24812](https://github.com/remvze/moodist/commit/1f24812efa3b64fdbfc794bcb546226cc2ef07d4))
- change border to shadow ([a53800c](https://github.com/remvze/moodist/commit/a53800c6b194e7520d2e7ee13c5e00f77db9f5f7))
- change button animation ([6983559](https://github.com/remvze/moodist/commit/6983559032d731ad6264ad56f0786b1a84f7cf4e))
- change button animation ([c44a863](https://github.com/remvze/moodist/commit/c44a86361ebf3a77d68148564a2983e60b522c29))
- change copy ([6242308](https://github.com/remvze/moodist/commit/624230843c3328fdfb42e0e2f23084cef4dec614))
- change favicon ([a82dc3f](https://github.com/remvze/moodist/commit/a82dc3f36af098071b6be09491e9e25bda190b74))
- change icon backgrounds ([ef825ca](https://github.com/remvze/moodist/commit/ef825cae68f3cd4ef58016212a45820d3b272f96))
- change icon color on selection ([e6abca6](https://github.com/remvze/moodist/commit/e6abca61fe9eb36ca6968339a4cb67beeb5f8fdc))
- change label cursor ([15953ef](https://github.com/remvze/moodist/commit/15953ef8565a27da2b41330753fbc40931987aa7))
- change like color ([d8c9806](https://github.com/remvze/moodist/commit/d8c9806a1964042b787baabf43e2852bab23dcfa))
- change logo ([9f702db](https://github.com/remvze/moodist/commit/9f702dbfa74b524b4553bd1686532bc7d35d9985))
- change primary color ([ed9a027](https://github.com/remvze/moodist/commit/ed9a0271f7c49b499ab07487072cfd7bab5277db))
- change reason copy ([69c4ec1](https://github.com/remvze/moodist/commit/69c4ec150849a15e2aa222ac4b6f2982cc9536df))
- change spacing ([cc26f68](https://github.com/remvze/moodist/commit/cc26f68097bd137bea1f62a9eba566844b1cb069))
- change tagline ([f3603e8](https://github.com/remvze/moodist/commit/f3603e84318a9b69145ae69d3aa02447ed1235e6))
- decrease gradient shine ([8f58794](https://github.com/remvze/moodist/commit/8f587944fd1ad5e11bb6bc3afc7e9380afa43a6c))
- decrease margin ([d700195](https://github.com/remvze/moodist/commit/d7001952f9ce323d746118583e0b34e001a8a517))
- decrease scale animation ([7e668e5](https://github.com/remvze/moodist/commit/7e668e5b393c7df71bec8bf11696acbae22d70e4))
- fix margins ([99775b7](https://github.com/remvze/moodist/commit/99775b7c6487b009bbf87fbd834ed8730508d1ce))
- fix snackbar pointer ([14c9e88](https://github.com/remvze/moodist/commit/14c9e88bfbef4b68dce0a1a8e570c1a9d9894dfd))
- fix tooltip z-index ([fb061c3](https://github.com/remvze/moodist/commit/fb061c3d66d3fa7c3fce63bae1e04e502fcbb891))
- fix z-index ([fa71709](https://github.com/remvze/moodist/commit/fa71709f897cc2b7a5ba03dbc1cb60a3198bf9f4))
- increase padding ([eedbf53](https://github.com/remvze/moodist/commit/eedbf53e0e07ba75161e9f397dc0554204bc004a))
- increase sounds per row ([cd8ec5e](https://github.com/remvze/moodist/commit/cd8ec5e8649f8808d0a89a74c1426b92628efbc7))
- relocate the play button ([403a755](https://github.com/remvze/moodist/commit/403a755ca7a9d93ef6940d1954fcde058505c1b8))
- remove extra colors ([38f05a3](https://github.com/remvze/moodist/commit/38f05a3e757ab0c8d91b1f84938bfb8443450769))
- remove gradient line ([de03cac](https://github.com/remvze/moodist/commit/de03cac6b374e836da65d00b7fe732bf17600554))
- remove gradient line ([6720e86](https://github.com/remvze/moodist/commit/6720e86a0af14c8c05d73f305ee12664f3b264b7))
- remove layout animation ([ef952d0](https://github.com/remvze/moodist/commit/ef952d0a03b2cc3490b65535f1c5707b6578836d))
- remove layout animation ([efd6f99](https://github.com/remvze/moodist/commit/efd6f9941d1483e6a6df8db861ba221084a1f298))
- remove opacity effect on disabled ([4266557](https://github.com/remvze/moodist/commit/4266557366977534a4fba24922904ac51aaae74d))
- reverse gradient line ([87f3a2b](https://github.com/remvze/moodist/commit/87f3a2b51104d635dcaf6e48281b99193a7d931a))
- widen the container ([e7c786f](https://github.com/remvze/moodist/commit/e7c786f25986436606fa723441338588a84b00b3))
### 🐛 Bug Fixes
* add aria label to shuffle button ([6d02cfb](https://github.com/remvze/moodist/commit/6d02cfb134bc925b9824040307b1b40626312fd1))
* add aria labels ([85768d8](https://github.com/remvze/moodist/commit/85768d8bca10f2732e98d138a3d83ec3116816d4))
* add keys to filler elements ([b7c7d40](https://github.com/remvze/moodist/commit/b7c7d40bf9c47c4a2793335e406ac4173d98a1e0))
* change icon path ([8cceb6e](https://github.com/remvze/moodist/commit/8cceb6ecd1d0183e0d5f0aeb7af4d80b2dc41b34))
* change icon path ([dc6a9e1](https://github.com/remvze/moodist/commit/dc6a9e120a0617761c9a36a3f1268c50d4a1b7c5))
* change icon path ([c184246](https://github.com/remvze/moodist/commit/c184246a1280e9e8cf85c77d1de8d32bf1d7592b))
* change link address ([1b4d216](https://github.com/remvze/moodist/commit/1b4d216b0813f8d336fba93c2e3bb794a988f834))
* change page title ([3bebb3e](https://github.com/remvze/moodist/commit/3bebb3e9d259dd7f87d17f29ea85df67c5e2ada5))
* fix icon imports ([a3eb479](https://github.com/remvze/moodist/commit/a3eb47914024eb7b9493adae95f916be591bb748))
* fix some animation issues ([eccba87](https://github.com/remvze/moodist/commit/eccba87557e0f444adb740e8d6488adad8a2ce42))
* fix some types ([04061e2](https://github.com/remvze/moodist/commit/04061e23c3063279afa493a1e120817f80447840))
* make sound count dynamic ([79458bb](https://github.com/remvze/moodist/commit/79458bba54189147af8b8e3f38b34c756d4bd58e))
* rehydrate store only on mount ([2c443d3](https://github.com/remvze/moodist/commit/2c443d3f33d9d9f4d00ed1e99a8b092597abce97))
* remove extra play calls ([e0164c3](https://github.com/remvze/moodist/commit/e0164c362d72fea7587f67470e4d295007e5ad5e))
* remove history on favorite toggle ([190f06a](https://github.com/remvze/moodist/commit/190f06aa78b1aff931348a65da864404b2d0f4d5))
* remove history on select ([5bd1dd3](https://github.com/remvze/moodist/commit/5bd1dd3016cf97ad397b4371015605473c55dee8))
* remove tooltip ([b634d6f](https://github.com/remvze/moodist/commit/b634d6f3c354a51e4403374b2e3505e4f2c09351))
* rotate the spinner when unselected ([cf7600e](https://github.com/remvze/moodist/commit/cf7600e6c72d9d9638c3a9ad0513675d353422cd))
* set aria label to ID ([7e0a9af](https://github.com/remvze/moodist/commit/7e0a9afb179d228301effe00575c2f67b426e3da))
* typo ([5cfb9a8](https://github.com/remvze/moodist/commit/5cfb9a8293a215b83a826c403d996d00108d49b5))
- add aria label to shuffle button ([6d02cfb](https://github.com/remvze/moodist/commit/6d02cfb134bc925b9824040307b1b40626312fd1))
- add aria labels ([85768d8](https://github.com/remvze/moodist/commit/85768d8bca10f2732e98d138a3d83ec3116816d4))
- add keys to filler elements ([b7c7d40](https://github.com/remvze/moodist/commit/b7c7d40bf9c47c4a2793335e406ac4173d98a1e0))
- change icon path ([8cceb6e](https://github.com/remvze/moodist/commit/8cceb6ecd1d0183e0d5f0aeb7af4d80b2dc41b34))
- change icon path ([dc6a9e1](https://github.com/remvze/moodist/commit/dc6a9e120a0617761c9a36a3f1268c50d4a1b7c5))
- change icon path ([c184246](https://github.com/remvze/moodist/commit/c184246a1280e9e8cf85c77d1de8d32bf1d7592b))
- change link address ([1b4d216](https://github.com/remvze/moodist/commit/1b4d216b0813f8d336fba93c2e3bb794a988f834))
- change page title ([3bebb3e](https://github.com/remvze/moodist/commit/3bebb3e9d259dd7f87d17f29ea85df67c5e2ada5))
- fix icon imports ([a3eb479](https://github.com/remvze/moodist/commit/a3eb47914024eb7b9493adae95f916be591bb748))
- fix some animation issues ([eccba87](https://github.com/remvze/moodist/commit/eccba87557e0f444adb740e8d6488adad8a2ce42))
- fix some types ([04061e2](https://github.com/remvze/moodist/commit/04061e23c3063279afa493a1e120817f80447840))
- make sound count dynamic ([79458bb](https://github.com/remvze/moodist/commit/79458bba54189147af8b8e3f38b34c756d4bd58e))
- rehydrate store only on mount ([2c443d3](https://github.com/remvze/moodist/commit/2c443d3f33d9d9f4d00ed1e99a8b092597abce97))
- remove extra play calls ([e0164c3](https://github.com/remvze/moodist/commit/e0164c362d72fea7587f67470e4d295007e5ad5e))
- remove history on favorite toggle ([190f06a](https://github.com/remvze/moodist/commit/190f06aa78b1aff931348a65da864404b2d0f4d5))
- remove history on select ([5bd1dd3](https://github.com/remvze/moodist/commit/5bd1dd3016cf97ad397b4371015605473c55dee8))
- remove tooltip ([b634d6f](https://github.com/remvze/moodist/commit/b634d6f3c354a51e4403374b2e3505e4f2c09351))
- rotate the spinner when unselected ([cf7600e](https://github.com/remvze/moodist/commit/cf7600e6c72d9d9638c3a9ad0513675d353422cd))
- set aria label to ID ([7e0a9af](https://github.com/remvze/moodist/commit/7e0a9afb179d228301effe00575c2f67b426e3da))
- typo ([5cfb9a8](https://github.com/remvze/moodist/commit/5cfb9a8293a215b83a826c403d996d00108d49b5))
### 🚚 Chores
* add more sounds ([eed5a13](https://github.com/remvze/moodist/commit/eed5a1329d6fc36d1e6375feaeaf2bba26167bf5))
* add more sounds ([5a7936f](https://github.com/remvze/moodist/commit/5a7936f11c4510886d14400e088ac0d8977a4806))
* add more sounds ([8c75f87](https://github.com/remvze/moodist/commit/8c75f875f0e39d392f8394d67b64d3d6d4e6f4a0))
* add robots.txt file ([6bdf28a](https://github.com/remvze/moodist/commit/6bdf28afdcf218c02f3bddc2a55fc1b6b88ebcff))
* change README banner ([c450028](https://github.com/remvze/moodist/commit/c450028ac7e58e961204de4789231d357d129ca1))
* change README file ([85e42f3](https://github.com/remvze/moodist/commit/85e42f3606f9fba281f2177d0dbffc86851603f9))
* upgrade Astro ([72fa516](https://github.com/remvze/moodist/commit/72fa516316cf1077cf5ab09bc59b76de147c6d38))
- add more sounds ([eed5a13](https://github.com/remvze/moodist/commit/eed5a1329d6fc36d1e6375feaeaf2bba26167bf5))
- add more sounds ([5a7936f](https://github.com/remvze/moodist/commit/5a7936f11c4510886d14400e088ac0d8977a4806))
- add more sounds ([8c75f87](https://github.com/remvze/moodist/commit/8c75f875f0e39d392f8394d67b64d3d6d4e6f4a0))
- add robots.txt file ([6bdf28a](https://github.com/remvze/moodist/commit/6bdf28afdcf218c02f3bddc2a55fc1b6b88ebcff))
- change README banner ([c450028](https://github.com/remvze/moodist/commit/c450028ac7e58e961204de4789231d357d129ca1))
- change README file ([85e42f3](https://github.com/remvze/moodist/commit/85e42f3606f9fba281f2177d0dbffc86851603f9))
- upgrade Astro ([72fa516](https://github.com/remvze/moodist/commit/72fa516316cf1077cf5ab09bc59b76de147c6d38))
### ♻️ Code Refactoring
* better tooltip ([5fecd38](https://github.com/remvze/moodist/commit/5fecd383aaf757dbb563a1abd7eee0e64905902c))
* change data file structure ([c9e8bd4](https://github.com/remvze/moodist/commit/c9e8bd41fd79f6c73c11e6fcdbe8b24c6c0bbeb4))
* relocate sections ([d672bf6](https://github.com/remvze/moodist/commit/d672bf6f85fe7b3a5c20fc53668705ab3d7827c5))
* remove seperate favorite store ([d7fd17e](https://github.com/remvze/moodist/commit/d7fd17ea8bb79ab44220bedfd62c98f9abf1d9f6))
* remove seperate playing context ([daee746](https://github.com/remvze/moodist/commit/daee7465bc4460a11b6aa5885cbd0eb7191c0026))
* rename component ([f5cdb8c](https://github.com/remvze/moodist/commit/f5cdb8c06b44f9cdde27e6e7c7e3d4d156c21dca))
* separate sounds ([a1ea9a1](https://github.com/remvze/moodist/commit/a1ea9a19e64f062c1d63ecef7fb200fbba063fe4))
* seperate buttons ([b117a4b](https://github.com/remvze/moodist/commit/b117a4b495bed8d7b034c42a70e080bc062ad672))
* seperate common types ([bad2d31](https://github.com/remvze/moodist/commit/bad2d31b2dfa6a1f01c1c9cd767209c2c6f58f5c))
* seperate favorite button ([4124beb](https://github.com/remvze/moodist/commit/4124beb5b4818f1eee322fa6a4777f2e422d04ba))
* seperate irrelevant logic ([f1688cb](https://github.com/remvze/moodist/commit/f1688cb53ccf7199759b8a60f1d05787edd05790))
* seperate motion variants ([7fce9e1](https://github.com/remvze/moodist/commit/7fce9e1dff3dfe2b17a92872125bb29f61fee23f))
* seperate range input ([89149dc](https://github.com/remvze/moodist/commit/89149dca78069affadb5633ba1354dd50fb616ae))
* sort interface keys ([c5240ff](https://github.com/remvze/moodist/commit/c5240ff507fba8d979ef842ceba05b712b76220d))
* turn footer into Astro component ([a67083c](https://github.com/remvze/moodist/commit/a67083c0e9812acc1dd71fade41a81f307669116))
* turn hero into Astro component ([77f9fcc](https://github.com/remvze/moodist/commit/77f9fcc50e54cecb31877eaccb3a578c291f99fe))
* turn sections into Astro components ([9398ae0](https://github.com/remvze/moodist/commit/9398ae0eddb4fac9695569a97a829bd518500363))
* use scrollIntoView instead of link ([4d2645f](https://github.com/remvze/moodist/commit/4d2645f06c846eea791f182224be0bc6e3db76dc))
- better tooltip ([5fecd38](https://github.com/remvze/moodist/commit/5fecd383aaf757dbb563a1abd7eee0e64905902c))
- change data file structure ([c9e8bd4](https://github.com/remvze/moodist/commit/c9e8bd41fd79f6c73c11e6fcdbe8b24c6c0bbeb4))
- relocate sections ([d672bf6](https://github.com/remvze/moodist/commit/d672bf6f85fe7b3a5c20fc53668705ab3d7827c5))
- remove seperate favorite store ([d7fd17e](https://github.com/remvze/moodist/commit/d7fd17ea8bb79ab44220bedfd62c98f9abf1d9f6))
- remove seperate playing context ([daee746](https://github.com/remvze/moodist/commit/daee7465bc4460a11b6aa5885cbd0eb7191c0026))
- rename component ([f5cdb8c](https://github.com/remvze/moodist/commit/f5cdb8c06b44f9cdde27e6e7c7e3d4d156c21dca))
- separate sounds ([a1ea9a1](https://github.com/remvze/moodist/commit/a1ea9a19e64f062c1d63ecef7fb200fbba063fe4))
- seperate buttons ([b117a4b](https://github.com/remvze/moodist/commit/b117a4b495bed8d7b034c42a70e080bc062ad672))
- seperate common types ([bad2d31](https://github.com/remvze/moodist/commit/bad2d31b2dfa6a1f01c1c9cd767209c2c6f58f5c))
- seperate favorite button ([4124beb](https://github.com/remvze/moodist/commit/4124beb5b4818f1eee322fa6a4777f2e422d04ba))
- seperate irrelevant logic ([f1688cb](https://github.com/remvze/moodist/commit/f1688cb53ccf7199759b8a60f1d05787edd05790))
- seperate motion variants ([7fce9e1](https://github.com/remvze/moodist/commit/7fce9e1dff3dfe2b17a92872125bb29f61fee23f))
- seperate range input ([89149dc](https://github.com/remvze/moodist/commit/89149dca78069affadb5633ba1354dd50fb616ae))
- sort interface keys ([c5240ff](https://github.com/remvze/moodist/commit/c5240ff507fba8d979ef842ceba05b712b76220d))
- turn footer into Astro component ([a67083c](https://github.com/remvze/moodist/commit/a67083c0e9812acc1dd71fade41a81f307669116))
- turn hero into Astro component ([77f9fcc](https://github.com/remvze/moodist/commit/77f9fcc50e54cecb31877eaccb3a578c291f99fe))
- turn sections into Astro components ([9398ae0](https://github.com/remvze/moodist/commit/9398ae0eddb4fac9695569a97a829bd518500363))
- use scrollIntoView instead of link ([4d2645f](https://github.com/remvze/moodist/commit/4d2645f06c846eea791f182224be0bc6e3db76dc))
### 0.0.1 (2023-10-05)
### 🚚 Chores
* add Commitizen 9d7cdde
* add Commitlint 50341d1
* add Editor Config a7d3495
* add ESLint be2a66e
* add Husky 3bed00a
* add Lint Staged 6cad460
* add npm config 297f7a7
* add path alias 123839d
* add PostCSS 332bd49
* add Prettier 110359b
* add Standard Version afc330e
* add Stylelint 0e5948f
- add Commitizen 9d7cdde
- add Commitlint 50341d1
- add Editor Config a7d3495
- add ESLint be2a66e
- add Husky 3bed00a
- add Lint Staged 6cad460
- add npm config 297f7a7
- add path alias 123839d
- add PostCSS 332bd49
- add Prettier 110359b
- add Standard Version afc330e
- add Stylelint 0e5948f

25
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,25 @@
# Contributing Guidelines
Thank you for considering contributing to our project! We welcome your contributions.
## How to Contribute
1. Fork the repository.
2. Create a new branch: `git checkout -b feature/your-feature-name`.
3. Make your changes and commit them: `git commit -m 'feat: add some feature'`.
4. Push to the branch: `git push origin feature/your-feature-name`.
5. Submit a pull request. ⚡
⚠️ **Notice**: Commit messages should follow [Conventional Commits Specification](https://www.conventionalcommits.org/en/v1.0.0/).
## Report Bugs
To report a bug, please open an issue on GitHub and provide detailed information about the bug, including steps to reproduce it.
## Request Features
To request a new feature, open an issue on GitHub and describe the feature you would like to see added.
## License
By contributing, you agree that your contributions will be licensed under the project's [LICENSE](LICENSE).

View File

@@ -1,11 +1,11 @@
FROM node:20-alpine3.18 AS build
FROM docker.io/node:20-alpine3.18 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine AS runtime
FROM docker.io/nginx:alpine AS runtime
COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY --from=build /app/dist /usr/share/nginx/html

View File

@@ -4,3 +4,85 @@
<p>Ambient sounds for focus and calm.</p>
<a href="https://moodist.app">Visit <strong>Moodist</strong></a> | <a href="https://buymeacoffee.com/remvze">Buy Me a Coffee</a>
</div>
## Table of Contents
- ⚡ [Features](#features)
- 🧰 [Tools](#tools)
- 🔮 [Commands](#commands)
- 🚧 [Contributing](#contributing)
- ⭐ [Support](#support-moodist)
- 📜 [License](#license)
## Features
1. 🎵 Over 75 ambient sounds
1. 📝 Persistent sound selection
1. ✈️ Sharing sound selections with others
1. 🧰 Custom sound presets
1. 🌙 Sleep timer for sounds
1. 📓 Notepad for quick notes
1. 🍅 Pomodoro timer
1. ✅ Simple to-do list (soon)
1. ⌨️ Keyboard shortcuts for everything
1. 🥷 Privacy focused: no data collection
1. 💰 Completely free, open-source, and self-hostable
## Tools
-**TypeScript**: Programming Language
- 🔨 **React**: UI Library
- 🧑‍🚀 **Astro**: Meta Framework
- 🎨 **CSS Modules**: Styling
- 🐻 **Zustand**: State Management
- 🎭 **Framer Motion**: Animation Library
- ⚙️ **Radix**: Accessible Components
- 📕 **Storybook**: Component Documentation
- 🧪 **Vitest**: Unit Testing (soon)
- 🔭 **Playwright**: End-To-End Testing (soon)
- 🔍 **ESLint**: Code Linting
- 🧹 **Prettier**: Code Formatting
- 🧼 **Stylelint**: CSS Linting
- 🐶 **Husky**: Git Hooks
- 📝 **Lint Staged**: Running Linters on Staged Files
- 🧽 **Commitlint**: Git Commit Linting
- 🧭 **Commitizen**: Git Commit Message Helper
- 📓 **Standard Version**: Versioning and CHANGLOG Generation
- 🧰 **PostCSS**: CSS Transformations
## Commands
- `npm run dev`: run development server
- `npm run build`: build for production
- `npm run preview`: preview the built app
- `npm run lint`: lint files using ESLint
- `npm run lint:fix`: lint and fix using ESLint
- `npm run lint:style`: lint styles using Stylelint
- `npm run lint:style:fix`: lint and fix styles using Stylelint
- `npm run format`: format files using Prettier
- `npm run commit`: commit message using Commitizen
- `npm run release:major`: release major version
- `npm run release:minor`: release minor version
- `npm run release:patch`: release patch version
- `npm run storybook`: run Storybook
## Contributing
🚧 Please check [CONTRIBUTING.md](CONTRIBUTING.md) file.
## Support Moodist
⭐ Give a star if you liked this project.
☕ [Buy Me a Coffee](https://buymeacoffee.com/remvze) to help me maintain Moodist.
## License
This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.
### ⚠️ Third-Party Assets
Some sounds used in this project are sourced from third-party providers and **are subject to different licenses**:
- Sounds licensed under the **Pixabay Content License**: [Pixabay Content License](https://pixabay.com/service/license-summary/)
- Sounds licensed under **CC0**: [Creative Commons Zero License](https://creativecommons.org/publicdomain/zero/1.0/)

View File

@@ -1,8 +1,7 @@
import { defineConfig } from 'astro/config';
import react from "@astrojs/react";
import react from '@astrojs/react';
// https://astro.build/config
export default defineConfig({
integrations: [react()]
});
integrations: [react()],
});

9418
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "moodist",
"type": "module",
"version": "1.4.2",
"version": "1.5.0",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
@@ -18,27 +18,43 @@
"release": "standard-version --no-verify",
"release:major": "npm run release -- --release-as major",
"release:minor": "npm run release -- --release-as minor",
"release:patch": "npm run release -- --release-as patch"
"release:patch": "npm run release -- --release-as patch",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"dependencies": {
"@astrojs/react": "^3.0.3",
"@floating-ui/react": "0.26.0",
"@radix-ui/react-dropdown-menu": "2.0.6",
"@radix-ui/react-tooltip": "1.0.7",
"@types/howler": "2.2.10",
"@types/react": "^18.2.25",
"@types/react-dom": "^18.2.10",
"astro": "4.0.3",
"deepmerge": "4.3.1",
"focus-trap-react": "10.2.3",
"framer-motion": "10.16.4",
"howler": "2.2.4",
"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",
"zustand": "4.4.3"
},
"devDependencies": {
"@chromatic-com/storybook": "1.3.3",
"@commitlint/cli": "17.7.2",
"@commitlint/config-conventional": "17.7.0",
"@storybook/addon-a11y": "8.0.9",
"@storybook/addon-essentials": "8.0.9",
"@storybook/addon-interactions": "8.0.9",
"@storybook/addon-links": "8.0.9",
"@storybook/addon-onboarding": "8.0.9",
"@storybook/blocks": "8.0.9",
"@storybook/react": "8.0.9",
"@storybook/react-vite": "8.0.9",
"@storybook/test": "8.0.9",
"@typescript-eslint/eslint-plugin": "6.7.4",
"@typescript-eslint/parser": "6.7.4",
"astro-eslint-parser": "0.16.0",
@@ -57,6 +73,7 @@
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-sort-destructure-keys": "1.5.0",
"eslint-plugin-sort-keys-fix": "1.1.2",
"eslint-plugin-storybook": "0.8.0",
"eslint-plugin-typescript-sort-keys": "3.1.0",
"husky": "8.0.3",
"lint-staged": "14.0.1",
@@ -64,7 +81,9 @@
"postcss-nesting": "12.0.1",
"prettier": "3.0.3",
"prettier-plugin-astro": "0.12.0",
"prop-types": "15.8.1",
"standard-version": "9.5.0",
"storybook": "8.0.9",
"stylelint": "15.10.3",
"stylelint-config-html": "1.1.0",
"stylelint-config-recess-order": "4.4.0",

View File

@@ -83,8 +83,14 @@
transform: translateX(-50%);
}
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-neutral-100);
}
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
}

View File

@@ -14,13 +14,18 @@ import { Toolbar } from '@/components/toolbar';
import { SnackbarProvider } from '@/contexts/snackbar';
import { sounds } from '@/data/sounds';
import { FADE_OUT } from '@/constants/events';
import type { Sound } from '@/data/types';
import { subscribe } from '@/lib/event';
export function App() {
const categories = useMemo(() => sounds.categories, []);
const favorites = useSoundStore(useShallow(state => state.getFavorites()));
const pause = useSoundStore(state => state.pause);
const lock = useSoundStore(state => state.lock);
const unlock = useSoundStore(state => state.unlock);
const favoriteSounds = useMemo(() => {
const favoriteSounds = categories
@@ -52,6 +57,19 @@ export function App() {
return () => document.removeEventListener('visibilitychange', onChange);
}, []);
useEffect(() => {
const unsubscribe = subscribe(FADE_OUT, (e: { duration: number }) => {
lock();
setTimeout(() => {
pause();
unlock();
}, e.duration);
});
return unsubscribe;
}, [pause, lock, unlock]);
const allCategories = useMemo(() => {
const favorites = [];

View File

@@ -12,7 +12,6 @@
background-color: var(--color-neutral-950);
border: 1px solid var(--color-neutral-50);
border-radius: 100px;
outline: none;
transition: 0.2s;
&:hover {
@@ -27,4 +26,9 @@
& span {
font-size: var(--font-lg);
}
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}

View File

@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useCallback, useEffect } from 'react';
import { BiPause, BiPlay } from 'react-icons/bi/index';
import { useSoundStore } from '@/store';
@@ -12,24 +12,39 @@ export function PlayButton() {
const pause = useSoundStore(state => state.pause);
const toggle = useSoundStore(state => state.togglePlay);
const noSelected = useSoundStore(state => state.noSelected());
const locked = useSoundStore(state => state.locked);
const showSnackbar = useSnackbar();
const handleClick = () => {
const handleToggle = useCallback(() => {
if (locked) return;
if (noSelected) return showSnackbar('Please first select a sound to play.');
toggle();
};
}, [showSnackbar, toggle, noSelected, locked]);
useEffect(() => {
if (isPlaying && noSelected) pause();
}, [isPlaying, pause, noSelected]);
useEffect(() => {
const listener = (e: KeyboardEvent) => {
if (e.shiftKey && e.key === ' ') {
handleToggle();
}
};
document.addEventListener('keydown', listener);
return () => document.removeEventListener('keydown', listener);
}, [handleToggle]);
return (
<button
aria-disabled={noSelected}
className={cn(styles.playButton, noSelected && styles.disabled)}
onClick={handleClick}
onClick={handleToggle}
>
{isPlaying ? (
<>

View File

@@ -12,7 +12,6 @@
background-color: var(--color-neutral-100);
border: 1px solid var(--color-neutral-300);
border-radius: 100px;
outline: none;
transition: 0.2s;
&:disabled,
@@ -20,9 +19,15 @@
cursor: not-allowed;
}
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-neutral-200);
}
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
.tooltip {

View File

@@ -1,3 +1,4 @@
import { useEffect, useCallback } from 'react';
import { BiUndo, BiTrash } from 'react-icons/bi/index';
import { AnimatePresence, motion } from 'framer-motion';
@@ -14,12 +15,31 @@ export function UnselectButton() {
const restoreHistory = useSoundStore(state => state.restoreHistory);
const hasHistory = useSoundStore(state => !!state.history);
const unselectAll = useSoundStore(state => state.unselectAll);
const locked = useSoundStore(state => state.locked);
const variants = {
...mix(fade(), slideX(15)),
exit: { opacity: 0 },
};
const handleToggle = useCallback(() => {
if (locked) return;
if (hasHistory) restoreHistory();
else if (!noSelected) unselectAll(true);
}, [hasHistory, noSelected, unselectAll, restoreHistory, locked]);
useEffect(() => {
const listener = (e: KeyboardEvent) => {
if (e.shiftKey && e.key === 'R') {
handleToggle();
}
};
document.addEventListener('keydown', listener);
return () => document.removeEventListener('keydown', listener);
}, [handleToggle]);
return (
<>
<AnimatePresence mode="wait">
@@ -31,7 +51,6 @@ export function UnselectButton() {
variants={variants}
>
<Tooltip
hideDelay={0}
showDelay={0}
content={
hasHistory
@@ -50,10 +69,7 @@ export function UnselectButton() {
styles.unselectButton,
noSelected && !hasHistory && styles.disabled,
)}
onClick={() => {
if (hasHistory) restoreHistory();
else if (!noSelected) unselectAll(true);
}}
onClick={handleToggle}
>
{hasHistory ? <BiUndo /> : <BiTrash />}
</button>

View File

@@ -2,7 +2,7 @@
display: flex;
column-gap: 8px;
align-items: center;
justify-content: flex-start;
justify-content: space-between;
width: 100%;
height: 40px;
min-height: 40px;
@@ -24,12 +24,20 @@
opacity: 0.4;
}
&:not(:disabled):hover {
&:not(:disabled):hover,
&:not(:disabled):focus-visible {
color: var(--color-foreground);
background-color: var(--color-neutral-200);
border: 1px solid var(--color-neutral-300);
}
& .label {
display: flex;
column-gap: 8px;
align-items: center;
justify-content: flex-start;
}
& .icon {
color: var(--color-foreground);
}
@@ -40,4 +48,8 @@
background: var(--color-neutral-950);
border-radius: 50%;
}
& .shortcut {
font-size: var(--font-2xsm);
}
}

View File

@@ -1,3 +1,6 @@
import { FiExternalLink } from 'react-icons/fi/index';
import { Item as DropdownItem } from '@radix-ui/react-dropdown-menu';
import styles from './item.module.css';
interface ItemProps {
@@ -7,6 +10,7 @@ interface ItemProps {
icon: React.ReactElement;
label: string;
onClick?: () => void;
shortcut?: string;
}
export function Item({
@@ -16,18 +20,31 @@ export function Item({
icon,
label,
onClick = () => {},
shortcut,
}: ItemProps) {
const Comp = href ? 'a' : 'button';
return (
<Comp
className={styles.item}
disabled={disabled}
onClick={onClick}
{...(href ? { href, target: '_blank' } : {})}
>
<span className={styles.icon}>{icon}</span> {label}
{active && <div className={styles.active} />}
</Comp>
<DropdownItem asChild onClick={onClick}>
<Comp
className={styles.item}
disabled={disabled}
{...(href ? { href, target: '_blank' } : {})}
aria-label={label}
>
<span className={styles.label}>
<span className={styles.icon}>{icon}</span> {label}
{active && <div className={styles.active} />}
</span>
{shortcut && <span className={styles.shortcut}>{shortcut}</span>}
{href && (
<span className={styles.external}>
<FiExternalLink />
</span>
)}
</Comp>
</DropdownItem>
);
}

View File

@@ -0,0 +1,13 @@
import { MdOutlineTimer } from 'react-icons/md/index';
import { Item } from '../item';
export function CountdownTimer() {
return (
<Item
href="https://timesy.app"
icon={<MdOutlineTimer />}
label="Countdown Timer"
/>
);
}

View File

@@ -5,3 +5,6 @@ export { Notepad as NotepadItem } from './notepad';
export { Source as SourceItem } from './source';
export { Pomodoro as PomodoroItem } from './pomodoro';
export { Presets as PresetsItem } from './presets';
export { Shortcuts as ShortcutsItem } from './shortcuts';
export { SleepTimer as SleepTimerItem } from './sleep-timer';
export { CountdownTimer as CountdownTimerItem } from './countdown-timer';

View File

@@ -16,6 +16,7 @@ export function Notepad({ open }: NotepadProps) {
active={!!note.length}
icon={<MdNotes />}
label="Notepad"
shortcut="Shift + N"
onClick={open}
/>
);

View File

@@ -16,6 +16,7 @@ export function Pomodoro({ open }: PomodoroProps) {
active={running}
icon={<MdOutlineAvTimer />}
label="Pomodoro"
shortcut="Shift + P"
onClick={open}
/>
);

View File

@@ -7,5 +7,12 @@ interface PresetsProps {
}
export function Presets({ open }: PresetsProps) {
return <Item icon={<RiPlayListFill />} label="Your Presets" onClick={open} />;
return (
<Item
icon={<RiPlayListFill />}
label="Your Presets"
shortcut="Shift + Alt + P"
onClick={open}
/>
);
}

View File

@@ -16,6 +16,7 @@ export function Share({ open }: ShareProps) {
disabled={noSelected}
icon={<IoShareSocialSharp />}
label="Share Sounds"
shortcut="Shift + S"
onClick={open}
/>
);

View File

@@ -0,0 +1,18 @@
import { MdKeyboardCommandKey } from 'react-icons/md/index';
import { Item } from '../item';
interface ShortcutsProps {
open: () => void;
}
export function Shortcuts({ open }: ShortcutsProps) {
return (
<Item
icon={<MdKeyboardCommandKey />}
label="Shortcuts"
shortcut="Shift + H"
onClick={open}
/>
);
}

View File

@@ -6,6 +6,14 @@ import { Item } from '../item';
export function Shuffle() {
const shuffle = useSoundStore(state => state.shuffle);
const locked = useSoundStore(state => state.locked);
return <Item icon={<BiShuffle />} label="Shuffle Sounds" onClick={shuffle} />;
return (
<Item
disabled={locked}
icon={<BiShuffle />}
label="Shuffle Sounds"
onClick={shuffle}
/>
);
}

View File

@@ -0,0 +1,18 @@
import { IoMoonSharp } from 'react-icons/io5/index';
import { Item } from '../item';
interface SleepTimerProps {
open: () => void;
}
export function SleepTimer({ open }: SleepTimerProps) {
return (
<Item
icon={<IoMoonSharp />}
label="Sleep Timer"
shortcut="Shift + T"
onClick={open}
/>
);
}

View File

@@ -13,21 +13,29 @@
border-radius: 50%;
transition: 0.2s;
&:hover {
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&:hover,
&:focus-visible {
background-color: var(--color-neutral-200);
}
}
& .menu {
display: flex;
flex-direction: column;
row-gap: 4px;
width: 240px;
height: max-content;
padding: 4px;
overflow: auto;
background-color: var(--color-neutral-100);
border: 1px solid var(--color-neutral-300);
border-radius: 4px;
}
}
.menu {
z-index: 15;
display: flex;
flex-direction: column;
row-gap: 4px;
width: 250px;
height: max-content;
max-height: var(--radix-dropdown-menu-content-available-height);
padding: 4px;
overflow: auto;
background-color: var(--color-neutral-100);
border: 1px solid var(--color-neutral-300);
border-radius: 4px;
}

View File

@@ -1,18 +1,8 @@
import { useState } from 'react';
import { useState, useMemo, useCallback } from 'react';
import { IoMenu, IoClose } from 'react-icons/io5/index';
import {
useFloating,
autoUpdate,
offset,
flip,
shift,
size,
useClick,
useDismiss,
useRole,
useInteractions,
FloatingFocusManager,
} from '@floating-ui/react';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import { useHotkeys } from 'react-hotkeys-hook';
import { AnimatePresence, motion } from 'framer-motion';
import {
ShuffleItem,
@@ -22,96 +12,140 @@ import {
SourceItem,
PomodoroItem,
PresetsItem,
ShortcutsItem,
SleepTimerItem,
CountdownTimerItem,
} from './items';
import { Divider } from './divider';
import { ShareLinkModal } from '@/components/modals/share-link';
import { PresetsModal } from '@/components/modals/presets';
import { ShortcutsModal } from '@/components/modals/shortcuts';
import { SleepTimerModal } from '@/components/modals/sleep-timer';
import { Notepad, Pomodoro } from '@/components/toolbox';
import { fade, mix, slideY } from '@/lib/motion';
import { useSoundStore } from '@/store';
import styles from './menu.module.css';
import { useCloseListener } from '@/hooks/use-close-listener';
import { closeModals } from '@/lib/modal';
export function Menu() {
const [isOpen, setIsOpen] = useState(false);
const [showPresets, setShowPresets] = useState(false);
const [showShareLink, setShowShareLink] = useState(false);
const [showNotepad, setShowNotepad] = useState(false);
const [showPomodoro, setShowPomodoro] = useState(false);
const noSelected = useSoundStore(state => state.noSelected());
const { context, floatingStyles, refs } = useFloating({
middleware: [
offset(12),
flip(),
shift(),
size({
apply({ availableHeight, elements }) {
Object.assign(elements.floating.style, {
maxHeight: `${availableHeight}px`,
});
},
padding: 10,
}),
],
onOpenChange: setIsOpen,
open: isOpen,
placement: 'top-end',
whileElementsMounted: autoUpdate,
});
const initial = useMemo(
() => ({
notepad: false,
pomodoro: false,
presets: false,
shareLink: false,
shortcuts: false,
sleepTimer: false,
}),
[],
);
const click = useClick(context);
const dismiss = useDismiss(context);
const role = useRole(context);
const [modals, setModals] = useState(initial);
const { getFloatingProps, getReferenceProps } = useInteractions([
click,
dismiss,
role,
]);
const close = useCallback((name: string) => {
setModals(prev => ({ ...prev, [name]: false }));
}, []);
const closeAll = useCallback(() => setModals(initial), [initial]);
const open = useCallback(
(name: string) => {
closeAll();
setIsOpen(false);
closeModals();
setModals(prev => ({ ...prev, [name]: true }));
},
[closeAll],
);
useHotkeys('shift+m', () => setIsOpen(prev => !prev));
useHotkeys('shift+n', () => open('notepad'));
useHotkeys('shift+p', () => open('pomodoro'));
useHotkeys('shift+alt+p', () => open('presets'));
useHotkeys('shift+h', () => open('shortcuts'));
useHotkeys('shift+s', () => open('shareLink'), { enabled: !noSelected });
useHotkeys('shift+t', () => open('sleepTimer'));
useCloseListener(closeAll);
const variants = mix(fade(), slideY());
return (
<>
<div className={styles.wrapper}>
<button
aria-label="Menu"
className={styles.menuButton}
ref={refs.setReference}
onClick={() => setIsOpen(prev => !prev)}
{...getReferenceProps()}
>
{isOpen ? <IoClose /> : <IoMenu />}
</button>
<DropdownMenu.Root open={isOpen} onOpenChange={o => setIsOpen(o)}>
<DropdownMenu.Trigger asChild>
<button aria-label="Menu" className={styles.menuButton}>
{isOpen ? <IoClose /> : <IoMenu />}
</button>
</DropdownMenu.Trigger>
{isOpen && (
<FloatingFocusManager context={context} modal={false}>
<div
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps()}
className={styles.menu}
>
<PresetsItem open={() => setShowPresets(true)} />
<ShareItem open={() => setShowShareLink(true)} />
<ShuffleItem />
<Divider />
<NotepadItem open={() => setShowNotepad(true)} />
<PomodoroItem open={() => setShowPomodoro(true)} />
<Divider />
<DonateItem />
<SourceItem />
</div>
</FloatingFocusManager>
)}
<AnimatePresence>
{isOpen && (
<DropdownMenu.Portal forceMount>
<DropdownMenu.Content
align="end"
asChild
collisionPadding={10}
side="top"
sideOffset={12}
>
<motion.div
animate="show"
className={styles.menu}
exit="hidden"
initial="hidden"
variants={variants}
>
<PresetsItem open={() => open('presets')} />
<ShareItem open={() => open('shareLink')} />
<ShuffleItem />
<SleepTimerItem open={() => open('sleepTimer')} />
<Divider />
<NotepadItem open={() => open('notepad')} />
<PomodoroItem open={() => open('pomodoro')} />
<CountdownTimerItem />
<Divider />
<ShortcutsItem open={() => open('shortcuts')} />
<Divider />
<DonateItem />
<SourceItem />
</motion.div>
</DropdownMenu.Content>
</DropdownMenu.Portal>
)}
</AnimatePresence>
</DropdownMenu.Root>
</div>
<ShareLinkModal
show={showShareLink}
onClose={() => setShowShareLink(false)}
show={modals.shareLink}
onClose={() => close('shareLink')}
/>
<ShortcutsModal
show={modals.shortcuts}
onClose={() => close('shortcuts')}
/>
<PresetsModal show={modals.presets} onClose={() => close('presets')} />
<Notepad show={modals.notepad} onClose={() => close('notepad')} />
<Pomodoro
open={() => open('pomodoro')}
show={modals.pomodoro}
onClose={() => close('pomodoro')}
/>
<SleepTimerModal
show={modals.sleepTimer}
onClose={() => close('sleepTimer')}
/>
<PresetsModal show={showPresets} onClose={() => setShowPresets(false)} />
<Notepad show={showNotepad} onClose={() => setShowNotepad(false)} />
<Pomodoro show={showPomodoro} onClose={() => setShowPomodoro(false)} />
</>
);
}

View File

@@ -50,7 +50,13 @@
cursor: pointer;
background-color: transparent;
border: none;
border-radius: 4px;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
}
}

View File

@@ -0,0 +1,26 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Modal } from './modal';
const meta: Meta<typeof Modal> = {
component: Modal,
title: 'Modal',
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
children: 'Hello World',
show: true,
},
};
export const Wide: Story = {
args: {
...Default.args,
wide: true,
},
};

View File

@@ -1,6 +1,7 @@
import { useEffect } from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { IoClose } from 'react-icons/io5/index';
import FocusTrap from 'focus-trap-react';
import { Portal } from '@/components/portal';
@@ -37,36 +38,50 @@ export function Modal({
}
}, [show, lockBody]);
useEffect(() => {
function keyListener(e: KeyboardEvent) {
if (show && e.key === 'Escape') {
onClose();
}
}
document.addEventListener('keydown', keyListener);
return () => document.removeEventListener('keydown', keyListener);
}, [onClose, show]);
return (
<Portal>
<AnimatePresence>
{show && (
<>
<motion.div
animate="show"
className={styles.overlay}
exit="hidden"
initial="hidden"
variants={variants.overlay}
onClick={onClose}
onKeyDown={onClose}
/>
<div className={styles.modal}>
<FocusTrap>
<div>
<motion.div
animate="show"
className={cn(styles.content, wide && styles.wide)}
className={styles.overlay}
exit="hidden"
initial="hidden"
variants={variants.modal}
>
<button className={styles.close} onClick={onClose}>
<IoClose />
</button>
variants={variants.overlay}
onClick={onClose}
onKeyDown={onClose}
/>
<div className={styles.modal}>
<motion.div
animate="show"
className={cn(styles.content, wide && styles.wide)}
exit="hidden"
initial="hidden"
variants={variants.modal}
>
<button className={styles.close} onClick={onClose}>
<IoClose />
</button>
{children}
</motion.div>
{children}
</motion.div>
</div>
</div>
</>
</FocusTrap>
)}
</AnimatePresence>
</Portal>

View File

@@ -34,6 +34,11 @@
background: transparent;
border: none;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
& button {
@@ -51,6 +56,11 @@
border-radius: 4px;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&.primary {
font-size: var(--font-xsm);
color: var(--color-foreground);

View File

@@ -31,6 +31,11 @@
background: transparent;
border: none;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
& button {
@@ -48,6 +53,11 @@
border-radius: 4px;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&:disabled {
cursor: not-allowed;
}

View File

@@ -31,6 +31,11 @@
background: transparent;
border: none;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
& button {
@@ -47,7 +52,13 @@
outline: none;
transition: 0.2s;
&:hover {
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&:hover,
&:focus-visible {
background-color: var(--color-neutral-200);
}
}

View File

@@ -51,7 +51,13 @@
outline: none;
transition: 0.2s;
&:hover {
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&:hover,
&:focus-visible {
color: var(--color-foreground);
background-color: var(--color-neutral-300);
}
@@ -60,7 +66,8 @@
color: var(--color-neutral-200);
background-color: var(--color-neutral-950);
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-neutral-800);
}
}

View File

@@ -4,6 +4,7 @@ import { Modal } from '@/components/modal';
import { useSoundStore } from '@/store';
import { useSnackbar } from '@/contexts/snackbar';
import { useCloseListener } from '@/hooks/use-close-listener';
import { cn } from '@/helpers/styles';
import { sounds } from '@/data/sounds';
@@ -77,6 +78,8 @@ export function SharedModal() {
showSnackbar('Done! You can now play the new selection.');
};
useCloseListener(() => setIsOpen(false));
return (
<Modal show={isOpen} onClose={() => setIsOpen(false)}>
<h1 className={styles.heading}>New sound mix detected!</h1>

View File

@@ -0,0 +1 @@
export { ShortcutsModal } from './shortcuts';

View File

@@ -0,0 +1,47 @@
.heading {
margin-bottom: 20px;
font-family: var(--font-heading);
font-size: var(--font-md);
font-weight: 600;
}
.shortcuts {
display: flex;
flex-direction: column;
row-gap: 12px;
}
.row {
display: flex;
column-gap: 12px;
align-items: center;
justify-content: space-between;
& .label {
font-weight: 500;
color: var(--color-foreground-subtle);
}
& .divider {
flex-grow: 1;
height: 1px;
background-color: var(--color-neutral-200);
}
& .keys {
display: flex;
column-gap: 8px;
align-items: center;
}
}
.key {
padding: 6px 8px;
font-size: var(--font-2xsm);
background-color: var(--color-neutral-100);
border: 1px solid var(--color-neutral-200);
border-radius: 4px;
box-shadow:
inset 0 1px 1px var(--color-neutral-400),
inset 0 -2px 0 var(--color-neutral-50);
}

View File

@@ -0,0 +1,87 @@
import { Modal } from '@/components/modal';
import styles from './shortcuts.module.css';
interface ShortcutsModalProps {
onClose: () => void;
show: boolean;
}
export function ShortcutsModal({ onClose, show }: ShortcutsModalProps) {
const shortcuts = [
{
keys: ['Shift', 'H'],
label: 'Shortcuts List',
},
{
keys: ['Shift', 'Alt', 'P'],
label: 'Presets',
},
{
keys: ['Shift', 'S'],
label: 'Share Sounds',
},
{
keys: ['Shift', 'N'],
label: 'Notepad',
},
{
keys: ['Shift', 'P'],
label: 'Pomodoro Timer',
},
{
keys: ['Shift', 'T'],
label: 'Sleep Timer',
},
{
keys: ['Shift', 'Space'],
label: 'Toggle Play',
},
{
keys: ['Shift', 'R'],
label: 'Unselect All Sounds',
},
];
return (
<Modal show={show} onClose={onClose}>
<h1 className={styles.heading}>Keyboard Shortcuts</h1>
<div className={styles.shortcuts}>
{shortcuts.map(shortcut => (
<Row
key={shortcut.label}
keys={shortcut.keys}
label={shortcut.label}
/>
))}
</div>
</Modal>
);
}
interface RowProps {
keys: Array<string>;
label: string;
}
function Row({ keys, label }: RowProps) {
return (
<div className={styles.row}>
<p className={styles.label}>{label}</p>
<div className={styles.divider} />
<div className={styles.keys}>
{keys.map(key => (
<Key key={`${label}-${key}`}>{key}</Key>
))}
</div>
</div>
);
}
interface KeyProps {
children: React.ReactNode;
}
function Key({ children }: KeyProps) {
return <div className={styles.key}>{children}</div>;
}

View File

@@ -0,0 +1 @@
export { SleepTimerModal } from './sleep-timer';

View File

@@ -0,0 +1,92 @@
.header {
margin-bottom: 16px;
& .title {
margin-bottom: 8px;
font-family: var(--font-heading);
font-size: var(--font-md);
font-weight: 600;
}
& .desc {
color: var(--color-foreground-subtle);
}
}
.controls {
margin-top: 8px;
& .inputs {
display: flex;
column-gap: 12px;
align-items: flex-end;
width: 100%;
& .field {
flex-grow: 1;
& .label {
display: block;
margin-bottom: 4px;
font-weight: 500;
}
& .input {
display: block;
width: 100%;
min-width: 0;
height: 40px;
padding: 0 8px;
color: var(--color-foreground);
background-color: var(--color-neutral-50);
border: 1px solid var(--color-neutral-200);
border-radius: 4px;
outline: none;
}
}
}
& .buttons {
display: flex;
column-gap: 8px;
align-items: center;
justify-content: flex-end;
width: 100%;
margin-top: 16px;
& .button {
padding: 12px 16px;
font-family: var(--font-heading);
font-size: var(--font-sm);
font-weight: 600;
color: var(--color-foreground-subtle);
cursor: pointer;
background-color: var(--color-neutral-200);
border: none;
border-radius: 4px;
outline: none;
transition: 0.2s;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&:hover,
&:focus-visible {
color: var(--color-foreground);
background-color: var(--color-neutral-300);
}
&.primary {
color: var(--color-neutral-200);
background-color: var(--color-neutral-950);
&:hover,
&:focus-visible {
background-color: var(--color-neutral-800);
}
}
}
}
}

View File

@@ -0,0 +1,157 @@
import { useEffect, useState, useRef, useMemo } from 'react';
import { Modal } from '@/components/modal';
import { Timer } from '@/components/timer';
import { dispatch } from '@/lib/event';
import { useSoundStore } from '@/store';
import { cn } from '@/helpers/styles';
import { FADE_OUT } from '@/constants/events';
import styles from './sleep-timer.module.css';
interface SleepTimerModalProps {
onClose: () => void;
show: boolean;
}
export function SleepTimerModal({ onClose, show }: SleepTimerModalProps) {
const [running, setRunning] = useState(false);
const [hours, setHours] = useState<string>('0');
const [minutes, setMinutes] = useState<string>('10');
const totalSeconds = useMemo(
() =>
(hours === '' ? 0 : parseInt(hours)) * 3600 +
(minutes === '' ? 0 : parseInt(minutes)) * 60,
[hours, minutes],
);
const [timeSpent, setTimeSpent] = useState(0);
const timeLeft = useMemo(
() => totalSeconds - timeSpent,
[totalSeconds, timeSpent],
);
const timerId = useRef<ReturnType<typeof setInterval>>();
const isPlaying = useSoundStore(state => state.isPlaying);
const play = useSoundStore(state => state.play);
const pause = useSoundStore(state => state.pause);
const handleStart = () => {
if (timerId.current) clearInterval(timerId.current);
if (!isPlaying) play();
if (totalSeconds > 0) {
setRunning(true);
const newTimerId = setInterval(() => {
setTimeSpent(prev => prev + 1);
}, 1000);
timerId.current = newTimerId;
}
};
useEffect(() => {
if (timeLeft === 0) {
setRunning(false);
// pause();
dispatch(FADE_OUT, { duration: 1000 });
setTimeSpent(0);
if (timerId.current) clearInterval(timerId.current);
}
}, [timeLeft, pause]);
const handleReset = () => {
if (timerId.current) clearInterval(timerId.current);
setTimeSpent(0);
setHours('0');
setMinutes('10');
setRunning(false);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
handleStart();
};
return (
<Modal show={show} onClose={onClose}>
<header className={styles.header}>
<h2 className={styles.title}>Sleep Timer</h2>
<p className={styles.desc}>
Stop sounds after a certain amount of time.
</p>
</header>
<form onSubmit={handleSubmit}>
<div className={styles.controls}>
<div className={styles.inputs}>
{!running && (
<Field label="Hours" value={hours} onChange={setHours} />
)}
{!running && (
<Field label="Minutes" value={minutes} onChange={setMinutes} />
)}
</div>
{running ? <Timer displayHours={true} timer={timeLeft} /> : null}
<div className={styles.buttons}>
{running && (
<button
className={styles.button}
type="button"
onClick={handleReset}
>
Reset
</button>
)}
{!running && (
<button
className={cn(styles.button, styles.primary)}
type="submit"
>
Start
</button>
)}
</div>
</div>
</form>
</Modal>
);
}
interface FieldProps {
label: string;
onChange: (value: string) => void;
value: string;
}
function Field({ label, onChange, value }: FieldProps) {
return (
<div className={styles.field}>
<label className={styles.label} htmlFor={label.toLocaleLowerCase()}>
{label}
</label>
<input
className={styles.input}
id={label.toLocaleLowerCase()}
max="59"
min="0"
required
type="number"
value={value}
onChange={e => onChange(e.target.value === '' ? '' : e.target.value)}
/>
</div>
);
}

View File

@@ -12,7 +12,13 @@
border-radius: 50%;
transition: 0.2s;
&:hover {
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&:hover,
&:focus-visible {
background-color: var(--color-neutral-200);
}
}

View File

@@ -9,7 +9,7 @@ export function Shuffle() {
const shuffle = useSoundStore(state => state.shuffle);
return (
<Tooltip content="Shuffle sounds" hideDelay={0} showDelay={0}>
<Tooltip content="Shuffle sounds" showDelay={0}>
<button
aria-label="Shuffle sounds"
className={styles.button}

View File

@@ -0,0 +1,18 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Snackbar } from './snackbar';
const meta: Meta<typeof Snackbar> = {
component: Snackbar,
title: 'Snackbar',
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
message: 'Hello World',
},
};

View File

@@ -14,13 +14,18 @@
background-color: var(--color-neutral-100);
border: 1px solid var(--color-neutral-200);
border-radius: 50%;
outline: none;
transition: 0.2s;
&:hover {
&:hover,
&:focus-visible {
color: var(--color-foreground);
}
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&.isFavorite {
color: var(--color-foreground);
}

View File

@@ -7,21 +7,33 @@ import { fade } from '@/lib/motion';
import styles from './favorite.module.css';
import { useKeyboardButton } from '@/hooks/use-keyboard-button';
interface FavoriteProps {
id: string;
label: string;
}
export function Favorite({ id }: FavoriteProps) {
export function Favorite({ id, label }: FavoriteProps) {
const isFavorite = useSoundStore(state => state.sounds[id].isFavorite);
const toggleFavorite = useSoundStore(state => state.toggleFavorite);
const variants = fade();
const handleKeyDown = useKeyboardButton(() => {
toggleFavorite(id);
});
return (
<AnimatePresence initial={false} mode="wait">
<button
aria-label="Add Sound to Favorites"
className={cn(styles.favoriteButton, isFavorite && styles.isFavorite)}
aria-label={
isFavorite
? `Remove ${label} Sound from Favorites`
: `Add ${label} Sound to Favorites`
}
onKeyDown={handleKeyDown}
onClick={e => {
e.stopPropagation();
toggleFavorite(id);

View File

@@ -4,16 +4,18 @@ import styles from './range.module.css';
interface RangeProps {
id: string;
label: string;
}
export function Range({ id }: RangeProps) {
export function Range({ id, label }: RangeProps) {
const setVolume = useSoundStore(state => state.setVolume);
const volume = useSoundStore(state => state.sounds[id].volume);
const isSelected = useSoundStore(state => state.sounds[id].isSelected);
const locked = useSoundStore(state => state.locked);
return (
<input
aria-labelledby={id}
aria-label={`${label} sound volume`}
autoComplete="off"
className={styles.range}
disabled={!isSelected}
@@ -21,8 +23,10 @@ export function Range({ id }: RangeProps) {
min={0}
type="range"
value={volume * 100}
onChange={e => isSelected && setVolume(id, Number(e.target.value) / 100)}
onClick={e => e.stopPropagation()}
onChange={e =>
!locked && isSelected && setVolume(id, Number(e.target.value) / 100)
}
/>
);
}

View File

@@ -11,6 +11,11 @@
border-radius: 8px;
transition: 0.2s;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&.hidden {
display: none;
}
@@ -78,7 +83,8 @@
}
}
&:hover .icon {
&:hover .icon,
&:focus-visible .icon {
color: var(--color-foreground-subtle);
}

View File

@@ -1,4 +1,4 @@
import { useCallback, useEffect } from 'react';
import { useCallback, useEffect, forwardRef } from 'react';
import { ImSpinner9 } from 'react-icons/im/index';
import { Range } from './range';
@@ -10,25 +10,21 @@ import { cn } from '@/helpers/styles';
import styles from './sound.module.css';
import type { Sound } from '@/data/types';
import type { Sound as SoundType } from '@/data/types';
interface SoundProps extends Sound {
import { useKeyboardButton } from '@/hooks/use-keyboard-button';
interface SoundProps extends SoundType {
functional: boolean;
hidden: boolean;
selectHidden: (key: string) => void;
unselectHidden: (key: string) => void;
}
export function Sound({
functional,
hidden,
icon,
id,
label,
selectHidden,
src,
unselectHidden,
}: SoundProps) {
export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
{ functional, hidden, icon, id, label, selectHidden, src, unselectHidden },
ref,
) {
const isPlaying = useSoundStore(state => state.isPlaying);
const play = useSoundStore(state => state.play);
const select = useSoundStore(state => state.select);
@@ -36,18 +32,21 @@ export function Sound({
const setVolume = useSoundStore(state => state.setVolume);
const volume = useSoundStore(state => state.sounds[id].volume);
const isSelected = useSoundStore(state => state.sounds[id].isSelected);
const locked = useSoundStore(state => state.locked);
const isLoading = useLoadingStore(state => state.loaders[src]);
const sound = useSound(src, { loop: true, volume });
useEffect(() => {
if (locked) return;
if (isSelected && isPlaying && functional) {
sound?.play();
} else {
sound?.pause();
}
}, [isSelected, sound, isPlaying, functional]);
}, [isSelected, sound, isPlaying, functional, locked]);
useEffect(() => {
if (hidden && isSelected) selectHidden(label);
@@ -55,32 +54,46 @@ export function Sound({
}, [label, isSelected, hidden, selectHidden, unselectHidden]);
const _select = useCallback(() => {
if (locked) return;
select(id);
play();
}, [select, play, id]);
}, [select, play, id, locked]);
const _unselect = useCallback(() => {
if (locked) return;
unselect(id);
setVolume(id, 0.5);
}, [unselect, setVolume, id]);
}, [unselect, setVolume, id, locked]);
const toggle = useCallback(() => {
if (isSelected) return _unselect();
if (locked) return;
if (isSelected) _unselect();
else _select();
}, [isSelected, _select, _unselect, locked]);
_select();
}, [isSelected, _unselect, _select]);
const handleClick = useCallback(() => {
toggle();
}, [toggle]);
const handleKeyDown = useKeyboardButton(() => {
toggle();
});
return (
<div
aria-label={`${label} sound`}
ref={ref}
role="button"
tabIndex={0}
className={cn(
styles.sound,
isSelected && styles.selected,
hidden && styles.hidden,
)}
onClick={toggle}
onKeyDown={toggle}
onClick={handleClick}
onKeyDown={handleKeyDown}
>
<Favorite id={id} />
<Favorite id={id} label={label} />
<div className={styles.icon}>
{isLoading ? (
<span className={styles.spinner}>
@@ -93,7 +106,7 @@ export function Sound({
<div className={styles.label} id={id}>
{label}
</div>
<Range id={id} />
<Range id={id} label={label} />
</div>
);
}
});

View File

@@ -20,6 +20,17 @@
background-color: var(--color-neutral-50);
border: 1px solid var(--color-neutral-200);
border-radius: 50px;
transition: 0.2s;
&:hover,
&:focus-visible {
background-color: var(--color-neutral-100);
}
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&::before {
position: absolute;

View File

@@ -1,4 +1,4 @@
import { useState, useMemo, useCallback } from 'react';
import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { Sound } from '@/components/sound';
@@ -18,6 +18,20 @@ interface SoundsProps {
export function Sounds({ functional, id, sounds }: SoundsProps) {
const [showAll, setShowAll] = useLocalStorage(`${id}-show-more`, false);
const [clickedMore, setClickedMore] = useState(false);
const [isAnimating, setIsAnimating] = useState(false);
const firstNewSound = useRef<HTMLDivElement>(null);
useEffect(() => {
if (showAll && clickedMore) {
firstNewSound.current?.focus();
setClickedMore(false);
}
}, [showAll, clickedMore]);
const showMoreButton = useRef<HTMLButtonElement>(null);
const [hiddenSelections, setHiddenSelections] = useState<{
[key: string]: boolean;
@@ -43,6 +57,13 @@ export function Sounds({ functional, id, sounds }: SoundsProps) {
}));
}, []);
const toggleMore = () => {
if (!isAnimating) {
setShowAll(prev => !prev);
setClickedMore(true);
}
};
const variants = mix(fade(), scale(0.9));
return (
@@ -54,6 +75,7 @@ export function Sounds({ functional, id, sounds }: SoundsProps) {
{...sound}
functional={functional}
hidden={!showAll && index > 5}
ref={index === 6 ? firstNewSound : undefined}
selectHidden={selectHidden}
unselectHidden={unselectHidden}
/>
@@ -66,23 +88,28 @@ export function Sounds({ functional, id, sounds }: SoundsProps) {
</div>
{sounds.length > 6 && (
<AnimatePresence initial={false} mode="wait">
<motion.button
animate="show"
exit="hidden"
initial="hidden"
key={showAll ? `${id}-show-less` : `${id}-show-more`}
transition={{ duration: 0.2 }}
variants={variants}
className={cn(
styles.button,
hasHiddenSelection && !showAll && styles.active,
)}
onClick={() => setShowAll(prev => !prev)}
>
{showAll ? 'Show Less' : 'Show More'}
</motion.button>
</AnimatePresence>
<button
ref={showMoreButton}
className={cn(
styles.button,
hasHiddenSelection && !showAll && styles.active,
)}
onClick={toggleMore}
>
<AnimatePresence initial={false} mode="wait">
<motion.span
animate="show"
exit="hidden"
initial="hidden"
key={showAll ? `${id}-show-less` : `${id}-show-more`}
variants={variants}
onAnimationComplete={() => setIsAnimating(false)}
onAnimationStart={() => setIsAnimating(true)}
>
{showAll ? 'Show Less' : 'Show More'}
</motion.span>
</AnimatePresence>
</button>
)}
</div>
);

View File

@@ -18,6 +18,11 @@
border-radius: 50px;
transition: 0.2s;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&::after {
position: absolute;
top: 1px;
@@ -58,7 +63,8 @@
animation-iteration-count: infinite;
}
&:hover::after {
&:hover::after,
&:focus-visible::after {
background-color: var(--color-neutral-100);
}
}

View File

@@ -0,0 +1,20 @@
import type { Meta, StoryObj } from '@storybook/react';
import { SpecialButton } from './special-button';
const meta: Meta<typeof SpecialButton> = {
component: SpecialButton,
tags: ['autodocs'],
title: 'SpecialButton',
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
children: 'Hello World',
href: '#',
},
};

View File

@@ -0,0 +1,36 @@
import { padNumber } from '@/helpers/number';
import styles from './timer.module.css';
interface TimerProps {
displayHours?: boolean;
timer: number;
}
export function Timer({ displayHours = false, timer }: TimerProps) {
let hours = Math.floor(timer / 3600);
let minutes = Math.floor((timer % 3600) / 60);
let seconds = timer % 60;
hours = isNaN(hours) ? 0 : hours;
minutes = isNaN(minutes) ? 0 : minutes;
seconds = isNaN(seconds) ? 0 : seconds;
const formattedHours = padNumber(hours);
const formattedMinutes = padNumber(minutes);
const formattedSeconds = padNumber(seconds);
return (
<div className={styles.timer}>
{displayHours ? (
<>
{formattedHours}:{formattedMinutes}:{formattedSeconds}
</>
) : (
<>
{formattedMinutes}:{formattedSeconds}
</>
)}
</div>
);
}

View File

@@ -13,11 +13,22 @@
outline: none;
transition: 0.2s;
&:hover {
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&:hover,
&:focus-visible {
background-color: var(--color-neutral-200);
}
&.smallIcon {
font-size: var(--font-xsm);
}
&:disabled {
cursor: not-allowed;
opacity: 0.4;
}
}

View File

@@ -5,17 +5,25 @@ import { cn } from '@/helpers/styles';
import styles from './button.module.css';
interface ButtonProps {
disabled?: boolean;
icon: React.ReactElement;
onClick: () => void;
smallIcon?: boolean;
tooltip: string;
}
export function Button({ icon, onClick, smallIcon, tooltip }: ButtonProps) {
export function Button({
disabled = false,
icon,
onClick,
smallIcon,
tooltip,
}: ButtonProps) {
return (
<Tooltip content={tooltip} hideDelay={0} placement="bottom" showDelay={0}>
<Tooltip content={tooltip} placement="bottom" showDelay={0}>
<button
className={cn(styles.button, smallIcon && styles.smallIcon)}
disabled={disabled}
onClick={onClick}
>
{icon}

View File

@@ -14,6 +14,11 @@
transition: 0.2s;
transition-property: border-color, color, background-color;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&.critical {
color: #f43f5e;
border-color: #f43f5e;
@@ -33,7 +38,8 @@
}
}
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-neutral-200);
}
}

View File

@@ -20,7 +20,7 @@ export function Button({
tooltip,
}: ButtonProps) {
return (
<Tooltip content={tooltip} hideDelay={0} placement="bottom" showDelay={0}>
<Tooltip content={tooltip} placement="bottom" showDelay={0}>
<button
className={cn(
styles.button,

View File

@@ -29,6 +29,11 @@
border-radius: 4px;
outline: none;
scroll-padding-bottom: 12px;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
.counter {

View File

@@ -1,3 +1,4 @@
import { useRef, useEffect } from 'react';
import { BiTrash } from 'react-icons/bi/index';
import { LuCopy, LuDownload } from 'react-icons/lu/index';
import { FaCheck } from 'react-icons/fa6/index';
@@ -18,6 +19,8 @@ interface NotepadProps {
}
export function Notepad({ onClose, show }: NotepadProps) {
const textareaRef = useRef<HTMLTextAreaElement>(null);
const note = useNoteStore(state => state.note);
const history = useNoteStore(state => state.history);
const write = useNoteStore(state => state.write);
@@ -28,6 +31,20 @@ export function Notepad({ onClose, show }: NotepadProps) {
const { copy, copying } = useCopy();
useEffect(() => {
if (show && textareaRef.current) {
setTimeout(() => {
textareaRef.current?.focus();
}, 10);
}
}, [show]);
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
e.stopPropagation();
if (e.key === 'Escape') onClose();
};
return (
<Modal show={show} wide onClose={onClose}>
<header className={styles.header}>
@@ -57,8 +74,11 @@ export function Notepad({ onClose, show }: NotepadProps) {
className={styles.textarea}
dir="auto"
placeholder="What is on your mind?"
ref={textareaRef}
spellCheck={false}
value={note}
onChange={e => write(e.target.value)}
onKeyDown={handleKeyDown}
/>
<p className={styles.counter}>

View File

@@ -3,23 +3,25 @@ import { FaUndo, FaPlay, FaPause } from 'react-icons/fa/index';
import { IoMdSettings } from 'react-icons/io/index';
import { Modal } from '@/components/modal';
import { Button } from '../generics/button';
import { Timer } from '@/components/timer';
import { Tabs } from './tabs';
import { Timer } from './timer';
import { Button } from './button';
import { Setting } from './setting';
import { useLocalStorage } from '@/hooks/use-local-storage';
import { useSoundEffect } from '@/hooks/use-sound-effect';
import { usePomodoroStore } from '@/store';
import { useCloseListener } from '@/hooks/use-close-listener';
import styles from './pomodoro.module.css';
interface PomodoroProps {
onClose: () => void;
open: () => void;
show: boolean;
}
export function Pomodoro({ onClose, show }: PomodoroProps) {
export function Pomodoro({ onClose, open, show }: PomodoroProps) {
const [showSetting, setShowSetting] = useState(false);
const [selectedTab, setSelectedTab] = useState('pomodoro');
@@ -61,6 +63,8 @@ export function Pomodoro({ onClose, show }: PomodoroProps) {
[],
);
useCloseListener(() => setShowSetting(false));
useEffect(() => {
if (running) {
if (interval.current) clearInterval(interval.current);
@@ -125,7 +129,10 @@ export function Pomodoro({ onClose, show }: PomodoroProps) {
<Button
icon={<IoMdSettings />}
tooltip="Change Times"
onClick={() => setShowSetting(true)}
onClick={() => {
onClose();
setShowSetting(true);
}}
/>
</div>
</header>
@@ -157,10 +164,14 @@ export function Pomodoro({ onClose, show }: PomodoroProps) {
<Setting
show={showSetting}
times={times}
onClose={() => setShowSetting(false)}
onChange={times => {
setShowSetting(false);
setTimes(times);
open();
}}
onClose={() => {
setShowSetting(false);
open();
}}
/>
</>

View File

@@ -33,6 +33,11 @@
border: 1px solid var(--color-neutral-200);
border-radius: 4px;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
}
}
@@ -57,6 +62,11 @@
border-radius: 4px;
outline: none;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&.primary {
color: var(--color-neutral-100);
background-color: var(--color-neutral-950);

View File

@@ -12,18 +12,36 @@ interface SettingProps {
}
export function Setting({ onChange, onClose, show, times }: SettingProps) {
const [values, setValues] = useState(times);
const [values, setValues] = useState<Record<string, number | string>>(times);
useEffect(() => setValues(times), [times]);
useEffect(() => {
if (show) setValues(times);
}, [times, show]);
const handleChange = (id: string) => (value: number) => {
setValues(prev => ({ ...prev, [id]: value * 60 }));
const handleChange = (id: string) => (value: number | string) => {
setValues(prev => ({
...prev,
[id]: typeof value === 'number' ? value * 60 : '',
}));
};
const handleSubmit = e => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
onChange(values);
const newValues: Record<string, number> = {};
Object.keys(values).forEach(name => {
newValues[name] =
typeof values[name] === 'number' ? values[name] : times[name];
});
onChange(newValues);
};
const handleCancel = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.preventDefault();
onClose();
};
return (
@@ -34,32 +52,29 @@ export function Setting({ onChange, onClose, show, times }: SettingProps) {
<Field
id="pomodoro"
label="Pomodoro"
value={values.pomodoro / 60}
value={values.pomodoro}
onChange={handleChange('pomodoro')}
/>
<Field
id="short"
label="Short Break"
value={values.short / 60}
value={values.short}
onChange={handleChange('short')}
/>
<Field
id="long"
label="Long Break"
value={values.long / 60}
value={values.long}
onChange={handleChange('long')}
/>
<div className={styles.buttons}>
<button
onClick={e => {
e.preventDefault();
onClose();
}}
>
<button type="button" onClick={handleCancel}>
Cancel
</button>
<button className={styles.primary}>Save</button>
<button className={styles.primary} type="submit">
Save
</button>
</div>
</form>
</Modal>
@@ -69,8 +84,8 @@ export function Setting({ onChange, onClose, show, times }: SettingProps) {
interface FieldProps {
id: string;
label: string;
onChange: (value: number) => void;
value: number;
onChange: (value: number | string) => void;
value: number | string;
}
function Field({ id, label, onChange, value }: FieldProps) {
@@ -83,9 +98,12 @@ function Field({ id, label, onChange, value }: FieldProps) {
className={styles.input}
max={120}
min={1}
required
type="number"
value={value}
onChange={e => onChange(Number(e.target.value))}
value={typeof value === 'number' ? value / 60 : ''}
onChange={e => {
onChange(e.target.value === '' ? '' : Number(e.target.value));
}}
/>
</div>
);

View File

@@ -20,15 +20,22 @@
background-color: transparent;
border: 1px solid transparent;
border-radius: 4px;
outline: none;
transition: 0.2s;
&:focus-visible {
outline: 2px solid var(--color-neutral-400);
outline-offset: 2px;
}
&.selected {
color: var(--color-foreground);
background-color: var(--color-neutral-200);
border-color: var(--color-neutral-300);
}
&:not(.selected):hover {
&:not(.selected):hover,
&:not(.selected):focus-visible {
color: var(--color-foreground);
background-color: var(--color-neutral-100);
}

View File

@@ -1,15 +0,0 @@
import { padNumber } from '@/helpers/number';
import styles from './timer.module.css';
interface TimerProps {
timer: number;
}
export function Timer({ timer }: TimerProps) {
return (
<div className={styles.timer}>
{padNumber(Math.floor(timer / 60))}:{padNumber(timer % 60)}
</div>
);
}

View File

@@ -1,4 +1,5 @@
.tooltip {
z-index: 99;
width: max-content;
padding: 6px 12px;
font-size: var(--font-xsm);

View File

@@ -1,27 +1,28 @@
import { useState, cloneElement } from 'react';
import {
useFloating,
autoUpdate,
offset,
flip,
shift,
useHover,
useFocus,
useDismiss,
useRole,
useInteractions,
type Placement,
} from '@floating-ui/react';
import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
import { slideX, slideY, mix, fade } from '@/lib/motion';
import styles from './tooltip.module.css';
type Placement =
| 'top'
| 'right'
| 'bottom'
| 'left'
| 'top-start'
| 'top-end'
| 'right-start'
| 'right-end'
| 'bottom-start'
| 'bottom-end'
| 'left-start'
| 'left-end';
interface TooltipProps {
children: JSX.Element;
content: string;
hideDelay?: number;
placement?: Placement;
showDelay?: number;
}
@@ -29,91 +30,57 @@ interface TooltipProps {
export function Tooltip({
children,
content,
hideDelay = 100,
placement = 'top',
showDelay = 500,
}: TooltipProps) {
const [isTooltipOpen, setIsTooltipOpen] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const {
context,
floatingStyles,
placement: computedPlacement,
refs,
} = useFloating({
middleware: [offset(12), flip(), shift({ padding: 8 })],
onOpenChange: setIsTooltipOpen,
open: isTooltipOpen,
placement: placement,
whileElementsMounted: autoUpdate,
});
const hover = useHover(context, {
delay: showDelay,
move: false,
restMs: hideDelay,
});
const focus = useFocus(context);
const dismiss = useDismiss(context);
const role = useRole(context, { role: 'tooltip' });
const { getFloatingProps, getReferenceProps } = useInteractions([
hover,
focus,
dismiss,
role,
]);
const side = placement.split('-')[0] as 'top' | 'right' | 'bottom' | 'left';
const align = placement.split('-')[1] as
| 'start'
| 'end'
| 'center'
| undefined;
const slide = {
bottom: slideY(-5),
left: slideX(5),
right: slideX(-5),
top: slideY(5),
}[
computedPlacement.includes('-')
? computedPlacement.split('-')[0]
: computedPlacement
];
}[side];
const variants = mix(fade(), slide!);
const textVariants = fade();
return (
<>
{cloneElement(
children,
getReferenceProps({ ref: refs.setReference, ...children.props }),
)}
<TooltipPrimitive.Provider delayDuration={showDelay}>
<TooltipPrimitive.Root open={isOpen} onOpenChange={o => setIsOpen(o)}>
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
<AnimatePresence>
{isTooltipOpen && (
<div
ref={refs.setFloating}
{...getFloatingProps({ style: { ...floatingStyles, zIndex: 99 } })}
>
<motion.div
animate="show"
className={styles.tooltip}
exit="hidden"
initial="hidden"
variants={variants}
>
<AnimatePresence initial={false} mode="wait">
<motion.span
<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}
exit="hidden"
initial="hidden"
key={content}
transition={{ duration: 0.15 }}
variants={textVariants}
variants={variants}
>
{content}
</motion.span>
</AnimatePresence>
</motion.div>
</div>
)}
</AnimatePresence>
</>
</motion.div>
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
)}
</AnimatePresence>
</TooltipPrimitive.Root>
</TooltipPrimitive.Provider>
);
}

2
src/constants/events.ts Normal file
View File

@@ -0,0 +1,2 @@
export const FADE_OUT = 'FADE_OUT';
export const CLOSE_MODALS = 'CLOSE_MODALS';

View File

@@ -0,0 +1,26 @@
import type { Meta, StoryObj } from '@storybook/react';
import { SnackbarProvider, useSnackbar } from '../snackbar';
const meta: Meta<typeof Snackbar> = {
component: SnackbarProvider,
title: 'SnackbarProvider',
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => (
<SnackbarProvider>
<Snackbar />
</SnackbarProvider>
),
};
function Snackbar() {
const snackbar = useSnackbar();
return <button onClick={() => snackbar('Hello World')}>Show Snackbar</button>;
}

View File

@@ -0,0 +1,11 @@
import { useEffect } from 'react';
import { onCloseModals } from '@/lib/modal';
export function useCloseListener(listener: () => void) {
useEffect(() => {
const unsubscribe = onCloseModals(listener);
return unsubscribe;
}, [listener]);
}

View File

@@ -0,0 +1,19 @@
import { useCallback } from 'react';
import type { KeyboardEvent } from 'react';
export const useKeyboardButton = (
actionCallback: () => void,
): ((event: KeyboardEvent<HTMLElement>) => void) => {
const handleKeyDown = useCallback(
(event: KeyboardEvent<HTMLElement>) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
actionCallback();
event.stopPropagation();
}
},
[actionCallback],
);
return handleKeyDown;
};

View File

@@ -2,7 +2,9 @@ import { useMemo, useEffect, useCallback, useState } from 'react';
import { Howl } from 'howler';
import { useLoadingStore } from '@/store';
import { subscribe } from '@/lib/event';
import { useSSR } from './use-ssr';
import { FADE_OUT } from '@/constants/events';
export function useSound(
src: string,
@@ -62,9 +64,27 @@ export function useSound(
if (sound) sound.pause();
}, [sound]);
const fadeOut = useCallback(
(duration: number) => {
sound?.fade(sound.volume(), 0, duration);
setTimeout(() => {
pause();
sound?.volume(options.volume || 0.5);
}, duration);
},
[options.volume, sound, pause],
);
useEffect(() => {
const listener = (e: { duration: number }) => fadeOut(e.duration);
return subscribe(FADE_OUT, listener);
}, [fadeOut]);
const control = useMemo(
() => ({ isLoading, pause, play, stop }),
[play, stop, pause, isLoading],
() => ({ fadeOut, isLoading, pause, play, stop }),
[play, stop, pause, isLoading, fadeOut],
);
return control;

23
src/lib/event.ts Normal file
View File

@@ -0,0 +1,23 @@
export function dispatch<T>(eventName: string, detail?: T) {
const event = new CustomEvent(eventName, { detail });
document.dispatchEvent(event);
}
export function subscribe<T>(eventName: string, listener: (e: T) => void) {
const handler = (event: Event) => {
if ('detail' in event) {
const payload = event.detail as T;
listener(payload);
}
};
document.addEventListener(eventName, handler);
return () => unsubscribe(eventName, handler);
}
export function unsubscribe(eventName: string, listener: (e: Event) => void) {
document.removeEventListener(eventName, listener);
}

12
src/lib/modal.ts Normal file
View File

@@ -0,0 +1,12 @@
import { dispatch, subscribe } from './event';
import { CLOSE_MODALS } from '@/constants/events';
export function closeModals() {
dispatch(CLOSE_MODALS);
}
export function onCloseModals(listener: () => void) {
const unsubscribe = subscribe(CLOSE_MODALS, listener);
return unsubscribe;
}

View File

@@ -5,6 +5,7 @@ import type { SoundState } from './sound.state';
import { pickMany, random } from '@/helpers/random';
export interface SoundActions {
lock: () => void;
override: (sounds: Record<string, number>) => void;
pause: () => void;
play: () => void;
@@ -14,6 +15,7 @@ export interface SoundActions {
shuffle: () => void;
toggleFavorite: (id: string) => void;
togglePlay: () => void;
unlock: () => void;
unselect: (id: string) => void;
unselectAll: (pushToHistory?: boolean) => void;
}
@@ -25,6 +27,10 @@ export const createActions: StateCreator<
SoundActions
> = (set, get) => {
return {
lock() {
set({ locked: true });
},
override(newSounds) {
get().unselectAll();
@@ -111,6 +117,10 @@ export const createActions: StateCreator<
set({ isPlaying: !get().isPlaying });
},
unlock() {
set({ locked: false });
},
unselect(id) {
set({
sounds: {

View File

@@ -14,6 +14,7 @@ export interface SoundState {
};
} | null;
isPlaying: boolean;
locked: boolean;
noSelected: () => boolean;
sounds: {
[id: string]: {
@@ -40,6 +41,7 @@ export const createState: StateCreator<
},
history: null,
isPlaying: false,
locked: false,
noSelected() {
const { sounds } = get();
const keys = Object.keys(sounds);