134 lines
5.3 KiB
Plaintext
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>
|
|
}
|