diff --git a/.lintstagedrc.json b/.lintstagedrc.json
index 8a39d85..78a3868 100644
--- a/.lintstagedrc.json
+++ b/.lintstagedrc.json
@@ -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"],
diff --git a/package-lock.json b/package-lock.json
index ef0527e..a9eacdf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 284ce06..b8f30d1 100644
--- a/package.json
+++ b/package.json
@@ -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"
}
}
diff --git a/src/components/Card.astro b/src/components/Card.astro
deleted file mode 100644
index bd6d597..0000000
--- a/src/components/Card.astro
+++ /dev/null
@@ -1,61 +0,0 @@
----
-interface Props {
- title: string;
- body: string;
- href: string;
-}
-
-const { href, title, body } = Astro.props;
----
-
-
-
-
- {title}
- →
-
-
- {body}
-
-
-
-
diff --git a/src/components/categories/categories.tsx b/src/components/categories/categories.tsx
new file mode 100644
index 0000000..c0ed77d
--- /dev/null
+++ b/src/components/categories/categories.tsx
@@ -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: ,
+ urban: ,
+ };
+
+ 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 (
+
+
+ {categories.map(category => (
+
+ ))}
+
+
+ );
+}
diff --git a/src/components/categories/index.ts b/src/components/categories/index.ts
new file mode 100644
index 0000000..22b78ae
--- /dev/null
+++ b/src/components/categories/index.ts
@@ -0,0 +1 @@
+export { Categories } from './categories';
diff --git a/src/components/category/category.module.css b/src/components/category/category.module.css
new file mode 100644
index 0000000..00531e2
--- /dev/null
+++ b/src/components/category/category.module.css
@@ -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;
+ }
+}
diff --git a/src/components/category/category.tsx b/src/components/category/category.tsx
new file mode 100644
index 0000000..7fce723
--- /dev/null
+++ b/src/components/category/category.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/category/index.ts b/src/components/category/index.ts
new file mode 100644
index 0000000..349d6ee
--- /dev/null
+++ b/src/components/category/index.ts
@@ -0,0 +1 @@
+export { Category } from './category';
diff --git a/src/components/hero/hero.module.css b/src/components/hero/hero.module.css
index ca7600e..d6cdb1a 100644
--- a/src/components/hero/hero.module.css
+++ b/src/components/hero/hero.module.css
@@ -1,5 +1,5 @@
.hero {
- padding: 100px 0;
+ padding: 100px 0 10px;
text-align: center;
& .logo {
diff --git a/src/data/sounds.json b/src/data/sounds.json
index 4ccf1ad..43372e8 100644
--- a/src/data/sounds.json
+++ b/src/data/sounds.json
@@ -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",
diff --git a/src/helpers/styles.ts b/src/helpers/styles.ts
new file mode 100644
index 0000000..ba45cf7
--- /dev/null
+++ b/src/helpers/styles.ts
@@ -0,0 +1,7 @@
+type className = undefined | null | false | string;
+
+export function cn(...classNames: Array): string {
+ const className = classNames.filter(className => !!className).join(' ');
+
+ return className;
+}
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 4b6dd3f..6aebd3e 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -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';
---
+