8 Commits

Author SHA1 Message Date
MAZE
c60dcc74ed chore(release): 1.5.1 2024-06-14 20:53:41 +03:30
MAZE
aca746148e Merge branch 'develop' 2024-06-14 20:53:14 +03:30
MAZE
095e3c795e chore: add more sounds 2024-06-14 20:51:35 +03:30
MAZE
7e65bb75f9 chore: add washing machine sound 2024-06-14 20:36:41 +03:30
MAZE
0533460667 refactor: rename some functions 2024-06-14 19:08:00 +04:30
MAZE
9d633a9637 refactor: use nullish operator 2024-06-14 18:57:13 +04:30
MAZE
a9fe7f7b4f chore: update README file 2024-06-12 23:42:28 +03:30
MAZE
ffe260f4a0 refactor: migrate to Astro components 2024-05-20 13:14:42 +04:30
34 changed files with 577 additions and 555 deletions

View File

@@ -2,6 +2,22 @@
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.5.1](https://github.com/remvze/moodist/compare/v1.5.0...v1.5.1) (2024-06-14)
### ♻️ Code Refactoring
* 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 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)

View File

@@ -16,17 +16,17 @@
## 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
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

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "moodist",
"version": "1.5.0",
"version": "1.5.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "moodist",
"version": "1.5.0",
"version": "1.5.1",
"dependencies": {
"@astrojs/react": "^3.0.3",
"@floating-ui/react": "0.26.0",

View File

@@ -1,7 +1,7 @@
{
"name": "moodist",
"type": "module",
"version": "1.5.0",
"version": "1.5.1",
"scripts": {
"dev": "astro dev",
"start": "astro dev",

Binary file not shown.

Binary file not shown.

Binary file not shown.

160
src/components/about.astro Normal file
View 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 goes beyond just ambient sounds by offering a suite of productivity tools to help you stay organized and focused. Utilize the built-in pomodoro timer to structure your workday in focused intervals, jot down thoughts and ideas in the simple notepad, and keep track of your tasks with the handy to-do list. These tools seamlessly integrate with the ambient soundscapes, allowing you to create a personalized environment that fosters both 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>

View File

@@ -1,96 +0,0 @@
.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;
}
}
}

View File

@@ -1,60 +0,0 @@
import { Container } from '@/components/container';
import { count as soundCount } from '@/lib/sounds';
import styles from './about.module.css';
export function About() {
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 goes beyond just ambient sounds by offering a suite of productivity tools to help you stay organized and focused. Utilize the built-in pomodoro timer to structure your workday in focused intervals, jot down thoughts and ideas in the simple notepad, and keep track of your tasks with the handy to-do list. These tools seamlessly integrate with the ambient soundscapes, allowing you to create a personalized environment that fosters both 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',
},
];
const handleClick = () => {
const app = document.getElementById('app');
app?.scrollIntoView();
};
return (
<section className={styles.about}>
<div className={styles.effect} />
<Container tight>
{paragraphs.map((paragraph, index) => (
<div className={styles.paragraph} key={index}>
<div className={styles.counter}>
<span>0{index + 1}</span> / 0{paragraphs.length}
</div>
<h2 className={styles.title}>{paragraph.title}</h2>
<p className={styles.body}>{paragraph.body}</p>
</div>
))}
<button className={styles.button} onClick={handleClick}>
Use Moodist
</button>
</Container>
</section>
);
}

View File

@@ -1 +0,0 @@
export { About } from './about';

View File

@@ -0,0 +1,57 @@
---
import { Container } from './container';
---
<Container>
<section class="wrapper">
<p class="text">
Enjoy Moodist?{' '}
<a
href="https://buymeacoffee.com/remvze"
rel="noreferrer"
target="_blank"
>
Support with a donation!
</a>
</p>
</section>
</Container>
<style>
.wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 16px;
font-size: var(--font-xsm);
color: var(--color-foreground-subtle);
&::after {
position: absolute;
bottom: 0;
left: 50%;
width: 80%;
height: 1px;
content: '';
background: linear-gradient(
90deg,
transparent,
var(--color-neutral-200),
transparent
);
transform: translateX(-50%);
}
& .text {
text-align: center;
& a {
font-weight: 500;
color: var(--color-foreground);
text-decoration: none;
}
}
}
</style>

