style(ui): maximize topic card images and fix RTL wizard arrows
Frontend-only application of prod_v2 (55e959b, 9e99b46). Dev docker-compose.yml changes excluded.
This commit is contained in:
@@ -5,39 +5,62 @@ import { faNum } from "../lib/formatters";
|
|||||||
import { cn } from "../lib/utils";
|
import { cn } from "../lib/utils";
|
||||||
|
|
||||||
export interface TopicGridProps {
|
export interface TopicGridProps {
|
||||||
topics: Topic[]; // از store (API) میآید
|
topics: Topic[];
|
||||||
selectedTopic?: string;
|
selectedTopic?: string;
|
||||||
onSelect: (topicName: string) => void;
|
onSelect: (topicName: string) => void;
|
||||||
showCounts?: boolean; // تعداد تأمینکنندههای هر تاپیک
|
showCounts?: boolean;
|
||||||
counts?: Record<string, number>; // topic name → count
|
counts?: Record<string, number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// گرید تاپیکها (از /material-categories — نه لیست ثابت)
|
|
||||||
export function TopicGrid({ topics, selectedTopic, onSelect, showCounts = false, counts }: TopicGridProps) {
|
export function TopicGrid({ topics, selectedTopic, onSelect, showCounts = false, counts }: TopicGridProps) {
|
||||||
if (!topics.length) {
|
if (!topics.length) {
|
||||||
return <EmptyState emoji="🗂️" text="در حال بارگذاری دستهبندیها…" />;
|
return <EmptyState emoji="🗂️" text="در حال بارگذاری دستهبندیها…" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4">
|
<div className="grid grid-cols-2 gap-3 sm:gap-4 sm:grid-cols-3 lg:grid-cols-4">
|
||||||
{topics.map((t) => {
|
{topics.map((t) => {
|
||||||
const selected = selectedTopic != null && normalize(selectedTopic) === normalize(t.name);
|
const selected = selectedTopic != null && normalize(selectedTopic) === normalize(t.name);
|
||||||
const count = counts?.[t.name] ?? 0;
|
const count = counts?.[t.name] ?? 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
key={t.key}
|
key={t.key}
|
||||||
className={cn("topic-card flex flex-col items-center justify-center p-4", selected && "selected")}
|
|
||||||
onClick={() => onSelect(t.name)}
|
onClick={() => onSelect(t.name)}
|
||||||
|
className={cn(
|
||||||
|
"group relative flex flex-col items-center justify-between rounded-2xl border bg-white p-2.5 sm:p-4 text-center transition-all duration-200 cursor-pointer shadow-xs active:scale-[0.98] overflow-hidden",
|
||||||
|
selected
|
||||||
|
? "border-blue-600 ring-2 ring-blue-600/25 shadow-md bg-blue-50/20"
|
||||||
|
: "border-slate-200 hover:border-blue-300 hover:shadow-md"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{/* استفاده از استایل اینلاین برای تضمین تغییر سایز و دور زدن CSSهای قبلی */}
|
{/* کادر تصویر بسیار بزرگتر شده برای پر کردن تمام فضای مربع */}
|
||||||
<img
|
<div className="flex h-36 sm:h-48 md:h-52 w-full items-center justify-center overflow-hidden rounded-xl bg-slate-50/50">
|
||||||
src={t.icon}
|
<img
|
||||||
alt=""
|
src={t.icon}
|
||||||
style={{ width: '130px', height: '80px', objectFit: 'contain' }}
|
alt={t.name}
|
||||||
className="mb-2"
|
className="h-full w-full object-contain transform scale-115 group-hover:scale-125 transition-transform duration-300 drop-shadow-xs"
|
||||||
/>
|
loading="lazy"
|
||||||
<div className="t-name text-[13px] font-semibold">{t.name}</div>
|
/>
|
||||||
{showCounts && <div className="t-count text-[11px] text-muted">{faNum(count)} تأمینکننده</div>}
|
</div>
|
||||||
|
|
||||||
|
{/* بخش عنوان و تعداد */}
|
||||||
|
<div className="mt-3 w-full pb-1">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"truncate text-[13px] sm:text-[15px] font-bold transition-colors",
|
||||||
|
selected ? "text-blue-600" : "text-slate-800 group-hover:text-blue-600"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{t.name}
|
||||||
|
</div>
|
||||||
|
{showCounts && (
|
||||||
|
<div className="mt-0.5 truncate text-[11px] sm:text-xs text-slate-400 font-medium">
|
||||||
|
{faNum(count)} تأمینکننده
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Link, useNavigate, useSearchParams } from "react-router-dom";
|
import { Link, useNavigate, useSearchParams } from "react-router-dom";
|
||||||
|
import { ChevronRight, ChevronLeft, Check } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import type { LineItem, Quote } from "../../lib/types";
|
import type { LineItem, Quote } from "../../lib/types";
|
||||||
import { api, nextId } from "../../lib/api";
|
import { api, nextId } from "../../lib/api";
|
||||||
@@ -453,17 +454,17 @@ export function WizardPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* پاورقی ویزارد — طراحی بازسازیشده با ناوبری استاندارد */}
|
{/* پاورقی ویزارد — با آیکونهای استاندارد و جهتگیری دقیق RTL */}
|
||||||
<div className="mt-5 flex items-center justify-between rounded-xl border border-line bg-panel p-3.5 shadow-sm">
|
<div className="mt-5 flex items-center justify-between rounded-xl border border-line bg-panel p-3.5 shadow-sm">
|
||||||
{/* دکمه مرحله قبلی */}
|
{/* دکمه مرحله قبلی (فلش رو به راست = بازگشت در فارسی) */}
|
||||||
<div>
|
<div>
|
||||||
{currentStep > 1 && (
|
{currentStep > 1 && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => goToStep(currentStep - 1)}
|
onClick={() => goToStep(currentStep - 1)}
|
||||||
className="inline-flex items-center gap-1.5 px-4 py-2 rounded-xl border border-gray-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-gray-700 dark:text-zinc-200 hover:bg-gray-50 dark:hover:bg-zinc-700 text-sm font-medium transition-colors shadow-xs"
|
className="inline-flex items-center gap-1.5 px-4 py-2 rounded-xl border border-slate-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-slate-700 dark:text-zinc-200 hover:bg-slate-50 dark:hover:bg-zinc-700 text-sm font-medium transition-colors shadow-xs cursor-pointer"
|
||||||
>
|
>
|
||||||
<span>›</span>
|
<ChevronRight className="h-4 w-4" />
|
||||||
<span>قبلی</span>
|
<span>قبلی</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@@ -473,19 +474,20 @@ export function WizardPage() {
|
|||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Link
|
<Link
|
||||||
to="/"
|
to="/"
|
||||||
className="inline-flex items-center justify-center px-4 py-2 rounded-xl text-sm font-medium text-gray-500 hover:text-gray-700 hover:bg-gray-100 dark:text-zinc-400 dark:hover:text-zinc-200 dark:hover:bg-zinc-800 transition-colors no-underline"
|
className="inline-flex items-center justify-center px-4 py-2 rounded-xl text-sm font-medium text-slate-500 hover:text-slate-700 hover:bg-slate-100 dark:text-zinc-400 dark:hover:text-zinc-200 dark:hover:bg-zinc-800 transition-colors no-underline"
|
||||||
>
|
>
|
||||||
انصراف
|
انصراف
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
{/* دکمه مرحله بعدی (فلش رو به چپ = پیشروی در فارسی) */}
|
||||||
{currentStep < TOTAL_STEPS && (
|
{currentStep < TOTAL_STEPS && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={next}
|
onClick={next}
|
||||||
className="inline-flex items-center gap-2 px-6 py-2 rounded-xl bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white text-sm font-semibold shadow-sm hover:shadow transition-all duration-150"
|
className="inline-flex items-center gap-1.5 px-6 py-2 rounded-xl bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white text-sm font-semibold shadow-sm hover:shadow transition-all duration-150 cursor-pointer"
|
||||||
>
|
>
|
||||||
<span>بعدی</span>
|
<span>بعدی</span>
|
||||||
<span className="text-xs">‹</span>
|
<ChevronLeft className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -493,10 +495,10 @@ export function WizardPage() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => void save()}
|
onClick={() => void save()}
|
||||||
className="inline-flex items-center gap-2 px-6 py-2 rounded-xl bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 text-white text-sm font-semibold shadow-sm hover:shadow transition-all duration-150"
|
className="inline-flex items-center gap-1.5 px-6 py-2 rounded-xl bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 text-white text-sm font-semibold shadow-sm hover:shadow transition-all duration-150 cursor-pointer"
|
||||||
>
|
>
|
||||||
<span>ذخیره پیشنهاد</span>
|
<span>ذخیره پیشنهاد</span>
|
||||||
<span className="text-xs">✓</span>
|
<Check className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user