Learning-HTMX/18-expenses-chart/templates/index.templ

134 lines
5.3 KiB
Plaintext

package templates
import "fmt"
import "slices"
type PageData struct {
Balance float32
Expenses []float32
TotalThisMonth float32
PercentComparedToLastMonth float32
}
templ myBalanceComponent(balance float32) {
<div class="flex flex-row rounded-xl text-neutral-very-pale-orange text-xs md:text-base bg-primary-soft-red p-4 shadow md:rounded-[1rem] md:p-7">
<div class="grow ">
My balance
<p class="text-xl md:text-2xl font-bold">${ fmt.Sprintf("%.2f", balance) }</p>
</div>
<img
src="./static/images/logo.svg"
alt="App logo: a white circle overlapping from the left a filled in black circle"
/>
</div>
}
var days []string = []string{"mon", "tue", "wed", "thu", "fri", "sat", "sun"}
// returns templ SummaryComponent
// with all attributes computed from the expenses slice
// the percentages of the columns, current day number, etc
// NOTE: this seems to be the way to mix go calculations and templates
func prepareSummaryComponent(expenses []float32, totalThisMonth, percentComparedToLastMonth float32) templ.Component {
fmt.Println("hello, preparing expenses: ", expenses)
max := slices.Max(expenses)
percentages := make([]float32, 0, len(expenses))
for _, price := range expenses {
percentages = append(percentages, price/max)
}
currentDayNum := 2
return spendingSummaryComponent(expenses, percentages, currentDayNum, percentComparedToLastMonth, totalThisMonth)
}
css expenseBarVars(percentage float32) {
--height-percentage: { fmt.Sprintf("%.2f", percentage) };
height: calc(var(--height-percentage) * 8rem);
}
templ dayExpenseColumn(expense, percentage float32, day string, isCurrentDay bool) {
<div class="flex flex-col justify-end items-center h-32">
<div
class={ "rounded group relative w-full h-12",
expenseBarVars(percentage),
templ.KV("bg-primary-soft-red hover:bg-primary-soft-red/70", !isCurrentDay),
templ.KV("bg-primary-cyan hover:bg-primary-cyan/70", isCurrentDay),
"hover:cursor-pointer" }
>
<span class="absolute left-1/2 -translate-x-1/2 -translate-y-7 opacity-0 group-hover:opacity-100 bg-neutral-dark-brown text-neutral-cream rounded text-xs p-1">${ fmt.Sprintf("%.2f", expense ) }</span>
</div>
<p class="text-neutral-medium-brown text-xs py-2">{ day }</p>
</div>
}
// The 7 vertical bars of the per-day expenses
templ expensesChart(expenses, percentages []float32, currentDayNum int) {
<div class="grid grid-cols-7 place-content-between gap-x-3">
for i := 0; i < 7; i++ {
@dayExpenseColumn(expenses[i], percentages[i], days[i], currentDayNum == i)
}
</div>
}
// Big container with chard and total expenses of the week
templ spendingSummaryComponent(expenses, percentages []float32, currentDayNum int, totalThisMonth, percentComparedToLastMonth float32) {
<div class="bg-neutral-very-pale-orange rounded-xl shadow p-4 py-6 flex flex-col gap-y-4 md:p-7 md:px-10 md:rounded-[1rem] md:gap-y-5">
<p2 class="text-neutral-dark-brown text-xl font-bold pb-6 md:text-2xl md:pb-12 ">Spending - Last 7 days</p2>
@expensesChart(expenses, percentages, currentDayNum)
<hr class="bg-neutral-cream border-t-0 h-0.5"/>
<div class="grid grid-cols-2 text-sm text-neutral-medium-brown">
<p class="col-span-full">Total this month</p>
<div class="grow">
<p class="grid items-center text-neutral-dark-brown text-2xl font-bold h-full md:text-4xl md:py-2">$ { fmt.Sprintf("%.2f", totalThisMonth) }</p>
</div>
<div class="text-right grid content-center">
<div class="text-neutral-dark-brown font-bold ">
if (percentComparedToLastMonth > 0) {
<span class="inline">+</span>
}
{ fmt.Sprintf("%.2f", percentComparedToLastMonth) }%
</div>
from last month
</div>
</div>
</div>
}
templ WidgetsComponend(pageData PageData) {
<div class="flex flex-col gap-4">
@myBalanceComponent(pageData.Balance)
@prepareSummaryComponent(pageData.Expenses, pageData.PercentComparedToLastMonth, pageData.TotalThisMonth)
</div>
}
templ IndexPage(pageData PageData) {
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="/styles/templ.css"/>
<link href="/static/output.css" rel="stylesheet"/>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <!-- displays site properly based on user's device -->
<link rel="icon" type="image/png" sizes="32x32" href="./static/images/favicon-32x32.png"/>
<title>Frontend Mentor | Expenses chart component</title>
<!-- Feel free to remove these styles or customise in your own stylesheet 👍 -->
<style>
.attribution { font-size: 11px; text-align: center; }
.attribution a { color: hsl(228, 45%, 44%); }
</style>
</head>
<body class="bg-neutral-cream text-bold p-4 h-full grid place-items-center">
<main class="w-full md:w-1/4">
@WidgetsComponend(pageData)
</main>
<div class="attribution fixed bottom-0 inset-x-0">
Challenge by <a href="https://www.frontendmentor.io?ref=challenge" target="_blank">Frontend Mentor</a>.
Coded by <a href="#">Your Name Here</a>.
</div>
</body>
</html>
}