View File

@@ -1,36 +0,0 @@
.wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 16px;
font-size: var(--font-xsm);
color: var(--color-foreground-subtle);
&::after {
position: absolute;
bottom: 0;
left: 50%;
width: 80%;
height: 1px;
content: '';
background: linear-gradient(
90deg,
transparent,
var(--color-neutral-200),
transparent
);
transform: translateX(-50%);
}
& .text {
text-align: center;
& a {
font-weight: 500;
color: var(--color-foreground);
text-decoration: none;
}
}
}

View File

@@ -1,22 +0,0 @@
import { Container } from '@/components/container';
import styles from './donate.module.css';
export function Donate() {
return (
<Container>
<section className={styles.wrapper}>
<p className={styles.text}>
Enjoy Moodist?{' '}
<a
href="https://buymeacoffee.com/remvze"
rel="noreferrer"
target="_blank"
>
Support with a donation!
</a>
</p>
</section>
</Container>
);
}

View File

@@ -1 +0,0 @@
export { Donate } from './donate';

View File

@@ -0,0 +1,31 @@
---
import { Container } from './container';
---
<footer class="footer">
<Container>
<p>
Created by <a href="https://twitter.com/remvze">Maze ✦</a>
</p>
</Container>
</footer>
<style>
.footer {
display: flex;
align-items: center;
height: 100px;
& p {
font-size: var(--font-sm);
color: var(--color-foreground-subtle);
text-align: center;
& a {
font-weight: 500;
color: var(--color-foreground);
text-decoration: none;
}
}
}
</style>

View File

@@ -1,17 +0,0 @@
.footer {
display: flex;
align-items: center;
height: 100px;
& p {
font-size: var(--font-sm);
color: var(--color-foreground-subtle);
text-align: center;
& a {
font-weight: 500;
color: var(--color-foreground);
text-decoration: none;
}
}
}

View File

@@ -1,15 +0,0 @@
import { Container } from '@/components/container';
import styles from './footer.module.css';
export function Footer() {
return (
<footer className={styles.footer}>
<Container>
<p>
Created by <a href="https://twitter.com/remvze">Maze </a>
</p>
</Container>
</footer>
);
}

View File

@@ -1 +0,0 @@
export { Footer } from './footer';

142
src/components/hero.astro Normal file
View File

@@ -0,0 +1,142 @@
---
import { BsSoundwave } from 'react-icons/bs/index';
import { Container } from './container';
import { count as soundCount } from '@/lib/sounds';
const count = soundCount();
---
<div class="hero">
<Container>
<div class="wrapper">
<img
alt="Faded Moodist Logo"
class="logo"
height={45}
src="/logo.svg"
width={45}
/>
<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>
</Container>
</div>
<style>
.hero {
text-align: center;
.wrapper {
position: relative;
padding: 100px 0 80px;
}
& .logo {
display: block;
width: 45px;
margin: 0 auto 12px;
}
& .title {
display: flex;
column-gap: 15px;
align-items: center;
& div {
flex-grow: 1;
height: 1px;
&.left {
background: linear-gradient(
90deg,
transparent,
transparent,
var(--color-neutral-200),
var(--color-neutral-300)
);
}
&.right {
background: linear-gradient(
90deg,
var(--color-neutral-300),
var(--color-neutral-200),
transparent,
transparent
);
}
}
& h2 {
font-family: var(--font-display);
font-size: var(--font-2xlg);
font-weight: 600;
}
}
& .desc {
margin-top: 5px;
line-height: 1.6;
color: var(--color-foreground-subtle);
}
& .sounds {
position: relative;
display: flex;
column-gap: 8px;
align-items: center;
justify-content: center;
width: max-content;
height: 28px;
padding-right: 12px;
margin: 20px auto 0;
font-size: var(--font-xsm);
color: var(--color-foreground-subtle);
background: linear-gradient(var(--color-neutral-100), transparent);
border: 1px solid var(--color-neutral-200);
border-radius: 100px;
& .icon {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 0 10px;
color: var(--color-foreground);
border-right: 1px solid var(--color-neutral-200);
border-radius: 0 100px 100px 0;
}
&::before {
position: absolute;
top: -1px;
left: 50%;
width: 70%;
height: 1px;
content: '';
background: linear-gradient(
90deg,
transparent,
var(--color-neutral-400),
transparent
);
transform: translateX(-50%);
}
}
}
</style>

