@akshatbuilds/sonix 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +7 -6
  2. package/cli/index.mjs +82 -17
  3. package/package.json +9 -38
  4. package/app/globals.css +0 -110
  5. package/app/layout.tsx +0 -54
  6. package/app/page.tsx +0 -40
  7. package/app/usage/page.tsx +0 -9
  8. package/components/sound-card.tsx +0 -595
  9. package/components/sounds-gallery.tsx +0 -137
  10. package/components/theme-provider.tsx +0 -11
  11. package/components/theme-toggle.tsx +0 -82
  12. package/components/ui/button.tsx +0 -57
  13. package/components/ui/checkbox.tsx +0 -30
  14. package/components/ui/slider.tsx +0 -28
  15. package/components/ui/switch.tsx +0 -29
  16. package/components/ui/tooltip.tsx +0 -30
  17. package/components/usage-guide.tsx +0 -155
  18. package/components.json +0 -21
  19. package/lib/sounds.ts +0 -329
  20. package/lib/utils.ts +0 -6
  21. package/next-env.d.ts +0 -6
  22. package/next.config.mjs +0 -5
  23. package/postcss.config.mjs +0 -8
  24. package/public/click1.mp3 +0 -0
  25. package/public/click2.mp3 +0 -0
  26. package/public/registry/index.json +0 -92
  27. package/public/registry/sounds/button-click-secondary.json +0 -13
  28. package/public/registry/sounds/button-click.json +0 -13
  29. package/public/registry/sounds/error-beep.json +0 -10
  30. package/public/registry/sounds/error-buzz.json +0 -10
  31. package/public/registry/sounds/hover-blip.json +0 -10
  32. package/public/registry/sounds/hover-soft.json +0 -10
  33. package/public/registry/sounds/key-press.json +0 -10
  34. package/public/registry/sounds/notification-ping.json +0 -10
  35. package/public/registry/sounds/notification-subtle.json +0 -10
  36. package/public/registry/sounds/pop.json +0 -10
  37. package/public/registry/sounds/slider-tick.json +0 -10
  38. package/public/registry/sounds/success-bell.json +0 -10
  39. package/public/registry/sounds/success-chime.json +0 -10
  40. package/public/registry/sounds/swoosh.json +0 -10
  41. package/scripts/build-registry.mjs +0 -293
  42. package/tailwind.config.ts +0 -100
  43. package/tsconfig.json +0 -33
package/README.md CHANGED
@@ -11,7 +11,7 @@ Micro UX audio for interactive web applications. Zero dependencies. Copy-paste r
11
11
  - **14 sounds** — clicks, hovers, success, error, notifications, transitions, and more
12
12
  - **Zero dependencies** — every snippet is standalone Web Audio API code
13
13
  - **Copy & paste** — hit the copy button on any card to get production-ready code
14
- - **CLI** — `npx sonix add pop` to scaffold sounds into your project
14
+ - **CLI** — `npx @akshatbuilds/sonix add pop` to scaffold sounds into your project
15
15
  - **Framework agnostic** — works with React, Vue, Svelte, vanilla JS, anything
16
16
  - **Dark mode** — with cinematic circular reveal transition
17
17
  - **`prefers-reduced-motion`** — respects user accessibility preferences
@@ -36,7 +36,7 @@ osc.stop(ctx.currentTime + 0.15);
36
36
  ### MP3 (for button clicks)
37
37
 
38
38
  ```js
39
- const audio = new Audio('/click1.mp3');
39
+ const audio = new Audio('/sonix/click1.mp3');
40
40
  audio.volume = 0.5;
41
41
  audio.play();
42
42
  ```
@@ -44,10 +44,10 @@ audio.play();
44
44
  ### React Hook
45
45
 
46
46
  ```tsx
47
- import { playSound } from './lib/sounds';
47
+ import { playPop } from '@/components/sonix';
48
48
 
49
49
  function MyButton() {
50
- return <button onClick={() => playSound('pop')}>Click</button>;
50
+ return <button onClick={playPop}>Click</button>;
51
51
  }
52
52
  ```
53
53
 
@@ -61,7 +61,8 @@ npx @akshatbuilds/sonix add pop # Add a single sound
61
61
  npx @akshatbuilds/sonix add pop swoosh # Add multiple sounds
