mirror of
https://git.meshkee.com/BaloutPastry/dashboards.git
synced 2026-08-11 22:30:59 +04:30
Initial commit of Balout Pastry admin dashboards.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
ChevronLeft,
|
||||
FolderPlus,
|
||||
Pencil,
|
||||
SlidersHorizontal,
|
||||
Trash2,
|
||||
} from 'lucide-react'
|
||||
import type { Category } from '../data/categories'
|
||||
import styles from './CategoryItem.module.css'
|
||||
|
||||
type CategoryItemProps = {
|
||||
category: Category
|
||||
depth?: number
|
||||
onAddChild: (parentId: string) => void
|
||||
onEdit: (category: Category) => void
|
||||
onOpenOptions: (category: Category) => void
|
||||
onRemove: (id: string) => void
|
||||
}
|
||||
|
||||
export function CategoryItem({
|
||||
category,
|
||||
depth = 0,
|
||||
onAddChild,
|
||||
onEdit,
|
||||
onOpenOptions,
|
||||
onRemove,
|
||||
}: CategoryItemProps) {
|
||||
const hasChildren = category.children.length > 0
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
function toggleOpen() {
|
||||
if (!hasChildren) return
|
||||
setOpen((value) => !value)
|
||||
}
|
||||
|
||||
return (
|
||||
<li className={styles.item}>
|
||||
<div
|
||||
className={`${styles.row} ${depth > 0 ? styles.childRow : ''} ${hasChildren ? styles.rowClickable : ''}`}
|
||||
role={hasChildren ? 'button' : undefined}
|
||||
tabIndex={hasChildren ? 0 : undefined}
|
||||
aria-expanded={hasChildren ? open : undefined}
|
||||
onClick={toggleOpen}
|
||||
onKeyDown={(event) => {
|
||||
if (!hasChildren) return
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault()
|
||||
toggleOpen()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className={`${styles.collapseIcon} ${!hasChildren ? styles.collapseIconEmpty : ''}`}
|
||||
aria-hidden
|
||||
>
|
||||
{hasChildren && (
|
||||
<ChevronLeft
|
||||
size={18}
|
||||
strokeWidth={1.75}
|
||||
className={`${styles.chevron} ${open ? styles.chevronOpen : ''}`}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
|
||||
<div className={styles.titles}>
|
||||
<span className={styles.nameFa}>{category.nameFa}</span>
|
||||
<span className={styles.nameEn}>{category.nameEn}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={styles.controls}
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onKeyDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.iconBtn}
|
||||
aria-label="افزودن زیرشاخه"
|
||||
data-tooltip="افزودن زیرشاخه"
|
||||
onClick={() => {
|
||||
setOpen(true)
|
||||
onAddChild(category.id)
|
||||
}}
|
||||
>
|
||||
<FolderPlus size={17} strokeWidth={1.75} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className={styles.iconBtn}
|
||||
aria-label="ویرایش"
|
||||
data-tooltip="ویرایش"
|
||||
onClick={() => onEdit(category)}
|
||||
>
|
||||
<Pencil size={17} strokeWidth={1.75} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className={styles.iconBtn}
|
||||
aria-label="گزینهها"
|
||||
data-tooltip="گزینهها"
|
||||
onClick={() => onOpenOptions(category)}
|
||||
>
|
||||
<SlidersHorizontal size={17} strokeWidth={1.75} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className={`${styles.iconBtn} ${styles.removeBtn}`}
|
||||
aria-label="حذف"
|
||||
data-tooltip="حذف"
|
||||
onClick={() => onRemove(category.id)}
|
||||
>
|
||||
<Trash2 size={17} strokeWidth={1.75} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hasChildren && open && (
|
||||
<ul className={styles.children}>
|
||||
{category.children.map((child) => (
|
||||
<CategoryItem
|
||||
key={child.id}
|
||||
category={child}
|
||||
depth={depth + 1}
|
||||
onAddChild={onAddChild}
|
||||
onEdit={onEdit}
|
||||
onOpenOptions={onOpenOptions}
|
||||
onRemove={onRemove}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user