bank/islands/BudgetCard.tsx

147 lines
3.6 KiB
TypeScript
Raw Normal View History

2024-08-24 11:31:45 -05:00
import { JSX } from 'preact/jsx-runtime'
import { Budget } from '../models.ts'
import { Currency } from '../components/Currency.tsx'
import { Percentage } from '../components/Percentage.tsx'
2024-08-24 22:35:03 -05:00
import { Component } from 'https://esm.sh/stable/preact@10.19.6/denonext/preact.mjs'
2024-08-25 09:04:22 -05:00
import { truncate } from '../mod.ts'
2024-08-24 11:31:45 -05:00
2024-08-24 22:35:03 -05:00
function BudgetCardLit(
2024-08-24 11:31:45 -05:00
{ budget, ...props }:
& { budget: Budget }
& JSX.HTMLAttributes<HTMLDivElement>,
) {
const remainingRatio = 1.0 - (budget.spent / budget.target)
const bgColor = remainingRatio < 0 ? 'bg-red' : 'bg-green'
const textColor = remainingRatio < 0 ? 'text-red' : 'text-green'
return (
<div
class='bg-surface0 rounded shadow hover:bg-surface1 transition-colors flex justify-between relative z-0 cursor-pointer'
{...props}
>
<div
class={`rounded absolute top-0 bottom-0 left-0 ${bgColor} z-[-1] opacity-10`}
style={`right: ${
(remainingRatio < 0 ? 0 : (Math.abs(1.0 - remainingRatio))) * 100
}%;`}
/>
<h2
class={`py-2 px-3 text-2xl flex flex-none max-w-xs items-center ${textColor} truncate`}
>
{budget.name}
</h2>
<div class={`p-2 pl-0 flex-1 leading-none`}>
<span class={textColor}>
</span>
<br />
<small>
<Currency amount={budget.spent} /> of{' '}
<Currency amount={budget.target} />
{' spent '}
(<Percentage ratio={remainingRatio} /> remaining)
</small>
</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>
*/
}
</div>
)
}
2024-08-24 22:35:03 -05:00
export function BudgetCard(
{ budget, ...props }:
& { budget: Budget }
& JSX.HTMLAttributes<HTMLDivElement>,
) {
2024-08-25 09:04:22 -05:00
const spentRatio = budget.spent / budget.target
const remainingRatio = 1.0 - spentRatio
const bgClass = (spentRatio > 1.0 ? 'bg-red' : 'bg-green') + ' opacity-10'
2024-08-24 22:35:03 -05:00
const accentTextClass = remainingRatio < 0 ? 'text-red' : 'text-green'
return (
<ProgressBarCard
2024-08-25 09:04:22 -05:00
heading={truncate(budget.name, 20)}
2024-08-24 22:35:03 -05:00
bgClass={bgClass}
accentTextClass={accentTextClass}
2024-08-25 09:04:22 -05:00
fillRatio={remainingRatio < 0 ? 1 : remainingRatio}
2024-08-24 22:35:03 -05:00
subheading={
<>
<Currency amount={Math.abs(budget.target - budget.spent)} />
2024-08-25 09:04:22 -05:00
{spentRatio >= 0 ? ` left ` : ` over `}
2024-08-24 22:35:03 -05:00
</>
}
{...props}
>
<small>
<Currency amount={budget.spent} /> of{' '}
<Currency amount={budget.target} />
{' spent '}
2024-08-25 09:04:22 -05:00
(<Percentage ratio={1.0 - spentRatio} /> remaining)
2024-08-24 22:35:03 -05:00
</small>
</ProgressBarCard>
)
}
interface ProgressBarCardProps {
heading: string
subheading: JSX.Element
bgClass: string
accentTextClass: string
2024-08-25 09:04:22 -05:00
fillRatio: number
2024-08-24 22:35:03 -05:00
}
export function ProgressBarCard(
2024-08-25 09:04:22 -05:00
{
heading,
subheading,
bgClass,
accentTextClass,
fillRatio,
children,
...props
}:
2024-08-24 22:35:03 -05:00
& ProgressBarCardProps
& JSX.HTMLAttributes<HTMLDivElement>,
) {
2024-08-25 09:04:22 -05:00
console.log({ fillRatio })
2024-08-24 22:35:03 -05:00
return (
<div
class='bg-surface0 rounded shadow hover:bg-surface1 transition-colors flex justify-between relative z-0 cursor-pointer'
{...props}
>
<div
class={`rounded absolute top-0 bottom-0 left-0 ${bgClass} z-[-1]`}
2024-08-25 09:04:22 -05:00
style={`right: ${Math.abs(fillRatio - 1.0) * 100}%;`}
2024-08-24 22:35:03 -05:00
/>
<h2
class={`py-2 px-3 text-2xl flex flex-none max-w-xs items-center ${accentTextClass} truncate`}
>
{heading}
</h2>
<div class={`p-2 pl-0 flex-1 leading-none`}>
<span class={accentTextClass}>
{subheading}
</span>
<br />
{children}
</div>
</div>
)
}