frontmatter in skills files

This commit is contained in:
2026-02-18 01:23:22 +00:00
parent 030cf9fbd3
commit c2660cd125
16 changed files with 959 additions and 506 deletions
+73 -88
View File
@@ -1,8 +1,7 @@
import { useState, useRef, useMemo } from 'react';
import { Search, Play, Square, AudioLines, ChevronDown, ChevronUp } from 'lucide-react';
import { Card } from '@/components/Card';
import { Search, Play, Square, AudioLines } from 'lucide-react';
import { Widget } from '@/components/Widget';
import { Input } from '@/components/ui/input';
import { useUserState } from '@/state/useUserState';
import { categories, allSounds } from './catalog-data';
import type { SoundAsset } from './types';
@@ -50,7 +49,6 @@ const SoundCard = ({
);
export const Catalog = () => {
const [collapsed, setCollapsed] = useUserState('widget:soundLibrary:collapsed', true);
const [search, setSearch] = useState('');
const [activeCategory, setActiveCategory] = useState<ActiveCategory>('all');
const [playingId, setPlayingId] = useState<string | null>(null);
@@ -90,90 +88,77 @@ export const Catalog = () => {
];
return (
<div className="w-full">
<Card className="overflow-hidden">
<div className={`flex items-center justify-between px-4 pt-3 ${collapsed ? 'pb-3' : 'pb-1'}`}>
<span className="text-xs font-semibold text-duck-dark/60 uppercase tracking-wide">Sound Library</span>
<button
onClick={() => setCollapsed((c) => !c)}
className="text-duck-dark/40 hover:text-duck-dark/70 cursor-pointer transition-colors"
>
{collapsed ? <ChevronDown className="h-4 w-4" /> : <ChevronUp className="h-4 w-4" />}
</button>
</div>
{!collapsed && (
<div className="flex flex-col gap-4 px-4 pb-4">
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-3">
<div className="relative w-full sm:w-56">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-duck-dark/40" />
<Input
placeholder="Search sounds..."
value={search}
onChange={(ev) => setSearch(ev.target.value)}
className="pl-9"
/>
</div>
<div className="flex flex-wrap gap-1.5">
{tabs.map((tab) => (
<button
key={tab.id}
type="button"
onClick={() => setActiveCategory(tab.id)}
className={`px-2.5 py-1 rounded-full text-xs font-medium cursor-pointer transition-colors border ${
activeCategory === tab.id
? 'border-duck-teal bg-duck-teal/10 text-duck-teal'
: 'border-duck-dark/15 text-duck-dark/50 hover:border-duck-dark/30'
}`}
>
{tab.label} <span className="opacity-60">{tab.count}</span>
</button>
))}
</div>
<span className="text-xs text-duck-dark/40 ml-auto hidden sm:block">{filtered.length} sounds</span>
</div>
{filtered.length === 0 && <p className="text-sm text-duck-dark/40 py-8 text-center">No sounds found.</p>}
<div className="max-h-[400px] overflow-y-auto">
<div className="grid grid-cols-2 sm:grid-cols-3 gap-2">
{filtered.map((sound) => (
<SoundCard
key={sound.name}
sound={sound}
isPlaying={playingId === sound.name}
onPlay={() => play(sound)}
onStop={stop}
/>
))}
</div>
</div>
<div className="flex items-center justify-between pt-1">
<span className="text-[11px] text-duck-dark/70">
CC0 licensed &middot; Original audio by{' '}
<a
href="https://kenney.nl/"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-duck-dark"
>
Kenney
</a>
</span>
<a
href="https://www.soundcn.xyz/"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 hover:opacity-80 transition-opacity"
>
<span className="text-xs text-duck-dark/40">powered by</span>
<AudioLines className="h-5 w-5" style={{ color: '#F5A32F' }} />
<span className="text-sm font-bold text-duck-dark">soundcn</span>
</a>
</div>
<Widget title="Sound Library">
<div className="flex flex-col gap-4 px-4 pb-4">
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-3">
<div className="relative w-full sm:w-56">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-duck-dark/40" />
<Input
placeholder="Search sounds..."
value={search}
onChange={(ev) => setSearch(ev.target.value)}
className="pl-9"
/>
</div>
)}
</Card>
</div>
<div className="flex flex-wrap gap-1.5">
{tabs.map((tab) => (
<button
key={tab.id}
type="button"
onClick={() => setActiveCategory(tab.id)}
className={`px-2.5 py-1 rounded-full text-xs font-medium cursor-pointer transition-colors border ${
activeCategory === tab.id
? 'border-duck-teal bg-duck-teal/10 text-duck-teal'
: 'border-duck-dark/15 text-duck-dark/50 hover:border-duck-dark/30'
}`}
>
{tab.label} <span className="opacity-60">{tab.count}</span>
</button>
))}
</div>
<span className="text-xs text-duck-dark/40 ml-auto hidden sm:block">{filtered.length} sounds</span>
</div>
{filtered.length === 0 && <p className="text-sm text-duck-dark/40 py-8 text-center">No sounds found.</p>}
<div className="max-h-[400px] overflow-y-auto">
<div className="grid grid-cols-2 sm:grid-cols-3 gap-2">
{filtered.map((sound) => (
<SoundCard
key={sound.name}
sound={sound}
isPlaying={playingId === sound.name}
onPlay={() => play(sound)}
onStop={stop}
/>
))}
</div>
</div>
<div className="flex items-center justify-between pt-1">
<span className="text-[11px] text-duck-dark/70">
CC0 licensed &middot; Original audio by{' '}
<a
href="https://kenney.nl/"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-duck-dark"
>
Kenney
</a>
</span>
<a
href="https://www.soundcn.xyz/"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 hover:opacity-80 transition-opacity"
>
<span className="text-xs text-duck-dark/40">powered by</span>
<AudioLines className="h-5 w-5" style={{ color: '#F5A32F' }} />
<span className="text-sm font-bold text-duck-dark">soundcn</span>
</a>
</div>
</div>
</Widget>
);
};