summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--contrib/Makefile5
-rw-r--r--contrib/invoice-01.md28
-rw-r--r--contrib/metadata.yml13
-rw-r--r--contrib/template.html204
-rw-r--r--go.mod12
-rw-r--r--go.sum15
-rw-r--r--main.go31
8 files changed, 310 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9c6bdfa
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+contrib/invoice*.html
+contrib/invoice*.pdf
diff --git a/contrib/Makefile b/contrib/Makefile
new file mode 100644
index 0000000..e04d380
--- /dev/null
+++ b/contrib/Makefile
@@ -0,0 +1,5 @@
+invoice-01.pdf: invoice-01.md
+ pandoc -s -t html --template template.html --metadata-file metadata.yml $^ | tee invoice-01.html | weasyprint - $@
+
+clean:
+ - rm invoice-01.pdf invoice-01.html
diff --git a/contrib/invoice-01.md b/contrib/invoice-01.md
new file mode 100644
index 0000000..74705ae
--- /dev/null
+++ b/contrib/invoice-01.md
@@ -0,0 +1,28 @@
+---
+number: "0001"
+date: 2024-07-08
+due_date: 2024-08-01
+
+notes: ":3"
+
+currency: EUR
+
+client:
+ name: Example
+ address: Ex Ample, Elpam Xe
+ email: hello@example.org
+
+services:
+ - name: Programming
+ comment: Lorem ipsum
+ rate: 1
+ qty: 1
+ sum: 1
+
+ - name: System administration
+ rate: 2.5
+ qty: 10
+ sum: 25
+
+total: 26
+---
diff --git a/contrib/metadata.yml b/contrib/metadata.yml
new file mode 100644
index 0000000..61a633c
--- /dev/null
+++ b/contrib/metadata.yml
@@ -0,0 +1,13 @@
+---
+
+author:
+ name: John Smith
+ address: 123 Sesame St, Cloud, Earth
+ email: john@smi.th
+ website: https://smi.th
+ phone: "+101010101"
+
+bank:
+ name: ABC
+ iban: 2323232323
+ swift: LLLLLLXXX
diff --git a/contrib/template.html b/contrib/template.html
new file mode 100644
index 0000000..458af62
--- /dev/null
+++ b/contrib/template.html
@@ -0,0 +1,204 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8"/>
+ <style>
+ * {
+ margin: 0;
+ padding: 0;
+ font-family: monospace, monospace;
+ font-size: 14px;
+ color: #111;
+ }
+
+ @page {
+ size: A4 portrait;
+ margin: 16mm;
+ }
+
+ h1, h2, h3 {
+ margin: 0;
+ color: #444;
+ }
+
+ h2 {
+ font-size: 1.2em;
+ }
+
+ ul li {
+ list-style: none;
+ }
+
+ a, a:visited {
+ color: #000;
+ }
+
+ article {
+ margin-top: 2em;
+ margin-bottom: 2em;
+ }
+
+ header article {
+ margin: 0;
+ }
+
+ header {
+ display: flex;
+ }
+
+ footer {
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ }
+
+ table * {
+ vertical-align: top;
+ }
+
+ p.comment {
+ color: #444;
+ margin-left: .5em;
+ }
+
+ #services table {
+ border-collapse: collapse;
+ margin: 2em 0 2em 0;
+ }
+
+ #services table tr th:last-child,
+ #services table tr td:last-child {
+ text-align: right;
+ }
+
+ #services table thead tr th:first-child {
+ width: 60%;
+ }
+
+ #services table tfoot, table thead {
+ border-bottom: solid 1px black;
+ }
+
+ #services table tfoot {
+ border-top: solid 1px black;
+ }
+
+ #services table tfoot td {
+ font-weight: 700;
+ }
+
+ #services table {
+ width: 100%;
+ }
+
+ #author {
+ width: 60%;
+ }
+
+ #header-title h2 {
+ width: 60%;
+ }
+
+ #bank table {
+ width: 50%;
+ }
+
+ #metadata {
+ width: 40%;
+ }
+
+ #metadata table {
+ width: 100%;
+ }
+
+ </style>
+</head>
+
+<body>
+
+ <header>
+ <article id="author">
+ <h2>Invoice from</h2>
+ <ul>
+ <li>${ author.name }</li>
+ <li>${ author.address }</li>
+ <li><a href="${ author.website }">${ author.website }</a></li>
+ <li><a href="mailto:${ author.email }">${ author.email }</a></li>
+ <li><a href="tel:${ author.phone }">${ author.phone }</a></li>
+ </ul>
+ </article>
+
+ <article id="metadata">
+ <table>
+ <tr><td><h2>Invoice</h2></td><td> #${ number }</td></tr>
+ <tr><td>issued at:</td><td> ${ date }</td></tr>
+ <tr><td>due at:</td><td> ${ due_date }</td></tr>
+ </table>
+ </article>
+ </header>
+
+ <section>
+ <article id="client">
+ <h2>Invoice for</h2>
+ <ul>
+ <li>${ client.name }</li>
+ <li>${ client.address }</li>
+ <li>${ client.email }</li>
+ </ul>
+ </article>
+ ${ if(notes) }
+ <article id="notes">
+ <p>${ notes }</p>
+ </article>
+ ${ endif }
+ </section>
+
+ <section>
+ <article id="services">
+ <table>
+ <thead>
+ <tr>
+ <th>Description</th>
+ <th>Rate</th>
+ <th>Quantity</th>
+ <th>Amount</th>
+ </tr>
+ </thead>
+ <tbody>
+ ${ for(services) }
+ <tr>
+ <td>
+ ${ it.name }
+ ${ if(it.comment) }
+ <p class="comment">${ it.comment }</p>
+ ${ endif }
+ </td>
+ <td>${ it.rate }</td>
+ <td>${ it.qty }</td>
+ <td>${ it.sum }</td>
+ </tr>
+ ${ endfor }
+ </tbody>
+ <tfoot>
+ <tr>
+ <td colspan="3">Total in ${ currency }</td>
+ <td>${ total }</td>
+ </tr>
+ </tfoot>
+ </table>
+ </article>
+ </section>
+
+ <footer>
+ <hr>
+ <article id="bank">
+ <h2>Bank details</h2>
+ <table>
+ <tr><td>name:</td><td> ${ bank.name }</td></tr>
+ <tr><td>SWIFT:</td><td> ${ bank.swift }</td></tr>
+ <tr><td>IBAN:</td><td> ${ bank.iban }</td></tr>
+ </table>
+ </article>
+ </footer>
+</body>
+</html>
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..56e6ada
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,12 @@
+module main.go
+
+go 1.22.5
+
+require (
+ github.com/fatih/color v1.17.0 // indirect
+ github.com/goccy/go-yaml v1.11.3 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ golang.org/x/sys v0.22.0 // indirect
+ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..d0915ad
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,15 @@
+github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
+github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
+github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
+github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..ce58679
--- /dev/null
+++ b/main.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "os"
+ "fmt"
+ "html/template"
+ "github.com/goccy/go-yaml"
+)
+
+func check(e error) {
+ if e != nil {
+ fmt.Println(e)
+ panic(e)
+ }
+}
+
+func main() {
+ template_file, err := os.ReadFile(os.Args[1])
+ check(err)
+
+ data_file, err := os.ReadFile(os.Args[2])
+ check(err)
+
+ template_obj, err := template.New("template").Parse(string(template_file))
+ check(err)
+
+ data_raw, err := yaml.Marshal(string(data_file))
+ check(err)
+
+ template_obj.Execute(os.Stdout, data_raw)
+}
remember that computers suck.