feat: implement ui/ux dashboard improvements (search, layout, cta) #1

Open
falah wants to merge 1 commits from ui-ux-dashboard-improvements into main
+55 -18
View File
@@ -6,6 +6,7 @@
let families = $state([]); let families = $state([]);
let invites = $state([]); let invites = $state([]);
let newFamilyName = $state(''); let newFamilyName = $state('');
let searchQuery = $state('');
let loading = $state(true); let loading = $state(true);
let error = $state(''); let error = $state('');
@@ -45,6 +46,7 @@
} }
const isAgentForMultiple = $derived(families.filter(f => f.role === 'agent').length > 1); const isAgentForMultiple = $derived(families.filter(f => f.role === 'agent').length > 1);
const filteredFamilies = $derived(families.filter(f => f.name.toLowerCase().includes(searchQuery.toLowerCase())));
</script> </script>
<div class="switcher-screen"> <div class="switcher-screen">
@@ -65,12 +67,22 @@
{#if loading} {#if loading}
<p class="loading">Loading your families…</p> <p class="loading">Loading your families…</p>
{:else} {:else}
<div class="section">
<h3>Start your own family estate</h3>
<p class="hint">If you're the head of family setting this up for the first time, create your family here. You can invite an estate agent to help manage it once it's set up.</p>
<label class="field"><span>Family name</span><input type="text" bind:value={newFamilyName} placeholder="e.g. The Ismail Family" /></label>
<button class="btn-primary" onclick={handleCreate}>Create family</button>
</div>
{#if invites.length} {#if invites.length}
<div class="section"> <div class="section">
<h3>Pending invitations</h3> <h3>Pending invitations</h3>
{#each invites as inv} {#each invites as inv}
<div class="invite-row"> <div class="invite-row card-layout">
<span>{inv.familyName} — as <strong>{inv.role}</strong></span> <div class="card-info">
<span class="card-title">{inv.familyName}</span>
<span class="card-meta">Role: <strong>{inv.role}</strong></span>
</div>
<button class="btn-small" onclick={() => handleAccept(inv)}>Accept</button> <button class="btn-small" onclick={() => handleAccept(inv)}>Accept</button>
</div> </div>
{/each} {/each}
@@ -79,22 +91,29 @@
{#if families.length} {#if families.length}
<div class="section"> <div class="section">
<h3>{isAgentForMultiple ? 'Your assigned families' : 'Your families'}</h3> <div class="section-header">
{#each families as f} <h3>{isAgentForMultiple ? 'Your assigned families' : 'Your families'}</h3>
<button class="family-row" onclick={() => selectFamily(f.id)}> <input type="text" class="search-input" bind:value={searchQuery} placeholder="Search families..." />
<span>{f.name}</span> </div>
<span class="role-badge" class:owner={f.role === 'owner'}>{f.role}</span> <div class="cards-grid">
</button> {#each filteredFamilies as f}
{/each} <button class="family-card" onclick={() => selectFamily(f.id)}>
<div class="card-top">
<span class="card-title">{f.name}</span>
<span class="role-badge" class:owner={f.role === 'owner'}>{f.role}</span>
</div>
<div class="card-bottom">
<span class="status-indicator">Active</span>
<span class="action-hint">Manage estate &rarr;</span>
</div>
</button>
{/each}
{#if filteredFamilies.length === 0}
<p class="empty-state">No families found matching "{searchQuery}"</p>
{/if}
</div>
</div> </div>
{/if} {/if}
<div class="section">
<h3>Start your own family estate</h3>
<p class="hint">If you're the head of family setting this up for the first time, create your family here. You can invite an estate agent to help manage it once it's set up.</p>
<label class="field"><span>Family name</span><input type="text" bind:value={newFamilyName} placeholder="e.g. The Ismail Family" /></label>
<button class="btn-primary" onclick={handleCreate}>Create family</button>
</div>
{/if} {/if}
</div> </div>
@@ -114,12 +133,30 @@
.hint { font-size: 11.5px; color: #8A8478; line-height: 1.5; margin-bottom: 12px; } .hint { font-size: 11.5px; color: #8A8478; line-height: 1.5; margin-bottom: 12px; }
.invite-row { display: flex; justify-content: space-between; align-items: center; background: rgba(201,168,76,0.08); border: 1px solid rgba(201,168,76,0.25); border-radius: 10px; padding: 12px; margin-bottom: 8px; font-size: 13px; color: #E8E4DC; } .invite-row { display: flex; justify-content: space-between; align-items: center; background: rgba(201,168,76,0.08); border: 1px solid rgba(201,168,76,0.25); border-radius: 10px; padding: 12px; margin-bottom: 8px; font-size: 13px; color: #E8E4DC; }
.btn-small { background: #C9A84C; color: #070A0D; border: none; border-radius: 8px; padding: 8px 12px; font-size: 12px; font-weight: 600; cursor: pointer; } .btn-small { background: #C9A84C; color: #070A0D; border: none; border-radius: 8px; padding: 8px 12px; font-size: 12px; font-weight: 600; cursor: pointer; }
.family-row { width: 100%; display: flex; justify-content: space-between; align-items: center; background: rgba(255,255,255,0.04); border: none; border-radius: 10px; padding: 14px; margin-bottom: 8px; font-size: 14px; color: #E8E4DC; cursor: pointer; text-align: left; }
.section-header { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.search-input { background: rgba(255,255,255,0.05); border: 1px solid rgba(201,168,76,0.2); border-radius: 8px; padding: 8px 12px; color: #E8E4DC; font-size: 13px; width: 100%; outline: none; transition: border-color 0.2s; }
.search-input:focus { border-color: #C9A84C; }
.cards-grid { display: flex; flex-direction: column; gap: 10px; }
.family-card { width: 100%; display: flex; flex-direction: column; gap: 12px; background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 16px; font-size: 14px; color: #E8E4DC; cursor: pointer; text-align: left; transition: all 0.2s; }
.family-card:hover { background: rgba(255,255,255,0.06); border-color: rgba(201,168,76,0.3); transform: translateY(-1px); }
.card-top { display: flex; justify-content: space-between; align-items: center; width: 100%; }
.card-bottom { display: flex; justify-content: space-between; align-items: center; width: 100%; font-size: 11px; color: #8A8478; border-top: 1px solid rgba(255,255,255,0.05); padding-top: 10px; }
.card-title { font-weight: 600; font-size: 15px; }
.status-indicator { display: flex; align-items: center; gap: 4px; }
.status-indicator::before { content: ''; width: 6px; height: 6px; background: #2ECC71; border-radius: 50%; }
.action-hint { color: #C9A84C; opacity: 0; transition: opacity 0.2s; }
.family-card:hover .action-hint { opacity: 1; }
.empty-state { text-align: center; color: #8A8478; font-size: 13px; padding: 20px 0; font-style: italic; }
.role-badge { font-size: 10px; text-transform: uppercase; padding: 3px 8px; border-radius: 6px; background: rgba(255,255,255,0.1); color: #B8B2A6; } .role-badge { font-size: 10px; text-transform: uppercase; padding: 3px 8px; border-radius: 6px; background: rgba(255,255,255,0.1); color: #B8B2A6; }
.role-badge.owner { background: rgba(201,168,76,0.15); color: #C9A84C; } .role-badge.owner { background: rgba(201,168,76,0.15); color: #C9A84C; }
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; } .field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.field span { font-size: 12px; color: #B8B2A6; } .field span { font-size: 12px; color: #B8B2A6; }
.field input { background: rgba(255,255,255,0.05); border: 1px solid rgba(201,168,76,0.2); border-radius: 8px; padding: 10px 12px; color: #E8E4DC; font-size: 14px; width: 100%; } .field input { background: rgba(255,255,255,0.05); border: 1px solid rgba(201,168,76,0.2); border-radius: 8px; padding: 10px 12px; color: #E8E4DC; font-size: 14px; width: 100%; }
.btn-primary { width: 100%; padding: 12px; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; background: #C9A84C; color: #070A0D; } .btn-primary { width: 100%; padding: 12px; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; background: #C9A84C; color: #070A0D; transition: opacity 0.2s; }
.btn-primary:hover { opacity: 0.9; }
.error-text { color: #EF4444; font-size: 12.5px; margin-bottom: 12px; } .error-text { color: #EF4444; font-size: 12.5px; margin-bottom: 12px; }
</style> </style>