[CLAUDE] FE-User FE-Admin: Plan AA wrap fix - sidebar label dài wrap về đầu hàng + text smaller
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s
UAT feedback 2026-05-15 sau Run #213 deploy: bro screenshot sidebar label custom Mig 27 dài "1. Duyệt Nhà Cung Cấp - Thầu phụ (NCC -TP)" wrap 2 dòng, dòng 2 "(NCC -TP)" indent SAU icon thay vì về đầu hàng. Root cause: flex container [items-center, gap-2] + inner span chứa Icon + label text → text wraps within INNER span (đã indent past icon area). Pattern phù hợp cho 1-dòng label, KHÔNG phù hợp khi multi-line. Fix pattern (3 sites fe-user + 2 sites fe-admin mirror rule §3.9): - MenuGroup button: flex → relative block + inline-block icon + inline text + absolute ChevronDown right. Text wrap về left edge button (under icon). - MenuLeaf NavLink: flex → block + inline-block icon + inline text. - StaticLeaf NavLink (fe-user only): mirror MenuLeaf pattern. Smaller text: - text-[13px] → text-[12px] (medium label group + leaf) - text-sm (14px) → text-[12px] (MenuLeaf top level) - text-[12px] → text-[11px] (MenuLeaf deep level) - leading-snug (1.375) compact 2-line height Icon adjust: -mt-0.5 align with inline text baseline. Button px-3 pr-7: pad right 28px reserve cho absolute ChevronDown (KHÔNG bị đẩy xuống khi label wrap). Verify: - npm run build fe-user PASS clean 432ms - npm run build fe-admin PASS clean 494ms Em main solo CSS polish < 30 min (criteria #6 REFUSE Implementer). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -135,21 +135,21 @@ function MenuGroup({ node, depth }: { node: MenuNode; depth: number }) {
|
|||||||
<button
|
<button
|
||||||
onClick={() => setOpen(o => !o)}
|
onClick={() => setOpen(o => !o)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex w-full items-center justify-between rounded-md transition',
|
'relative block w-full rounded-md text-left transition',
|
||||||
isTopLevel
|
isTopLevel
|
||||||
? 'px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500 hover:bg-slate-100 whitespace-nowrap'
|
? 'px-3 py-2 pr-7 text-[11px] font-semibold uppercase tracking-wide text-slate-500 hover:bg-slate-100 whitespace-nowrap'
|
||||||
: 'px-3 py-1.5 text-[13px] font-medium text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
: 'px-3 py-1.5 pr-7 text-[12px] font-medium leading-snug text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* [Plan AA S24 t1] Revert truncate Plan U S23 t11 — mirror fe-user
|
{/* [Plan AA S24 t2 wrap fix] inline-block icon + inline text — label
|
||||||
rule §3.9. Admin sidebar không có label custom Mig 27 (luôn Label
|
dài wrap về đầu hàng (under icon, KHÔNG indent sau icon). Mirror
|
||||||
gốc) nên label rarely overflow, nhưng pattern uniform với fe-user.
|
fe-user rule §3.9. ChevronDown absolute right. */}
|
||||||
min-w-0 flex-1 + shrink-0 giữ responsive smooth. */}
|
<Icon className="mr-1.5 -mt-0.5 inline-block h-4 w-4 align-middle" />
|
||||||
<span className="flex min-w-0 flex-1 items-center gap-2">
|
<span className="align-middle" title={node.label}>{node.label}</span>
|
||||||
<Icon className="h-4 w-4 shrink-0" />
|
<ChevronDown className={cn(
|
||||||
<span title={node.label}>{node.label}</span>
|
'absolute right-2 top-2 h-3.5 w-3.5 text-slate-400 transition',
|
||||||
</span>
|
!open && '-rotate-90',
|
||||||
<ChevronDown className={cn('h-3.5 w-3.5 shrink-0 text-slate-400 transition', !open && '-rotate-90')} />
|
)} />
|
||||||
</button>
|
</button>
|
||||||
{open && (
|
{open && (
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
@ -199,16 +199,16 @@ function MenuLeaf({ node, depth }: { node: MenuNode; depth: number }) {
|
|||||||
to={path}
|
to={path}
|
||||||
title={node.label}
|
title={node.label}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex min-w-0 items-center gap-2.5 rounded-md transition',
|
'block rounded-md leading-snug transition',
|
||||||
isDeep ? 'px-3 py-1 text-[12px]' : 'px-3 py-2 text-sm font-medium',
|
isDeep ? 'px-3 py-1 text-[11px]' : 'px-3 py-2 text-[12px] font-medium',
|
||||||
isActive
|
isActive
|
||||||
? 'bg-brand-50 text-brand-700'
|
? 'bg-brand-50 text-brand-700'
|
||||||
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Icon className={cn('shrink-0', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
|
{/* [Plan AA S24 t2 wrap fix] inline-block icon + inline text → mirror fe-user. */}
|
||||||
{/* [Plan AA S24 t1] Revert truncate Plan U S23 t11 — mirror fe-user. */}
|
<Icon className={cn('mr-2 -mt-0.5 inline-block align-middle', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
|
||||||
<span>{node.label}</span>
|
<span className="align-middle">{node.label}</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,24 +176,25 @@ function MenuGroup({ node, depth }: { node: MenuNode; depth: number }) {
|
|||||||
<button
|
<button
|
||||||
onClick={toggle}
|
onClick={toggle}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex w-full items-center justify-between rounded-md transition',
|
'relative block w-full rounded-md text-left transition',
|
||||||
isTopLevel
|
isTopLevel
|
||||||
? 'px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500 hover:bg-slate-100 whitespace-nowrap'
|
? 'px-3 py-2 pr-7 text-[11px] font-semibold uppercase tracking-wide text-slate-500 hover:bg-slate-100 whitespace-nowrap'
|
||||||
: 'px-3 py-1.5 text-[13px] font-medium text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
: 'px-3 py-1.5 pr-7 text-[12px] font-medium leading-snug text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
||||||
// Highlight Ct_ group đang active (accordion open) bằng tinted background
|
// Highlight Ct_ group đang active (accordion open) bằng tinted background
|
||||||
isAccordion && open && 'bg-slate-50 text-slate-900',
|
isAccordion && open && 'bg-slate-50 text-slate-900',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* [Plan AA S24 t1] Revert truncate Plan U S23 t11 — bro request hiển
|
{/* [Plan AA S24 t2 wrap fix] Bro UAT request: label dài 2 dòng phải về
|
||||||
thị đầy đủ label custom. Sidebar widen w-72 xl:w-80 fit ~44 chars
|
đầu hàng (under icon, KHÔNG indent sau icon). Pattern: inline-block
|
||||||
1 dòng. Label cực dài fallback wrap multi-line natural CSS.
|
icon + inline text → text wrap natural về left edge button.
|
||||||
min-w-0 flex-1 + shrink-0 icon/chevron giữ responsive smooth. title
|
ChevronDown absolute right để KHÔNG bị đẩy xuống khi text wrap.
|
||||||
tooltip giữ (no harm — accessibility bonus). */}
|
Smaller text-[12px] + leading-snug compact 2-line height. */}
|
||||||
<span className="flex min-w-0 flex-1 items-center gap-2">
|
<Icon className="mr-1.5 -mt-0.5 inline-block h-4 w-4 align-middle" />
|
||||||
<Icon className="h-4 w-4 shrink-0" />
|
<span className="align-middle" title={effectiveLabel(node)}>{effectiveLabel(node)}</span>
|
||||||
<span title={effectiveLabel(node)}>{effectiveLabel(node)}</span>
|
<ChevronDown className={cn(
|
||||||
</span>
|
'absolute right-2 top-2 h-3.5 w-3.5 text-slate-400 transition',
|
||||||
<ChevronDown className={cn('h-3.5 w-3.5 shrink-0 text-slate-400 transition', !open && '-rotate-90')} />
|
!open && '-rotate-90',
|
||||||
|
)} />
|
||||||
</button>
|
</button>
|
||||||
{open && (
|
{open && (
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
@ -246,17 +247,17 @@ function MenuLeaf({ node, depth }: { node: MenuNode; depth: number }) {
|
|||||||
to={path}
|
to={path}
|
||||||
title={effectiveLabel(node)}
|
title={effectiveLabel(node)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex min-w-0 items-center gap-2.5 rounded-md transition',
|
'block rounded-md leading-snug transition',
|
||||||
isDeep ? 'px-3 py-1 text-[12px]' : 'px-3 py-2 text-sm font-medium',
|
isDeep ? 'px-3 py-1 text-[11px]' : 'px-3 py-2 text-[12px] font-medium',
|
||||||
isActive
|
isActive
|
||||||
? 'bg-brand-50 text-brand-700'
|
? 'bg-brand-50 text-brand-700'
|
||||||
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Icon className={cn('shrink-0', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
|
{/* [Plan AA S24 t2 wrap fix] inline-block icon + inline text → label dài
|
||||||
{/* [Plan AA S24 t1] Revert truncate Plan U S23 t11 — fit full label hoặc
|
wrap về đầu hàng (under icon, KHÔNG indent sau icon). */}
|
||||||
wrap natural. NavLink `title` (line 241) giữ tooltip accessibility. */}
|
<Icon className={cn('mr-2 -mt-0.5 inline-block align-middle', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
|
||||||
<span>{effectiveLabel(node)}</span>
|
<span className="align-middle">{effectiveLabel(node)}</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -283,16 +284,15 @@ function StaticLeaf({ node }: { node: MenuNode }) {
|
|||||||
title={effectiveLabel(node)}
|
title={effectiveLabel(node)}
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
cn(
|
cn(
|
||||||
'flex min-w-0 items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium transition',
|
'block rounded-md px-3 py-2 text-[12px] font-medium leading-snug transition',
|
||||||
isActive ? 'bg-brand-50 text-brand-700' : 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
isActive ? 'bg-brand-50 text-brand-700' : 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Icon className="h-4 w-4 shrink-0" />
|
{/* [Plan AA S24 t2 wrap fix] inline-block icon + inline text — consistent
|
||||||
{/* [Plan AA S24 t1] Revert truncate Plan U S23 t11 — StaticLeaf "Hộp thư"
|
với MenuLeaf + MenuGroup. */}
|
||||||
label ngắn (7 chars) không bao giờ overflow, drop truncate cho
|
<Icon className="mr-2 -mt-0.5 inline-block h-4 w-4 align-middle" />
|
||||||
consistent với MenuLeaf + MenuGroup. */}
|
<span className="align-middle">{effectiveLabel(node)}</span>
|
||||||
<span>{effectiveLabel(node)}</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user