Compare commits
No commits in common. "0af01290540776bd0a23dc68af66b458980aac38" and "fa11926642d913946a4e4979509dd8ae0f562b02" have entirely different histories.
0af0129054
...
fa11926642
|
@ -25,4 +25,4 @@ run: $(GENERATED_FILES) $(OUTPUT_CSS)
|
||||||
# and then do `go run .` to rebuild all else
|
# and then do `go run .` to rebuild all else
|
||||||
.PHONY: run/live
|
.PHONY: run/live
|
||||||
run/live:
|
run/live:
|
||||||
wgo -verbose -file=.go -file=.templ -file=$(INPUT_CSS) -file=$(TAILWIND_CONFIG) make run
|
wgo -verbose -file=.go -file=.templ make run
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
rec {
|
rec {
|
||||||
description = "expenses chart exercise";
|
description = "templ-practice";
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs";
|
nixpkgs.url = "github:nixos/nixpkgs";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
@ -11,55 +11,7 @@ rec {
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
templPkg = templ.packages.${system}.templ;
|
templPkg = templ.packages.${system}.templ;
|
||||||
pname = "expenses-chart";
|
in {
|
||||||
version = "0.0.1";
|
|
||||||
in rec {
|
|
||||||
thePackage = pkgs.buildGoModule {
|
|
||||||
inherit pname version;
|
|
||||||
src = pkgs.nix-gitignore.gitignoreSource [ ] ./.;
|
|
||||||
vendorHash = "sha256-sKuP3TsRD3MXBGtdSRnX62eXBQE1ASWFQu0kLlXSlFA=";
|
|
||||||
|
|
||||||
preBuild = ''
|
|
||||||
# Adding the Tailwind build step to preBuild
|
|
||||||
${pkgs.nodePackages.tailwindcss}/bin/tailwindcss -i ./input.css -o static/output.css
|
|
||||||
# Adding generation of go code from templ files
|
|
||||||
${templPkg}/bin/templ generate
|
|
||||||
'';
|
|
||||||
|
|
||||||
};
|
|
||||||
packages = rec {
|
|
||||||
"${pname}" = thePackage;
|
|
||||||
"${pname}-image" = pkgs.dockerTools.buildLayeredImage {
|
|
||||||
name = pname;
|
|
||||||
tag = "latest";
|
|
||||||
created = "now";
|
|
||||||
config = {
|
|
||||||
Cmd = [ "${thePackage}/bin/templ-exercise" ];
|
|
||||||
ExposedPorts = { "3000/tcp" = { }; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
image-hello = pkgs.dockerTools.buildLayeredImage { # so, wow, this works
|
|
||||||
name = pname;
|
|
||||||
tag = "latest";
|
|
||||||
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
image = pkgs.dockerTools.buildImage {
|
|
||||||
name = pname;
|
|
||||||
tag = "latest";
|
|
||||||
created = "now";
|
|
||||||
copyToRoot = pkgs.buildEnv {
|
|
||||||
name = "image-root";
|
|
||||||
paths = [ thePackage pkgs.dockerTools.binSh pkgs.coreutils ];
|
|
||||||
pathsToLink = [ "/bin" "/dist" "/public" ];
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
Cmd = [ "/bin/templ-exercise" ];
|
|
||||||
ExposedPorts = { "8080/tcp" = { }; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
pkgs.go
|
pkgs.go
|
||||||
|
@ -68,7 +20,7 @@ rec {
|
||||||
pkgs.gopls
|
pkgs.gopls
|
||||||
pkgs.gnumake
|
pkgs.gnumake
|
||||||
templPkg
|
templPkg
|
||||||
pkgs.nodePackages.tailwindcss
|
pkgs.tailwindcss
|
||||||
];
|
];
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
export GOPATH=$PWD/.go
|
export GOPATH=$PWD/.go
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
html {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,29 +1,17 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"sunshine.industries/temp-exercise/templates"
|
"sunshine.industries/temp-exercise/templates"
|
||||||
|
"github.com/a-h/templ"
|
||||||
)
|
)
|
||||||
|
|
||||||
func randomDailyExpense() float32 {
|
|
||||||
return 10 + rand.Float32()*100
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
component := templates.Hello("some name")
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.Handle("/", templ.Handler(component))
|
||||||
component := templates.IndexPage(templates.PageData{
|
|
||||||
Balance: 500 + rand.Float32()*1000,
|
|
||||||
Expenses: []float32{randomDailyExpense(), randomDailyExpense(), randomDailyExpense(), randomDailyExpense(), randomDailyExpense(), randomDailyExpense(), randomDailyExpense()},
|
|
||||||
TotalThisMonth: 50 + rand.Float32()*600,
|
|
||||||
PercentComparedToLastMonth: -5 + 10*rand.Float32(),
|
|
||||||
})
|
|
||||||
component.Render(context.Background(), w)
|
|
||||||
})
|
|
||||||
|
|
||||||
staticFs := http.FileServer(http.Dir("./static"))
|
staticFs := http.FileServer(http.Dir("./static"))
|
||||||
http.Handle("/static/", http.StripPrefix("/static/", staticFs))
|
http.Handle("/static/", http.StripPrefix("/static/", staticFs))
|
||||||
|
|
|
@ -34,74 +34,3 @@ how would i commit to subtree upstream if there are conflicting changes?
|
||||||
maybe i'll just get denied, as simple as that.
|
maybe i'll just get denied, as simple as that.
|
||||||
|
|
||||||
allright! let's add exercise specific data (again)
|
allright! let's add exercise specific data (again)
|
||||||
|
|
||||||
* so, starting dev
|
|
||||||
|
|
||||||
old process:
|
|
||||||
1. open second browser and open png with style
|
|
||||||
first mobile
|
|
||||||
2. enable view C-S-m in firefox
|
|
||||||
the responsive mode
|
|
||||||
|
|
||||||
i suppose next is adding colors to tailwind configuration?
|
|
||||||
from the styleguide file
|
|
||||||
|
|
||||||
also
|
|
||||||
3. check desktop style, whether any big rearrangements are required
|
|
||||||
so that i'd start mobile with way to rearrange things
|
|
||||||
|
|
||||||
do i have a separate note with all of these things?
|
|
||||||
i've also used some commands to vertically center my stuff
|
|
||||||
|
|
||||||
** DONE allright, tailwind config go
|
|
||||||
font, size, colors
|
|
||||||
|
|
||||||
** well, i don't really want to go on.
|
|
||||||
but yeah, i'll need hierarchy of the elements.
|
|
||||||
|
|
||||||
** ok. thoughs:
|
|
||||||
the componets would be
|
|
||||||
- my balance bubble
|
|
||||||
because it is spacially separate
|
|
||||||
- spending summary
|
|
||||||
- graph inside spending summary
|
|
||||||
or maybe don't even need that
|
|
||||||
|
|
||||||
the component should take up all space provided to it.
|
|
||||||
if parent would want to add space around - that's easy to do,
|
|
||||||
but if component insists on adding space around itself - harder to reuse?
|
|
||||||
because then if parent would want to have child take up all space - negative padding?
|
|
||||||
|
|
||||||
*** allright, @ to include sub templates
|
|
||||||
|
|
||||||
** well, last part? preparing the docker container for deployment on Render.com?
|
|
||||||
|
|
||||||
which port should be used?
|
|
||||||
also, this would be first time i'll add templ as a build step
|
|
||||||
|
|
||||||
** for some reason image doesn't work well
|
|
||||||
|
|
||||||
podman run -d -p 9090:8080 localhost/expenses-chart:latest /nix/store/l4r6glmzbvkhg97lp4dn7nm76w6hz41g-expenses-chart-0.0.1/bin/temp-exercise
|
|
||||||
|
|
||||||
this runs,
|
|
||||||
but podman run -it expenses-chart:latest
|
|
||||||
Error: crun: executable file `/nix/store/l4r6glmzbvkhg97lp4dn7nm76w6hz41g-expenses-chart-0.0.1/bin/templ-exercise` not found in $PATH: No such file or directory: OCI runtime attempted to invoke a command that was not found
|
|
||||||
|
|
||||||
oh, well
|
|
||||||
|
|
||||||
** you know what - i give up
|
|
||||||
|
|
||||||
for some reason when i open url to app running in container,
|
|
||||||
and it's on the 8080 port of the host machine - the static files are served
|
|
||||||
|
|
||||||
if i use any other port of local machine, to forward into container,
|
|
||||||
the static files are not served
|
|
||||||
|
|
||||||
maybe this is bug in go? i don't know
|
|
||||||
StripPrefix doesn't seem to do anything
|
|
||||||
|
|
||||||
and for some reason in this specific exercise CMD doesn't work in the container
|
|
||||||
so let's just give up!
|
|
||||||
|
|
||||||
i could try to write a docker file and check with that, but yeah
|
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,8 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./templates/index.templ"],
|
content: ["./**/*.templ"],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {},
|
||||||
fontFamily: {
|
|
||||||
'sans': ['DM Sans', 'sans-serif'],
|
|
||||||
},
|
|
||||||
fontWeight: {
|
|
||||||
'normal': 400,
|
|
||||||
'bold': 700,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colors: {
|
|
||||||
primary: {
|
|
||||||
'soft-red': 'hsl(10, 79%, 65%)',
|
|
||||||
cyan: 'hsl(186, 34%, 60%)',
|
|
||||||
},
|
|
||||||
neutral: {
|
|
||||||
'dark-brown': 'hsl(25, 47%, 15%)',
|
|
||||||
'medium-brown': 'hsl(28, 10%, 53%)',
|
|
||||||
cream: 'hsl(27, 66%, 92%)',
|
|
||||||
'very-pale-orange': 'hsl(33, 100%, 98%)',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package templates
|
||||||
|
|
||||||
|
var myVar string = "some string, changed. and more"
|
||||||
|
var anotherVar string = "hoho, cool"
|
||||||
|
|
||||||
|
templ Hello(name string) {
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>This is the title of the the webpage!</title>
|
||||||
|
<link href="/static/output.css" rel="stylesheet"/>
|
||||||
|
</head>
|
||||||
|
<body class="bg-blue-100 text-xl">
|
||||||
|
<p class="text-purple-700">This is an example paragraph. Anything in the <strong>body</strong> tag will appear on the page, just like this <strong>p</strong> tag and its contents.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<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="./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>
|
||||||
|
|
||||||
|
My balance
|
||||||
|
$921.48
|
||||||
|
|
||||||
|
Spending - Last 7 days
|
||||||
|
|
||||||
|
mon
|
||||||
|
tue
|
||||||
|
wed
|
||||||
|
thu
|
||||||
|
fri
|
||||||
|
sat
|
||||||
|
sun
|
||||||
|
|
||||||
|
Total this month
|
||||||
|
$478.33
|
||||||
|
|
||||||
|
+2.4%
|
||||||
|
from last month
|
||||||
|
|
||||||
|
<div class="attribution">
|
||||||
|
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>
|
|
@ -1,133 +0,0 @@
|
||||||
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>
|
|
||||||
}
|
|
Loading…
Reference in New Issue