62
62
  ```
63
63
 
64
- Sounds are written to `lib/sounds/` as standalone files — no runtime dependency.
64
+ Sounds are written to `components/sonix/` as standalone files — no runtime dependency.
65
+ MP3 assets are downloaded automatically to `public/sonix/`.
65
66
 
66
67
  ## Available Sounds
67
68
 
@@ -93,7 +94,7 @@ To manually control sound:
93
94
  const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
94
95
 
95
96
  if (!prefersReducedMotion) {
96
- playSound('pop');
97
+ playPop();
97
98
  }
98
99
  ```
99
100
 
package/cli/index.mjs CHANGED
@@ -4,20 +4,23 @@
4
4
  * sonix CLI — add sounds to your project
5
5
  *
6
6
  * Usage:
7
- * npx sonix add <sound-name> Add a single sound
8
- * npx sonix add <s1> <s2> ... Add multiple sounds
9
- * npx sonix list List all available sounds
7
+ * npx @akshatbuilds/sonix add <sound-name> Add a single sound
8
+ * npx @akshatbuilds/sonix add <s1> <s2> ... Add multiple sounds
9
+ * npx @akshatbuilds/sonix list List all available sounds
10
10
  *
11
11
  * Sounds are fetched from the public registry and written
12
12
  * to your project as standalone files — no runtime dependency.
13
13
  */
14
14
 
15
- import { writeFileSync, mkdirSync, existsSync } from "node:fs";
16
- import { join } from "node:path";
15
+ import { writeFileSync, mkdirSync, existsSync, readdirSync } from "node:fs";
16
+ import { join, dirname, relative } from "node:path";
17
17
 
18
18
  const REGISTRY_URL =
19
19
  process.env.SONIX_REGISTRY ||
20
20
  "https://soundcomponents.vercel.app/registry";
21
+ const DEFAULT_OUT_DIR = process.env.SONIX_OUT_DIR || "components";
22
+ const SOUNDS_SUBDIR = "sonix";
23
+ const ASSETS_SUBDIR = "sonix";
21
24
 
