refactor: migrate to Astro components

This commit is contained in:
MAZE 2024-05-20 13:14:42 +04:30
parent 78656bb61f
commit ffe260f4a0
21 changed files with 498 additions and 523 deletions

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

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,21 +1,20 @@
--- ---
import Layout from '@/layouts/layout.astro'; 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 { 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"> <Layout title="Moodist: Ambient Sounds for Focus and Calm">
<Donate /> <Donate />
<Hero /> <Hero />
<App client:load /> <App client:load />
<About client:load /> <About />
<!-- <Features client:load /> -->
<Source /> <Source />
<Footer /> <Footer />
</Layout> </Layout>