View File

@@ -1,120 +0,0 @@
.hero {
text-align: center;
.container {
position: relative;
padding: 100px 0 80px;
/* padding: 120px 0 60px; */
& .pattern {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
background-image: radial-gradient(
var(--color-neutral-300) 5%,
transparent 5%
);
background-position: top center;
background-size: 31px 31px;
opacity: 0.9;
mask-image: linear-gradient(#fff, transparent, transparent);
}
}
& .logo {
display: block;
width: 45px;
margin: 0 auto 12px;
}
& .title {
display: flex;
column-gap: 15px;
align-items: center;
& div {
flex-grow: 1;
height: 1px;
&.left {
background: linear-gradient(
90deg,
transparent,
transparent,
var(--color-neutral-200),
var(--color-neutral-300)
);
}
&.right {
background: linear-gradient(
90deg,
var(--color-neutral-300),
var(--color-neutral-200),
transparent,
transparent
);
}
}
& h2 {
font-family: var(--font-display);
font-size: var(--font-2xlg);
font-weight: 600;
}
}
& .desc {
margin-top: 5px;
line-height: 1.6;
color: var(--color-foreground-subtle);
}
& .sounds {
position: relative;
display: flex;
column-gap: 8px;
align-items: center;
justify-content: center;
width: max-content;
height: 28px;
padding-right: 12px;
margin: 20px auto 0;
font-size: var(--font-xsm);
color: var(--color-foreground-subtle);
background: linear-gradient(var(--color-neutral-100), transparent);
border: 1px solid var(--color-neutral-200);
border-radius: 100px;
& .icon {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 0 10px;
color: var(--color-foreground);
border-right: 1px solid var(--color-neutral-200);
border-radius: 0 100px 100px 0;
}
&::before {
position: absolute;
top: -1px;
left: 50%;
width: 70%;
height: 1px;
content: '';
background: linear-gradient(
90deg,
transparent,
var(--color-neutral-400),
transparent
);
transform: translateX(-50%);
}
}
}

View File

@@ -1,42 +0,0 @@
import { useMemo } from 'react';
import { BsSoundwave } from 'react-icons/bs/index';
import { Container } from '@/components/container';
import { count as soundCount } from '@/lib/sounds';
import styles from './hero.module.css';
export function Hero() {
const count = useMemo(soundCount, []);
return (
<div className={styles.hero}>
<Container className={styles.container}>
{/* <div className={styles.pattern} /> */}
<img
alt="Faded Moodist Logo"
className={styles.logo}
height={45}
src="/logo.svg"
width={45}
/>
<div className={styles.title}>
<div className={styles.left}></div>
<h2>Moodist</h2>
<div className={styles.right}></div>
</div>
<h1 className={styles.desc}>Ambient sounds for focus and calm.</h1>
<p className={styles.sounds}>
<span className={styles.icon}>
<BsSoundwave />
</span>
<span>{count} Sounds</span>
</p>
</Container>
</div>
);
}

View File

@@ -1 +0,0 @@
export { Hero } from './hero';

View File

@@ -27,8 +27,8 @@ export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
) {
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);
@@ -53,23 +53,23 @@ export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
else if (hidden && !isSelected) unselectHidden(label);
}, [label, isSelected, hidden, selectHidden, unselectHidden]);
const _select = useCallback(() => {
const select = useCallback(() => {
if (locked) return;
select(id);
selectSound(id);
play();
}, [select, play, id, locked]);
}, [selectSound, play, id, locked]);
const _unselect = useCallback(() => {
const unselect = useCallback(() => {
if (locked) return;
unselect(id);
unselectSound(id);
setVolume(id, 0.5);
}, [unselect, setVolume, id, locked]);
}, [unselectSound, setVolume, id, locked]);
const toggle = useCallback(() => {
if (locked) return;
if (isSelected) _unselect();
else _select();
}, [isSelected, _select, _unselect, locked]);
if (isSelected) unselect();
else select();
}, [isSelected, select, unselect, locked]);
const handleClick = useCallback(() => {
toggle();

101
src/components/source.astro Normal file
View File

@@ -0,0 +1,101 @@
---
import { FaGithub } from 'react-icons/fa/index';
import { SpecialButton } from './special-button';
import { Container } from './container';
---
<div class="source">
<Container>
<div class="wrapper">
<div class="iconContainer">
<div class="tail"></div>
<div class="icon">
<FaGithub />
</div>
</div>
<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>
<style>
.source {
margin-top: 40px;
& .wrapper {
position: relative;
padding: 0 20px 40px;
background: linear-gradient(transparent, rgb(24 24 27 / 70%));
border-radius: 0 0 20px 20px;
&::after {
position: absolute;
bottom: 0;
left: 50%;
width: 70%;
height: 1px;
content: '';
background: linear-gradient(
90deg,
transparent,
var(--color-neutral-400),
transparent
);
transform: translateX(-50%);
}
}
& .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 {
font-family: var(--font-display);
font-size: var(--font-lg);
font-weight: 600;
text-align: center;
}
& .desc {
margin-top: 8px;
color: var(--color-foreground-subtle);
text-align: center;
}
.button {
display: flex;
justify-content: center;
margin: 16px auto 0;
}
}
</style>

View File

@@ -1 +0,0 @@
export { Source } from './source';

View File

@@ -1,70 +0,0 @@
.source {
/* margin-top: 80px; */
margin-top: 40px;
& .wrapper {
position: relative;
padding: 0 20px 40px;
background: linear-gradient(transparent, rgb(24 24 27 / 70%));
border-radius: 0 0 20px 20px;
&::after {
position: absolute;
bottom: 0;
left: 50%;
width: 70%;
height: 1px;
content: '';
background: linear-gradient(
90deg,
transparent,
var(--color-neutral-400),
transparent
);
transform: translateX(-50%);
}
}
& .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 {
font-family: var(--font-display);
font-size: var(--font-lg);
font-weight: 600;
text-align: center;
}
& .desc {
margin-top: 8px;
color: var(--color-foreground-subtle);
text-align: center;
}
.button {
margin: 16px auto 0;
}
}

View File

@@ -1,32 +0,0 @@
import { FaGithub } from 'react-icons/fa/index';
import { Container } from '@/components/container';
import { SpecialButton } from '@/components/special-button';
import styles from './source.module.css';
export function Source() {
return (
<div className={styles.source}>
<Container>
<div className={styles.wrapper}>
<div className={styles.iconContainer}>
<div className={styles.tail} />
<div className={styles.icon}>
<FaGithub />
</div>
</div>
<h2 className={styles.title}>Open Source</h2>
<p className={styles.desc}>Moodist is free and open-source!</p>
<SpecialButton
className={styles.button}
href="https://github.com/remvze/moodist"
>
Source Code
</SpecialButton>
</div>
</Container>
</div>
);
}

View File

@@ -1,7 +1,13 @@
import { GiWaterfall } from 'react-icons/gi/index';
import { BsFire, BsFillDropletFill } from 'react-icons/bs/index';
import { BiSolidTree, BiWater } from 'react-icons/bi/index';
import { FaWater, FaWind, FaLeaf, FaRegSnowflake } from 'react-icons/fa/index';
import {
FaWater,
FaWind,
FaLeaf,
FaRegSnowflake,
FaTree,
} from 'react-icons/fa/index';
import type { Category } from '../types';
@@ -69,6 +75,12 @@ export const nature: Category = {
label: 'Droplets',
src: '/sounds/nature/droplets.mp3',
},
{
icon: <FaTree />,
id: 'jungle',
label: 'Jungle',
src: '/sounds/nature/jungle.mp3',
},
],
title: 'Nature',
};

