feat: add initial application structure with configuration, UI components, and state management
This commit is contained in:
parent
fadf94002c
commit
0af6b17792
56 changed files with 6137 additions and 129 deletions
264
pages/budget.vue
Normal file
264
pages/budget.vue
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
<template>
|
||||
<section class="py-8 space-y-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-2xl font-semibold">Operating Plan</h2>
|
||||
<USelect
|
||||
v-model="selectedMonth"
|
||||
:options="months"
|
||||
placeholder="Select month" />
|
||||
</div>
|
||||
|
||||
<!-- Cash Waterfall Summary -->
|
||||
<UCard>
|
||||
<template #header>
|
||||
<h3 class="text-lg font-medium">
|
||||
Cash Waterfall - {{ selectedMonth }}
|
||||
</h3>
|
||||
</template>
|
||||
<div
|
||||
class="flex items-center justify-between py-4 border-b border-gray-200">
|
||||
<div class="flex items-center gap-8">
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold text-blue-600">€12,000</div>
|
||||
<div class="text-xs text-gray-600">Gross Revenue</div>
|
||||
</div>
|
||||
<UIcon name="i-heroicons-arrow-right" class="text-gray-400" />
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold text-red-600">-€450</div>
|
||||
<div class="text-xs text-gray-600">Fees</div>
|
||||
</div>
|
||||
<UIcon name="i-heroicons-arrow-right" class="text-gray-400" />
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold text-green-600">€11,550</div>
|
||||
<div class="text-xs text-gray-600">Net Revenue</div>
|
||||
</div>
|
||||
<UIcon name="i-heroicons-arrow-right" class="text-gray-400" />
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold text-blue-600">€300</div>
|
||||
<div class="text-xs text-gray-600">To Savings</div>
|
||||
</div>
|
||||
<UIcon name="i-heroicons-arrow-right" class="text-gray-400" />
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold text-purple-600">€6,400</div>
|
||||
<div class="text-xs text-gray-600">Payroll</div>
|
||||
</div>
|
||||
<UIcon name="i-heroicons-arrow-right" class="text-gray-400" />
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold text-orange-600">€2,300</div>
|
||||
<div class="text-xs text-gray-600">Overhead</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-lg font-medium">Available for Operations</span>
|
||||
<span class="text-2xl font-bold text-green-600">€2,550</span>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
|
||||
<!-- Monthly Revenue Table -->
|
||||
<UCard>
|
||||
<template #header>
|
||||
<h3 class="text-lg font-medium">Revenue by Stream</h3>
|
||||
</template>
|
||||
<UTable :rows="revenueStreams" :columns="revenueColumns">
|
||||
<template #name-data="{ row }">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium">{{ row.name }}</span>
|
||||
<RestrictionChip :restriction="row.restrictions" size="xs" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #target-data="{ row }">
|
||||
<span class="font-medium">€{{ row.target.toLocaleString() }}</span>
|
||||
</template>
|
||||
|
||||
<template #committed-data="{ row }">
|
||||
<span class="font-medium text-green-600"
|
||||
>€{{ row.committed.toLocaleString() }}</span
|
||||
>
|
||||
</template>
|
||||
|
||||
<template #actual-data="{ row }">
|
||||
<span
|
||||
class="font-medium"
|
||||
:class="
|
||||
row.actual >= row.committed ? 'text-green-600' : 'text-orange-600'
|
||||
">
|
||||
€{{ row.actual.toLocaleString() }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #variance-data="{ row }">
|
||||
<span :class="row.variance >= 0 ? 'text-green-600' : 'text-red-600'">
|
||||
{{ row.variance >= 0 ? "+" : "" }}€{{
|
||||
row.variance.toLocaleString()
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
</UTable>
|
||||
</UCard>
|
||||
|
||||
<!-- Costs Breakdown -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<UCard>
|
||||
<template #header>
|
||||
<h3 class="text-lg font-medium">Costs</h3>
|
||||
</template>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h4 class="font-medium text-sm mb-2">Payroll</h4>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Wages (320h @ €20)</span>
|
||||
<span class="font-medium">€6,400</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">On-costs (25%)</span>
|
||||
<span class="font-medium">€1,600</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between text-sm font-medium border-t pt-2">
|
||||
<span>Total Payroll</span>
|
||||
<span>€8,000</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 class="font-medium text-sm mb-2">Overhead</h4>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Coworking space</span>
|
||||
<span class="font-medium">€800</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Tools & software</span>
|
||||
<span class="font-medium">€400</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Insurance</span>
|
||||
<span class="font-medium">€200</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between text-sm font-medium border-t pt-2">
|
||||
<span>Total Overhead</span>
|
||||
<span>€1,400</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 class="font-medium text-sm mb-2">Production</h4>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Dev kits</span>
|
||||
<span class="font-medium">€500</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between text-sm font-medium border-t pt-2">
|
||||
<span>Total Production</span>
|
||||
<span>€500</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
|
||||
<UCard>
|
||||
<template #header>
|
||||
<h3 class="text-lg font-medium">Net Impact on Savings</h3>
|
||||
</template>
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-3">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Net Revenue</span>
|
||||
<span class="font-medium text-green-600">€11,550</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Total Costs</span>
|
||||
<span class="font-medium text-red-600">-€9,900</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-lg font-bold border-t pt-3">
|
||||
<span>Net</span>
|
||||
<span class="text-green-600">+€1,650</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-50 rounded-lg p-4">
|
||||
<h4 class="font-medium text-sm mb-3">Allocation</h4>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">To Savings</span>
|
||||
<span class="font-medium">€1,200</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600">Available</span>
|
||||
<span class="font-medium">€450</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-gray-600 space-y-1">
|
||||
<p>
|
||||
<RestrictionChip restriction="Restricted" size="xs" /> funds can
|
||||
only be used for approved purposes.
|
||||
</p>
|
||||
<p>
|
||||
<RestrictionChip restriction="General" size="xs" /> funds have no
|
||||
restrictions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const selectedMonth = ref("2024-01");
|
||||
const months = ref([
|
||||
{ label: "January 2024", value: "2024-01" },
|
||||
{ label: "February 2024", value: "2024-02" },
|
||||
{ label: "March 2024", value: "2024-03" },
|
||||
]);
|
||||
|
||||
const revenueStreams = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: "Client Services",
|
||||
target: 7800,
|
||||
committed: 6500,
|
||||
actual: 7200,
|
||||
variance: 700,
|
||||
restrictions: "General",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Platform Sales",
|
||||
target: 3000,
|
||||
committed: 2000,
|
||||
actual: 2400,
|
||||
variance: 400,
|
||||
restrictions: "General",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Grant Funding",
|
||||
target: 1200,
|
||||
committed: 0,
|
||||
actual: 1400,
|
||||
variance: 1400,
|
||||
restrictions: "Restricted",
|
||||
},
|
||||
]);
|
||||
|
||||
const revenueColumns = [
|
||||
{ id: "name", key: "name", label: "Stream" },
|
||||
{ id: "target", key: "target", label: "Target" },
|
||||
{ id: "committed", key: "committed", label: "Committed" },
|
||||
{ id: "actual", key: "actual", label: "Actual" },
|
||||
{ id: "variance", key: "variance", label: "Variance" },
|
||||
];
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue