refactor: update app.vue and various components to enhance UI consistency, replace color classes for improved accessibility, and refine layout for better user experience

This commit is contained in:
Jennie Robinson Faber 2025-09-10 11:02:54 +01:00
parent 7b4fb6c2fd
commit 24e8b7a3a8
41 changed files with 2395 additions and 1603 deletions

View file

@ -11,7 +11,7 @@
'px-4 py-2 font-medium transition-none',
activeView === 'monthly'
? 'bg-black text-white'
: 'bg-white text-black hover:bg-zinc-100',
: 'bg-white text-black hover:bg-neutral-100',
]">
Monthly
</button>
@ -21,7 +21,7 @@
'px-4 py-2 font-medium border-l-2 border-black transition-none',
activeView === 'annual'
? 'bg-black text-white'
: 'bg-white text-black hover:bg-zinc-100',
: 'bg-white text-black hover:bg-neutral-100',
]">
Annual
</button>
@ -48,14 +48,14 @@
<div class="max-w-md mx-auto space-y-6">
<div class="text-6xl">📊</div>
<h3 class="text-xl font-bold text-black">No budget data found</h3>
<p class="text-gray-600">
<p class="text-neutral-600">
Your budget is empty. Complete the setup wizard to add your revenue
streams, team members, and expenses.
</p>
<div class="flex justify-center">
<NuxtLink
to="/coop-builder"
class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-black hover:bg-zinc-800 border-2 border-black transition-colors">
class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-black hover:bg-neutral-800 border-2 border-black transition-colors">
Complete Setup Wizard
</NuxtLink>
</div>
@ -79,7 +79,7 @@
<th
v-for="month in monthlyHeaders"
:key="month.key"
class="border-r border-gray-400 px-2 py-3 text-center font-medium min-w-[80px] last:border-r-0">
class="border-r border-neutral-400 px-2 py-3 text-center font-medium min-w-[80px] last:border-r-0">
{{ month.label }}
</th>
</tr>
@ -94,7 +94,7 @@
@click="showAddRevenueModal = true"
size="xs"
:ui="{
base: 'bg-white text-black hover:bg-zinc-200 transition-none',
base: 'bg-white text-black hover:bg-neutral-200 transition-none',
}">
+ Add
</UButton>
@ -107,9 +107,9 @@
<template
v-for="(items, categoryName) in groupedRevenue"
:key="`revenue-${categoryName}`">
<tr v-if="items.length > 0" class="border-t border-gray-300">
<tr v-if="items.length > 0" class="border-t border-neutral-300">
<td
class="px-4 py-1 font-semibold sticky left-0 bg-zinc-100 z-10 border-black"
class="px-4 py-1 font-semibold sticky left-0 bg-neutral-100 z-10 border-black"
:colspan="monthlyHeaders.length + 1">
{{ categoryName }}
</td>
@ -118,17 +118,17 @@
v-for="item in items"
:key="item.id"
:class="[
'border-t border-gray-200 hover:bg-zinc-50 transition-all duration-300',
'border-t border-neutral-200 hover:bg-neutral-50 transition-all duration-300',
highlightedItemId === item.id &&
'bg-yellow-100 animate-pulse',
]">
<td
class="border-r-1 border-zinc-200 px-4 py-2 sticky left-0 bg-white z-10">
class="border-r-1 border-neutral-200 px-4 py-2 sticky left-0 bg-white z-10">
<div class="flex items-center justify-between group">
<div class="flex-1">
<div class="text-left w-full">
<div class="font-medium">{{ item.name }}</div>
<div class="text-xs text-gray-600">
<div class="text-xs text-neutral-600">
{{ item.subcategory }}
</div>
</div>
@ -147,7 +147,7 @@
<td
v-for="month in monthlyHeaders"
:key="month.key"
class="border-r border-gray-200 px-1 py-1 last:border-r-0">
class="border-r border-neutral-200 px-1 py-1 last:border-r-0">
<input
type="text"
:value="formatValue(item.monthlyValues?.[month.key] || 0)"
@ -157,9 +157,9 @@
"
@blur="handleBlur($event, 'revenue', item.id, month.key)"
@keydown.enter="handleEnter($event)"
class="w-full text-right px-1 py-0.5 border border-transparent hover:border-gray-400 focus:border-black focus:outline-none transition-none"
class="w-full text-right px-1 py-0.5 border border-transparent hover:border-neutral-400 focus:border-black focus:outline-none transition-none"
:class="{
'bg-zinc-50': !item.monthlyValues?.[month.key],
'bg-neutral-50': !item.monthlyValues?.[month.key],
}" />
</td>
</tr>
@ -167,9 +167,9 @@
<!-- Total Revenue Row -->
<tr
class="border-t-1 border-black border-b-1 font-bold bg-zinc-100">
class="border-t-1 border-black border-b-1 font-bold bg-neutral-100">
<td
class="border-r-1 border-black px-4 py-2 sticky left-0 bg-zinc-100 z-10">
class="border-r-1 border-black px-4 py-2 sticky left-0 bg-neutral-100 z-10">
TOTAL REVENUE
</td>
<td
@ -189,7 +189,7 @@
@click="showAddExpenseModal = true"
size="xs"
:ui="{
base: 'bg-white text-black hover:bg-zinc-200 transition-none',
base: 'bg-white text-black hover:bg-neutral-200 transition-none',
}">
+ Add
</UButton>
@ -202,9 +202,9 @@
<template
v-for="(items, categoryName) in groupedExpenses"
:key="`expense-${categoryName}`">
<tr v-if="items.length > 0" class="border-t border-gray-300">
<tr v-if="items.length > 0" class="border-t border-neutral-300">
<td
class="px-4 py-1 font-semibold sticky left-0 bg-zinc-100 z-10"
class="px-4 py-1 font-semibold sticky left-0 bg-neutral-100 z-10"
:colspan="monthlyHeaders.length + 1">
{{ categoryName }}
</td>
@ -213,12 +213,12 @@
v-for="item in items"
:key="item.id"
:class="[
'border-t border-gray-200 hover:bg-zinc-50 transition-all duration-300',
'border-t border-neutral-200 hover:bg-neutral-50 transition-all duration-300',
highlightedItemId === item.id &&
'bg-yellow-100 animate-pulse',
]">
<td
class="border-r-1 border-zinc-200 px-4 py-2 sticky left-0 bg-white z-10">
class="border-r-1 border-neutral-200 px-4 py-2 sticky left-0 bg-white z-10">
<div class="flex items-center justify-between group">
<div class="flex-1">
<div class="text-left w-full">
@ -236,7 +236,7 @@
Auto
</span>
</div>
<div class="text-xs text-gray-600" v-if="!isPayrollItem(item.id)">
<div class="text-xs text-neutral-600" v-if="!isPayrollItem(item.id)">
{{ item.subcategory }}
</div>
</div>
@ -258,7 +258,7 @@
<td
v-for="month in monthlyHeaders"
:key="month.key"
class="border-r border-gray-200 px-1 py-1 last:border-r-0">
class="border-r border-neutral-200 px-1 py-1 last:border-r-0">
<input
type="text"
:value="formatValue(item.monthlyValues?.[month.key] || 0)"
@ -271,12 +271,12 @@
@keydown.enter="handleEnter($event)"
class="w-full text-right px-1 py-0.5 border-2 transition-none"
:class="{
'bg-zinc-50':
'bg-neutral-50':
!item.monthlyValues?.[month.key] &&
!isPayrollItem(item.id),
'bg-zinc-50 border-none cursor-not-allowed text-zinc-500':
'bg-neutral-50 border-none cursor-not-allowed text-neutral-500':
isPayrollItem(item.id),
'border-transparent hover:border-zinc-400 focus:border-black focus:outline-none':
'border-transparent hover:border-neutral-400 focus:border-black focus:outline-none':
!isPayrollItem(item.id),
}"
:title="
@ -289,15 +289,15 @@
</template>
<!-- Total Expenses Row -->
<tr class="border-t-1 border-black font-bold bg-zinc-100">
<tr class="border-t-1 border-black font-bold bg-neutral-100">
<td
class="border-r-1 border-black px-4 py-2 sticky left-0 bg-zinc-100 z-10">
class="border-r-1 border-black px-4 py-2 sticky left-0 bg-neutral-100 z-10">
TOTAL EXPENSES
</td>
<td
v-for="month in monthlyHeaders"
:key="month.key"
class="border-r border-gray-400 px-2 py-2 text-right last:border-r-0">
class="border-r border-neutral-400 px-2 py-2 text-right last:border-r-0">
{{ formatCurrency(monthlyTotals[month.key]?.expenses || 0) }}
</td>
</tr>
@ -311,7 +311,7 @@
<td
v-for="month in monthlyHeaders"
:key="month.key"
class="border-r border-gray-400 px-2 py-3 text-right last:border-r-0"
class="border-r border-neutral-400 px-2 py-3 text-right last:border-r-0"
:class="
getNetIncomeClass(monthlyTotals[month.key]?.net || 0)
">
@ -320,7 +320,7 @@
</tr>
<!-- Cumulative Balance Row -->
<tr class="border-t-1 border-gray-400 font-bold text-lg bg-blue-50">
<tr class="border-t-1 border-neutral-400 font-bold text-lg bg-blue-50">
<td
class="border-r-1 border-black px-4 py-3 sticky left-0 bg-blue-50 z-10">
CUMULATIVE BALANCE
@ -328,7 +328,7 @@
<td
v-for="month in monthlyHeaders"
:key="month.key"
class="border-r border-gray-400 px-2 py-3 text-right last:border-r-0"
class="border-r border-neutral-400 px-2 py-3 text-right last:border-r-0"
:class="
getCumulativeBalanceClass(cumulativeBalances[month.key] || 0)
">
@ -403,19 +403,19 @@
placeholder="Enter annual amount (e.g., 12000)"
size="lg">
<template #leading>
<span class="text-gray-500 font-medium">$</span>
<span class="text-neutral-500 font-medium">$</span>
</template>
</UInput>
</UFormField>
<div class="bg-white rounded-lg p-4 border border-gray-200">
<div class="bg-white rounded-lg p-4 border border-neutral-200">
<div class="mb-2">
<span class="text-sm font-medium text-gray-700"
<span class="text-sm font-medium text-neutral-700"
>Distribution Preview</span
>
</div>
<p class="text-sm text-gray-600">
<p class="text-sm text-neutral-600">
This will divide
<span class="font-semibold text-gray-900"
<span class="font-semibold text-neutral-900"
>${{ newRevenue.annualAmount || 0 }}</span
>
equally across all 12 months (<span
@ -440,17 +440,17 @@
placeholder="Enter monthly amount (e.g., 1000)"
size="lg">
<template #leading>
<span class="text-gray-500 font-medium">$</span>
<span class="text-neutral-500 font-medium">$</span>
</template>
</UInput>
</UFormField>
<div class="bg-white rounded-lg p-4 border border-gray-200">
<div class="bg-white rounded-lg p-4 border border-neutral-200">
<div class="mb-2">
<span class="text-sm font-medium text-gray-700"
<span class="text-sm font-medium text-neutral-700"
>Monthly Preview</span
>
</div>
<p class="text-sm text-gray-600">
<p class="text-sm text-neutral-600">
This will set
<span class="font-semibold text-green-600"
>${{ newRevenue.monthlyAmount || 0 }}</span
@ -463,8 +463,8 @@
<!-- Start Empty -->
<div v-else>
<div
class="bg-white rounded-lg p-6 border border-gray-200 text-center">
<p class="text-sm text-gray-600">
class="bg-white rounded-lg p-6 border border-neutral-200 text-center">
<p class="text-sm text-neutral-600">
The revenue item will be created with no initial values. You
can fill them in later directly in the budget table.
</p>
@ -545,19 +545,19 @@
size="lg"
class="text-sm font-medium w-full">
<template #leading>
<span class="text-gray-500 font-medium">$</span>
<span class="text-neutral-500 font-medium">$</span>
</template>
</UInput>
</UFormField>
<div class="bg-white rounded-lg p-4 border border-gray-200">
<div class="bg-white rounded-lg p-4 border border-neutral-200">
<div class="mb-2">
<span class="text-sm font-medium text-gray-700"
<span class="text-sm font-medium text-neutral-700"
>Distribution Preview</span
>
</div>
<p class="text-sm text-gray-600">
<p class="text-sm text-neutral-600">
This will divide
<span class="font-semibold text-gray-900"
<span class="font-semibold text-neutral-900"
>${{ newExpense.annualAmount || 0 }}</span
>
equally across all 12 months (<span
@ -583,17 +583,17 @@
size="lg"
class="text-sm font-medium w-full">
<template #leading>
<span class="text-gray-500 font-medium">$</span>
<span class="text-neutral-500 font-medium">$</span>
</template>
</UInput>
</UFormField>
<div class="bg-white rounded-lg p-4 border border-gray-200">
<div class="bg-white rounded-lg p-4 border border-neutral-200">
<div class="mb-2">
<span class="text-sm font-medium text-gray-700"
<span class="text-sm font-medium text-neutral-700"
>Monthly Preview</span
>
</div>
<p class="text-sm text-gray-600">
<p class="text-sm text-neutral-600">
This will set
<span class="font-semibold text-red-600"
>${{ newExpense.monthlyAmount || 0 }}</span
@ -606,8 +606,8 @@
<!-- Start Empty -->
<div v-else>
<div
class="bg-white rounded-lg p-6 border border-gray-200 text-center">
<p class="text-sm text-gray-600">
class="bg-white rounded-lg p-6 border border-neutral-200 text-center">
<p class="text-sm text-neutral-600">
The expense item will be created with no initial values. You
can fill them in later directly in the budget table.
</p>
@ -650,8 +650,8 @@
<!-- Revenue Section -->
<div>
<h4 class="font-semibold text-green-600 mb-2">📈 Revenue Calculation</h4>
<p class="text-sm text-gray-600 mb-2">Revenue comes from your setup wizard streams and any manual additions:</p>
<ul class="text-sm text-gray-600 space-y-1 ml-4">
<p class="text-sm text-neutral-600 mb-2">Revenue comes from your setup wizard streams and any manual additions:</p>
<ul class="text-sm text-neutral-600 space-y-1 ml-4">
<li> Monthly amounts you entered for each revenue stream</li>
<li> Varies by month based on your specific projections</li>
</ul>
@ -660,7 +660,7 @@
<!-- Payroll Section -->
<div>
<h4 class="font-semibold text-blue-600 mb-2">👥 Smart Payroll Calculation</h4>
<p class="text-sm text-gray-600 mb-2">Payroll uses a <strong>cumulative balance approach</strong> to ensure sustainability:</p>
<p class="text-sm text-neutral-600 mb-2">Payroll uses a <strong>cumulative balance approach</strong> to ensure sustainability:</p>
<div class="bg-blue-50 border border-blue-200 rounded p-3 text-sm">
<p class="font-medium mb-2">Step-by-step process:</p>
<ol class="space-y-1 ml-4">
@ -671,7 +671,7 @@
<li>5. Ensure cumulative balance doesn't fall below threshold</li>
</ol>
</div>
<p class="text-sm text-gray-600 mt-2">
<p class="text-sm text-neutral-600 mt-2">
This means payroll varies by month - higher in good cash flow months, lower when cash is tight.
</p>
</div>
@ -679,8 +679,8 @@
<!-- Cumulative Balance Section -->
<div>
<h4 class="font-semibold text-purple-600 mb-2">💰 Cumulative Balance</h4>
<p class="text-sm text-gray-600 mb-2">Shows your running cash position over time:</p>
<ul class="text-sm text-gray-600 space-y-1 ml-4">
<p class="text-sm text-neutral-600 mb-2">Shows your running cash position over time:</p>
<ul class="text-sm text-neutral-600 space-y-1 ml-4">
<li> Starts at $0 (current cash position)</li>
<li> Adds each month's net income (Revenue - All Expenses)</li>
<li> Helps you see when cash might run low</li>
@ -691,7 +691,7 @@
<!-- Policy Explanation -->
<div>
<h4 class="font-semibold text-orange-600 mb-2"> Pay Policy: {{ getPolicyName() }}</h4>
<div class="text-sm text-gray-600">
<div class="text-sm text-neutral-600">
<p v-if="coopBuilderStore.policy?.relationship === 'equal-pay'">
Everyone gets equal hourly wage (${{ coopBuilderStore.equalHourlyWage || 0 }}/hour) based on their monthly hours.
</p>
@ -704,8 +704,8 @@
</div>
</div>
<div class="bg-gray-50 border border-gray-200 rounded p-3">
<p class="text-sm text-gray-700">
<div class="bg-neutral-50 border border-neutral-200 rounded p-3">
<p class="text-sm text-neutral-700">
<strong>Key insight:</strong> This system prioritizes sustainability over theoretical maximums.
You might not always get full theoretical wages, but you'll never run out of cash.
</p>
@ -1231,7 +1231,7 @@ function formatCurrency(amount: number): string {
function getNetIncomeClass(amount: number): string {
if (amount > 0) return "text-green-600 font-bold";
if (amount < 0) return "text-red-600 font-bold";
return "text-gray-600";
return "text-neutral-600";
}
function getCumulativeBalanceClass(amount: number): string {