Skip to content

Commit

Permalink
add demo site
Browse files Browse the repository at this point in the history
  • Loading branch information
euforic committed Feb 20, 2024
1 parent 4dae9e2 commit c92f41b
Show file tree
Hide file tree
Showing 7 changed files with 789 additions and 25 deletions.
27 changes: 2 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,6 @@
import "github.com/euforic/templit"
```

## Index

- [Variables](<#variables>)
- [func ToCamelCase(s string) string](<#ToCamelCase>)
- [func ToKebabCase(s string) string](<#ToKebabCase>)
- [func ToPascalCase(s string) string](<#ToPascalCase>)
- [func ToSnakeCase(s string) string](<#ToSnakeCase>)
- [type DefaultGitClient](<#DefaultGitClient>)
- [func NewDefaultGitClient(token string) *DefaultGitClient](<#NewDefaultGitClient>)
- [func (d *DefaultGitClient) Checkout(path, branch string) error](<#DefaultGitClient.Checkout>)
- [func (d *DefaultGitClient) Clone(host, owner, repo, dest string) error](<#DefaultGitClient.Clone>)
- [type DepInfo](<#DepInfo>)
- [func ParseDepURL(rawURL string) (*DepInfo, error)](<#ParseDepURL>)
- [type Executor](<#Executor>)
- [func NewExecutor() *Executor](<#NewExecutor>)
- [func (e *Executor) EmbedFunc(client GitClient) func(remotePath string, data interface{}) (string, error)](<#Executor.EmbedFunc>)
- [func (e *Executor) ImportFunc(client GitClient) func(repoAndTag, destPath string, data interface{}) (string, error)](<#Executor.ImportFunc>)
- [func (e *Executor) ParsePath(inputPath string) error](<#Executor.ParsePath>)
- [func (e Executor) Render(name string, data interface{}) (string, error)](<#Executor.Render>)
- [func (e Executor) StringRender(templateString string, data interface{}) (string, error)](<#Executor.StringRender>)
- [func (e *Executor) WalkAndProcessDir(inputDir, outputDir string, data interface{}) error](<#Executor.WalkAndProcessDir>)
- [type GitClient](<#GitClient>)


## Variables

<a name="DefaultFuncMap"></a>DefaultFuncMap is the default function map for templates.
Expand Down Expand Up @@ -177,6 +153,7 @@ Executor is a wrapper around the template.Template type
```go
type Executor struct {
*template.Template
git GitClient
}
```

Expand Down Expand Up @@ -219,7 +196,7 @@ Placeholders:
### func (*Executor) ImportFunc

```go
func (e *Executor) ImportFunc() func(repoAndTag, destPath string, data interface{}) (string, error)
func (e *Executor) ImportFunc(destPath string) func(repoAndTag, path string, data interface{}) (string, error)
```

ImportFunc returns a function that can be used as a template function to import and process a template from a remote git repository. ImportFunc allows embedding content from a remote repository into a Go template.
Expand Down
5 changes: 5 additions & 0 deletions docs/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/euforic/exp

go 1.21.1

require github.com/davecgh/go-spew v1.1.1
2 changes: 2 additions & 0 deletions docs/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
64 changes: 64 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Go Template Renderer</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.63.3/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.63.3/theme/material-darker.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.63.3/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.63.3/mode/go/go.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.63.3/mode/javascript/javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.63.3/keymap/vim.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
<style>
#output>.CodeMirror {
height: 80vh;
}
</style>
</head>

<body class="font-sans bg-gray-100 text-gray-800 p-5 h-screen overflow-hidden">
<div class="flex h-full">
<div class="w-1/2 h-screen p-2">
<div class="p-4 mb-4">
<h2 class="font-bold mb-2">Go Template</h2>
<div id="template" class="h-64"></div>
</div>
<div class="p-4">
<h2 class="font-bold mb-2">JSON Data</h2>
<div id="json" class="h-64"></div>
</div>
<div class="flex mt-10 mb-10 ml-5">
<input type="checkbox" id="vim-toggle" class="form-checkbox mr-2">
<label for="vim-toggle" class="select-none cursor-pointer">Enable Vim Keybindings</label>
</div>

</div>

<div class="w-1/2 h-screen p-2">
<div class="p-4 h-screen">
<h2 class="font-bold mb-2">Output</h2>
<div id="output" class="h-screen pb-4"></div>
</div>
</div>
</div>

<script src="wasm_exec.js"></script>
<script type="text/javascript">function fetchAndInstantiate(url, importObject) {
return fetch(url).then(response => response.arrayBuffer()).then(bytes => WebAssembly.instantiate(bytes, importObject)).then(results => results.instance);
}

var go = new Go();
var mod = fetchAndInstantiate("/main.wasm ", go.importObject);

window.onload = function () {
mod.then(function (instance) {
go.run(instance);
});
}
</script>
</body>

</html>
155 changes: 155 additions & 0 deletions docs/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//go:build js && wasm
// +build js,wasm

//go:generate cp $GOROOT/misc/wasm/wasm_exec.js .
package main

import (
"bytes"
"encoding/json"
"fmt"
"syscall/js"
"text/template"
)

type App struct {
templateEditor js.Value
jsonEditor js.Value
outputEditor js.Value
}

func main() {
app := &App{}
app.init()

// Block forever to keep the Go program running
select {}
}

func (app *App) init() {
app.initExports()
app.initCodeMirror()
app.initVimToggle()
app.initRender()
}

func (app *App) initExports() {
js.Global().Set("renderTemplate", js.FuncOf(app.renderTemplate))
}

func (app *App) initCodeMirror() {
cm := js.Global().Get("CodeMirror")
app.templateEditor = cm.New(js.Global().Get("document").Call("getElementById", "template"), js.ValueOf(map[string]interface{}{
"mode": "go",
"theme": "material-darker",
"lineNumbers": true,
"value": "Hello, {{.Name}}",
}))

app.jsonEditor = cm.New(js.Global().Get("document").Call("getElementById", "json"), js.ValueOf(map[string]interface{}{
"mode": "javascript",
"theme": "material-darker",
"lineNumbers": true,
"value": `{
"Name": "World"
}`,
}))

app.outputEditor = cm.New(js.Global().Get("document").Call("getElementById", "output"), js.ValueOf(map[string]interface{}{
"lineNumbers": true,
"readOnly": true,
"theme": "material-darker",
"value": "Hello, World",
}))
}

func (app *App) initVimToggle() {
vimToggle := js.Global().Get("document").Call("getElementById", "vim-toggle")
isVimEnabled := js.Global().Get("localStorage").Call("getItem", "vimEnabled").String() == "true"
app.setKeyMap(isVimEnabled)
vimToggle.Set("checked", isVimEnabled)
vimToggle.Call("addEventListener", "change", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
app.setKeyMap(vimToggle.Get("checked").Bool())
js.Global().Get("localStorage").Call("setItem", "vimEnabled", vimToggle.Get("checked").Bool())
return nil
}))
}

func (app *App) setKeyMap(vimEnabled bool) {
keyMap := "default"
if vimEnabled {
keyMap = "vim"
}
app.templateEditor.Call("setOption", "keyMap", keyMap)
app.jsonEditor.Call("setOption", "keyMap", keyMap)
app.outputEditor.Call("setOption", "keyMap", keyMap)
}

func (app *App) initRender() {
saveFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
app.saveCurrentData()
return nil
})
renderFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
go app.render()
return nil
})
app.templateEditor.Call("on", "change", saveFunc)
app.jsonEditor.Call("on", "change", saveFunc)
app.templateEditor.Call("on", "change", renderFunc)
app.jsonEditor.Call("on", "change", renderFunc)
app.loadPersistedData()
}

func (app *App) render() {
template := app.templateEditor.Call("getValue").String()
json := app.jsonEditor.Call("getValue").String()
result := app.renderTemplate(js.Null(), []js.Value{js.ValueOf(template), js.ValueOf(json)}).(string)
app.outputEditor.Call("setValue", result)
}

func (app *App) renderTemplate(this js.Value, args []js.Value) interface{} {
tmplStr := args[0].String()
jsonStr := args[1].String()

tmpl, err := template.New("tmpl").Parse(tmplStr)
if err != nil {
return fmt.Sprintf("Template error: %v", err)
}

var data interface{}
err = json.Unmarshal([]byte(jsonStr), &data)
if err != nil {
return fmt.Sprintf("JSON error: %v", err)
}

var buf bytes.Buffer
err = tmpl.Execute(&buf, data)
if err != nil {
return fmt.Sprintf("Execution error: %v", err)
}

return buf.String()
}

func (app *App) saveCurrentData() {
js.Global().Get("localStorage").Call("setItem", "templateData", app.templateEditor.Call("getValue").String())
js.Global().Get("localStorage").Call("setItem", "jsonData", app.jsonEditor.Call("getValue").String())
}

func (app *App) loadPersistedData() {
persistedTemplateData := js.Global().Get("localStorage").Call("getItem", "templateData").String()
persistedJsonData := js.Global().Get("localStorage").Call("getItem", "jsonData").String()

if persistedTemplateData != "<null>" {
app.templateEditor.Call("setValue", persistedTemplateData)
}

if persistedJsonData != "<null>" {
app.jsonEditor.Call("setValue", persistedJsonData)
}

if persistedTemplateData != "<null>" || persistedJsonData != "<null>" {
app.render()
}
}
Binary file added docs/main.wasm
Binary file not shown.
Loading

0 comments on commit c92f41b

Please sign in to comment.