View File

@@ -1,4 +1,8 @@
import { BiSolidCoffeeAlt, BiSolidPlaneAlt } from 'react-icons/bi/index';
import {
BiSolidCoffeeAlt,
BiSolidPlaneAlt,
BiSolidDryer,
} from 'react-icons/bi/index';
import { FaChurch, FaSubway, FaShoppingBasket } from 'react-icons/fa/index';
import { TbScubaMask, TbBeerFilled } from 'react-icons/tb/index';
import { GiVillage, GiCarousel } from 'react-icons/gi/index';
@@ -94,6 +98,12 @@ export const places: Category = {
label: 'Laboratory',
src: '/sounds/places/laboratory.mp3',
},
{
icon: <BiSolidDryer />,
id: 'laundry-room',
label: 'Laundry Room',
src: '/sounds/places/laundry-room.mp3',
},
],
title: 'Places',
};

View File

@@ -1,4 +1,8 @@
import { GiWindchimes, GiFilmProjector } from 'react-icons/gi/index';
import {
GiWindchimes,
GiFilmProjector,
GiWashingMachine,
} from 'react-icons/gi/index';
import { BsFillKeyboardFill } from 'react-icons/bs/index';
import { FaKeyboard, FaClock, FaFan } from 'react-icons/fa/index';
import { MdSmartToy, MdWaterDrop, MdRadio } from 'react-icons/md/index';
@@ -91,6 +95,12 @@ export const things: Category = {
label: 'Morse Code',
src: '/sounds/things/morse-code.mp3',
},
{
icon: <GiWashingMachine />,
id: 'washing-machine',
label: 'Washing Machine',
src: '/sounds/things/washing-machine.mp3',
},
],
title: 'Things',
};

