feat: single select equipment category and updated fitting room header
- Refactored `Equipments` page to use single category selection. - Updated `FittingRoom` page to use `PageHeader` component. - Added `backButton` prop to `PageHeader` component to support navigation controls. - Removed "Manage looks for" hint text from Fitting Room header.
This commit is contained in:
1 parent
221dbea09f
commit
a9dfa41083
3 files changed
+41
-44
No files matched your search
@@ -6,6 +6,7 @@ interface PageHeaderProps {
|
||||
title: ReactNode
|
||||
subtitle?: ReactNode
|
||||
actions?: ReactNode
|
||||
backButton?: ReactNode
|
||||
children?: ReactNode
|
||||
className?: string
|
||||
sticky?: boolean
|
||||
@@ -16,6 +17,7 @@ export function PageHeader({
|
||||
title,
|
||||
subtitle,
|
||||
actions,
|
||||
backButton,
|
||||
children,
|
||||
className,
|
||||
sticky = true,
|
||||
@@ -32,18 +34,21 @@ export function PageHeader({
|
||||
style={sticky ? { top: topOffset } : undefined}
|
||||
>
|
||||
<div className="flex justify-between items-end animate-fade-in-down">
|
||||
<div>
|
||||
{subtitle && (
|
||||
<div className="flex items-center gap-2 text-cyan-600 mb-2 tracking-[0.3em] text-xs font-mono uppercase">
|
||||
<Hexagon size={12} className="animate-spin-slow" />
|
||||
{subtitle}
|
||||
</div>
|
||||
)}
|
||||
<h1 className="text-3xl md:text-5xl font-display font-black uppercase text-slate-900 tracking-tighter">
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-cyan-600 to-blue-600">
|
||||
{title}
|
||||
</span>
|
||||
</h1>
|
||||
<div className="flex items-center gap-4">
|
||||
{backButton}
|
||||
<div>
|
||||
{subtitle && (
|
||||
<div className="flex items-center gap-2 text-cyan-600 mb-2 tracking-[0.3em] text-xs font-mono uppercase">
|
||||
<Hexagon size={12} className="animate-spin-slow" />
|
||||
{subtitle}
|
||||
</div>
|
||||
)}
|
||||
<h1 className="text-3xl md:text-5xl font-display font-black uppercase text-slate-900 tracking-tighter">
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-cyan-600 to-blue-600">
|
||||
{title}
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
{actions && <div className="flex items-center gap-4">{actions}</div>}
|
||||
</div>
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function Equipments() {
|
||||
const [items, setItems] = useState<EquipmentItem[]>([])
|
||||
const [outfits, setOutfits] = useState<OutfitItem[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [selectedCategories, setSelectedCategories] = useState<string[]>([])
|
||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null)
|
||||
const [extractorOpen, setExtractorOpen] = useState(false)
|
||||
const [createOutfitOpen, setCreateOutfitOpen] = useState(false)
|
||||
const [viewMode, setViewMode] = useState<'equipments' | 'outfits'>('equipments')
|
||||
@@ -49,7 +49,7 @@ export default function Equipments() {
|
||||
} else {
|
||||
fetchOutfits()
|
||||
}
|
||||
}, [viewMode, selectedCategories])
|
||||
}, [viewMode, selectedCategory])
|
||||
|
||||
const fetchItems = async () => {
|
||||
setLoading(true)
|
||||
@@ -58,8 +58,8 @@ export default function Equipments() {
|
||||
limit: '100',
|
||||
}
|
||||
|
||||
if (selectedCategories.length > 0) {
|
||||
query.category = selectedCategories
|
||||
if (selectedCategory) {
|
||||
query.category = [selectedCategory]
|
||||
}
|
||||
|
||||
const res = await client.equipments.$get({
|
||||
@@ -106,9 +106,7 @@ export default function Equipments() {
|
||||
}
|
||||
|
||||
const toggleCategory = (category: string) => {
|
||||
setSelectedCategories((prev) =>
|
||||
prev.includes(category) ? prev.filter((c) => c !== category) : [...prev, category],
|
||||
)
|
||||
setSelectedCategory((prev) => (prev === category ? null : category))
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -157,7 +155,7 @@ export default function Equipments() {
|
||||
<ScrollArea className="w-full whitespace-nowrap">
|
||||
<div className="flex w-max space-x-2 p-1">
|
||||
{EQUIPMENT_CATEGORIES.map((cat) => {
|
||||
const isSelected = selectedCategories.includes(cat.main_category)
|
||||
const isSelected = selectedCategory === cat.main_category
|
||||
return (
|
||||
<Badge
|
||||
key={cat.main_category}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { client } from '../client'
|
||||
import { CreateLookDialog } from '../components/CreateLookDialog'
|
||||
import { LookDetailsDialog } from '../components/LookDetailsDialog'
|
||||
import { PageHeader } from '../components/PageHeader'
|
||||
import { Button } from '../components/ui/button'
|
||||
import { Card } from '../components/ui/card'
|
||||
|
||||
@@ -73,36 +74,29 @@ export default function FittingRoom() {
|
||||
|
||||
return (
|
||||
<div className="p-8 animate-fade-in-up h-screen flex flex-col overflow-hidden bg-stone-50/30">
|
||||
{/* Header */}
|
||||
<div className="flex justify-between items-center mb-6 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<PageHeader
|
||||
title="Fitting Room"
|
||||
subtitle="System // FITTING_ROOM/"
|
||||
backButton={
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => navigate('/characters')}
|
||||
className="rounded-full hover:bg-stone-200"
|
||||
className="rounded-full hover:bg-stone-200 text-stone-600"
|
||||
>
|
||||
<ArrowLeft className="w-5 h-5 text-stone-600" />
|
||||
<ArrowLeft className="w-5 h-5" />
|
||||
</Button>
|
||||
<div>
|
||||
<h1 className="text-3xl font-black text-stone-800 uppercase tracking-tighter">
|
||||
Fitting Room
|
||||
</h1>
|
||||
<p className="text-stone-500 text-sm font-medium flex items-center gap-2">
|
||||
Manage looks for{' '}
|
||||
<span className="text-stone-900 font-bold bg-stone-200 px-2 py-0.5 rounded text-xs uppercase">
|
||||
{character.name}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => setCreateLookOpen(true)}
|
||||
className="bg-stone-900 hover:bg-stone-800 text-white shadow-lg hover:shadow-xl transition-all"
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" /> Create New Look
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
actions={
|
||||
<Button
|
||||
onClick={() => setCreateLookOpen(true)}
|
||||
className="bg-stone-900 hover:bg-stone-800 text-white shadow-lg hover:shadow-xl transition-all"
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" /> Create New Look
|
||||
</Button>
|
||||
}
|
||||
className="mb-6 shrink-0"
|
||||
/>
|
||||
|
||||
<div className="flex flex-col lg:flex-row flex-1 gap-6 overflow-hidden pb-4">
|
||||
{/* Left: Character Preview */}
|
||||
|
||||
Reference in new issue
Block a user