wip: bento card layout + zinc/emerald tokens (in progress)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yusuf Suleman
2026-03-30 21:10:07 -05:00
parent 3704687793
commit 1a9ec9d0e4
6 changed files with 188 additions and 194 deletions

View File

@@ -61,17 +61,18 @@
}
.budget-amount {
font-size: var(--text-3xl);
font-weight: 500;
font-size: 36px;
font-weight: 800;
font-family: var(--mono);
letter-spacing: -0.04em;
color: var(--text-1);
line-height: 1;
}
.budget-label {
font-size: var(--text-base);
color: var(--text-3);
margin-top: var(--sp-1.5);
font-size: 12px;
color: var(--text-4);
margin-top: 4px;
}
.budget-rows {
@@ -92,18 +93,19 @@
}
.budget-row-name {
font-size: var(--text-base);
color: var(--text-2);
font-size: 13px;
color: var(--text-3);
}
.budget-row-amount {
font-size: var(--text-base);
font-size: 12px;
font-family: var(--mono);
color: var(--text-1);
font-weight: 500;
color: var(--text-2);
}
.budget-row-amount.income {
color: var(--success);
color: var(--accent);
}
@media (max-width: 768px) {

View File

@@ -14,147 +14,139 @@
size?: 'primary' | 'secondary';
href: string;
} = $props();
// Extract the number from title (e.g. "78 uncategorized..." → "78")
function extractNumber(t: string): { num: string; rest: string } {
const match = t.match(/^([\d,\.]+)\s+(.*)$/);
if (match) return { num: match[1], rest: match[2] };
return { num: '', rest: t };
}
const parsed = $derived(extractNumber(title));
</script>
<a {href} class="action-card {size} {variant}">
<div class="action-card-left">
<div class="action-card-icon {variant}">
<a {href} class="bento {variant}">
<div class="bento-top">
<span class="bento-label">
{#if variant === 'budget'}Budget{:else if variant === 'inventory'}Inventory{:else}Calories{/if}
</span>
<div class="bento-icon {variant}">
{#if variant === 'budget'}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
{:else if variant === 'inventory'}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16.5 9.4l-9-5.19"/><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
{:else if variant === 'fitness'}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>
{:else}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
{/if}
</div>
<div class="action-card-text">
<div class="action-card-title">{title}</div>
<div class="action-card-desc">{description}</div>
</div>
</div>
<div class="action-card-right">
{#if parsed.num}
<div class="bento-value">{parsed.num}</div>
<div class="bento-desc">{parsed.rest}<br>{description}</div>
{:else}
<div class="bento-desc-only">{title}<br>{description}</div>
{/if}
<div class="bento-action">
{action}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 2l3.5 3.5L4 9"/></svg>
</div>
</a>
<style>
.action-card {
.bento {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--sp-4) var(--sp-5);
flex-direction: column;
padding: 22px 24px;
border-radius: var(--radius);
background: var(--card);
border: 1px solid var(--border);
border-left: 3px solid var(--border);
box-shadow: var(--shadow-xs);
transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
border-top: 2px solid transparent;
box-shadow: var(--shadow-sm);
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
cursor: pointer;
text-decoration: none;
color: inherit;
}
.action-card.budget { border-left-color: var(--accent); }
.action-card.inventory { border-left-color: var(--error); }
.action-card.fitness { border-left-color: var(--success); }
.action-card:hover {
transform: translateY(-2px);
.bento:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-md);
}
.action-card.budget:hover { box-shadow: 0 4px 16px var(--accent-dim), var(--shadow-sm); }
.action-card.inventory:hover { box-shadow: 0 4px 16px var(--error-dim), var(--shadow-sm); }
.action-card.fitness:hover { box-shadow: 0 4px 16px var(--success-dim), var(--shadow-sm); }
.bento.budget:hover { border-top-color: var(--accent); }
.bento.inventory:hover { border-top-color: var(--error); }
.bento.fitness:hover { border-top-color: var(--success); }
.action-card:active { transform: scale(0.985); }
.bento:active { transform: scale(0.985); }
.action-card.primary {
box-shadow: var(--shadow-sm);
}
.action-card-left {
.bento-top {
display: flex;
align-items: center;
gap: var(--inner-gap);
flex: 1;
min-width: 0;
justify-content: space-between;
margin-bottom: 14px;
}
.action-card-icon {
width: 36px;
height: 36px;
border-radius: var(--radius-md);
.bento-label {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--text-4);
}
.bento-icon {
width: 28px;
height: 28px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.bento-icon.budget { background: var(--accent-dim); color: var(--accent); }
.bento-icon.inventory { background: var(--error-dim); color: var(--error); }
.bento-icon.fitness { background: var(--success-dim); color: var(--success); }
.bento-icon :global(svg) { width: 14px; height: 14px; }
/* Icon variants — using semantic tokens for both themes */
.action-card-icon.budget { background: var(--accent-bg); color: var(--accent); }
.action-card-icon.inventory { background: var(--error-bg); color: var(--error); }
.action-card-icon.fitness { background: var(--success-bg); color: var(--success); }
.action-card-icon :global(svg) {
width: 18px;
height: 18px;
}
.action-card-text {
flex: 1;
min-width: 0;
}
.action-card-title {
font-size: var(--text-md);
font-weight: 600;
.bento-value {
font-size: 32px;
font-weight: 700;
font-family: var(--mono);
letter-spacing: -0.04em;
line-height: 1;
color: var(--text-1);
line-height: var(--leading-snug);
margin-bottom: 6px;
}
.action-card-desc {
font-size: var(--text-sm);
.bento-desc {
font-size: 13px;
color: var(--text-3);
margin-top: var(--sp-0.5);
line-height: 1.4;
line-height: 1.5;
}
.action-card-right {
font-size: var(--text-sm);
.bento-desc-only {
font-size: 14px;
font-weight: 500;
color: var(--text-3);
display: flex;
color: var(--text-2);
line-height: 1.5;
margin-bottom: 4px;
}
.bento-action {
display: inline-flex;
align-items: center;
gap: 1px;
flex-shrink: 0;
padding: var(--sp-1) var(--sp-2);
border-radius: var(--radius-md);
transition: all var(--transition);
white-space: nowrap;
}
.action-card:hover .action-card-right {
gap: 4px;
font-size: 11px;
font-weight: 600;
color: var(--accent);
background: var(--accent-dim);
}
.action-card-right :global(svg) {
width: var(--sp-4);
height: var(--sp-4);
transition: transform var(--transition);
}
.action-card:hover .action-card-right :global(svg) {
transform: translateX(2px);
margin-top: 12px;
letter-spacing: 0.02em;
transition: gap 0.2s;
}
.bento:hover .bento-action { gap: 7px; }
@media (max-width: 768px) {
.action-card {
padding: var(--sp-4);
gap: var(--sp-2);
}
.action-card-left {
gap: var(--sp-3);
}
.bento { padding: 18px 20px; }
.bento-value { font-size: 24px; }
}
</style>

View File

@@ -97,25 +97,25 @@
-webkit-backdrop-filter: blur(20px) saturate(1.4);
}
.navbar-inner {
max-width: 1400px;
max-width: 1280px;
margin: 0 auto;
display: flex;
align-items: center;
height: 52px;
height: 48px;
padding: 0 var(--sp-6);
gap: var(--sp-5);
gap: var(--sp-6);
}
.navbar-logo {
font-weight: 700;
font-size: var(--text-md);
font-size: 14px;
display: flex;
align-items: center;
gap: var(--sp-2);
gap: 7px;
color: var(--text-1);
flex-shrink: 0;
letter-spacing: -0.02em;
letter-spacing: -0.04em;
}
.navbar-logo svg { width: 18px; height: 18px; color: var(--accent); }
.navbar-logo svg { width: 16px; height: 16px; color: var(--accent); }
.navbar-links {
display: flex;
@@ -124,19 +124,18 @@
flex: 1;
}
.navbar-link {
padding: 5px var(--sp-3);
border-radius: var(--radius-md);
font-size: var(--text-sm);
padding: 4px 12px;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
color: var(--text-3);
transition: all 0.15s ease;
color: var(--text-4);
transition: all 0.2s cubic-bezier(0.16,1,0.3,1);
background: none;
border: none;
position: relative;
text-decoration: none;
letter-spacing: 0.01em;
}
.navbar-link:hover { color: var(--text-1); background: var(--card-hover); }
.navbar-link:hover { color: var(--text-2); background: rgba(0,0,0,0.03); }
.navbar-link.active {
color: var(--accent);
background: var(--accent-dim);