From 5eaf7fb046885a2f8914f8028089b729e5401453 Mon Sep 17 00:00:00 2001 From: Alireza Hassani Date: Sat, 8 Aug 2026 14:46:30 +0330 Subject: [PATCH] Polish category edit, product image placeholder, and menu blur. Add a clear pencil edit on category rows, show a proper no-image placeholder on product cards, and strengthen overflow menu glass blur. Co-authored-by: Cursor --- apps/business/src/components/CategoryRow.tsx | 14 +++---- apps/business/src/components/CategoryTree.tsx | 8 ++-- .../src/components/ProductCard.module.css | 14 +++++++ apps/business/src/components/ProductCard.tsx | 37 +++++++++++++++---- apps/business/src/pages/CategoriesPage.tsx | 2 +- .../BusinessActionsOverflowMenu.module.css | 13 ++++--- 6 files changed, 64 insertions(+), 24 deletions(-) diff --git a/apps/business/src/components/CategoryRow.tsx b/apps/business/src/components/CategoryRow.tsx index b55d522..022e0d2 100644 --- a/apps/business/src/components/CategoryRow.tsx +++ b/apps/business/src/components/CategoryRow.tsx @@ -1,4 +1,4 @@ -import { FolderPlus, Layers, ListTree, Trash2, ChevronRight, ClipboardList } from 'lucide-react' +import { FolderPlus, Layers, Trash2, ChevronRight, ClipboardList, Pencil } from 'lucide-react' import { useLocale } from '@meshkee/dashboard-ui' import type { Category } from '../types/category' import { useT } from '../i18n/useT' @@ -16,7 +16,7 @@ interface CategoryRowProps { onAddSub: (id: string) => void onVariations: (id: string) => void onTechnicalForm: (id: string) => void - onOptions: (id: string) => void + onEdit: (id: string) => void onRemove: (id: string) => void } @@ -31,7 +31,7 @@ export function CategoryRow({ onAddSub, onVariations, onTechnicalForm, - onOptions, + onEdit, onRemove, }: CategoryRowProps) { const t = useT() @@ -121,13 +121,13 @@ export function CategoryRow({ )} - + diff --git a/apps/business/src/components/CategoryTree.tsx b/apps/business/src/components/CategoryTree.tsx index 1c1f65e..76b72c8 100644 --- a/apps/business/src/components/CategoryTree.tsx +++ b/apps/business/src/components/CategoryTree.tsx @@ -12,7 +12,7 @@ interface CategoryTreeProps { onAddSub: (id: string) => void onVariations: (id: string) => void onTechnicalForm: (id: string) => void - onOptions: (id: string) => void + onEdit: (id: string) => void onRemove: (id: string) => void parentId?: string | null depth?: number @@ -27,7 +27,7 @@ export function CategoryTree({ onAddSub, onVariations, onTechnicalForm, - onOptions, + onEdit, onRemove, parentId = null, depth = 0, @@ -53,7 +53,7 @@ export function CategoryTree({ onAddSub={onAddSub} onVariations={onVariations} onTechnicalForm={onTechnicalForm} - onOptions={onOptions} + onEdit={onEdit} onRemove={onRemove} /> {childCount && ( @@ -68,7 +68,7 @@ export function CategoryTree({ onAddSub={onAddSub} onVariations={onVariations} onTechnicalForm={onTechnicalForm} - onOptions={onOptions} + onEdit={onEdit} onRemove={onRemove} parentId={category.id} depth={depth + 1} diff --git a/apps/business/src/components/ProductCard.module.css b/apps/business/src/components/ProductCard.module.css index 8bbc85e..f4acade 100644 --- a/apps/business/src/components/ProductCard.module.css +++ b/apps/business/src/components/ProductCard.module.css @@ -46,6 +46,20 @@ padding: 10px; } +.imagePlaceholder { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: rgba(148, 163, 184, 0.75); + background: linear-gradient( + 135deg, + rgba(148, 163, 184, 0.14) 0%, + rgba(148, 163, 184, 0.05) 100% + ); +} + .badge { position: absolute; top: 8px; diff --git a/apps/business/src/components/ProductCard.tsx b/apps/business/src/components/ProductCard.tsx index 28b4c38..6c1f4fd 100644 --- a/apps/business/src/components/ProductCard.tsx +++ b/apps/business/src/components/ProductCard.tsx @@ -1,5 +1,14 @@ +import { useEffect, useState } from 'react' import { Link } from 'react-router-dom' -import { Pencil, Info, Trash2, Layers, MessageSquare, ClipboardList } from 'lucide-react' +import { + Pencil, + Info, + Trash2, + Layers, + MessageSquare, + ClipboardList, + ImageOff, +} from 'lucide-react' import { useLocale } from '@meshkee/dashboard-ui' import type { Product } from '../types/product' import { useT } from '../i18n/useT' @@ -39,17 +48,31 @@ export function ProductCard({ : '' : product.nameFa const categoryLabel = isFa ? product.categoryFa || product.category : product.category + const imageSrc = product.image?.trim() || '' + const [imageFailed, setImageFailed] = useState(false) + const showImage = Boolean(imageSrc) && !imageFailed + + useEffect(() => { + setImageFailed(false) + }, [imageSrc]) return (
- {primaryName} + {showImage ? ( + {primaryName} setImageFailed(true)} + /> + ) : ( + + )} {product.status === 'draft' && ( {t('products.card.draft')} )} diff --git a/apps/business/src/pages/CategoriesPage.tsx b/apps/business/src/pages/CategoriesPage.tsx index 72d00ee..1087960 100644 --- a/apps/business/src/pages/CategoriesPage.tsx +++ b/apps/business/src/pages/CategoriesPage.tsx @@ -453,7 +453,7 @@ export function CategoriesPage() { onAddSub={(id) => openCreateModal(id, t('categories.addSub'))} onVariations={openVariations} onTechnicalForm={openTechnicalForm} - onOptions={(id) => { + onEdit={(id) => { const category = categories.find((item) => item.id === id) if (category) openEditModal(category) }} diff --git a/apps/super-admin/src/components/BusinessActionsOverflowMenu.module.css b/apps/super-admin/src/components/BusinessActionsOverflowMenu.module.css index f3d284d..405ded6 100644 --- a/apps/super-admin/src/components/BusinessActionsOverflowMenu.module.css +++ b/apps/super-admin/src/components/BusinessActionsOverflowMenu.module.css @@ -31,11 +31,14 @@ min-width: 220px; padding: 6px; border-radius: 10px; - border: 1px solid rgba(255, 255, 255, 0.85); - background: rgba(255, 255, 255, 0.78); - backdrop-filter: blur(72px) saturate(1.35); - -webkit-backdrop-filter: blur(72px) saturate(1.35); - box-shadow: 0 12px 40px rgba(15, 23, 42, 0.16); + border: 1px solid rgba(255, 255, 255, 0.92); + background: rgba(255, 255, 255, 0.58); + backdrop-filter: blur(160px) saturate(1.85); + -webkit-backdrop-filter: blur(160px) saturate(1.85); + box-shadow: + 0 12px 40px rgba(15, 23, 42, 0.16), + inset 0 1px 0 rgba(255, 255, 255, 0.65); + isolation: isolate; animation: menuIn 0.14s ease; }