Redesign Table

This commit is contained in:
Thanakarn Klangkasame
2025-10-09 14:59:20 +07:00
parent 6821f585d6
commit bdb7e49003

View File

@@ -125,6 +125,9 @@ const pill = (t: Tone) =>
const U = (s: string) => s.toUpperCase();
// เส้นคอลัมน์โทนอ่อน (ใช้กับทั้ง th/td)
const COL_BORDER = "border-r border-neutral-200/60 last:border-r-0";
const IconLabel = ({ Icon, label, pillTone }: { Icon: LucideIcon; label: string; pillTone?: Tone }) => {
const content = (
<span className="inline-flex items-center gap-1.5">
@@ -226,7 +229,7 @@ const renderWarehouse = (w: Order["warehouseCode"]) => {
return <IconLabel Icon={Icon} label={label} />;
};
/* For selects (native <option> เรนเดอร์ React icon ไม่ได้ จึงใช้ตัวอักษรอย่างเดียว) */
/* For selects */
const CHANNELS = Object.keys(CHANNEL_META) as Channel[];
const PAYMENT_STATUSES = Object.keys(PAYMENT_STATUS_META) as PaymentStatus[];
const FULFILL_STATUSES = Object.keys(FULFILL_META) as FulfillmentStatus[];
@@ -787,7 +790,7 @@ export default function OrdersPage() {
return (
<>
{/* ทำให้กว้างหน้า "นิ่งเท่ากัน" เสมอ โดยจองที่สกรอลล์บาร์ */}
{/* กว้างหน้า นิ่ง” + ปรับสไตล์เส้นหัวตาราง */}
<style jsx global>{`
html { scrollbar-gutter: stable both-edges; }
@supports not (scrollbar-gutter: stable both-edges) { html { overflow-y: scroll; } }
@@ -829,7 +832,7 @@ export default function OrdersPage() {
placeholder="ค้นหา: เลขออเดอร์ / อ้างอิง / ลูกค้า / เบอร์ / อีเมล / ผู้เปิด / เลขภาษี / Tracking…"
value={q}
onChange={(e) => setQ(e.target.value)}
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2 text-sm shadow-sm outline-none placeholder:text-neutral-400 focus:border-neutral-300"
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2.5 text-sm shadow-sm outline-none placeholder:text-neutral-400 focus:border-neutral-300"
/>
</div>
@@ -837,7 +840,7 @@ export default function OrdersPage() {
<select
value={channel}
onChange={(e) => setChannel(e.target.value as "all" | Channel)}
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2 text-sm shadow-sm outline-none"
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2.5 text-sm shadow-sm outline-none"
>
<option value="all"></option>
{CHANNELS.map((c) => (
@@ -852,7 +855,7 @@ export default function OrdersPage() {
<select
value={payment}
onChange={(e) => setPayment(e.target.value as "all" | PaymentStatus)}
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2 text-sm shadow-sm outline-none"
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2.5 text-sm shadow-sm outline-none"
>
<option value="all">การชำระเงิน: ทั้งหมด</option>
{PAYMENT_STATUSES.map((ps) => (
@@ -867,7 +870,7 @@ export default function OrdersPage() {
<select
value={fulfillment}
onChange={(e) => setFulfillment(e.target.value as "all" | FulfillmentStatus)}
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2 text-sm shadow-sm outline-none"
className="w-full rounded-xl border border-neutral-200/70 bg-white/70 px-3 py-2.5 text-sm shadow-sm outline-none"
>
<option value="all">จัดส่ง: ทั้งหมด</option>
{FULFILL_STATUSES.map((fs) => (
@@ -884,24 +887,27 @@ export default function OrdersPage() {
<section className="rounded-3xl border border-neutral-200/70 bg-white/80 p-5 shadow-[0_10px_30px_-12px_rgba(0,0,0,0.08)]">
<div className="-mx-5 overflow-x-auto">
<div className="px-5">
<table className="min-w-full table-auto text-sm">
{/* ใช้ border-separate + border-spacing-0 เพื่อควบคุมเส้นคอลัมน์เอง */}
<table className="min-w-full table-auto border-separate border-spacing-0 text-sm">
<thead>
<tr className="text-neutral-600">
{/* Group row (กว้างขึ้น + เส้นล่าง + เส้นคอลัมน์อ่อน) */}
<tr className="bg-neutral-50/80 text-neutral-700">
{topHeaderSegments.map((seg, idx) => (
<th
key={`${seg.groupTH}-${idx}`}
colSpan={seg.colSpan}
className="whitespace-nowrap pb-1 pr-4 text-center text-[12px] font-semibold"
className={`whitespace-nowrap px-3 py-2.5 text-center text-[13px] font-semibold border-b border-neutral-200/70 ${COL_BORDER}`}
>
{seg.groupTH}
</th>
))}
</tr>
<tr className="text-left text-neutral-500">
{/* Column labels (กว้างขึ้น + ตัวหนา + เส้นคอลัมน์อ่อน) */}
<tr className="bg-neutral-50/80 text-neutral-600">
{visibleCols.map((c) => (
<th
key={String(c.key)}
className={`whitespace-nowrap pb-2 pr-4 ${c.align === "right" ? "text-right" : ""}`}
className={`whitespace-nowrap px-3 py-2.5 text-[12.5px] font-semibold border-b border-neutral-200/70 ${c.align === "right" ? "text-right" : "text-left"} ${COL_BORDER}`}
>
{c.labelTH}
</th>
@@ -909,15 +915,19 @@ export default function OrdersPage() {
</tr>
</thead>
<tbody className="divide-y divide-neutral-200/70">
{rows.map((o) => (
<tr key={o.id} className="align-middle">
{/* แถบเส้นแบ่งแถว + zebra อ่อน ๆ เพื่อ “แบ่งสายตา” */}
<tbody className="divide-y divide-neutral-200/60">
{rows.map((o, rowIdx) => (
<tr key={o.id} className={rowIdx % 2 === 0 ? "bg-white" : "bg-neutral-50/40"}>
{visibleCols.map((c) => {
const raw = getProp(o, c.key);
const content: ReactNode = c.format ? c.format(raw, o) : defaultCell(raw);
const align = c.align === "right" ? "text-right" : "";
return (
<td key={`${o.id}-${String(c.key)}`} className={`whitespace-nowrap py-2 pr-4 ${align}`}>
<td
key={`${o.id}-${String(c.key)}`}
className={`whitespace-nowrap px-3 py-2.5 ${align} ${COL_BORDER}`}
>
{c.key === "orderNo" ? (
<a
href={`/orders/${o.id}`}