mirror of
https://github.com/remvze/moodist.git
synced 2026-03-06 03:53:13 +08:00
Compare commits
245 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60cb453847 | ||
|
|
fc4f52146e | ||
|
|
1a1359c989 | ||
|
|
a6c7ac41ad | ||
|
|
3e11fb6123 | ||
|
|
d356d77aa9 | ||
|
|
9cc0ccd325 | ||
|
|
cad85c7667 | ||
|
|
def9a57e0c | ||
|
|
74f6b5851d | ||
|
|
f4c66e3092 | ||
|
|
28abc16b9c | ||
|
|
787a9b60b5 | ||
|
|
73a5c21be9 | ||
|
|
cfd2744e92 | ||
|
|
4c0f417469 | ||
|
|
9d1d8f8035 | ||
|
|
8a79ccf018 | ||
|
|
a3c384d105 | ||
|
|
96ca376885 | ||
|
|
18987cc339 | ||
|
|
919831538f | ||
|
|
edd15f4b9a | ||
|
|
09c0a6ce93 | ||
|
|
2bfb9b181c | ||
|
|
c272914416 | ||
|
|
d73b2bc1ff | ||
|
|
c5657d0642 | ||
|
|
c35409ce0a | ||
|
|
7658842324 | ||
|
|
78222be011 | ||
|
|
2c8135db43 | ||
|
|
fddf75cdca | ||
|
|
0f50e6ae8b | ||
|
|
4ae0504937 | ||
|
|
af075b32e6 | ||
|
|
82d8240b97 | ||
|
|
096251ec0a | ||
|
|
2a86a88ed6 | ||
|
|
c60dcc74ed | ||
|
|
aca746148e | ||
|
|
095e3c795e | ||
|
|
7e65bb75f9 | ||
|
|
0533460667 | ||
|
|
9d633a9637 | ||
|
|
a9fe7f7b4f | ||
|
|
ffe260f4a0 | ||
|
|
78656bb61f | ||
|
|
629f0a514e | ||
|
|
9338b1d30a | ||
|
|
34d3f07581 | ||
|
|
cf4870b0d6 | ||
|
|
9f0a28d930 | ||
|
|
56b0e9bf1a | ||
|
|
4f752bb6d0 | ||
|
|
1547b0a436 | ||
|
|
9ad16306cf | ||
|
|
4b73e45dd4 | ||
|
|
05b298f51e | ||
|
|
8d01d74bd3 | ||
|
|
f311ec114e | ||
|
|
df1b05f7ce | ||
|
|
ea0dfff9c1 | ||
|
|
fc1bd07b7d | ||
|
|
f79e941527 | ||
|
|
11a4514a0f | ||
|
|
e41f901041 | ||
|
|
de49d37f08 | ||
|
|
5f066a4eff | ||
|
|
b925a2e04f | ||
|
|
c66cddc4c9 | ||
|
|
7cb0f1c752 | ||
|
|
d09e598297 | ||
|
|
5899d1bbbb | ||
|
|
81678ea384 | ||
|
|
d9246b692b | ||
|
|
c893e2a6ad | ||
|
|
f025213ef2 | ||
|
|
6ce766af47 | ||
|
|
7c57fb686b | ||
|
|
dc139e41e6 | ||
|
|
b990778142 | ||
|
|
672988c36e | ||
|
|
06d0dfbe7e | ||
|
|
954a1b1ce2 | ||
|
|
383f898125 | ||
|
|
8d90344b26 | ||
|
|
c614e3d4f5 | ||
|
|
781adcf17e | ||
|
|
3e44516509 | ||
|
|
aeccf2dabd | ||
|
|
8e6e690006 | ||
|
|
75e7c48b21 | ||
|
|
dcef777295 | ||
|
|
cc77f9e9c0 | ||
|
|
8fe90daf1e | ||
|
|
34d3c72f35 | ||
|
|
9d458fb60e | ||
|
|
e674738ce7 | ||
|
|
77e2ec5e79 | ||
|
|
4adfb3ddc9 | ||
|
|
ae0cbf1aa3 | ||
|
|
dbbd68b73d | ||
|
|
2e375ad40a | ||
|
|
58bf28bb24 | ||
|
|
0517c31fc1 | ||
|
|
71b62ed3dd | ||
|
|
0300df3852 | ||
|
|
3f3bcdda21 | ||
|
|
f19d151f4a | ||
|
|
43f6245227 | ||
|
|
9b7d3c645b | ||
|
|
f8fb1ed61e | ||
|
|
6fe9ce8915 | ||
|
|
603d318e68 | ||
|
|
65ca7e1c94 | ||
|
|
583578b315 | ||
|
|
60f167c4d7 | ||
|
|
99f3a41598 | ||
|
|
d3a2a12e1f | ||
|
|
ebb35deaf9 | ||
|
|
9ad49d021a | ||
|
|
8307657628 | ||
|
|
3b0c22968e | ||
|
|
e490a1da84 | ||
|
|
7c6f068d15 | ||
|
|
a46a4cdc96 | ||
|
|
b955fc93f4 | ||
|
|
54c777276d | ||
|
|
136a009379 | ||
|
|
601ba6def7 | ||
|
|
89a83089c5 | ||
|
|
2192335238 | ||
|
|
af92b1ed90 | ||
|
|
f81ea9e7bd | ||
|
|
98e5021f56 | ||
|
|
9774532308 | ||
|
|
837826fbc1 | ||
|
|
2f84268017 | ||
|
|
24a53c81df | ||
|
|
ab9d47befb | ||
|
|
60cc2e9369 | ||
|
|
42f82ab95d | ||
|
|
669df1f082 | ||
|
|
a3cfbb98db | ||
|
|
3c8d75b018 | ||
|
|
e7d7a37a12 | ||
|
|
6f9c941a87 | ||
|
|
8596a0014c | ||
|
|
908fe01c5e | ||
|
|
8009e1519f | ||
|
|
0252fa96ab | ||
|
|
48291a6457 | ||
|
|
ddae0b660f | ||
|
|
8669489747 | ||
|
|
4f4ffe3e3a | ||
|
|
42d3bd9e8c | ||
|
|
4b5456a51d | ||
|
|
fa9711a1e0 | ||
|
|
73a8e03d66 | ||
|
|
017c27fb2b | ||
|
|
43ba975408 | ||
|
|
42bd47bbea | ||
|
|
faf7f78b8c | ||
|
|
7ec7ea74d5 | ||
|
|
ede480186c | ||
|
|
6dfa998ffe | ||
|
|
a8a8c36434 | ||
|
|
7390a9b3de | ||
|
|
0eb47ba2e1 | ||
|
|
110356b2da | ||
|
|
158cffca8c | ||
|
|
def69de6e4 | ||
|
|
69cb45bff7 | ||
|
|
e7fd84bd4e | ||
|
|
dfd6c1fc4a | ||
|
|
38a9a23790 | ||
|
|
2484e01273 | ||
|
|
98d2f76438 | ||
|
|
0e12a5203e | ||
|
|
3205145d54 | ||
|
|
8f36c863d7 | ||
|
|
941e1f0241 | ||
|
|
240fd9c6e0 | ||
|
|
665e2173f4 | ||
|
|
1ac52861d1 | ||
|
|
a7e5368591 | ||
|
|
f3cb2a1b63 | ||
|
|
586e502c3c | ||
|
|
5b83710c75 | ||
|
|
7ed016d855 | ||
|
|
9f7de336e5 | ||
|
|
758f2f48dc | ||
|
|
d055e66dd9 | ||
|
|
79afb8d92f | ||
|
|
408734d49f | ||
|
|
7463334053 | ||
|
|
ae3ea8c74f | ||
|
|
24245235b1 | ||
|
|
b143e46e92 | ||
|
|
e923559709 | ||
|
|
8930e7b76a | ||
|
|
5f40435c0c | ||
|
|
38c11f124e | ||
|
|
a5d2ba45f8 | ||
|
|
653d309e64 | ||
|
|
663cb92135 | ||
|
|
1a499be244 | ||
|
|
4515aa8e7a | ||
|
|
831a9c8ea0 | ||
|
|
f66a6ffde7 | ||
|
|
9028675057 | ||
|
|
37505a6b3f | ||
|
|
400ea0aeaf | ||
|
|
e4e332ad75 | ||
|
|
341a896924 | ||
|
|
1a6ecd82ab | ||
|
|
d725d59703 | ||
|
|
52176bc3f9 | ||
|
|
c505c574a8 | ||
|
|
3f45be3942 | ||
|
|
a514a364ec | ||
|
|
81e6666776 | ||
|
|
56802b67f2 | ||
|
|
d4cc24e468 | ||
|
|
f7302dec5b | ||
|
|
1a01a00866 | ||
|
|
38da02a0d3 | ||
|
|
5fc3e7e5d0 | ||
|
|
0f32de3c0c | ||
|
|
ac24da2940 | ||
|
|
5916e86d3c | ||
|
|
f3e7224267 | ||
|
|
e1b9a1736c | ||
|
|
2078648c66 | ||
|
|
6d30a0123e | ||
|
|
8471a3ca49 | ||
|
|
182a8c7aad | ||
|
|
0ad4bb72e1 | ||
|
|
405fcccd95 | ||
|
|
2b843747b4 | ||
|
|
8e500136ce | ||
|
|
882d44079c | ||
|
|
82e4ea72f4 | ||
|
|
dc22b51548 |
@@ -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",
|
||||
@@ -46,6 +41,7 @@
|
||||
"sort-destructure-keys/sort-destructure-keys": "warn",
|
||||
"jsx-a11y/no-static-element-interactions": "off",
|
||||
"jsx-a11y/media-has-caption": "off",
|
||||
"jsx-a11y/no-noninteractive-tabindex": "off",
|
||||
"react/jsx-sort-props": [
|
||||
"warn",
|
||||
{
|
||||
@@ -54,48 +50,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": {
|
||||
|
||||
18
.github/workflows/build_docker.yml
vendored
18
.github/workflows/build_docker.yml
vendored
@@ -20,15 +20,21 @@ jobs:
|
||||
username: ${{github.actor}}
|
||||
password: ${{secrets.ACCESS_TOKEN}}
|
||||
|
||||
- name: 'Build Inventory Image'
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: 'Build and push Inventory Image'
|
||||
run: |
|
||||
IMAGE_NAME="ghcr.io/remvze/moodist"
|
||||
|
||||
GIT_TAG=${{ github.ref }}
|
||||
GIT_TAG=${GIT_TAG#refs/tags/}
|
||||
|
||||
docker build . --tag $IMAGE_NAME:latest
|
||||
docker push $IMAGE_NAME:latest
|
||||
|
||||
docker build . --tag $IMAGE_NAME:$GIT_TAG
|
||||
docker push $IMAGE_NAME:$GIT_TAG
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-t $IMAGE_NAME:latest \
|
||||
-t $IMAGE_NAME:$GIT_TAG \
|
||||
--push .
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,3 +19,5 @@ pnpm-debug.log*
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
*storybook.log
|
||||
46
.storybook/main.ts
Normal file
46
.storybook/main.ts
Normal 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
16
.storybook/preview.ts
Normal 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;
|
||||
695
CHANGELOG.md
695
CHANGELOG.md
@@ -2,309 +2,540 @@
|
||||
|
||||
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.3.1](https://github.com/remvze/moodist/compare/v1.3.0...v1.3.1) (2024-02-01)
|
||||
### [1.5.1](https://github.com/remvze/moodist/compare/v1.5.0...v1.5.1) (2024-06-14)
|
||||
|
||||
|
||||
### ✨ Features
|
||||
### ♻️ Code Refactoring
|
||||
|
||||
* 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))
|
||||
* migrate to Astro components ([ffe260f](https://github.com/remvze/moodist/commit/ffe260f4a02238cb83cf92ed06c4f9c75ba189a4))
|
||||
* rename some functions ([0533460](https://github.com/remvze/moodist/commit/05334606673a6268ca35083ea31e28cdb11f1b86))
|
||||
* use nullish operator ([9d633a9](https://github.com/remvze/moodist/commit/9d633a963772c3444b6e9effc7920fe190b0614d))
|
||||
|
||||
|
||||
### 🚚 Chores
|
||||
|
||||
* add donation link to README file ([1f806c4](https://github.com/remvze/moodist/commit/1f806c4e561d79a00850130eda09376299d85ed2))
|
||||
* add more sounds ([095e3c7](https://github.com/remvze/moodist/commit/095e3c795ef699e9e99c5eb364badaadce8a884b))
|
||||
* add washing machine sound ([7e65bb7](https://github.com/remvze/moodist/commit/7e65bb75f9871603c30ecfc578ad109a969a2a58))
|
||||
* update README file ([a9fe7f7](https://github.com/remvze/moodist/commit/a9fe7f7b4f9ca91704d76a314e3c3368fbc4f1cf))
|
||||
|
||||
## [1.5.0](https://github.com/remvze/moodist/compare/v1.4.3...v1.5.0) (2024-05-19)
|
||||
|
||||
|
||||
### 💄 Styling
|
||||
|
||||
* 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
|
||||
|
||||
* 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))
|
||||
|
||||
### 💄 Styling
|
||||
|
||||
- widen the container ([7ec7ea7](https://github.com/remvze/moodist/commit/7ec7ea74d53db85cffa3af646c03270793453009))
|
||||
|
||||
### 🚚 Chores
|
||||
|
||||
- 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))
|
||||
|
||||
### 💄 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))
|
||||
|
||||
### ✨ 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))
|
||||
|
||||
### 🐛 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))
|
||||
|
||||
### [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))
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- 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))
|
||||
|
||||
## [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
25
CONTRIBUTING.md
Normal 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).
|
||||
@@ -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
|
||||
|
||||
|
||||
82
README.md
82
README.md
@@ -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/)
|
||||
|
||||
@@ -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()],
|
||||
});
|
||||
|
||||
12187
package-lock.json
generated
12187
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
33
package.json
33
package.json
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "moodist",
|
||||
"type": "module",
|
||||
"version": "1.3.1",
|
||||
"version": "1.5.1",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"test": "vitest",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.astro",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"lint:style": "stylelint ./**/*.{css,astro,html}",
|
||||
@@ -18,27 +19,45 @@
|
||||
"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",
|
||||
"@astrojs/react": "3.6.0",
|
||||
"@floating-ui/react": "0.26.0",
|
||||
"@formkit/auto-animate": "0.8.2",
|
||||
"@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",
|
||||
"astro": "4.10.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",
|
||||
"uuid": "10.0.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 +76,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,11 +84,14 @@
|
||||
"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",
|
||||
"stylelint-config-standard": "34.0.0",
|
||||
"stylelint-prettier": "4.0.2"
|
||||
"stylelint-prettier": "4.0.2",
|
||||
"vitest": "1.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/sounds/alarm.mp3
Normal file
BIN
public/sounds/alarm.mp3
Normal file
Binary file not shown.
BIN
public/sounds/nature/jungle.mp3
Normal file
BIN
public/sounds/nature/jungle.mp3
Normal file
Binary file not shown.
BIN
public/sounds/places/laundry-room.mp3
Normal file
BIN
public/sounds/places/laundry-room.mp3
Normal file
Binary file not shown.
BIN
public/sounds/things/washing-machine.mp3
Normal file
BIN
public/sounds/things/washing-machine.mp3
Normal file
Binary file not shown.
160
src/components/about.astro
Normal file
160
src/components/about.astro
Normal file
@@ -0,0 +1,160 @@
|
||||
---
|
||||
import { Container } from '@/components/container';
|
||||
|
||||
import { count as soundCount } from '@/lib/sounds';
|
||||
|
||||
const count = soundCount();
|
||||
|
||||
const paragraphs = [
|
||||
{
|
||||
body: 'Craving a calming escape from the daily grind? Do you need the perfect soundscape to boost your focus or lull you into peaceful sleep? Look no further than Moodist, your free and open-source ambient sound generator! Ditch the subscriptions and registrations – with Moodist, you unlock a world of soothing and immersive audio experiences, entirely for free.',
|
||||
title: 'Free Ambient Sounds',
|
||||
},
|
||||
{
|
||||
body: `Dive into an expansive library of ${count} carefully curated sounds. Nature lovers will find solace in the gentle murmur of streams, the rhythmic crash of waves, or the crackling warmth of a campfire. Cityscapes come alive with the soft hum of cafes, the rhythmic clatter of trains, or the calming white noise of traffic. And for those seeking deeper focus or relaxation, Moodist offers binaural beats and color noise designed to enhance your state of mind.`,
|
||||
title: 'Carefully Curated Sounds',
|
||||
},
|
||||
{
|
||||
body: 'The beauty of Moodist lies in its simplicity and customization. No complex menus or confusing options – just choose your desired sounds, adjust the volume balance, and hit play. Want to blend the gentle chirping of birds with the soothing sound of rain? No problem! Layer as many sounds as you like to create your personalized soundscape oasis.',
|
||||
title: 'Create Your Soundscape',
|
||||
},
|
||||
{
|
||||
body: 'Moodist offers more than ambient sounds with its suite of productivity tools to keep you organized and focused. Use the built-in pomodoro timer for structured work intervals, jot down ideas in the notepad, track tasks with the to-do list (coming soon), and set multiple timers with the distraction-free countdown timer. These tools integrate seamlessly with the ambient soundscapes, creating a personalized environment that fosters focus and relaxation.',
|
||||
title: 'A Productivity Toolbox',
|
||||
},
|
||||
{
|
||||
body: "Whether you're looking to unwind after a long day, enhance your focus during work, or lull yourself into a peaceful sleep, Moodist has the perfect soundscape waiting for you. The best part? It's completely free and open-source, so you can enjoy its benefits without any strings attached. Start using Moodist today and discover your new haven of tranquility and focus!",
|
||||
title: 'Sounds for Every Moment',
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<section class="about">
|
||||
<div class="effect"></div>
|
||||
|
||||
<Container tight>
|
||||
{
|
||||
paragraphs.map((paragraph, index) => (
|
||||
<div class="paragraph">
|
||||
<div class="counter">
|
||||
<span>0{index + 1}</span> / 0{paragraphs.length}
|
||||
</div>
|
||||
|
||||
<h2 class="title">{paragraph.title}</h2>
|
||||
<p class="body">{paragraph.body}</p>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
<button class="button" id="use-moodist"> Use Moodist</button>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<script lang="ts">
|
||||
const button = document.getElementById('use-moodist');
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
const app = document.getElementById('app');
|
||||
|
||||
app?.scrollIntoView();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.about {
|
||||
padding-top: 10px;
|
||||
|
||||
& .effect {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 80px;
|
||||
background: linear-gradient(var(--color-neutral-50), transparent);
|
||||
}
|
||||
|
||||
& .paragraph {
|
||||
padding: 30px 0;
|
||||
background: linear-gradient(
|
||||
transparent,
|
||||
var(--color-neutral-50) 10%,
|
||||
var(--color-neutral-50) 90%,
|
||||
transparent
|
||||
);
|
||||
|
||||
&:last-of-type {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
& .counter {
|
||||
width: max-content;
|
||||
padding: 6px 16px;
|
||||
margin-bottom: 16px;
|
||||
font-size: var(--font-xsm);
|
||||
color: var(--color-foreground-subtle);
|
||||
background: linear-gradient(var(--color-neutral-100), transparent);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 20px 20px 20px 8px;
|
||||
|
||||
& span {
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
& .title {
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--font-heading);
|
||||
font-size: var(--font-md);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
& .body {
|
||||
line-height: 1.6;
|
||||
color: var(--color-foreground-subtle);
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 16px;
|
||||
margin-top: 20px;
|
||||
font-size: var(--font-xsm);
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 50px;
|
||||
outline: none;
|
||||
transition: 0.2s;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: 50%;
|
||||
width: 70%;
|
||||
height: 1px;
|
||||
content: '';
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
var(--color-neutral-300),
|
||||
transparent
|
||||
);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
background-color: var(--color-neutral-100);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-neutral-400);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -3,25 +3,29 @@ import { useShallow } from 'zustand/react/shallow';
|
||||
import { BiSolidHeart } from 'react-icons/bi/index';
|
||||
import { Howler } from 'howler';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
||||
import { Container } from '@/components/container';
|
||||
import { StoreConsumer } from '@/components/store-consumer';
|
||||
import { Buttons } from '@/components/buttons';
|
||||
import { Categories } from '@/components/categories';
|
||||
import { ScrollToTop } from '@/components/scroll-to-top';
|
||||
import { SharedModal } from '@/components/modals/shared';
|
||||
import { Menu } from '@/components/menu/menu';
|
||||
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
|
||||
@@ -53,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 = [];
|
||||
|
||||
@@ -77,8 +94,7 @@ export function App() {
|
||||
<Categories categories={allCategories} />
|
||||
</Container>
|
||||
|
||||
<ScrollToTop />
|
||||
<Menu />
|
||||
<Toolbar />
|
||||
<SharedModal />
|
||||
</StoreConsumer>
|
||||
</SnackbarProvider>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { BiPause, BiPlay } from 'react-icons/bi/index';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { useSnackbar } from '@/contexts/snackbar';
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
||||
@@ -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 ? (
|
||||
<>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { BiUndo, BiTrash } from 'react-icons/bi/index';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
|
||||
import { Tooltip } from '@/components/tooltip';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { cn } from '@/helpers/styles';
|
||||
import { fade, mix, slideX } from '@/lib/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>
|
||||
|
||||
@@ -13,15 +13,11 @@ export function Categories({ categories }: CategoriesProps) {
|
||||
return (
|
||||
<AnimatePresence initial={false}>
|
||||
{categories.map((category, index) => (
|
||||
<>
|
||||
<Category
|
||||
functional={category.id !== 'favorites'}
|
||||
{...category}
|
||||
key={category.id}
|
||||
/>
|
||||
<div key={category.id}>
|
||||
<Category functional={category.id !== 'favorites'} {...category} />
|
||||
|
||||
{index === 3 && <Donate />}
|
||||
</>
|
||||
</div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
.donate {
|
||||
margin-bottom: 20px;
|
||||
|
||||
& .iconContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -38,26 +40,6 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: max-content;
|
||||
height: 40px;
|
||||
padding: 0 20px;
|
||||
margin: 16px auto 0;
|
||||
font-size: var(--font-xsm);
|
||||
font-weight: 500;
|
||||
color: var(--color-neutral-subtle);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
background-color: var(--color-neutral-50);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 50px;
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-neutral-100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { FaCoffee } from 'react-icons/fa/index';
|
||||
|
||||
import { SpecialButton } from '@/components/special-button';
|
||||
|
||||
import styles from './donate.module.css';
|
||||
|
||||
export function Donate() {
|
||||
@@ -12,16 +14,14 @@ export function Donate() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className={styles.title}>Support Me</h2>
|
||||
<div className={styles.title}>Support Me</div>
|
||||
<p className={styles.desc}>Help me keep Moodist ad-free.</p>
|
||||
<a
|
||||
<SpecialButton
|
||||
className={styles.button}
|
||||
href="https://buymeacoffee.com/remvze"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Donate Today
|
||||
</a>
|
||||
</SpecialButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ export function Category({
|
||||
title,
|
||||
}: CategoryProps) {
|
||||
return (
|
||||
<div className={styles.category}>
|
||||
<div className={styles.category} id={`category-${id}`}>
|
||||
<div className={styles.iconContainer}>
|
||||
<div className={styles.tail} />
|
||||
<div className={styles.icon}>{icon}</div>
|
||||
</div>
|
||||
|
||||
<h2 className={styles.title}>{title}</h2>
|
||||
<div className={styles.title}>{title}</div>
|
||||
|
||||
<Sounds functional={functional} id={id} sounds={sounds} />
|
||||
</div>
|
||||
|
||||
@@ -2,4 +2,12 @@
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
|
||||
&.tight {
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
&.wide {
|
||||
max-width: 760px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
||||
import styles from './container.module.css';
|
||||
|
||||
interface ContainerProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
tight?: boolean;
|
||||
wide?: boolean;
|
||||
}
|
||||
|
||||
export function Container({ children }: ContainerProps) {
|
||||
return <div className={styles.container}>{children}</div>;
|
||||
export function Container({
|
||||
children,
|
||||
className,
|
||||
tight,
|
||||
wide,
|
||||
}: ContainerProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
styles.container,
|
||||
className,
|
||||
tight && styles.tight,
|
||||
wide && styles.wide,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
---
|
||||
import { Container } from '@/components/container';
|
||||
import { Container } from './container';
|
||||
---
|
||||
|
||||
<Container>
|
||||
<section class="wrapper">
|
||||
<p class="text">
|
||||
Enjoy Moodist? <a
|
||||
Enjoy Moodist?{' '}
|
||||
<a
|
||||
href="https://buymeacoffee.com/remvze"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
|
||||
99
src/components/features/features.module.css
Normal file
99
src/components/features/features.module.css
Normal file
@@ -0,0 +1,99 @@
|
||||
.featuresSection {
|
||||
margin-top: 40px;
|
||||
|
||||
& .iconContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
& .tail {
|
||||
width: 1px;
|
||||
height: 75px;
|
||||
background: linear-gradient(transparent, var(--color-neutral-300));
|
||||
}
|
||||
|
||||
& .icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
font-size: var(--font-md);
|
||||
background-color: var(--color-neutral-100);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
& .title {
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--font-lg);
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& .features {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
row-gap: 32px;
|
||||
column-gap: 20px;
|
||||
margin-top: 24px;
|
||||
|
||||
& .icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 12px;
|
||||
font-size: var(--font-md);
|
||||
color: var(--color-foreground-subtle);
|
||||
background: linear-gradient(var(--color-neutral-100), transparent);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
& .label {
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--font-heading);
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& .body {
|
||||
width: 100%;
|
||||
max-width: 275px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.6;
|
||||
color: var(--color-foreground-subtle);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& .link {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
& .soon {
|
||||
display: flex;
|
||||
width: max-content;
|
||||
padding: 6px 12px;
|
||||
margin: 0 auto;
|
||||
margin-top: 8px;
|
||||
font-size: var(--font-2xsm);
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
background: linear-gradient(var(--color-neutral-100), transparent);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
107
src/components/features/features.tsx
Normal file
107
src/components/features/features.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { BiMoney, BiUserCircle, BiLogoGithub } from 'react-icons/bi/index';
|
||||
import { BsSoundwave, BsStars } from 'react-icons/bs/index';
|
||||
import { RxMixerHorizontal } from 'react-icons/rx/index';
|
||||
|
||||
import { Balancer } from 'react-wrap-balancer';
|
||||
|
||||
import { Container } from '@/components/container';
|
||||
import { count as soundCount } from '@/lib/sounds';
|
||||
|
||||
import styles from './features.module.css';
|
||||
|
||||
export function Features() {
|
||||
const count = soundCount();
|
||||
|
||||
const features = [
|
||||
{
|
||||
Icon: BiMoney,
|
||||
body: 'Immerse yourself in sound without spending a dime.',
|
||||
id: 'free-access',
|
||||
label: 'Free Access',
|
||||
},
|
||||
{
|
||||
Icon: BiUserCircle,
|
||||
body: 'Dive right in, no sign-up hoops to jump through.',
|
||||
id: 'no-registration',
|
||||
label: 'No Registration',
|
||||
},
|
||||
{
|
||||
Icon: BsSoundwave,
|
||||
body: `Explore ${count} unique soundscapes, from rainforests to cityscapes.`,
|
||||
id: 'diverse-sounds',
|
||||
label: 'Diverse Sounds',
|
||||
},
|
||||
{
|
||||
Icon: RxMixerHorizontal,
|
||||
body: 'Craft your perfect soundscape by blending and adjusting sounds.',
|
||||
id: 'customizable-mixes',
|
||||
label: 'Customizable Mixes',
|
||||
},
|
||||
{
|
||||
Icon: BiLogoGithub,
|
||||
body: 'Contribute and collaborate, making the best even better.',
|
||||
id: 'open-source',
|
||||
label: 'Open-Source',
|
||||
link: {
|
||||
label: 'Source Code',
|
||||
url: 'https://github.com/remvze/moodist',
|
||||
},
|
||||
},
|
||||
{
|
||||
Icon: BsStars,
|
||||
body: 'Uninterrupted immersion, focus on the sounds, not the tech.',
|
||||
id: 'seamless-experience',
|
||||
label: 'Seamless Experience',
|
||||
},
|
||||
{
|
||||
Icon: BsStars,
|
||||
body: 'Spread the calm, easily share your customized sound blends.',
|
||||
id: 'share-selections',
|
||||
label: 'Share Selections',
|
||||
},
|
||||
{
|
||||
Icon: BsStars,
|
||||
body: 'Lock in your favorite mixes for instant return to your sonic haven.',
|
||||
id: 'save-presets',
|
||||
label: 'Save Presets',
|
||||
soon: true,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section className={styles.featuresSection}>
|
||||
<Container>
|
||||
<div className={styles.iconContainer}>
|
||||
<div className={styles.tail} />
|
||||
<div className={styles.icon}>
|
||||
<BsStars />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className={styles.title}>Features</h2>
|
||||
|
||||
<div className={styles.features}>
|
||||
{features.map(feature => (
|
||||
<div className={styles.reason} key={feature.id}>
|
||||
<div className={styles.icon}>
|
||||
<feature.Icon />
|
||||
</div>
|
||||
<h3 className={styles.label}>{feature.label}</h3>
|
||||
<p className={styles.body}>
|
||||
<Balancer>{feature.body}</Balancer>
|
||||
</p>
|
||||
|
||||
{feature.link && (
|
||||
<a className={styles.link} href={feature.link.url}>
|
||||
{feature.link.label}
|
||||
</a>
|
||||
)}
|
||||
|
||||
{feature.soon && <div className={styles.soon}>Coming Soon</div>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
1
src/components/features/index.ts
Normal file
1
src/components/features/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { Features } from './features';
|
||||
@@ -1,14 +1,11 @@
|
||||
---
|
||||
import { Container } from '@/components/container';
|
||||
import { Container } from './container';
|
||||
---
|
||||
|
||||
<footer class="footer">
|
||||
<Container>
|
||||
<p>
|
||||
Created by{' '}
|
||||
<a href="https://twitter.com/remvze">
|
||||
Maze <span>✦</span>
|
||||
</a>
|
||||
Created by <a href="https://twitter.com/remvze">Maze ✦</a>
|
||||
</p>
|
||||
</Container>
|
||||
</footer>
|
||||
@@ -28,10 +25,6 @@ import { Container } from '@/components/container';
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
text-decoration: none;
|
||||
|
||||
& span {
|
||||
color: #c0eb75;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import { Balancer } from 'react-wrap-balancer';
|
||||
import { BsSoundwave } from 'react-icons/bs/index';
|
||||
|
||||
import { Container } from '@/components/container';
|
||||
import { Container } from './container';
|
||||
|
||||
import { count as soundCount } from '@/lib/sounds';
|
||||
|
||||
const count = soundCount();
|
||||
@@ -10,36 +10,42 @@ const count = soundCount();
|
||||
|
||||
<div class="hero">
|
||||
<Container>
|
||||
<img
|
||||
alt="Faded Moodist Logo"
|
||||
class="logo"
|
||||
height={45}
|
||||
src="/logo.svg"
|
||||
width={45}
|
||||
/>
|
||||
<div class="wrapper">
|
||||
<img
|
||||
alt="Faded Moodist Logo"
|
||||
class="logo"
|
||||
height={45}
|
||||
src="/logo.svg"
|
||||
width={45}
|
||||
/>
|
||||
|
||||
<div class="title">
|
||||
<div class="left"></div>
|
||||
<h1>Moodist</h1>
|
||||
<div class="right"></div>
|
||||
<div class="title">
|
||||
<div class="left"></div>
|
||||
<h2>Moodist</h2>
|
||||
<div class="right"></div>
|
||||
</div>
|
||||
|
||||
<h1 class="desc">Ambient sounds for focus and calm.</h1>
|
||||
|
||||
<p class="sounds">
|
||||
<span class="icon">
|
||||
<BsSoundwave />
|
||||
</span>
|
||||
<span>{count} Sounds</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="desc">
|
||||
<Balancer>Ambient sounds for focus and calm.</Balancer>
|
||||
</p>
|
||||
|
||||
<p class="sounds">
|
||||
<span class="icon"><BsSoundwave /></span>
|
||||
<span>{count} Sounds</span>
|
||||
</p>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hero {
|
||||
padding: 100px 0 60px;
|
||||
text-align: center;
|
||||
|
||||
.wrapper {
|
||||
position: relative;
|
||||
padding: 100px 0 80px;
|
||||
}
|
||||
|
||||
& .logo {
|
||||
display: block;
|
||||
width: 45px;
|
||||
@@ -59,6 +65,8 @@ const count = soundCount();
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
transparent,
|
||||
var(--color-neutral-200),
|
||||
var(--color-neutral-300)
|
||||
);
|
||||
}
|
||||
@@ -67,12 +75,14 @@ const count = soundCount();
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--color-neutral-300),
|
||||
var(--color-neutral-200),
|
||||
transparent,
|
||||
transparent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
& h1 {
|
||||
& h2 {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--font-2xlg);
|
||||
font-weight: 600;
|
||||
@@ -97,7 +107,7 @@ const count = soundCount();
|
||||
margin: 20px auto 0;
|
||||
font-size: var(--font-xsm);
|
||||
color: var(--color-foreground-subtle);
|
||||
background-color: var(--color-neutral-100);
|
||||
background: linear-gradient(var(--color-neutral-100), transparent);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 100px;
|
||||
|
||||
@@ -106,9 +116,10 @@ const count = soundCount();
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
padding: 0 8px 0 12px;
|
||||
padding: 0 10px;
|
||||
color: var(--color-foreground);
|
||||
border-right: 1px solid var(--color-neutral-200);
|
||||
border-radius: 0 100px 100px 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
|
||||
6
src/components/menu/divider/divider.module.css
Normal file
6
src/components/menu/divider/divider.module.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.divider {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
min-height: 1px;
|
||||
background-color: var(--color-neutral-200);
|
||||
}
|
||||
5
src/components/menu/divider/divider.tsx
Normal file
5
src/components/menu/divider/divider.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import styles from './divider.module.css';
|
||||
|
||||
export function Divider() {
|
||||
return <div className={styles.divider} />;
|
||||
}
|
||||
1
src/components/menu/divider/index.ts
Normal file
1
src/components/menu/divider/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { Divider } from './divider';
|
||||
@@ -2,18 +2,19 @@
|
||||
display: flex;
|
||||
column-gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 16px 12px;
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
padding: 0 12px;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
color: var(--color-foreground-subtle);
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
transition: 0.2s;
|
||||
@@ -23,12 +24,32 @@
|
||||
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);
|
||||
}
|
||||
|
||||
& .active {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: var(--color-neutral-950);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
& .shortcut {
|
||||
font-size: var(--font-2xsm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,50 @@
|
||||
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 {
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
href?: string;
|
||||
icon: React.ReactElement;
|
||||
label: string;
|
||||
onClick?: () => void;
|
||||
shortcut?: string;
|
||||
}
|
||||
|
||||
export function Item({
|
||||
active,
|
||||
disabled = false,
|
||||
href,
|
||||
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}
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
18
src/components/menu/items/breathing-exercise.tsx
Normal file
18
src/components/menu/items/breathing-exercise.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { IoMdFlower } from 'react-icons/io/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
interface BreathingExerciseProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function BreathingExercise({ open }: BreathingExerciseProps) {
|
||||
return (
|
||||
<Item
|
||||
icon={<IoMdFlower />}
|
||||
label="Breathing Exercise"
|
||||
shortcut="Shift + B"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
}
|
||||
18
src/components/menu/items/countdown-timer.tsx
Normal file
18
src/components/menu/items/countdown-timer.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { MdOutlineTimer } from 'react-icons/md/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
interface SleepTimerProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function CountdownTimer({ open }: SleepTimerProps) {
|
||||
return (
|
||||
<Item
|
||||
icon={<MdOutlineTimer />}
|
||||
label="Countdown Timer"
|
||||
shortcut="Shift + C"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
export { Shuffle as ShuffleItem } from './shuffle';
|
||||
export { Share as ShareItem } from './share';
|
||||
export { Donate as DonateItem } from './donate';
|
||||
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';
|
||||
export { BreathingExercise as BreathingExerciseItem } from './breathing-exercise';
|
||||
|
||||
23
src/components/menu/items/notepad.tsx
Normal file
23
src/components/menu/items/notepad.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { MdNotes } from 'react-icons/md/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
import { useNoteStore } from '@/stores/note';
|
||||
|
||||
interface NotepadProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function Notepad({ open }: NotepadProps) {
|
||||
const note = useNoteStore(state => state.note);
|
||||
|
||||
return (
|
||||
<Item
|
||||
active={!!note.length}
|
||||
icon={<MdNotes />}
|
||||
label="Notepad"
|
||||
shortcut="Shift + N"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
}
|
||||
23
src/components/menu/items/pomodoro.tsx
Normal file
23
src/components/menu/items/pomodoro.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { MdOutlineAvTimer } from 'react-icons/md/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
import { usePomodoroStore } from '@/stores/pomodoro';
|
||||
|
||||
interface PomodoroProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function Pomodoro({ open }: PomodoroProps) {
|
||||
const running = usePomodoroStore(state => state.running);
|
||||
|
||||
return (
|
||||
<Item
|
||||
active={running}
|
||||
icon={<MdOutlineAvTimer />}
|
||||
label="Pomodoro"
|
||||
shortcut="Shift + P"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
}
|
||||
18
src/components/menu/items/presets.tsx
Normal file
18
src/components/menu/items/presets.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { RiPlayListFill } from 'react-icons/ri/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
interface PresetsProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function Presets({ open }: PresetsProps) {
|
||||
return (
|
||||
<Item
|
||||
icon={<RiPlayListFill />}
|
||||
label="Your Presets"
|
||||
shortcut="Shift + Alt + P"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { IoShareSocialSharp } from 'react-icons/io5/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
||||
interface ShareProps {
|
||||
open: () => void;
|
||||
@@ -16,6 +16,7 @@ export function Share({ open }: ShareProps) {
|
||||
disabled={noSelected}
|
||||
icon={<IoShareSocialSharp />}
|
||||
label="Share Sounds"
|
||||
shortcut="Shift + S"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
|
||||
18
src/components/menu/items/shortcuts.tsx
Normal file
18
src/components/menu/items/shortcuts.tsx
Normal 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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,19 @@
|
||||
import { BiShuffle } from 'react-icons/bi/index';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
22
src/components/menu/items/sleep-timer.tsx
Normal file
22
src/components/menu/items/sleep-timer.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { IoMoonSharp } from 'react-icons/io5/index';
|
||||
|
||||
import { useSleepTimerStore } from '@/stores/sleep-timer';
|
||||
import { Item } from '../item';
|
||||
|
||||
interface SleepTimerProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function SleepTimer({ open }: SleepTimerProps) {
|
||||
const active = useSleepTimerStore(state => state.active);
|
||||
|
||||
return (
|
||||
<Item
|
||||
active={active}
|
||||
icon={<IoMoonSharp />}
|
||||
label="Sleep Timer"
|
||||
shortcut="Shift + T"
|
||||
onClick={open}
|
||||
/>
|
||||
);
|
||||
}
|
||||
13
src/components/menu/items/source.tsx
Normal file
13
src/components/menu/items/source.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { LuGithub } from 'react-icons/lu/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
export function Source() {
|
||||
return (
|
||||
<Item
|
||||
href="https://github.com/remvze/moodist"
|
||||
icon={<LuGithub />}
|
||||
label="Source Code"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
.wrapper {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
z-index: 5;
|
||||
|
||||
& .menuButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -18,40 +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;
|
||||
padding: 4px;
|
||||
background-color: var(--color-neutral-100);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 4px;
|
||||
|
||||
& .menuItem {
|
||||
position: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 12px 8px;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground-subtle);
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-foreground);
|
||||
background-color: var(--color-neutral-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
z-index: 15;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 4px;
|
||||
width: 270px;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,92 +1,171 @@
|
||||
import { useState } from 'react';
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
import { IoMenu, IoClose } from 'react-icons/io5/index';
|
||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
|
||||
import {
|
||||
useFloating,
|
||||
autoUpdate,
|
||||
offset,
|
||||
flip,
|
||||
shift,
|
||||
useClick,
|
||||
useDismiss,
|
||||
useRole,
|
||||
useInteractions,
|
||||
FloatingFocusManager,
|
||||
} from '@floating-ui/react';
|
||||
|
||||
import { ShuffleItem, ShareItem, DonateItem } from './items';
|
||||
ShuffleItem,
|
||||
ShareItem,
|
||||
DonateItem,
|
||||
NotepadItem,
|
||||
SourceItem,
|
||||
PomodoroItem,
|
||||
CountdownTimerItem,
|
||||
PresetsItem,
|
||||
ShortcutsItem,
|
||||
SleepTimerItem,
|
||||
BreathingExerciseItem,
|
||||
} from './items';
|
||||
import { Divider } from './divider';
|
||||
import { ShareLinkModal } from '@/components/modals/share-link';
|
||||
|
||||
import { slideY, fade, mix } from '@/lib/motion';
|
||||
import { PresetsModal } from '@/components/modals/presets';
|
||||
import { ShortcutsModal } from '@/components/modals/shortcuts';
|
||||
import { SleepTimerModal } from '@/components/modals/sleep-timer';
|
||||
import {
|
||||
Notepad,
|
||||
Pomodoro,
|
||||
CountdownTimer,
|
||||
BreathingExercise,
|
||||
} from '@/components/toolbox';
|
||||
import { fade, mix, slideY } from '@/lib/motion';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
||||
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 [showShareLink, setShowShareLink] = useState(false);
|
||||
const noSelected = useSoundStore(state => state.noSelected());
|
||||
|
||||
const variants = mix(slideY(-20), fade());
|
||||
const initial = useMemo(
|
||||
() => ({
|
||||
breathingExercise: false,
|
||||
countdownTimer: false,
|
||||
notepad: false,
|
||||
pomodoro: false,
|
||||
presets: false,
|
||||
shareLink: false,
|
||||
shortcuts: false,
|
||||
sleepTimer: false,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const { context, floatingStyles, refs } = useFloating({
|
||||
middleware: [offset(12), flip(), shift()],
|
||||
onOpenChange: setIsOpen,
|
||||
open: isOpen,
|
||||
placement: 'top-end',
|
||||
whileElementsMounted: autoUpdate,
|
||||
});
|
||||
const [modals, setModals] = useState(initial);
|
||||
|
||||
const click = useClick(context);
|
||||
const dismiss = useDismiss(context);
|
||||
const role = useRole(context);
|
||||
const close = useCallback((name: string) => {
|
||||
setModals(prev => ({ ...prev, [name]: false }));
|
||||
}, []);
|
||||
|
||||
const { getFloatingProps, getReferenceProps } = useInteractions([
|
||||
click,
|
||||
dismiss,
|
||||
role,
|
||||
]);
|
||||
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+c', () => open('countdownTimer'));
|
||||
useHotkeys('shift+b', () => open('breathingExercise'));
|
||||
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>
|
||||
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<FloatingFocusManager context={context} modal={false}>
|
||||
<div
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
{...getFloatingProps()}
|
||||
>
|
||||
<motion.div
|
||||
animate="show"
|
||||
className={styles.menu}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
variants={variants}
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<DropdownMenu.Portal forceMount>
|
||||
<DropdownMenu.Content
|
||||
align="end"
|
||||
asChild
|
||||
collisionPadding={10}
|
||||
side="top"
|
||||
sideOffset={12}
|
||||
>
|
||||
<ShareItem open={() => setShowShareLink(true)} />
|
||||
<ShuffleItem />
|
||||
<DonateItem />
|
||||
</motion.div>
|
||||
</div>
|
||||
</FloatingFocusManager>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<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 />
|
||||
<PomodoroItem open={() => open('pomodoro')} />
|
||||
<NotepadItem open={() => open('notepad')} />
|
||||
<BreathingExerciseItem
|
||||
open={() => open('breathingExercise')}
|
||||
/>
|
||||
<CountdownTimerItem open={() => open('countdownTimer')} />
|
||||
|
||||
<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')}
|
||||
/>
|
||||
<BreathingExercise
|
||||
show={modals.breathingExercise}
|
||||
onClose={() => close('breathingExercise')}
|
||||
/>
|
||||
<CountdownTimer
|
||||
show={modals.countdownTimer}
|
||||
onClose={() => close('countdownTimer')}
|
||||
/>
|
||||
<SleepTimerModal
|
||||
show={modals.sleepTimer}
|
||||
onClose={() => close('sleepTimer')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 10;
|
||||
z-index: 20;
|
||||
background-color: rgb(9 9 11 / 40%);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 12;
|
||||
z-index: 20;
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
padding: 50px 0;
|
||||
@@ -29,6 +29,13 @@
|
||||
background-color: var(--color-neutral-100);
|
||||
border-radius: 8px;
|
||||
|
||||
&.wide {
|
||||
width: 95%;
|
||||
max-width: 600px;
|
||||
padding: 12px;
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
& .close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
@@ -43,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
src/components/modal/modal.stories.tsx
Normal file
26
src/components/modal/modal.stories.tsx
Normal 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,
|
||||
},
|
||||
};
|
||||
@@ -1,52 +1,100 @@
|
||||
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';
|
||||
|
||||
import { fade, mix, slideY } from '@/lib/motion';
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
||||
import styles from './modal.module.css';
|
||||
|
||||
interface ModalProps {
|
||||
children: React.ReactNode;
|
||||
lockBody?: boolean;
|
||||
onClose: () => void;
|
||||
persist?: boolean;
|
||||
show: boolean;
|
||||
wide?: boolean;
|
||||
}
|
||||
|
||||
export function Modal({ children, onClose, show }: ModalProps) {
|
||||
export function Modal({
|
||||
children,
|
||||
lockBody = true,
|
||||
onClose,
|
||||
persist = false,
|
||||
show,
|
||||
wide,
|
||||
}: ModalProps) {
|
||||
const variants = {
|
||||
modal: mix(fade(), slideY(20)),
|
||||
overlay: fade(),
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{show && (
|
||||
<>
|
||||
<motion.div
|
||||
animate="show"
|
||||
className={styles.overlay}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
variants={variants.overlay}
|
||||
onClick={onClose}
|
||||
onKeyDown={onClose}
|
||||
/>
|
||||
<div className={styles.modal}>
|
||||
<motion.div
|
||||
animate="show"
|
||||
className={styles.content}
|
||||
exit="hidden"
|
||||
initial="hidden"
|
||||
variants={variants.modal}
|
||||
>
|
||||
<button className={styles.close} onClick={onClose}>
|
||||
<IoClose />
|
||||
</button>
|
||||
useEffect(() => {
|
||||
if (show && lockBody) {
|
||||
document.body.style.overflow = 'hidden';
|
||||
} else if (lockBody) {
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
}, [show, lockBody]);
|
||||
|
||||
{children}
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
useEffect(() => {
|
||||
function keyListener(e: KeyboardEvent) {
|
||||
if (show && e.key === 'Escape') {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', keyListener);
|
||||
|
||||
return () => document.removeEventListener('keydown', keyListener);
|
||||
}, [onClose, show]);
|
||||
|
||||
const animationProps = persist
|
||||
? {
|
||||
animate: show ? 'show' : 'hidden',
|
||||
}
|
||||
: {
|
||||
animate: 'show',
|
||||
exit: 'hidden',
|
||||
initial: 'hidden',
|
||||
};
|
||||
|
||||
const content = (
|
||||
<FocusTrap active={show}>
|
||||
<div>
|
||||
<motion.div
|
||||
{...animationProps}
|
||||
className={styles.overlay}
|
||||
variants={variants.overlay}
|
||||
onClick={onClose}
|
||||
onKeyDown={onClose}
|
||||
/>
|
||||
<div className={styles.modal}>
|
||||
<motion.div
|
||||
{...animationProps}
|
||||
className={cn(styles.content, wide && styles.wide)}
|
||||
variants={variants.modal}
|
||||
>
|
||||
<button className={styles.close} onClick={onClose}>
|
||||
<IoClose />
|
||||
</button>
|
||||
{children}
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</FocusTrap>
|
||||
);
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
{persist ? (
|
||||
<div style={{ display: show ? 'block' : 'none' }}>{content}</div>
|
||||
) : (
|
||||
<AnimatePresence>{show && content}</AnimatePresence>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</Portal>
|
||||
);
|
||||
}
|
||||
|
||||
1
src/components/modals/presets/index.ts
Normal file
1
src/components/modals/presets/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { PresetsModal } from './presets';
|
||||
1
src/components/modals/presets/list/index.ts
Normal file
1
src/components/modals/presets/list/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { List } from './list';
|
||||
72
src/components/modals/presets/list/list.module.css
Normal file
72
src/components/modals/presets/list/list.module.css
Normal file
@@ -0,0 +1,72 @@
|
||||
.list {
|
||||
& .title {
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground-subtle);
|
||||
}
|
||||
|
||||
& .empty {
|
||||
font-size: var(--font-sm);
|
||||
}
|
||||
|
||||
& .preset {
|
||||
display: flex;
|
||||
column-gap: 4px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
padding: 4px;
|
||||
margin-top: 8px;
|
||||
background-color: var(--color-neutral-50);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 8px;
|
||||
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
& input {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: var(--color-foreground);
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-neutral-400);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
& button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground-subtle);
|
||||
cursor: pointer;
|
||||
background-color: var(--color-neutral-100);
|
||||
border: none;
|
||||
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);
|
||||
background-color: var(--color-neutral-200);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/components/modals/presets/list/list.tsx
Normal file
54
src/components/modals/presets/list/list.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { FaPlay, FaRegTrashAlt } from 'react-icons/fa/index';
|
||||
|
||||
import styles from './list.module.css';
|
||||
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { usePresetStore } from '@/stores/preset';
|
||||
|
||||
interface ListProps {
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
export function List({ close }: ListProps) {
|
||||
const presets = usePresetStore(state => state.presets);
|
||||
const changeName = usePresetStore(state => state.changeName);
|
||||
const deletePreset = usePresetStore(state => state.deletePreset);
|
||||
const override = useSoundStore(state => state.override);
|
||||
const play = useSoundStore(state => state.play);
|
||||
|
||||
return (
|
||||
<div className={styles.list}>
|
||||
<h3 className={styles.title}>
|
||||
Your Presets {presets.length > 0 && `(${presets.length})`}
|
||||
</h3>
|
||||
|
||||
{!presets.length && (
|
||||
<p className={styles.empty}>You don't have any presets yet.</p>
|
||||
)}
|
||||
|
||||
{presets.map(preset => (
|
||||
<div className={styles.preset} key={preset.id}>
|
||||
<input
|
||||
placeholder="Untitled"
|
||||
type="text"
|
||||
value={preset.label}
|
||||
onChange={e => changeName(preset.id, e.target.value)}
|
||||
/>
|
||||
<button onClick={() => deletePreset(preset.id)}>
|
||||
<FaRegTrashAlt />
|
||||
</button>
|
||||
<button
|
||||
className={styles.primary}
|
||||
onClick={() => {
|
||||
override(preset.sounds);
|
||||
play();
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<FaPlay />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
1
src/components/modals/presets/new/index.ts
Normal file
1
src/components/modals/presets/new/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { New } from './new';
|
||||
72
src/components/modals/presets/new/new.module.css
Normal file
72
src/components/modals/presets/new/new.module.css
Normal file
@@ -0,0 +1,72 @@
|
||||
.new {
|
||||
margin-top: 16px;
|
||||
|
||||
& .title {
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground-subtle);
|
||||
}
|
||||
|
||||
& .form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
padding: 4px;
|
||||
margin-top: 8px;
|
||||
background-color: var(--color-neutral-50);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 8px;
|
||||
|
||||
&.disabled {
|
||||
filter: blur(2px);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
& input {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: var(--color-foreground);
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-neutral-400);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
& button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-neutral-50);
|
||||
cursor: pointer;
|
||||
background-color: var(--color-neutral-950);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-neutral-400);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .noSelected {
|
||||
margin-top: 8px;
|
||||
font-size: var(--font-sm);
|
||||
color: var(--color-foreground-subtle);
|
||||
}
|
||||
}
|
||||
60
src/components/modals/presets/new/new.tsx
Normal file
60
src/components/modals/presets/new/new.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { useState, type FormEvent } from 'react';
|
||||
|
||||
import { cn } from '@/helpers/styles';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { usePresetStore } from '@/stores/preset';
|
||||
|
||||
import styles from './new.module.css';
|
||||
|
||||
export function New() {
|
||||
const [name, setName] = useState('');
|
||||
|
||||
const noSelected = useSoundStore(state => state.noSelected());
|
||||
const sounds = useSoundStore(state => state.sounds);
|
||||
const addPreset = usePresetStore(state => state.addPreset);
|
||||
|
||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!name || noSelected) return;
|
||||
|
||||
const _sounds: Record<string, number> = {};
|
||||
|
||||
Object.keys(sounds)
|
||||
.filter(id => sounds[id].isSelected)
|
||||
.forEach(id => {
|
||||
_sounds[id] = sounds[id].volume;
|
||||
});
|
||||
|
||||
addPreset(name, _sounds);
|
||||
|
||||
setName('');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.new}>
|
||||
<h3 className={styles.title}>New Preset</h3>
|
||||
|
||||
<form
|
||||
className={cn(styles.form, noSelected && styles.disabled)}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<input
|
||||
disabled={noSelected}
|
||||
placeholder="Preset's Name"
|
||||
required
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
/>
|
||||
<button disabled={noSelected}>Save</button>
|
||||
</form>
|
||||
|
||||
{noSelected && (
|
||||
<p className={styles.noSelected}>
|
||||
To make a preset, first select some sounds.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
12
src/components/modals/presets/presets.module.css
Normal file
12
src/components/modals/presets/presets.module.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.title {
|
||||
font-family: var(--font-heading);
|
||||
font-size: var(--font-md);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
margin: 16px 0;
|
||||
background-color: var(--color-neutral-200);
|
||||
}
|
||||
21
src/components/modals/presets/presets.tsx
Normal file
21
src/components/modals/presets/presets.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Modal } from '@/components/modal';
|
||||
import { New } from './new';
|
||||
import { List } from './list';
|
||||
|
||||
import styles from './presets.module.css';
|
||||
|
||||
interface PresetsModalProps {
|
||||
onClose: () => void;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export function PresetsModal({ onClose, show }: PresetsModalProps) {
|
||||
return (
|
||||
<Modal show={show} onClose={onClose}>
|
||||
<h2 className={styles.title}>Presets</h2>
|
||||
<New />
|
||||
<div className={styles.divider} />
|
||||
<List close={onClose} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
& input {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
padding: 0 10px;
|
||||
font-size: var(--font-sm);
|
||||
@@ -30,6 +31,11 @@
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-neutral-400);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
& button {
|
||||
@@ -46,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { IoCopyOutline, IoCheckmark } from 'react-icons/io5/index';
|
||||
import { Modal } from '@/components/modal';
|
||||
|
||||
import { useCopy } from '@/hooks/use-copy';
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
||||
import styles from './share-link.module.css';
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ import { useState, useEffect } from 'react';
|
||||
|
||||
import { Modal } from '@/components/modal';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
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>
|
||||
|
||||
1
src/components/modals/shortcuts/index.ts
Normal file
1
src/components/modals/shortcuts/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { ShortcutsModal } from './shortcuts';
|
||||
47
src/components/modals/shortcuts/shortcuts.module.css
Normal file
47
src/components/modals/shortcuts/shortcuts.module.css
Normal 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);
|
||||
}
|
||||
95
src/components/modals/shortcuts/shortcuts.tsx
Normal file
95
src/components/modals/shortcuts/shortcuts.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
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', 'B'],
|
||||
label: 'Breathing Exercise',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'C'],
|
||||
label: 'Countdown 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>;
|
||||
}
|
||||
1
src/components/modals/sleep-timer/index.ts
Normal file
1
src/components/modals/sleep-timer/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { SleepTimerModal } from './sleep-timer';
|
||||
97
src/components/modals/sleep-timer/sleep-timer.module.css
Normal file
97
src/components/modals/sleep-timer/sleep-timer.module.css
Normal file
@@ -0,0 +1,97 @@
|
||||
.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;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-neutral-400);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
162
src/components/modals/sleep-timer/sleep-timer.tsx
Normal file
162
src/components/modals/sleep-timer/sleep-timer.tsx
Normal file
@@ -0,0 +1,162 @@
|
||||
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 '@/stores/sound';
|
||||
import { cn } from '@/helpers/styles';
|
||||
import { FADE_OUT } from '@/constants/events';
|
||||
import { useSleepTimerStore } from '@/stores/sleep-timer';
|
||||
|
||||
import styles from './sleep-timer.module.css';
|
||||
|
||||
interface SleepTimerModalProps {
|
||||
onClose: () => void;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export function SleepTimerModal({ onClose, show }: SleepTimerModalProps) {
|
||||
const setActive = useSleepTimerStore(state => state.set);
|
||||
|
||||
const [running, setRunning] = useState(false);
|
||||
|
||||
useEffect(() => setActive(running), [running, setActive]);
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
1
src/components/portal/index.ts
Normal file
1
src/components/portal/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { Portal } from './portal';
|
||||
14
src/components/portal/portal.tsx
Normal file
14
src/components/portal/portal.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
interface PortalProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Portal({ children }: PortalProps) {
|
||||
const [isClientSide, setIsClientSide] = useState(false);
|
||||
|
||||
useEffect(() => setIsClientSide(true), []);
|
||||
|
||||
return isClientSide ? createPortal(children, document.body) : null;
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
.button {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
z-index: 99;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -16,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export function ScrollToTop() {
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isVisible && (
|
||||
{isVisible ? (
|
||||
<motion.button
|
||||
animate="show"
|
||||
aria-label="Scroll to top"
|
||||
@@ -43,6 +43,8 @@ export function ScrollToTop() {
|
||||
>
|
||||
<BiUpArrowAlt />
|
||||
</motion.button>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
import { Container } from '@/components/container';
|
||||
import { count as soundCount } from '@/lib/sounds';
|
||||
|
||||
const count = soundCount();
|
||||
---
|
||||
|
||||
<div class="about">
|
||||
<Container>
|
||||
<div class="titleWrapper">
|
||||
<h2 class="title">What is Moodist?</h2>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
<p class="desc">
|
||||
Welcome to Moodist – your free, open-source ambient sound generator. With <span
|
||||
>{count} curated sounds</span
|
||||
>, effortlessly create your custom mix for focus or relaxation. No
|
||||
accounts, no hassle – just pure tranquility. Explore nature's calm
|
||||
and urban rhythms. Elevate your ambiance with Moodist, where simplicity
|
||||
meets serenity.
|
||||
</p>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.about {
|
||||
padding: 80px 0;
|
||||
|
||||
& .titleWrapper {
|
||||
display: flex;
|
||||
column-gap: 12px;
|
||||
align-items: center;
|
||||
|
||||
& .title {
|
||||
margin-bottom: 12px;
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--font-lg);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
& .line {
|
||||
flex-grow: 1;
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--color-neutral-300),
|
||||
transparent
|
||||
);
|
||||
transform: translateY(-0.25rem);
|
||||
}
|
||||
}
|
||||
|
||||
& .desc {
|
||||
line-height: 1.7;
|
||||
color: var(--color-foreground-subtle);
|
||||
|
||||
& span {
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,157 +0,0 @@
|
||||
---
|
||||
import { BiMoney, BiUserCircle, BiLogoGithub } from 'react-icons/bi/index';
|
||||
import { BsSoundwave, BsStars } from 'react-icons/bs/index';
|
||||
import { RxMixerHorizontal } from 'react-icons/rx/index';
|
||||
|
||||
import { Balancer } from 'react-wrap-balancer';
|
||||
|
||||
import { Container } from '@/components/container';
|
||||
import { count as soundCount } from '@/lib/sounds';
|
||||
|
||||
const count = soundCount();
|
||||
|
||||
const reasons = [
|
||||
{
|
||||
Icon: BiMoney,
|
||||
body: "Immerse yourself in Moodist's ambient world without spending a dime. All features are accessible to everyone, ensuring a cost-free auditory journey.",
|
||||
id: 'free-access',
|
||||
label: 'Free Access',
|
||||
},
|
||||
{
|
||||
Icon: BiUserCircle,
|
||||
body: 'Embrace simplicity – Moodist skips the registration process. No accounts, no hassle; just click, play, and enjoy the serenity.',
|
||||
id: 'no-registration',
|
||||
label: 'No Registration',
|
||||
},
|
||||
{
|
||||
Icon: BsSoundwave,
|
||||
body: `With a curated collection of ${count} sounds, Moodist offers a spectrum of auditory experiences. From the tranquility of nature to the beat of urban life, find the perfect backdrop for your mood.`,
|
||||
id: 'diverse-sounds',
|
||||
label: 'Diverse Sounds',
|
||||
},
|
||||
{
|
||||
Icon: RxMixerHorizontal,
|
||||
body: 'Tailor your ambiance effortlessly. Moodist allows you to create personalized mixes, adjusting the blend of sounds to suit your focus or relaxation needs.',
|
||||
id: 'customizable-mixes',
|
||||
label: 'Customizable Mixes',
|
||||
},
|
||||
{
|
||||
Icon: BiLogoGithub,
|
||||
body: 'Trust in transparency. Moodist is open-source, fostering collaboration and providing users with a platform they can explore and understand.',
|
||||
id: 'open-source',
|
||||
label: 'Open-Source',
|
||||
link: {
|
||||
label: 'Source Code',
|
||||
url: 'https://github.com/remvze/moodist',
|
||||
},
|
||||
},
|
||||
{
|
||||
Icon: BsStars,
|
||||
body: 'Navigate with ease. Moodist provides a user-friendly interface, ensuring a smooth and hassle-free experience as you explore the diverse soundscape of calm and rhythm.',
|
||||
id: 'seamless-experience',
|
||||
label: 'Seamless Experience',
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<div class="why">
|
||||
<Container>
|
||||
<div class="titleWrapper">
|
||||
<h2 class="title">Why use Moodist?</h2>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
|
||||
<div class="reasons">
|
||||
{
|
||||
reasons.map(reason => (
|
||||
<div class="reason">
|
||||
<div class="icon">
|
||||
<reason.Icon />
|
||||
</div>
|
||||
<h3 class="label">{reason.label}</h3>
|
||||
<p class="body">
|
||||
<Balancer>{reason.body}</Balancer>
|
||||
</p>
|
||||
{reason.link && (
|
||||
<a class="link" href={reason.link.url}>
|
||||
{reason.link.label} →
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.why {
|
||||
padding-bottom: 80px;
|
||||
|
||||
& .titleWrapper {
|
||||
display: flex;
|
||||
column-gap: 12px;
|
||||
align-items: center;
|
||||
|
||||
& .title {
|
||||
margin-bottom: 12px;
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--font-lg);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
& .line {
|
||||
flex-grow: 1;
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--color-neutral-300),
|
||||
transparent
|
||||
);
|
||||
transform: translateY(-0.25rem);
|
||||
}
|
||||
}
|
||||
|
||||
& .reasons {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
row-gap: 28px;
|
||||
column-gap: 20px;
|
||||
margin-top: 24px;
|
||||
|
||||
& .icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: 12px;
|
||||
font-size: var(--font-md);
|
||||
color: var(--color-foreground-subtle);
|
||||
background: linear-gradient(var(--color-neutral-100), transparent);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
& .label {
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--font-heading);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
& .body {
|
||||
line-height: 1.6;
|
||||
color: var(--color-foreground-subtle);
|
||||
}
|
||||
|
||||
& .link {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BiShuffle } from 'react-icons/bi/index';
|
||||
|
||||
import { Tooltip } from '@/components/tooltip';
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
||||
import styles from './shuffle.module.css';
|
||||
|
||||
@@ -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}
|
||||
|
||||
18
src/components/snackbar/snackbar.stories.tsx
Normal file
18
src/components/snackbar/snackbar.stories.tsx
Normal 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',
|
||||
},
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,30 +1,57 @@
|
||||
import { BiHeart, BiSolidHeart } from 'react-icons/bi/index';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { cn } from '@/helpers/styles';
|
||||
import { fade } from '@/lib/motion';
|
||||
|
||||
import styles from './favorite.module.css';
|
||||
|
||||
import { useKeyboardButton } from '@/hooks/use-keyboard-button';
|
||||
import { waitUntil } from '@/helpers/wait';
|
||||
|
||||
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 handleToggle = async () => {
|
||||
toggleFavorite(id);
|
||||
|
||||
// Check if false -> true
|
||||
if (!isFavorite) {
|
||||
await waitUntil(
|
||||
() => !!document.getElementById('category-favorites'),
|
||||
50,
|
||||
);
|
||||
|
||||
document
|
||||
.getElementById('category-favorites')
|
||||
?.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
};
|
||||
|
||||
const variants = fade();
|
||||
|
||||
const handleKeyDown = useKeyboardButton(handleToggle);
|
||||
|
||||
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);
|
||||
handleToggle();
|
||||
}}
|
||||
>
|
||||
<motion.span
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
|
||||
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)
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -91,7 +97,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
& h3 {
|
||||
& .label {
|
||||
margin-top: 8px;
|
||||
font-family: var(--font-heading);
|
||||
font-size: var(--font-sm);
|
||||
|
||||
@@ -1,86 +1,100 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useCallback, useEffect, forwardRef } from 'react';
|
||||
import { ImSpinner9 } from 'react-icons/im/index';
|
||||
|
||||
import { Range } from './range';
|
||||
import { Favorite } from './favorite';
|
||||
|
||||
import { useSound } from '@/hooks/use-sound';
|
||||
import { useSoundStore, useLoadingStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { useLoadingStore } from '@/stores/loading';
|
||||
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);
|
||||
const unselect = useSoundStore(state => state.unselect);
|
||||
const selectSound = useSoundStore(state => state.select);
|
||||
const unselectSound = useSoundStore(state => state.unselect);
|
||||
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);
|
||||
else if (hidden && !isSelected) unselectHidden(label);
|
||||
}, [label, isSelected, hidden, selectHidden, unselectHidden]);
|
||||
|
||||
const _select = useCallback(() => {
|
||||
select(id);
|
||||
const select = useCallback(() => {
|
||||
if (locked) return;
|
||||
selectSound(id);
|
||||
play();
|
||||
}, [select, play, id]);
|
||||
}, [selectSound, play, id, locked]);
|
||||
|
||||
const _unselect = useCallback(() => {
|
||||
unselect(id);
|
||||
const unselect = useCallback(() => {
|
||||
if (locked) return;
|
||||
unselectSound(id);
|
||||
setVolume(id, 0.5);
|
||||
}, [unselect, setVolume, id]);
|
||||
}, [unselectSound, 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}>
|
||||
@@ -90,8 +104,10 @@ export function Sound({
|
||||
icon
|
||||
)}
|
||||
</div>
|
||||
<h3 id={id}>{label}</h3>
|
||||
<Range id={id} />
|
||||
<div className={styles.label} id={id}>
|
||||
{label}
|
||||
</div>
|
||||
<Range id={id} label={label} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -1,42 +1,40 @@
|
||||
---
|
||||
import { RiSparkling2Line } from 'react-icons/ri/index';
|
||||
import { FaGithub } from 'react-icons/fa/index';
|
||||
|
||||
import { Container } from '@/components/container';
|
||||
import { SpecialButton } from './special-button';
|
||||
import { Container } from './container';
|
||||
---
|
||||
|
||||
<div class="ready">
|
||||
<div class="source">
|
||||
<Container>
|
||||
<div class="wrapper">
|
||||
<div class="iconContainer">
|
||||
<div class="tail"></div>
|
||||
<div class="icon">
|
||||
<RiSparkling2Line />
|
||||
<FaGithub />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="title">Are you ready?</h2>
|
||||
<p class="desc">Create your calm oasis in seconds!</p>
|
||||
<button class="button" id="button"> Use Moodist</button>
|
||||
<h2 class="title">Open Source</h2>
|
||||
<p class="desc">Moodist is free and open-source!</p>
|
||||
|
||||
<div class="button">
|
||||
<SpecialButton href="https://github.com/remvze/moodist">
|
||||
Source Code
|
||||
</SpecialButton>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const button = document.getElementById('button');
|
||||
|
||||
button?.addEventListener('click', () => {
|
||||
const app = document.getElementById('app');
|
||||
|
||||
app?.scrollIntoView(true);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ready {
|
||||
.source {
|
||||
margin-top: 40px;
|
||||
|
||||
& .wrapper {
|
||||
position: relative;
|
||||
padding: 0 20px 40px;
|
||||
background: linear-gradient(transparent, var(--color-neutral-100));
|
||||
background: linear-gradient(transparent, rgb(24 24 27 / 70%));
|
||||
border-radius: 0 0 20px 20px;
|
||||
|
||||
&::after {
|
||||
@@ -49,7 +47,7 @@ import { Container } from '@/components/container';
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
var(--color-neutral-300),
|
||||
var(--color-neutral-400),
|
||||
transparent
|
||||
);
|
||||
transform: translateX(-50%);
|
||||
@@ -82,7 +80,6 @@ import { Container } from '@/components/container';
|
||||
}
|
||||
|
||||
& .title {
|
||||
margin-bottom: 12px;
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--font-lg);
|
||||
font-weight: 600;
|
||||
@@ -90,32 +87,15 @@ import { Container } from '@/components/container';
|
||||
}
|
||||
|
||||
& .desc {
|
||||
margin-top: 8px;
|
||||
color: var(--color-foreground-subtle);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& .button {
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
margin: 24px auto 0;
|
||||
font-family: var(--font-heading);
|
||||
font-size: var(--font-sm);
|
||||
line-height: 0;
|
||||
color: var(--color-neutral-200);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
background-color: var(--color-neutral-950);
|
||||
border: none;
|
||||
border-radius: 100px;
|
||||
outline: none;
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-neutral-800);
|
||||
}
|
||||
margin: 16px auto 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1
src/components/special-button/index.ts
Normal file
1
src/components/special-button/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { SpecialButton } from './special-button';
|
||||
80
src/components/special-button/special-button.module.css
Normal file
80
src/components/special-button/special-button.module.css
Normal file
@@ -0,0 +1,80 @@
|
||||
.button {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: max-content;
|
||||
height: 40px;
|
||||
padding: 0 20px;
|
||||
overflow: hidden;
|
||||
font-size: var(--font-xsm);
|
||||
font-weight: 500;
|
||||
color: var(--color-neutral-subtle);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
background-color: var(--color-neutral-200);
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
transition: 0.2s;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-neutral-400);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
z-index: -1;
|
||||
width: calc(100% - 2px);
|
||||
height: calc(100% - 2px);
|
||||
content: '';
|
||||
background-color: var(--color-neutral-50);
|
||||
border-radius: 100px;
|
||||
transition: inherit;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: -2;
|
||||
width: 150%;
|
||||
aspect-ratio: 1 / 1;
|
||||
content: '';
|
||||
background-image: conic-gradient(
|
||||
transparent,
|
||||
transparent,
|
||||
var(--color-neutral-400),
|
||||
transparent,
|
||||
transparent,
|
||||
transparent,
|
||||
transparent,
|
||||
var(--color-neutral-400),
|
||||
transparent,
|
||||
transparent
|
||||
);
|
||||
transform: translate(-50%, -50%);
|
||||
animation-name: shine;
|
||||
animation-duration: 6s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
&:hover::after,
|
||||
&:focus-visible::after {
|
||||
background-color: var(--color-neutral-100);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) rotate(90deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(-50%, -50%) rotate(450deg);
|
||||
}
|
||||
}
|
||||
20
src/components/special-button/special-button.stories.tsx
Normal file
20
src/components/special-button/special-button.stories.tsx
Normal 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: '#',
|
||||
},
|
||||
};
|
||||
26
src/components/special-button/special-button.tsx
Normal file
26
src/components/special-button/special-button.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
||||
import styles from './special-button.module.css';
|
||||
|
||||
interface SpecialButtonProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export function SpecialButton({
|
||||
children,
|
||||
className,
|
||||
href,
|
||||
}: SpecialButtonProps) {
|
||||
return (
|
||||
<a
|
||||
className={cn(styles.button, className)}
|
||||
href={href}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useSoundStore } from '@/store';
|
||||
import { useSoundStore } from '@/stores/sound';
|
||||
import { useNoteStore } from '@/stores/note';
|
||||
import { usePresetStore } from '@/stores/preset';
|
||||
import { useCountdownTimers } from '@/stores/countdown-timers';
|
||||
|
||||
interface StoreConsumerProps {
|
||||
children: React.ReactNode;
|
||||
@@ -9,6 +12,9 @@ interface StoreConsumerProps {
|
||||
export function StoreConsumer({ children }: StoreConsumerProps) {
|
||||
useEffect(() => {
|
||||
useSoundStore.persist.rehydrate();
|
||||
useNoteStore.persist.rehydrate();
|
||||
usePresetStore.persist.rehydrate();
|
||||
useCountdownTimers.persist.rehydrate();
|
||||
}, []);
|
||||
|
||||
return <>{children}</>;
|
||||
|
||||
1
src/components/timer/index.ts
Normal file
1
src/components/timer/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { Timer } from './timer';
|
||||
12
src/components/timer/timer.module.css
Normal file
12
src/components/timer/timer.module.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.timer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 30px 0;
|
||||
font-size: var(--font-xlg);
|
||||
font-weight: 500;
|
||||
background-color: var(--color-neutral-50);
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 8px;
|
||||
}
|
||||
36
src/components/timer/timer.tsx
Normal file
36
src/components/timer/timer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
1
src/components/toolbar/index.ts
Normal file
1
src/components/toolbar/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { Toolbar } from './toolbar';
|
||||
13
src/components/toolbar/toolbar.module.css
Normal file
13
src/components/toolbar/toolbar.module.css
Normal file
@@ -0,0 +1,13 @@
|
||||
.wrapper {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
z-index: 15;
|
||||
width: 100%;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user