fix: dashboard layout spacing and CSS cascade layer bug
Move CSS reset into @layer base so Tailwind utilities aren't overridden. Fix settings panel: search icon overlap, cramped widget items, spacing between header card and widget grid using inline margin styles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7c4ed94975
commit
bed0942d12
2 changed files with 57 additions and 42 deletions
|
|
@ -21,7 +21,9 @@
|
||||||
--font-family-sans: 'Exo 2', sans-serif;
|
--font-family-sans: 'Exo 2', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Exo 2', sans-serif;
|
font-family: 'Exo 2', sans-serif;
|
||||||
|
|
|
||||||
|
|
@ -322,18 +322,18 @@ export default function AdminHomePage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AdminShell>
|
<AdminShell>
|
||||||
<div class="w-full bg-[#F9FAFB] pb-12">
|
<div class="w-full">
|
||||||
<div class="overflow-hidden rounded-2xl border border-[#E5E7EB] bg-white px-8 pt-10 pb-12 shadow-sm md:px-10 md:pt-11 md:pb-13">
|
<div class="rounded-2xl border border-[#E5E7EB] bg-white px-6 py-5 shadow-sm md:px-8" style="margin-bottom: 28px">
|
||||||
<div class="flex flex-col gap-5 lg:flex-row lg:items-center lg:justify-between">
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div class="max-w-3xl" style="padding-left: 40px; padding-right: 20px;">
|
<div>
|
||||||
<h1 class="text-[28px] font-bold leading-tight text-[#111827]">Dashboard Overview</h1>
|
<h1 class="text-[22px] font-bold leading-tight text-[#111827]">Dashboard Overview</h1>
|
||||||
<p class="mt-1 text-[14px] text-[#6B7280]">Manage widget layout, visibility, sizing, and dashboard presentation</p>
|
<p class="mt-0.5 text-[13px] text-[#6B7280]">Manage widget layout, visibility, sizing, and dashboard presentation</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex w-full lg:w-auto lg:justify-end" style="margin-right: 20px;">
|
<div class="flex shrink-0">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="inline-flex h-9 w-full items-center justify-center gap-1.5 whitespace-nowrap rounded-xl bg-[#0D0D2A] px-4 text-[13px] font-semibold leading-none text-white shadow-sm lg:w-auto lg:min-w-[190px]"
|
class="inline-flex h-9 items-center gap-1.5 whitespace-nowrap rounded-xl bg-[#0D0D2A] px-5 text-[13px] font-semibold leading-none text-white shadow-sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const next = !settingsOpen();
|
const next = !settingsOpen();
|
||||||
setSettingsOpen(next);
|
setSettingsOpen(next);
|
||||||
|
|
@ -347,14 +347,13 @@ export default function AdminHomePage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class={settingsOpen() ? 'h-10' : 'h-0'} />
|
|
||||||
|
|
||||||
<Show when={settingsOpen()}>
|
<Show when={settingsOpen()}>
|
||||||
<div class="rounded-2xl border border-[#E5E7EB] bg-white p-8 shadow-sm md:p-9">
|
<div class="rounded-2xl border border-[#E5E7EB] bg-white p-6 shadow-sm md:p-7">
|
||||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
{/* Settings header */}
|
||||||
<div class="pl-2 pt-1">
|
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||||
|
<div>
|
||||||
<h2 class="text-[15px] font-semibold text-[#111827]">Widget Settings</h2>
|
<h2 class="text-[15px] font-semibold text-[#111827]">Widget Settings</h2>
|
||||||
<p class="mt-2 text-[13px] text-[#6B7280]">Choose visible widgets and select a grid layout.</p>
|
<p class="mt-1 text-[13px] text-[#6B7280]">Choose visible widgets and select a grid layout.</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -365,68 +364,83 @@ export default function AdminHomePage() {
|
||||||
Reset Layout
|
Reset Layout
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 grid gap-5 md:grid-cols-2 xl:grid-cols-4">
|
|
||||||
<label class="relative">
|
{/* Filter controls */}
|
||||||
<Search size={14} class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[#FA5014]" />
|
<div class="mt-5 flex flex-wrap gap-3">
|
||||||
|
<div class="relative min-w-[200px] flex-1">
|
||||||
|
<Search size={14} class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[#FA5014]" style="z-index:1" />
|
||||||
<input
|
<input
|
||||||
value={search()}
|
value={search()}
|
||||||
onInput={(event) => setSearch(event.currentTarget.value)}
|
onInput={(event) => setSearch(event.currentTarget.value)}
|
||||||
placeholder="Search widgets"
|
placeholder="Search widgets"
|
||||||
class="h-11 w-full rounded-lg border border-[#E5E7EB] bg-white pl-9 pr-3 text-sm text-[#111827] outline-none"
|
class="h-10 w-full rounded-lg border border-[#E5E7EB] bg-white pl-10 pr-3 text-sm text-[#111827] outline-none focus:border-[#FA5014]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</div>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
class="h-11 rounded-lg border border-[#E5E7EB] bg-white px-3 text-sm text-[#111827]"
|
class="h-10 rounded-lg border border-[#E5E7EB] bg-white px-3 text-sm text-[#111827]"
|
||||||
value={filterMode()}
|
value={filterMode()}
|
||||||
onChange={(event) => setFilterMode(event.currentTarget.value as FilterMode)}
|
onChange={(event) => setFilterMode(event.currentTarget.value as FilterMode)}
|
||||||
>
|
>
|
||||||
<option value="all">Filter: All Widgets</option>
|
<option value="all">All Widgets</option>
|
||||||
<option value="summary">Filter: Summary Widgets</option>
|
<option value="summary">Summary Only</option>
|
||||||
<option value="analytics">Filter: Analytical Widgets</option>
|
<option value="analytics">Analytical Only</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
class="h-11 rounded-lg border border-[#E5E7EB] bg-white px-3 text-sm text-[#111827]"
|
class="h-10 rounded-lg border border-[#E5E7EB] bg-white px-3 text-sm text-[#111827]"
|
||||||
value={sortMode()}
|
value={sortMode()}
|
||||||
onChange={(event) => setSortMode(event.currentTarget.value as SortMode)}
|
onChange={(event) => setSortMode(event.currentTarget.value as SortMode)}
|
||||||
>
|
>
|
||||||
<option value="layout">Sort: Layout Order</option>
|
<option value="layout">Layout Order</option>
|
||||||
<option value="name">Sort: Name</option>
|
<option value="name">Name</option>
|
||||||
<option value="status">Sort: Status</option>
|
<option value="status">Status</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
class="h-11 rounded-lg border border-[#E5E7EB] bg-white px-3 text-sm text-[#111827]"
|
class="h-10 rounded-lg border border-[#E5E7EB] bg-white px-3 text-sm text-[#111827]"
|
||||||
value={gridLayout()}
|
value={gridLayout()}
|
||||||
onChange={(event) => setGridLayout(event.currentTarget.value as GridLayoutMode)}
|
onChange={(event) => setGridLayout(event.currentTarget.value as GridLayoutMode)}
|
||||||
>
|
>
|
||||||
<option value="3x4">Grid: 3 x 4</option>
|
<option value="3x4">Grid 3 × 4</option>
|
||||||
<option value="3x3">Grid: 3 x 3</option>
|
<option value="3x3">Grid 3 × 3</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 grid gap-5 md:grid-cols-2">
|
|
||||||
|
{/* Widget list */}
|
||||||
|
<div class="mt-5 grid gap-3 md:grid-cols-2">
|
||||||
<For each={ADMIN_DASHBOARD_WIDGETS}>
|
<For each={ADMIN_DASHBOARD_WIDGETS}>
|
||||||
{(definition) => {
|
{(definition) => {
|
||||||
const visible = () => layout().visibility[definition.widgetKey] !== false;
|
const visible = () => layout().visibility[definition.widgetKey] !== false;
|
||||||
|
const meta = WIDGET_META[definition.widgetKey];
|
||||||
|
const state = meta?.state || 'empty';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="rounded-2xl border border-[#E5E7EB] bg-[#F9FAFB] px-4 py-5">
|
<div class="flex items-center justify-between gap-4 rounded-xl border border-[#E5E7EB] bg-[#F9FAFB] px-4 py-4">
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center gap-3 min-w-0">
|
||||||
<div>
|
<div class="shrink-0 text-[#FA5014]">
|
||||||
<p class="text-sm font-semibold text-[#111827]">{definition.title}</p>
|
{iconForWidget(definition.widgetKey)}
|
||||||
<p class="mt-0.5 text-[11px] font-semibold uppercase tracking-wide text-[#9CA3AF]">{definition.moduleKey}</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="min-w-0">
|
||||||
|
<p class="text-sm font-semibold text-[#111827]">{definition.title}</p>
|
||||||
|
<p class="mt-0.5 text-[11px] font-medium uppercase tracking-wide text-[#9CA3AF]">{definition.moduleKey}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex shrink-0 items-center gap-2">
|
||||||
|
<span class={`hidden rounded-full border px-2 py-0.5 text-[10px] font-semibold sm:inline-flex ${badgeClass(state)}`}>
|
||||||
|
{meta?.statusLabel || 'No Data'}
|
||||||
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={`inline-flex h-8 items-center gap-1 rounded-md border px-3 text-xs font-semibold ${
|
class={`inline-flex h-8 items-center gap-1.5 rounded-md border px-3 text-xs font-semibold ${
|
||||||
visible()
|
visible()
|
||||||
? 'border-[#FDBA8C] bg-[#FFF1EB] text-[#FA5014]'
|
? 'border-[#FDBA8C] bg-[#FFF1EB] text-[#FA5014]'
|
||||||
: 'border-[#E5E7EB] bg-white text-[#6B7280]'
|
: 'border-[#E5E7EB] bg-white text-[#6B7280]'
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setWidgetVisibility(definition.widgetKey, !visible())}
|
onClick={() => setWidgetVisibility(definition.widgetKey, !visible())}
|
||||||
>
|
>
|
||||||
{visible() ? <Eye size={13} class="text-[#FA5014]" /> : <EyeOff size={13} class="text-[#FA5014]" />} {visible() ? 'Visible' : 'Hidden'}
|
{visible() ? <Eye size={12} /> : <EyeOff size={12} />}
|
||||||
|
{visible() ? 'Visible' : 'Hidden'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -434,15 +448,14 @@ export default function AdminHomePage() {
|
||||||
}}
|
}}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={isAutoSaving() || autoSaveNotice()}>
|
<Show when={isAutoSaving() || autoSaveNotice()}>
|
||||||
<p class="mt-4 text-xs text-[#6B7280]">{isAutoSaving() ? 'Saving layout...' : autoSaveNotice()}</p>
|
<p class="mt-4 text-xs text-[#6B7280]">{isAutoSaving() ? 'Saving layout...' : autoSaveNotice()}</p>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<div class={settingsOpen() ? 'h-8' : 'h-12'} />
|
<div class="grid grid-cols-1 gap-5 xl:grid-cols-12" style="margin-top: 28px">
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-7 xl:grid-cols-12">
|
|
||||||
<For each={orderedWidgets()}>
|
<For each={orderedWidgets()}>
|
||||||
{(definition) => {
|
{(definition) => {
|
||||||
const meta = WIDGET_META[definition.widgetKey];
|
const meta = WIDGET_META[definition.widgetKey];
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue