]> git.openfl.eu Git - yampl.git/commitdiff
initial commit
authorFl_GUI <flor.guilini@hotmail.com>
Sun, 26 Jan 2025 09:48:25 +0000 (10:48 +0100)
committerFl_GUI <flor.guilini@hotmail.com>
Sun, 26 Jan 2025 09:48:25 +0000 (10:48 +0100)
15 files changed:
examples/templates/name/main.html [new file with mode: 0644]
examples/templates/name/name.html [new file with mode: 0644]
examples/templates/yampl/details.html [new file with mode: 0644]
examples/templates/yampl/listitem.html [new file with mode: 0644]
examples/templates/yampl/main.html [new file with mode: 0644]
examples/toml/empty.toml [new file with mode: 0644]
examples/toml/yampl.toml [new file with mode: 0644]
file.go [new file with mode: 0644]
go.mod [new file with mode: 0644]
go.sum [new file with mode: 0644]
main.go [new file with mode: 0644]
out.html [new file with mode: 0644]
static/index.html [new file with mode: 0644]
static/style.css [new file with mode: 0644]
template.go [new file with mode: 0644]

diff --git a/examples/templates/name/main.html b/examples/templates/name/main.html
new file mode 100644 (file)
index 0000000..e06a6ca
--- /dev/null
@@ -0,0 +1,12 @@
+{{ define "main" }}
+<!DOCTYPE html>
+<html>
+  <head>
+  </head>
+  <body>
+    {{ range .Items }}
+    {{ template "item" . }}
+    {{ end }}
+  </body>
+</html>
+{{ end }}
diff --git a/examples/templates/name/name.html b/examples/templates/name/name.html
new file mode 100644 (file)
index 0000000..f7d4176
--- /dev/null
@@ -0,0 +1,9 @@
+{{ define "item" }} 
+<div>
+  {{ $color := "black" }}
+  {{ if .completed }}
+  {{ $color = "gray" }}
+  {{ end }}
+  <span style="color: {{ $color }}"> {{ .name }} </span>
+</div>
+{{ end }}
diff --git a/examples/templates/yampl/details.html b/examples/templates/yampl/details.html
new file mode 100644 (file)
index 0000000..9d882bd
--- /dev/null
@@ -0,0 +1,39 @@
+{{ define "item" }}
+<!DOCTYPE html>
+<html>
+  <head>
+    <link rel="stylesheet" href="/static/style.css">
+  </head>
+  <body>
+    <a href="/" class="link"> <span> > back </span> </a>
+    <div class="column">
+      {{/* Choose an emoji */}}
+      {{ $symbol := "" }}
+      {{ $gray := false }}
+      {{ if eq .type "task" }}
+        {{ if .completed }}
+          {{ $symbol = "✅" }}
+        {{ else }}
+          {{ $symbol = "❎" }}
+        {{ end}}
+      {{ else if eq .type "bug" }}
+        {{ $symbol = "🐞" }}
+        {{ $gray = .completed }}
+      {{ else if eq .type "milestone" }}
+        {{ $symbol = "🏆" }}
+        {{ $gray = not .completed }}
+      {{ end }}
+
+      {{/* Emoji tooltip */}}
+      {{ $completed := "" }}
+      {{ if .completed }}
+        {{ $completed = "completed" }}
+      {{ end }}
+      {{ $tooltip := printf "%s %s" $completed .type }}
+      
+      <h1> <span title="{{ $tooltip }}" {{ if $gray }} class="grayscale" {{ end }}> {{ $symbol }} <span/> {{ .name }} </h1>
+      <p> {{ .description }} </p>
+    </div>
+  </body>
+</html>
+{{ end }}
diff --git a/examples/templates/yampl/listitem.html b/examples/templates/yampl/listitem.html
new file mode 100644 (file)
index 0000000..ea6d85a
--- /dev/null
@@ -0,0 +1,9 @@
+{{ define "listitem" }} 
+<div>
+  {{ $color := "black" }}
+  {{ if .completed }}
+  {{ $color = "gray" }}
+  {{ end }}
+  <a href="{{ ._url }}" class="link"> <span class="bg{{.type}}" style="color: {{ $color }}"> {{ .name }} </span> </a>
+</div>
+{{ end }}
diff --git a/examples/templates/yampl/main.html b/examples/templates/yampl/main.html
new file mode 100644 (file)
index 0000000..d9559c5
--- /dev/null
@@ -0,0 +1,23 @@
+{{ define "main" }}
+<!DOCTYPE html>
+<html>
+  <head>
+    <link rel="stylesheet" href="/static/style.css">
+  </head>
+  <body>
+    <div class="column"> 
+      {{ with .Project }}
+      <h1> {{ .projectname }} </h1>
+      <p> {{ .projectdescription }} </p>
+      {{ end }}
+      <h2 class="centered"> backlog </h2>
+      <hr/>
+      <div class="items">
+      {{ range .Items }}
+      {{ template "listitem" . }}
+      {{ end }}
+      </div>
+    </div>
+  </body>
+</html>
+{{ end }}
diff --git a/examples/toml/empty.toml b/examples/toml/empty.toml
new file mode 100644 (file)
index 0000000..dd88931
--- /dev/null
@@ -0,0 +1,3 @@
+projectName = "void"
+
+items = []
diff --git a/examples/toml/yampl.toml b/examples/toml/yampl.toml
new file mode 100644 (file)
index 0000000..25cce17
--- /dev/null
@@ -0,0 +1,92 @@
+[project]
+projectname = "yampl"
+projectdescription = '''
+A toml-to-html site generator for project management.
+'''
+
+[[items]]
+name = "hello world"
+description = '''
+Have an program.
+'''
+type = "milestone"
+completed = true
+
+[[items]]
+name = "command line utility"
+description = '''
+Run the program once as command line utility.
+It acts as a conversion script.
+It turns the project file and template into a html file.
+'''
+type = "task"
+completed = true
+
+[[items]]
+name = "http server"
+description = '''
+Run the program as a http service.
+On request it reads the project file and runs the detemplating.
+'''
+type = "task"
+completed = true
+
+[[items]]
+name = "project repo"
+description = '''
+set up a git page for yampl.
+'''
+type = "task"
+completed = false
+
+[[items]]
+name = "static links to details"
+description = '''
+Links are based on index of the item, but this index can change.
+Figure out static routing, perhaps based on name.
+'''
+type = "bug"
+completed = false
+
+[[items]]
+name = "hosted"
+description = '''
+Host yampl for yampl on project.openfl.eu/yamlp
+'''
+type = "milestone"
+completed = false
+
+[[items]]
+name = "git hook"
+description = '''
+On push to main branch of yampl, the toml file must be checked out into the working directory.
+The yampl service should pick up that new file.
+'''
+type = "task"
+completed = false
+
+[[items]]
+name = "watch project file"
+description = '''
+Run the program as a http service, with websocket connection to the frontend.
+On project file change, reload the file, and update clients with new content.
+'''
+type = "task"
+completed = false
+
+[[items]]
+name = "auto hosted"
+description = '''
+Have the hosting be completely automatic, with automatic updates of the project file
+and the container. 
+'''
+type = "milestone"
+completed = false
+
+[[items]]
+name = "heat death of the universe"
+description = '''
+survive.
+'''
+type = "milestone"
+completed = false
diff --git a/file.go b/file.go
new file mode 100644 (file)
index 0000000..d99b529
--- /dev/null
+++ b/file.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+       "errors"
+       "fmt"
+       "io"
+       "io/fs"
+       "os"
+       "path"
+)
+
+var InvalidFilepathError = errors.New("invalid file.")
+
+func getFile(filepath string) (io.ReadCloser, error) {
+       dirname, filename := path.Split(filepath)
+       if dirname == "" {
+               return nil, fmt.Errorf("%w: the file '%s' could not be read", InvalidFilepathError, filepath)
+       }
+       dirFS := os.DirFS(dirname)
+       fileInfo, err := fs.Stat(dirFS, filename)
+       if err != nil {
+               return nil, fmt.Errorf("%w: could not check the file %s", InvalidFilepathError, filepath)
+       }
+       if !fileInfo.Mode().IsRegular() {
+               return nil, fmt.Errorf("%w: the file '%s' is not a text file", InvalidFilepathError, filepath)
+       }
+
+       return os.Open(filepath)
+}
diff --git a/go.mod b/go.mod
new file mode 100644 (file)
index 0000000..6c4c8db
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module go.openfl.eu/yampl
+
+go 1.23.5
+
+require github.com/BurntSushi/toml v1.4.0 // indirect
diff --git a/go.sum b/go.sum
new file mode 100644 (file)
index 0000000..8bc10f6
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
+github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
diff --git a/main.go b/main.go
new file mode 100644 (file)
index 0000000..311d998
--- /dev/null
+++ b/main.go
@@ -0,0 +1,106 @@
+package main
+
+import (
+       "flag"
+       "fmt"
+       "log"
+       "net/http"
+       "os"
+       "strconv"
+
+       "github.com/BurntSushi/toml"
+)
+
+type ProjectData struct {
+       Project Project
+       Items   []ProjectItems
+}
+
+type Project any
+type ProjectItems map[string]any
+
+var tomlfilepath = flag.String("toml", "", "path from current working directory to project file")
+var tempdirpath = flag.String("templ", "", "path from current working directory to a directory containing template files")
+var staticdirpath = flag.String("static", "", "path from current working direcotry to a directory containing static files to serve over http")
+
+func listRespond(w http.ResponseWriter, r *http.Request) {
+       templ, err := getTemplate(*tempdirpath)
+       if err != nil {
+               w.WriteHeader(http.StatusInternalServerError)
+               log.Println(err)
+               return
+       }
+
+       tomlfile, err := getFile(*tomlfilepath)
+       if err != nil {
+               w.WriteHeader(http.StatusInternalServerError)
+               log.Println(err)
+               return
+       }
+
+       var data ProjectData
+       _, err = toml.NewDecoder(tomlfile).Decode(&data)
+       if err != nil {
+               w.WriteHeader(http.StatusInternalServerError)
+               log.Println(err)
+               return
+       }
+       
+       for i, it := range data.Items {
+               it["_index"] = i
+               it["_url"] = fmt.Sprintf("/items/%d", i)
+       }
+
+       templ.ExecuteTemplate(w, "main", data)
+}
+
+func itemRespond(w http.ResponseWriter, r *http.Request) {
+       templ, err := getTemplate(*tempdirpath)
+       if err != nil {
+               w.WriteHeader(http.StatusInternalServerError)
+               log.Println(err)
+               return
+       }
+
+       tomlfile, err := getFile(*tomlfilepath)
+       if err != nil {
+               w.WriteHeader(http.StatusInternalServerError)
+               log.Println(err)
+               return
+       }
+
+       var data ProjectData
+       _, err = toml.NewDecoder(tomlfile).Decode(&data)
+       if err != nil {
+               w.WriteHeader(http.StatusInternalServerError)
+               log.Println(err)
+               return
+       }
+
+       index, err := strconv.Atoi(r.PathValue("index"))
+       if err != nil || index < 0 || len(data.Items) < index {
+               w.WriteHeader(http.StatusInternalServerError)
+               log.Println(err)
+               return
+       }
+
+       templ.ExecuteTemplate(w, "item", data.Items[index])
+}
+
+func main() {
+       flag.Parse()
+       if *tomlfilepath == "" || *tempdirpath == "" {
+               flag.Usage()
+               os.Exit(-1)
+       }
+
+       http.HandleFunc("GET /{$}", listRespond)
+       http.HandleFunc("GET /items/{index}", itemRespond)
+       if *staticdirpath != "" {
+               log.Println("serving static content")
+               http.Handle("GET /static/", http.StripPrefix("/static", http.FileServerFS(os.DirFS(*staticdirpath))))
+       }
+
+       fmt.Println("listening on localhost:8081")
+       panic(http.ListenAndServe(":8081", nil))
+}
diff --git a/out.html b/out.html
new file mode 100644 (file)
index 0000000..1e134bf
--- /dev/null
+++ b/out.html
@@ -0,0 +1,43 @@
+
+<!DOCTYPE html>
+<html>
+  <head>
+  </head>
+  <body>
+    
+     
+<div>
+  
+  
+  
+  
+  <span style="color: gray"> command line utility </span>
+</div>
+
+    
+     
+<div>
+  
+  
+  <span style="color: black"> http server </span>
+</div>
+
+    
+     
+<div>
+  
+  
+  <span style="color: black"> watch project file </span>
+</div>
+
+    
+     
+<div>
+  
+  
+  <span style="color: black"> heat death of the universe </span>
+</div>
+
+    
+  </body>
+</html>
diff --git a/static/index.html b/static/index.html
new file mode 100644 (file)
index 0000000..45b983b
--- /dev/null
@@ -0,0 +1 @@
+hi
diff --git a/static/style.css b/static/style.css
new file mode 100644 (file)
index 0000000..936cbf1
--- /dev/null
@@ -0,0 +1,41 @@
+body {
+  background-color: white;
+  display: flex;
+  justify-content: center;
+  font-family: monospace;
+  background-color: blanchedalmond;
+}
+.column {
+  max-width: 50%;
+}
+
+.items {
+}
+
+.link {
+  color: black;
+  text-decoration: none;;
+}
+
+.link :hover {
+  text-decoration: underline;
+}
+
+h2.centered  {
+  text-align: center;
+}
+
+.bgtask {
+  background-color: lightblue;
+}
+.bgbug {
+  background-color: crimson;
+}
+
+.bgmilestone {
+  background-color: goldenrod;
+}
+
+.grayscale {
+  filter: grayscale(100%);
+}
\ No newline at end of file
diff --git a/template.go b/template.go
new file mode 100644 (file)
index 0000000..9c416c8
--- /dev/null
@@ -0,0 +1,11 @@
+package main
+
+import (
+       "html/template"
+       "os"
+)
+
+func getTemplate(templpath string) (*template.Template, error) {
+       templfs := os.DirFS(templpath)
+       return template.ParseFS(templfs, "*.html")
+}