refactor: enhance AnnualBudget component layout with improved dark mode support, streamline table structure, and update CSS for better visual consistency

This commit is contained in:
Jennie Robinson Faber 2025-09-10 15:24:18 +01:00
parent 24e8b7a3a8
commit f073f91569
14 changed files with 1440 additions and 922 deletions

View file

@ -2,114 +2,164 @@
<div class="space-y-8">
<!-- Annual Budget Overview -->
<div class="space-y-4">
<h2 class="text-2xl font-bold">Annual Budget Overview</h2>
<div class="relative">
<div class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
<div
class="relative border border-black dark:border-neutral-600 bg-white dark:bg-neutral-950">
<table
class="w-full border-collapse text-sm bg-white dark:bg-neutral-950">
<thead>
<tr class="bg-neutral-100 dark:bg-neutral-950">
<th
class="border-r-1 border-black dark:border-neutral-400 px-4 py-3 text-left font-bold text-black dark:text-white">
Category
</th>
<th
class="border-r border-neutral-400 dark:border-neutral-600 px-4 py-3 text-right font-bold text-black dark:text-white">
Planned
</th>
<th
class="px-4 py-3 text-right font-bold text-black dark:text-white">
%
</th>
</tr>
</thead>
<tbody>
<!-- Revenue Section -->
<tr class="bg-black text-white dark:bg-white dark:text-black">
<td
class="px-4 py-2 font-bold text-white dark:text-black"
colspan="3">
REVENUE
</td>
</tr>
<div class="border border-black bg-white">
<table class="w-full border-collapse text-sm">
<thead>
<tr class="border-b-2 border-black bg-neutral-100">
<th class="border-r-1 border-black px-4 py-3 text-left font-bold">
Category
</th>
<th
class="border-r border-neutral-400 px-4 py-3 text-right font-bold">
Planned
</th>
<th class="px-4 py-3 text-right font-bold">%</th>
</tr>
</thead>
<tbody>
<!-- Revenue Section -->
<tr class="bg-black text-white">
<td class="px-4 py-2 font-bold" colspan="3">REVENUE</td>
</tr>
<!-- Revenue Categories -->
<tr
v-for="(category, index) in revenueCategories"
:key="`rev-${index}`"
class="border-t border-neutral-200 dark:border-neutral-700 text-black dark:text-white"
v-show="category.planned > 0">
<td
class="border-r-1 border-black dark:border-neutral-400 px-4 py-2 text-black dark:text-white">
{{ category.name }}
</td>
<td
class="border-r border-neutral-400 dark:border-neutral-600 px-4 py-2 text-right text-black dark:text-white font-mono">
{{ formatCurrency(category.planned) }}
</td>
<td
class="px-4 py-2 text-right text-black dark:text-white font-mono">
{{ category.percentage }}%
</td>
</tr>
<!-- Revenue Categories -->
<tr
v-for="(category, index) in revenueCategories"
:key="`rev-${index}`"
class="border-t border-neutral-200"
v-show="category.planned > 0">
<td class="border-r-1 border-black px-4 py-2">
{{ category.name }}
</td>
<td class="border-r border-neutral-400 px-4 py-2 text-right">
{{ formatCurrency(category.planned) }}
</td>
<td class="px-4 py-2 text-right">{{ category.percentage }}%</td>
</tr>
<!-- Total Revenue -->
<tr
class="border-t-2 border-black dark:border-neutral-400 font-semibold bg-neutral-50 dark:bg-neutral-800">
<td
class="border-r-1 border-black dark:border-neutral-400 px-4 py-2 text-black dark:text-white">
Total Revenue
</td>
<td
class="border-r border-neutral-400 dark:border-neutral-600 px-4 py-2 text-right text-black dark:text-white font-mono">
{{ formatCurrency(totalRevenuePlanned) }}
</td>
<td
class="px-4 py-2 text-right text-black dark:text-white font-mono">
100%
</td>
</tr>
<!-- Total Revenue -->
<tr class="border-t-2 border-black font-semibold bg-neutral-50">
<td class="border-r-1 border-black px-4 py-2">Total Revenue</td>
<td class="border-r border-neutral-400 px-4 py-2 text-right">
{{ formatCurrency(totalRevenuePlanned) }}
</td>
<td class="px-4 py-2 text-right">100%</td>
</tr>
<!-- Revenue Diversification Guidance -->
<tr class="bg-neutral-50 dark:bg-neutral-800">
<td
colspan="3"
class="border-t border-neutral-300 dark:border-neutral-700 px-4 py-3 text-black dark:text-white">
<div class="text-sm">
<p class="font-medium mb-2 text-black dark:text-white">
{{ diversificationGuidance }}
</p>
<p
class="text-neutral-600 dark:text-neutral-100 mb-2"
v-if="suggestedCategories.length > 0">
Consider developing: {{ suggestedCategories.join(", ") }}
</p>
<p class="text-xs text-black dark:text-white">
<NuxtLink
to="/help#revenue-diversification"
class="text-white dark:text-neutral-100 hover:text-white dark:hover:text-white underline">
Learn how to develop these revenue streams
</NuxtLink>
</p>
</div>
</td>
</tr>
<!-- Revenue Diversification Guidance -->
<tr :class="guidanceBackgroundClass">
<td colspan="3" class="border-t border-neutral-300 px-4 py-3">
<div class="text-sm">
<p class="font-medium mb-2">{{ diversificationGuidance }}</p>
<p
class="text-neutral-600 mb-2"
v-if="suggestedCategories.length > 0">
Consider developing: {{ suggestedCategories.join(", ") }}
</p>
<p class="text-xs">
<NuxtLink
to="/help#revenue-diversification"
class="text-blue-600 hover:text-blue-800 underline">
Learn how to develop these revenue streams
</NuxtLink>
</p>
</div>
</td>
</tr>
<!-- Expenses Section -->
<tr class="bg-black text-white dark:bg-white dark:text-black">
<td
class="px-4 py-2 font-bold text-white dark:text-black"
colspan="3">
EXPENSES
</td>
</tr>
<!-- Expenses Section -->
<tr class="bg-black text-white">
<td class="px-4 py-2 font-bold" colspan="3">EXPENSES</td>
</tr>
<!-- Expense Categories -->
<tr
v-for="(category, index) in expenseCategories"
:key="`exp-${index}`"
class="text-black dark:text-white"
v-show="category.planned > 0">
<td
class="border-r-1 border-black dark:border-neutral-400 px-4 py-2 text-black dark:text-white">
{{ category.name }}
</td>
<td
class="border-r border-neutral-400 dark:border-neutral-600 px-4 py-2 text-right text-black dark:text-white font-mono">
{{ formatCurrency(category.planned) }}
</td>
<td
class="px-4 py-2 text-right text-black dark:text-white font-mono">
{{ category.percentage }}%
</td>
</tr>
<!-- Expense Categories -->
<tr
v-for="(category, index) in expenseCategories"
:key="`exp-${index}`"
class="border-t border-neutral-200"
v-show="category.planned > 0">
<td class="border-r-1 border-black px-4 py-2">
{{ category.name }}
</td>
<td class="border-r border-neutral-400 px-4 py-2 text-right">
{{ formatCurrency(category.planned) }}
</td>
<td class="px-4 py-2 text-right">{{ category.percentage }}%</td>
</tr>
<!-- Total Expenses -->
<tr class="font-semibold bg-neutral-50 dark:bg-neutral-800">
<td
class="border-r-1 border-black dark:border-neutral-400 px-4 py-2 text-black dark:text-white">
Total Expenses
</td>
<td
class="border-r border-neutral-400 dark:border-neutral-600 px-4 py-2 text-right text-black dark:text-white font-mono">
{{ formatCurrency(totalExpensesPlanned) }}
</td>
<td
class="px-4 py-2 text-right text-black dark:text-white font-mono">
100%
</td>
</tr>
<!-- Total Expenses -->
<tr class="border-t-2 border-black font-semibold bg-neutral-50">
<td class="border-r-1 border-black px-4 py-2">Total Expenses</td>
<td class="border-r border-neutral-400 px-4 py-2 text-right">
{{ formatCurrency(totalExpensesPlanned) }}
</td>
<td class="px-4 py-2 text-right">100%</td>
</tr>
<!-- Net Total -->
<tr
class="border-t-2 border-black font-bold text-lg"
:class="netTotalClass">
<td class="border-r-1 border-black px-4 py-3">NET TOTAL</td>
<td class="border-r border-neutral-400 px-4 py-3 text-right">
{{ formatCurrency(netTotal) }}
</td>
<td class="px-4 py-3 text-right">-</td>
</tr>
</tbody>
</table>
<!-- Net Total -->
<tr
class="border-t-2 border-black dark:border-neutral-400 font-bold text-lg"
:class="netTotalClass">
<td
class="border-r-1 border-black dark:border-neutral-400 px-4 py-3 text-black dark:text-white">
NET TOTAL
</td>
<td
class="border-r border-neutral-400 dark:border-neutral-600 px-4 py-3 text-right text-black dark:text-white font-mono">
{{ formatCurrency(netTotal) }}
</td>
<td class="px-4 py-3 text-right text-black dark:text-white">
-
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
@ -242,9 +292,9 @@ const netTotal = computed(
);
const netTotalClass = computed(() => {
if (netTotal.value > 0) return "bg-green-50";
if (netTotal.value < 0) return "bg-red-50";
return "bg-neutral-50";
if (netTotal.value > 0) return "bg-green-50 dark:bg-green-950";
if (netTotal.value < 0) return "bg-red-50 dark:bg-red-950";
return "bg-neutral-50 dark:bg-neutral-800";
});
// Diversification guidance
@ -308,28 +358,6 @@ const diversificationGuidance = computed(() => {
return guidance;
});
const guidanceBackgroundClass = computed(() => {
const topCategory = revenueCategories.value.reduce(
(max, cat) => (cat.percentage > max.percentage ? cat : max),
{ percentage: 0 }
);
if (topCategory.percentage >= 70) {
return "bg-red-50";
} else if (topCategory.percentage >= 50) {
return "bg-red-50";
} else {
const categoriesAbove20 = revenueCategories.value.filter(
(cat) => cat.percentage >= 20
).length;
if (categoriesAbove20 >= 3) {
return "bg-green-50";
} else {
return "bg-yellow-50";
}
}
});
// Suggested categories to develop
const suggestedCategories = computed(() => {
const categoriesWithRevenue = revenueCategories.value.filter(
@ -394,10 +422,11 @@ function formatCurrency(amount: number): string {
}
function getPercentageClass(percentage: number): string {
if (percentage > 50) return "text-red-600 font-bold";
if (percentage > 35) return "text-yellow-600 font-semibold";
if (percentage > 20) return "text-black font-medium";
return "text-neutral-500";
if (percentage > 50) return "text-red-600 dark:text-red-400 font-bold";
if (percentage > 35)
return "text-yellow-600 dark:text-yellow-400 font-semibold";
if (percentage > 20) return "text-black dark:text-white font-medium";
return "text-neutral-500 dark:text-neutral-400";
}
// Initialize