22
25
  const COLORS = {
23
26
  reset: "\x1b[0m",
@@ -51,6 +54,16 @@ async function fetchJSON(url) {
51
54
  return res.json();
52
55
  }
53
56
 
57
+ async function fetchBinary(url) {
58
+ const res = await fetch(url);
59
+ if (!res.ok) throw new Error(`Failed to fetch ${url}: ${res.status}`);
60
+ return Buffer.from(await res.arrayBuffer());
61
+ }
62
+
63
+ function getRegistryHost() {
64
+ return REGISTRY_URL.replace(/\/registry\/?$/, "");
65
+ }
66
+
54
67
  async function listSounds() {
55
68
  try {
56
69
  const registry = await fetchJSON(`${REGISTRY_URL}/index.json`);
@@ -80,11 +93,16 @@ async function listSounds() {
80
93
  }
81
94
 
82
95
  async function addSounds(names) {
83
- const outDir = join(process.cwd(), "lib", "sounds");
96
+ const outDir = join(process.cwd(), DEFAULT_OUT_DIR, SOUNDS_SUBDIR);
97
+ const assetsDir = join(process.cwd(), "public", ASSETS_SUBDIR);
84
98
 
85
99
  if (!existsSync(outDir)) {
86
100
  mkdirSync(outDir, { recursive: true });
87
- success(`Created ${COLORS.cyan}lib/sounds/${COLORS.reset}`);
101
+ success(`Created ${COLORS.cyan}${DEFAULT_OUT_DIR}/${SOUNDS_SUBDIR}/${COLORS.reset}`);
102
+ }
103
+
104
+ if (!existsSync(assetsDir)) {
105
+ mkdirSync(assetsDir, { recursive: true });
88
106
  }
89
107
 
90
108
  for (const name of names) {
@@ -93,26 +111,73 @@ async function addSounds(names) {
93
111
 
94
112
  for (const file of sound.files) {
95
113
  const filePath = join(outDir, file.name);
114
+ mkdirSync(dirname(filePath), { recursive: true });
96
115
  writeFileSync(filePath, file.content + "\n");
97
- success(`Added ${COLORS.cyan}lib/sounds/${file.name}${COLORS.reset}`);
116
+ success(
117
+ `Added ${COLORS.cyan}${DEFAULT_OUT_DIR}/${SOUNDS_SUBDIR}/${file.name}${COLORS.reset}`
118
+ );
98
119
  }
99
120
 
100
121
  if (sound.assets?.length) {
101
- warn(
102
- `${name} requires asset files: ${sound.assets.join(", ")} — download them from the website and put in your public/ folder.`
103
- );
122
+ for (const assetName of sound.assets) {
123
+ const assetUrl = `${getRegistryHost()}/${assetName}`;
124
+ try {
125
+ const data = await fetchBinary(assetUrl);
126
+ writeFileSync(join(assetsDir, assetName), data);
127
+ success(`Added ${COLORS.cyan}public/${ASSETS_SUBDIR}/${assetName}${COLORS.reset}`);
128
+ } catch (assetErr) {
129
+ warn(`Could not fetch ${assetName} (${assetErr.message}). Download it manually to public/${ASSETS_SUBDIR}/.`);
130
+ }
131
+ }
104
132
  }
105
133
  } catch (err) {
106
134
  error(`Could not add "${name}": ${err.message}`);
107
135
  }
108
136
  }
109
137
 
138
+ const soundFiles = collectSoundFiles(outDir);
139
+ const uniqueExports = new Map();
140
+ for (const filePath of soundFiles) {
141
+ const importPath = relative(outDir, filePath).replace(/\\/g, "/").replace(/\.ts$/, "");
142
+ const base = importPath.split("/").pop() || "";
143
+ uniqueExports.set(`play${toPascal(base)}`, { exportName: `play${toPascal(base)}`, importPath });
144
+ }
145
+ const indexPath = join(outDir, "index.ts");
146
+ const indexContent = Array.from(uniqueExports.values())
147
+ .sort((a, b) => a.exportName.localeCompare(b.exportName))
148
+ .map((item) => `export { ${item.exportName} } from "./${item.importPath}";`)
149
+ .join("\n");
150
+ if (indexContent) {
151
+ writeFileSync(indexPath, `${indexContent}\n`);
152
+ success(`Added ${COLORS.cyan}${DEFAULT_OUT_DIR}/${SOUNDS_SUBDIR}/index.ts${COLORS.reset}`);
153
+ }
154
+
110
155
  log("");
111
156
  log(`${COLORS.dim}Import and use:${COLORS.reset}`);
112
- log(`${COLORS.dim} import { play${toPascal(names[0])} } from './lib/sounds/${names[0]}';${COLORS.reset}`);
157
+ log(
158
+ `${COLORS.dim} import { play${toPascal(names[0])} } from '@/components/sonix';${COLORS.reset}`
159
+ );
160
+ log(
161
+ `${COLORS.dim} // If you don't use @ alias: ../../components/sonix${COLORS.reset}`
162
+ );
113
163
  log("");
114
164
  }
115
165
 
166
+ function collectSoundFiles(dir) {
167
+ const files = [];
168
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
169
+ const full = join(dir, entry.name);
170
+ if (entry.isDirectory()) {
171
+ files.push(...collectSoundFiles(full));
172
+ continue;
173
+ }
174
+ if (entry.isFile() && entry.name.endsWith(".ts") && entry.name !== "index.ts") {
175
+ files.push(full);
176
+ }
177
+ }
178
+ return files;
179
+ }
180
+
116
181
  function toPascal(str) {
117
182
  return str
118
183
  .split("-")
@@ -129,9 +194,9 @@ if (!command || command === "help" || command === "--help") {
129
194
  log("");
130
195
  log(`${COLORS.bold}sonix${COLORS.reset} — UI sound effects for your app`);
131
196
  log("");
132
- log(` ${COLORS.cyan}npx sonix list${COLORS.reset} List all sounds`);
133
- log(` ${COLORS.cyan}npx sonix add <name>${COLORS.reset} Add a sound to your project`);
134
- log(` ${COLORS.cyan}npx sonix add pop swoosh${COLORS.reset} Add multiple sounds`);
197
+ log(` ${COLORS.cyan}npx @akshatbuilds/sonix list${COLORS.reset} List all sounds`);
198
+ log(` ${COLORS.cyan}npx @akshatbuilds/sonix add <name>${COLORS.reset} Add a sound to your project`);
199
+ log(` ${COLORS.cyan}npx @akshatbuilds/sonix add pop swoosh${COLORS.reset} Add multiple sounds`);
135
200
  log("");
136
201
  process.exit(0);
137
202
  }
@@ -141,11 +206,11 @@ if (command === "list") {
141
206
  } else if (command === "add") {
142
207
  const names = args.slice(1);
143
208
  if (names.length === 0) {
144
- error("Specify at least one sound name. Run `npx sonix list` to see options.");
209
+ error("Specify at least one sound name. Run `npx @akshatbuilds/sonix list` to see options.");
145
210
  process.exit(1);
146
211
  }
147
212
  await addSounds(names);
148
213
  } else {
149
- error(`Unknown command: ${command}. Run \`npx sonix --help\`.`);
214
+ error(`Unknown command: ${command}. Run \`npx @akshatbuilds/sonix --help\`.`);
150
215
  process.exit(1);
151
216
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akshatbuilds/sonix",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Micro UX sound effects for interactive web applications. Zero dependencies, copy-paste ready.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,63 +20,34 @@
20
20
  "bin": {
21
21
  "@akshatbuilds/sonix": "./cli/index.mjs"
22
22
  },
23
+ "files": [
24
+ "cli",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
23
28
  "scripts": {
24
29
  "dev": "next dev --turbo",
25
30
  "build": "next build",
26
31
  "start": "next start",
27
- "lint": "next lint"
32
+ "lint": "next lint",
33
+ "build:registry": "node scripts/build-registry.mjs"
28
34
  },
29
35
  "dependencies": {
30
- "@hookform/resolvers": "^3.9.1",
31
- "@radix-ui/react-accordion": "1.2.2",
32
- "@radix-ui/react-alert-dialog": "1.1.4",
33
- "@radix-ui/react-aspect-ratio": "1.1.1",
34
- "@radix-ui/react-avatar": "1.1.2",
35
36
  "@radix-ui/react-checkbox": "1.1.3",
36
- "@radix-ui/react-collapsible": "1.1.2",
37
- "@radix-ui/react-context-menu": "2.2.4",
38
- "@radix-ui/react-dialog": "1.1.4",
39
- "@radix-ui/react-dropdown-menu": "2.1.4",
40
- "@radix-ui/react-hover-card": "1.1.4",
41
- "@radix-ui/react-label": "2.1.1",
42
- "@radix-ui/react-menubar": "1.1.4",
43
- "@radix-ui/react-navigation-menu": "1.2.3",
44
- "@radix-ui/react-popover": "1.1.4",
45
- "@radix-ui/react-progress": "1.1.1",
46
- "@radix-ui/react-radio-group": "1.2.2",
47
- "@radix-ui/react-scroll-area": "1.2.2",
48
- "@radix-ui/react-select": "2.1.4",
49
- "@radix-ui/react-separator": "1.1.1",
50
37
  "@radix-ui/react-slider": "1.2.2",
51
38
  "@radix-ui/react-slot": "1.1.1",
52
39
  "@radix-ui/react-switch": "1.1.2",
53
- "@radix-ui/react-tabs": "1.1.2",
54
- "@radix-ui/react-toast": "1.2.4",
55
- "@radix-ui/react-toggle": "1.1.1",
56
- "@radix-ui/react-toggle-group": "1.1.1",
57
40
  "@radix-ui/react-tooltip": "1.1.6",
58
41
  "@vercel/analytics": "^1.6.1",
59
- "autoprefixer": "^10.4.20",
60
42
  "class-variance-authority": "^0.7.1",
61
43
  "clsx": "^2.1.1",
62
- "cmdk": "1.1.1",
63
- "date-fns": "4.1.0",
64
- "embla-carousel-react": "8.5.1",
65
- "input-otp": "1.4.1",
66
44
  "lucide-react": "^0.544.0",
67
45
  "next": "16.1.6",
68
46
  "next-themes": "^0.4.6",
69
47
  "react": "19.2.3",
70
- "react-day-picker": "8.10.1",
71
48
  "react-dom": "19.2.3",
72
- "react-hook-form": "^7.54.1",
73
- "react-resizable-panels": "^2.1.7",
74
- "recharts": "2.15.0",
75
- "sonner": "^1.7.1",
76
49
  "tailwind-merge": "^2.5.5",
77
- "tailwindcss-animate": "^1.0.7",
78
- "vaul": "^1.1.2",
79
- "zod": "^3.24.1"
50
+ "tailwindcss-animate": "^1.0.7"
80
51
  },
81
52
  "devDependencies": {
82
53
  "@tailwindcss/postcss": "^4.1.13",
package/app/globals.css DELETED
@@ -1,110 +0,0 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
4
-
5
- @layer utilities {
6
- .text-balance {
7
- text-wrap: balance;
8
- }
9
- }
10
-
11
- @layer base {
12
- :root {
13
- --background: 0 0% 100%;
14
- --foreground: 0 0% 3.9%;
15
- --card: 0 0% 100%;
16
- --card-foreground: 0 0% 3.9%;
17
- --popover: 0 0% 100%;
18
- --popover-foreground: 0 0% 3.9%;
19
- --primary: 0 0% 9%;
20
- --primary-foreground: 0 0% 98%;
21
- --secondary: 0 0% 96.1%;
22
- --secondary-foreground: 0 0% 9%;
23
- --muted: 0 0% 96.1%;
24
- --muted-foreground: 0 0% 45.1%;
25
- --accent: 0 0% 96.1%;
26
- --accent-foreground: 0 0% 9%;
27
- --destructive: 0 84.2% 60.2%;
28
- --destructive-foreground: 0 0% 98%;
29
- --border: 0 0% 89.8%;
30
- --input: 0 0% 89.8%;
31
- --ring: 0 0% 3.9%;
32
- --chart-1: 12 76% 61%;
33
- --chart-2: 173 58% 39%;
34
- --chart-3: 197 37% 24%;
35
- --chart-4: 43 74% 66%;
36
- --chart-5: 27 87% 67%;
37
- --radius: 0.5rem;
38
- --sidebar-background: 0 0% 98%;
39
- --sidebar-foreground: 240 5.3% 26.1%;
40
- --sidebar-primary: 240 5.9% 10%;
41
- --sidebar-primary-foreground: 0 0% 98%;
42
- --sidebar-accent: 240 4.8% 95.9%;
43
- --sidebar-accent-foreground: 240 5.9% 10%;
44
- --sidebar-border: 220 13% 91%;
45
- --sidebar-ring: 217.2 91.2% 59.8%;
46
- }
47
- .dark {
48
- --background: 0 0% 3.9%;
49
- --foreground: 0 0% 98%;
50
- --card: 0 0% 3.9%;
51
- --card-foreground: 0 0% 98%;
52
- --popover: 0 0% 3.9%;
53
- --popover-foreground: 0 0% 98%;
54
- --primary: 0 0% 98%;
55
- --primary-foreground: 0 0% 9%;
56
- --secondary: 0 0% 14.9%;
57
- --secondary-foreground: 0 0% 98%;
58
- --muted: 0 0% 14.9%;
59
- --muted-foreground: 0 0% 63.9%;
60
- --accent: 0 0% 14.9%;
61
- --accent-foreground: 0 0% 98%;
62
- --destructive: 0 62.8% 30.6%;
63
- --destructive-foreground: 0 0% 98%;
64
- --border: 0 0% 14.9%;
65
- --input: 0 0% 14.9%;
66
- --ring: 0 0% 83.1%;
67
- --chart-1: 220 70% 50%;
68
- --chart-2: 160 60% 45%;
69
- --chart-3: 30 80% 55%;
70
- --chart-4: 280 65% 60%;
71
- --chart-5: 340 75% 55%;
72
- --sidebar-background: 240 5.9% 10%;
73
- --sidebar-foreground: 240 4.8% 95.9%;
74
- --sidebar-primary: 224.3 76.3% 48%;
75
- --sidebar-primary-foreground: 0 0% 100%;
76
- --sidebar-accent: 240 3.7% 15.9%;
77
- --sidebar-accent-foreground: 240 4.8% 95.9%;
78
- --sidebar-border: 240 3.7% 15.9%;
79
- --sidebar-ring: 217.2 91.2% 59.8%;
80
- }
81
- }
82
-
83
- @layer base {
84
- * {
85
- @apply border-border;
86
- }
87
- body {
88
- @apply bg-background text-foreground;
89
- }
90
- }
91
-
92
- /* Circular reveal via View Transition API for cinematic theme change */
93
- ::view-transition-old(root) {
94
- animation: none;
95
- z-index: 1;
96
- }
97
-
98
- ::view-transition-new(root) {
99
- animation: none;
100
- z-index: 9999;
101
- mix-blend-mode: normal;
102
- }
103
-
104
- /* Honor prefers-reduced-motion (Web Interface Guidelines: Animation) */
105
- @media (prefers-reduced-motion: reduce) {
106
- ::view-transition-old(root),
107
- ::view-transition-new(root) {
108
- animation: none !important;
109
- }
110
- }
package/app/layout.tsx DELETED
@@ -1,54 +0,0 @@
1
- import React from "react"
2
- import type { Metadata } from 'next'
3
- import { Geist, Geist_Mono } from 'next/font/google'
4
- import { ThemeProvider } from '@/components/theme-provider'
5
- import { Analytics } from '@vercel/analytics/next'
6
-
7
- import './globals.css'
8
-
9
- const geist = Geist({ subsets: ['latin'], variable: '--font-geist' })
10
- const geistMono = Geist_Mono({ subsets: ['latin'], variable: '--font-geist-mono' })
11
-
12
- export const metadata: Metadata = {
13
- title: 'Sonix — UI Sound Effects Library',
14
- description: 'Micro UX audio interactions for web apps. 14 sounds, zero dependencies, copy-paste ready.',
15
- metadataBase: new URL('https://abhi-yo.github.io/sound-library'),
16
- openGraph: {
17
- title: 'Sonix — UI Sound Effects Library',
18
- description: 'Micro UX audio interactions for web apps. 14 sounds, zero dependencies, copy-paste ready.',
19
- type: 'website',
20
- },
21
- twitter: {
22
- card: 'summary_large_image',
23
- title: 'Sonix — UI Sound Effects Library',
24
- description: 'Micro UX audio interactions for web apps. 14 sounds, zero dependencies, copy-paste ready.',
25
- },
26
- }
27
-
28
- export default function RootLayout({
29
- children,
30
- }: Readonly<{
31
- children: React.ReactNode
32
- }>) {
33
- return (
34
- <html lang="en" suppressHydrationWarning className={`${geist.variable} ${geistMono.variable}`}>
35
- <head>
36
- <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
37
- <meta name="theme-color" content="#0a0a0a" media="(prefers-color-scheme: dark)" />
38
- </head>
39
- <body className="font-sans antialiased">
40
- <a href="#main-content" className="sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-primary focus:px-4 focus:py-2 focus:text-primary-foreground">
41
- Skip to main content
42
- </a>
43
- <ThemeProvider
44
- attribute="class"
45
- defaultTheme="system"
46
- enableSystem
47
- >
48
- {children}
49
- </ThemeProvider>
50
- <Analytics />
51
- </body>
52
- </html>
53
- )
54
- }
package/app/page.tsx DELETED
@@ -1,40 +0,0 @@
1
- import { SoundsGallery } from '@/components/sounds-gallery';
2
- import { UsageGuide } from '@/components/usage-guide';
3
- import { ThemeToggle } from '@/components/theme-toggle';
4
-
5
- export const metadata = {
6
- title: 'UI Sound Effects Library',
7
- description: 'Tiny audio interactions for web apps. Button clicks, hover blips, success sounds, and error feedback.',
8
- };
9
-
10
- export default function Home() {
11
- return (
12
- <main id="main-content" className="flex min-h-screen flex-col bg-background text-foreground">
13
- <div className="flex flex-col gap-12 px-4 py-12 sm:px-8 lg:px-16">
14
- {/* Header */}
15
- <div className="flex flex-col gap-4 border-b border-border pb-8">
16
- <div className="flex items-center justify-between">
17
- <h1 className="font-sans text-4xl font-bold tracking-tight sm:text-5xl">
18
- Sound Effects
19
- </h1>
20
- <ThemeToggle />
21
- </div>
22
- <p className="max-w-2xl text-lg text-muted-foreground">
23
- Micro UX audio for interactive web applications. Click to preview, copy code to use.
24
- </p>
25
- </div>
26
-
27
- {/* Gallery */}
28
- <SoundsGallery />
29
-
30
- {/* Usage Guide */}
31
- <UsageGuide />
32
-
33
- {/* Footer */}
34
- <div className="border-t border-border py-8 text-center text-sm text-muted-foreground">
35
- <p>Click the play button to preview. Use the copy button to get code for your project.</p>
36
- </div>
37
- </div>
38
- </main>
39
- );
40
- }
@@ -1,9 +0,0 @@
1
- import { UsageGuide } from '@/components/usage-guide';
2
-
3
- export default function UsagePage() {
4
- return (
5
- <div className="container mx-auto px-4 py-12">
6
- <UsageGuide />
7
- </div>
8
- );
9
- }