mirror of
https://github.com/remvze/moodist.git
synced 2025-12-16 16:34:14 +00:00
feat: add basic categories
This commit is contained in:
parent
5791346a88
commit
8d7e4d26fd
13 changed files with 180 additions and 84 deletions
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"*.{ts,tsx}": ["eslint --fix", "tsc-files --noEmit"],
|
||||
"*.{js,jsx}": "eslint --fix",
|
||||
"*.{ts,tsx,js,jsx}": "eslint --fix",
|
||||
"*.{json,md}": "prettier --write",
|
||||
"*.css": "stylelint --fix",
|
||||
"*.astro": ["eslint --fix", "stylelint --fix"],
|
||||
|
|
|
|||
26
package-lock.json
generated
26
package-lock.json
generated
|
|
@ -13,7 +13,8 @@
|
|||
"@types/react-dom": "^18.2.10",
|
||||
"astro": "^3.2.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "4.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "17.7.2",
|
||||
|
|
@ -47,8 +48,7 @@
|
|||
"stylelint-config-html": "1.1.0",
|
||||
"stylelint-config-idiomatic-order": "9.0.0",
|
||||
"stylelint-config-standard": "34.0.0",
|
||||
"stylelint-prettier": "4.0.2",
|
||||
"tsc-files": "1.1.4"
|
||||
"stylelint-prettier": "4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
|
|
@ -12522,6 +12522,14 @@
|
|||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "4.11.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz",
|
||||
"integrity": "sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
|
@ -14674,18 +14682,6 @@
|
|||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/tsc-files": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tsc-files/-/tsc-files-1.1.4.tgz",
|
||||
"integrity": "sha512-RePsRsOLru3BPpnf237y1Xe1oCGta8rmSYzM76kYo5tLGsv5R2r3s64yapYorGTPuuLyfS9NVbh9ydzmvNie2w==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc-files": "cli.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
"@types/react-dom": "^18.2.10",
|
||||
"astro": "^3.2.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "4.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "17.7.2",
|
||||
|
|
@ -60,7 +61,6 @@
|
|||
"stylelint-config-html": "1.1.0",
|
||||
"stylelint-config-idiomatic-order": "9.0.0",
|
||||
"stylelint-config-standard": "34.0.0",
|
||||
"stylelint-prettier": "4.0.2",
|
||||
"tsc-files": "1.1.4"
|
||||
"stylelint-prettier": "4.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
body: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
const { href, title, body } = Astro.props;
|
||||
---
|
||||
|
||||
<li class="link-card">
|
||||
<a href={href}>
|
||||
<h2>
|
||||
{title}
|
||||
<span>→</span>
|
||||
</h2>
|
||||
<p>
|
||||
{body}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<style>
|
||||
.link-card {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
padding: 1px;
|
||||
background-color: #23262d;
|
||||
background-image: none;
|
||||
background-size: 400%;
|
||||
border-radius: 7px;
|
||||
background-position: 100%;
|
||||
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.link-card > a {
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
line-height: 1.4;
|
||||
padding: calc(1.5rem - 1px);
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
background-color: #23262d;
|
||||
opacity: 0.8;
|
||||
}
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
p {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.link-card:is(:hover, :focus-within) {
|
||||
background-position: 0;
|
||||
background-image: var(--accent-gradient);
|
||||
}
|
||||
.link-card:is(:hover, :focus-within) h2 {
|
||||
color: rgb(var(--accent-light));
|
||||
}
|
||||
</style>
|
||||
64
src/components/categories/categories.tsx
Normal file
64
src/components/categories/categories.tsx
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import { useMemo } from 'react';
|
||||
import { BiSolidTree } from 'react-icons/bi';
|
||||
import { FaCity } from 'react-icons/fa';
|
||||
|
||||
import { Container } from '@/components/container';
|
||||
import { Category } from '@/components/category';
|
||||
|
||||
interface CategoriesProps {
|
||||
sounds: {
|
||||
[id: string]: {
|
||||
title: string;
|
||||
sounds: Array<{
|
||||
label: string;
|
||||
src: string;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function Categories({ sounds }: CategoriesProps) {
|
||||
const categories = useMemo(() => {
|
||||
const idToColor: { [id: string]: string } = {
|
||||
nature: 'green',
|
||||
urban: 'indigo',
|
||||
};
|
||||
|
||||
const idToIcon: { [id: string]: React.ReactNode } = {
|
||||
nature: <BiSolidTree />,
|
||||
urban: <FaCity />,
|
||||
};
|
||||
|
||||
const ids = Object.keys(sounds);
|
||||
const categories: Array<{
|
||||
color: string;
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
id: string;
|
||||
sounds: Array<{ label: string; src: string }>;
|
||||
}> = [];
|
||||
|
||||
ids.forEach(id => {
|
||||
const category = sounds[id];
|
||||
|
||||
categories.push({
|
||||
color: idToColor[id] || 'green',
|
||||
icon: idToIcon[id] || '-',
|
||||
id: id,
|
||||
...category,
|
||||
});
|
||||
});
|
||||
|
||||
return categories;
|
||||
}, [sounds]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div>
|
||||
{categories.map(category => (
|
||||
<Category {...category} key={category.id} />
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
1
src/components/categories/index.ts
Normal file
1
src/components/categories/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { Categories } from './categories';
|
||||
50
src/components/category/category.module.css
Normal file
50
src/components/category/category.module.css
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
.category {
|
||||
& .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));
|
||||
|
||||
&.green {
|
||||
background: linear-gradient(transparent, #16a34a);
|
||||
}
|
||||
|
||||
&.indigo {
|
||||
background: linear-gradient(transparent, #4f46e5);
|
||||
}
|
||||
}
|
||||
|
||||
& .icon {
|
||||
display: flex;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 50%;
|
||||
font-size: var(--font-md);
|
||||
|
||||
&.green {
|
||||
border-color: #16a34a;
|
||||
background-color: rgb(22 163 74 / 20%);
|
||||
}
|
||||
|
||||
&.indigo {
|
||||
border-color: #4f46e5;
|
||||
background-color: rgb(79 70 229 / 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .title {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--font-lg);
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
35
src/components/category/category.tsx
Normal file
35
src/components/category/category.tsx
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { useMemo } from 'react';
|
||||
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
||||
import styles from './category.module.css';
|
||||
|
||||
interface CategoryProps {
|
||||
color: string;
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
id: string;
|
||||
sounds: Array<{ label: string; src: string }>;
|
||||
}
|
||||
|
||||
export function Category({ color, icon, title }: CategoryProps) {
|
||||
const colorStyle = useMemo(() => {
|
||||
const colorToStyle: { [color: string]: string } = {
|
||||
green: styles.green,
|
||||
indigo: styles.indigo,
|
||||
};
|
||||
|
||||
return colorToStyle[color];
|
||||
}, [color]);
|
||||
|
||||
return (
|
||||
<div className={styles.category}>
|
||||
<div className={styles.iconContainer}>
|
||||
<div className={cn(styles.tail, colorStyle)} />
|
||||
<div className={cn(styles.icon, colorStyle)}>{icon}</div>
|
||||
</div>
|
||||
|
||||
<h2 className={styles.title}>{title}</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
1
src/components/category/index.ts
Normal file
1
src/components/category/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { Category } from './category';
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
.hero {
|
||||
padding: 100px 0;
|
||||
padding: 100px 0 10px;
|
||||
text-align: center;
|
||||
|
||||
& .logo {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"sounds": {
|
||||
"nature": {
|
||||
"label": "Nature",
|
||||
"title": "Nature",
|
||||
"sounds": [
|
||||
{
|
||||
"label": "Rain",
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
]
|
||||
},
|
||||
"urban": {
|
||||
"label": "Urban",
|
||||
"title": "Urban",
|
||||
"sounds": [
|
||||
{
|
||||
"label": "Airport",
|
||||
|
|
|
|||
7
src/helpers/styles.ts
Normal file
7
src/helpers/styles.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
type className = undefined | null | false | string;
|
||||
|
||||
export function cn(...classNames: Array<className>): string {
|
||||
const className = classNames.filter(className => !!className).join(' ');
|
||||
|
||||
return className;
|
||||
}
|
||||
|
|
@ -3,9 +3,13 @@ import Layout from '@/layouts/layout.astro';
|
|||
|
||||
import { Gradient } from '@/components/gradient';
|
||||
import { Hero } from '@/components/hero';
|
||||
import { Categories } from '@/components/categories';
|
||||
|
||||
import sounds from '@/data/sounds.json';
|
||||
---
|
||||
|
||||
<Layout title="Welcome to Astro.">
|
||||
<Gradient />
|
||||
<Hero />
|
||||
<Categories client:load sounds={sounds.sounds} />
|
||||
</Layout>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue