Misc. pizzazz

This commit is contained in:
Daniel Flanagan 2024-08-24 08:53:29 -05:00
parent e0a73c5032
commit cc539727ca
2 changed files with 64 additions and 14 deletions

View file

@ -1,7 +1,7 @@
import { useSignal } from 'https://esm.sh/v135/@preact/signals@1.2.2/X-ZS8q/dist/signals.js' import { useSignal } from 'https://esm.sh/v135/@preact/signals@1.2.2/X-ZS8q/dist/signals.js'
import { JSX } from 'preact' import { JSX } from 'preact'
import { Budget } from '../models.ts' import { Budget, currency, percentage } from '../models.ts'
interface IconButtonProps { interface IconButtonProps {
active?: boolean active?: boolean
@ -15,30 +15,47 @@ function IconButton(
) { ) {
return ( return (
<button <button
class={'py-2 px-4 flex flex-col sm:flex-row flex-1 sm:flex-none bg-bg justify-center items-center sm:justify-start text-center sm:text-left rounded' + class={'p-2 sm:px-4 flex flex-col sm:flex-row flex-1 sm:flex-none bg-mantle justify-center items-center sm:justify-start text-center sm:text-left rounded' +
(active ? ' text-primary' : '')} (active ? ' text-primary' : '')}
{...props} {...props}
> >
<span class='sm:mr-2'>{icon}</span> <div class='sm:mr-2'>{icon}</div>
<span class=''>{children}</span> <div class=''>{children}</div>
</button> </button>
) )
} }
function BudgetCard( function BudgetCard(
{ children, ...props }: { budget, ...props }:
& { budget: Budget } & { budget: Budget }
& JSX.HTMLAttributes<HTMLDivElement>, & JSX.HTMLAttributes<HTMLDivElement>,
) { ) {
return ( return (
<button <div
class={'py-2 px-4 flex flex-col sm:flex-row flex-1 sm:flex-none bg-bg justify-center items-center sm:justify-start text-center sm:text-left rounded' + class='bg-surface0 rounded shadow hover:bg-surface1 transition-colors flex justify-between'
(active ? ' text-primary' : '')}
{...props} {...props}
> >
<span class='sm:mr-2'>{icon}</span> <div class='p-2'>
<span class=''>{children}</span> {budget.name}: {currency(budget.spent)} / {currency(budget.target)}{' '}
({percentage(budget.spent / budget.target)})
</div>
<button class='text-surface1 cursor-grab p-2'>
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
strokeWidth={1.5}
stroke='currentColor'
className='size-6'
>
<path
strokeLinecap='round'
strokeLinejoin='round'
d='M3.75 9h16.5m-16.5 6.75h16.5'
/>
</svg>
</button> </button>
</div>
) )
} }
@ -50,6 +67,21 @@ export default function Dashboard() {
target: 1000, target: 1000,
spent: 367.97, spent: 367.97,
}, },
{
name: 'Fast Food',
target: 300,
spent: 420.69,
},
{
name: 'Insurance',
target: 220.44,
spent: 0,
},
{
name: 'Mortgage',
target: 1310.47,
spent: 1310.47,
},
] ]
const navItems = [ const navItems = [
{ {
@ -113,11 +145,11 @@ export default function Dashboard() {
return ( return (
<div class='grid grid-rows-[1fr_auto] sm:grid-cols-2 sm:grid-rows-1 sm:grid-cols-[1fr_auto] h-[100vh]'> <div class='grid grid-rows-[1fr_auto] sm:grid-cols-2 sm:grid-rows-1 sm:grid-cols-[1fr_auto] h-[100vh]'>
<main class='p-2'> <main class='p-2 sm:pr-0 flex flex-col gap-2'>
This is the main content {budgets.map((budget, _i) => <BudgetCard budget={budget} />)}
</main> </main>
<nav class='w-full flex flex-1 sm:flex-col bg-mantle gap-1 p-1'> <nav class='w-full flex flex-1 sm:flex-col sm:bg-bg gap-2 p-2'>
{navItems.map(({ text, ...props }, i) => ( {navItems.map(({ text, ...props }, i) => (
<IconButton <IconButton
{...props} {...props}

View file

@ -16,3 +16,21 @@ export interface Transaction {
budget: string budget: string
amount: number amount: number
} }
const currencyFormat = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 2,
minimumFractionDigits: 2,
})
export function currency(amount: number): string {
return currencyFormat.format(amount)
}
const percentageFormat = new Intl.NumberFormat('en-US', {
currency: 'USD',
maximumFractionDigits: 2,
})
export function percentage(ratio: number): string {
return percentageFormat.format(ratio * 100) + '%'
}