View File

@@ -20,7 +20,7 @@ export function useSoundEffect(src: string, volume: number = 1) {
}, [src, isBrowser]);
useEffect(() => {
if (sound) sound.volume(typeof volume === 'number' ? volume : 1);
if (sound) sound.volume(volume ?? 1);
}, [sound, volume]);
const play = useCallback(() => {

View File

@@ -34,13 +34,12 @@ export function useSound(
useEffect(() => {
if (sound) {
sound.loop(typeof options.loop === 'boolean' ? options.loop : false);
sound.loop(options.loop ?? false);
}
}, [sound, options.loop]);
useEffect(() => {
if (sound)
sound.volume(typeof options.volume === 'number' ? options.volume : 0.5);
if (sound) sound.volume(options.volume ?? 0.5);
}, [sound, options.volume]);
const play = useCallback(() => {

View File

@@ -1,21 +1,20 @@
---
import Layout from '@/layouts/layout.astro';
import { Hero } from '@/components/hero';
import Donate from '@/components/donate.astro';
import Hero from '@/components/hero.astro';
import About from '@/components/about.astro';
import Source from '@/components/source.astro';
import Footer from '@/components/footer.astro';
import { App } from '@/components/app';
import { Source } from '@/components/source';
import { Donate } from '@/components/donate';
import { About } from '@/components/about';
// import { Features } from '@/components/features';
import { Footer } from '@/components/footer';
---
<Layout title="Moodist: Ambient Sounds for Focus and Calm">
<Donate />
<Hero />
<App client:load />
<About client:load />
<!-- <Features client:load /> -->
<About />
<Source />
<Footer />
</Layout>