├── .gitattributes
├── demo
├── web
│ ├── sf.jpg
│ ├── paris.jpg
│ ├── space.jpg
│ ├── beijing.jpg
│ ├── city.css
│ └── hello.css
├── makefile
├── go.mod
├── app.yaml
├── app
│ ├── main.go
│ ├── hello.go
│ └── city.go
├── README.md
├── .gcloudignore
├── server
│ └── main.go
└── go.sum
├── luck
├── web
│ ├── bg.jpg
│ ├── icon.png
│ └── luck.css
├── app
│ ├── main.go
│ ├── home.go
│ ├── select.go
│ └── game.go
├── makefile
├── go.mod
├── app.yaml
├── README.md
├── .gcloudignore
├── server
│ └── main.go
└── go.sum
├── hello
├── makefile
├── go.mod
├── main.go
├── README.md
└── go.sum
├── docs
├── makefile
├── go.mod
├── main.go
├── manifest.json
├── go.sum
├── app-worker.js
├── index.html
├── app.js
├── app.css
└── wasm_exec.js
├── README.md
├── hello-gcloud-func
├── infra
│ ├── google-cloud
│ │ └── cors.json
│ └── firebase
│ │ ├── firebase.json
│ │ ├── .gitignore
│ │ └── public
│ │ └── index2.html
├── go.mod
├── makefile
├── hello.go
├── .gcloudignore
├── .gitignore
├── go.sum
└── README.md
├── hello-local-external-root
├── makefile
├── go.mod
├── main.go
├── README.md
└── go.sum
├── hello-local
├── makefile
├── go.mod
├── main.go
├── README.md
└── go.sum
├── hello-docker
├── makefile
├── go.mod
├── dockerfile
├── main.go
├── go.sum
└── README.md
├── hello-gcloud-appengine
├── app.yaml
├── makefile
├── go.mod
├── main.go
├── .gcloudignore
├── go.sum
└── README.md
├── .gitignore
├── makefile
└── LICENSE
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/demo/web/sf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxence-charriere/go-app-demo/HEAD/demo/web/sf.jpg
--------------------------------------------------------------------------------
/luck/web/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxence-charriere/go-app-demo/HEAD/luck/web/bg.jpg
--------------------------------------------------------------------------------
/demo/web/paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxence-charriere/go-app-demo/HEAD/demo/web/paris.jpg
--------------------------------------------------------------------------------
/demo/web/space.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxence-charriere/go-app-demo/HEAD/demo/web/space.jpg
--------------------------------------------------------------------------------
/luck/web/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxence-charriere/go-app-demo/HEAD/luck/web/icon.png
--------------------------------------------------------------------------------
/demo/web/beijing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxence-charriere/go-app-demo/HEAD/demo/web/beijing.jpg
--------------------------------------------------------------------------------
/hello/makefile:
--------------------------------------------------------------------------------
1 | build:
2 | GOARCH=wasm GOOS=js go build -o app.wasm
3 |
4 | clean:
5 | @go clean
6 | @-rm app.wasm
7 |
--------------------------------------------------------------------------------
/docs/makefile:
--------------------------------------------------------------------------------
1 | build:
2 | go run main.go
3 | @cd ../hello && make build
4 | @cp ../hello/app.wasm ./web/
5 |
6 | clean:
7 | @go clean
8 | @-rm app.wasm
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # go-app-demo
2 |
3 | This repository contains examples using [go-app](https://github.com/maxence-charriere/go-app) package that work on different platforms.
4 |
--------------------------------------------------------------------------------
/docs/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/doc
2 |
3 | go 1.14
4 |
5 | require github.com/maxence-charriere/go-app/v7 v7.0.0-20200626193706-6701325e7b21 // indirect
6 |
--------------------------------------------------------------------------------
/hello-gcloud-func/infra/google-cloud/cors.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "maxAgeSeconds": 3600,
4 | "method": ["GET", "HEAD"],
5 | "origin": ["*"],
6 | "responseHeader": ["*"]
7 | }
8 | ]
9 |
--------------------------------------------------------------------------------
/hello-local-external-root/makefile:
--------------------------------------------------------------------------------
1 | build:
2 | @cd ../hello-local && make build
3 | @go build
4 |
5 | run: build
6 | ./hello-local-external-root
7 |
8 | clean:
9 | @go clean -v
10 |
--------------------------------------------------------------------------------
/hello-local/makefile:
--------------------------------------------------------------------------------
1 | build:
2 | @cd ../hello && make build
3 | @cp ../hello/app.wasm .
4 | @go build
5 |
6 | run: build
7 | ./hello-local
8 |
9 | clean:
10 | @go clean -v ./...
11 | @-rm app.wasm
12 |
--------------------------------------------------------------------------------
/luck/app/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/maxence-charriere/go-app/v6/pkg/app"
4 |
5 | func main() {
6 | app.Route("/", &home{})
7 | app.Route("/select", &gameSelect{})
8 | app.Run()
9 | }
10 |
--------------------------------------------------------------------------------
/demo/makefile:
--------------------------------------------------------------------------------
1 | build:
2 | @GOARCH=wasm GOOS=js go build -o app.wasm ./app
3 | @go build -o demo ./server
4 |
5 | run: build
6 | PORT=8000 ./demo
7 |
8 | deploy: build
9 | gcloud app deploy --project=murlok
10 |
11 |
--------------------------------------------------------------------------------
/luck/makefile:
--------------------------------------------------------------------------------
1 | build:
2 | @GOARCH=wasm GOOS=js go build -o app.wasm ./app
3 | @go build -o luck ./server
4 |
5 | run: build
6 | PORT=9000 ./luck
7 |
8 | deploy: build
9 | gcloud app deploy --project=murlok
10 |
11 |
--------------------------------------------------------------------------------
/hello-docker/makefile:
--------------------------------------------------------------------------------
1 | build:
2 | @cd ../hello && make build
3 | @cp ../hello/app.wasm .
4 | @docker build -t hello-docker .
5 |
6 | run: build
7 | docker run -p 7000:7000 hello-docker
8 |
9 | clean:
10 | @go clean
11 | @rm app.wasm
12 |
--------------------------------------------------------------------------------
/demo/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/demo
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/luck/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/luck
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/hello/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/hello
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/hello-local/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/hello-local
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/luck/app.yaml:
--------------------------------------------------------------------------------
1 | service: luck
2 | runtime: go113
3 | main: ./server
4 |
5 | instance_class: F1
6 | automatic_scaling:
7 | max_instances: 1
8 |
9 | handlers:
10 | - url: /.*
11 | script: auto
12 | secure: always
13 | redirect_http_response_code: 301
14 |
--------------------------------------------------------------------------------
/demo/app.yaml:
--------------------------------------------------------------------------------
1 | service: hello
2 | runtime: go113
3 | main: ./server
4 |
5 | instance_class: F1
6 | automatic_scaling:
7 | max_instances: 1
8 |
9 | handlers:
10 | - url: /.*
11 | script: auto
12 | secure: always
13 | redirect_http_response_code: 301
14 |
--------------------------------------------------------------------------------
/hello-docker/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/hello-docker
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/hello-gcloud-appengine/app.yaml:
--------------------------------------------------------------------------------
1 | runtime: go113
2 |
3 | instance_class: F1
4 | automatic_scaling:
5 | max_instances: 1
6 |
7 | handlers:
8 | # Enforce https:
9 | - url: /.*
10 | script: auto
11 | secure: always
12 | redirect_http_response_code: 301
13 |
--------------------------------------------------------------------------------
/hello-gcloud-appengine/makefile:
--------------------------------------------------------------------------------
1 | deploy:
2 | @cd ../hello && make build
3 | @cp ../hello/app.wasm .
4 | @-gcloud app deploy . --project go-app-demo-42
5 |
6 | run:
7 | @gcloud app browse --project=go-app-demo-42
8 |
9 | clean:
10 | @go clean
11 | @-rm app.wasm
12 |
--------------------------------------------------------------------------------
/hello-gcloud-func/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app/demo/hello-gcloud-func
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/hello-gcloud-appengine/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/hello-gcloud-appengine
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/hello-local-external-root/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/maxence-charriere/go-app-demo/hello-local-external-root
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/maxence-charriere/go-app/v6 v6.4.1
8 | gopkg.in/yaml.v2 v2.2.8 // indirect
9 | )
10 |
--------------------------------------------------------------------------------
/hello-gcloud-func/infra/firebase/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "public",
4 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
5 | "rewrites": [
6 | {
7 | "source": "**",
8 | "function": "Hello"
9 | }
10 | ]
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/demo/app/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/maxence-charriere/go-app/v6/pkg/app"
5 | )
6 |
7 | const (
8 | icon = "https://storage.googleapis.com/murlok-github/icon-192.png"
9 | )
10 |
11 | func main() {
12 | app.Route("/", &hello{})
13 | app.Route("/city", &city{})
14 | app.Run()
15 | }
16 |
--------------------------------------------------------------------------------
/luck/README.md:
--------------------------------------------------------------------------------
1 | # luck
2 |
3 | [](https://luck.murlok.io)
4 |
5 | Example that generates lottery numbers.
6 |
7 | ## Contribute
8 |
9 | Help to develop the [go-app](https://github.com/maxence-charriere/go-app) package by becoming a sponsor.
10 |
[Become a sponsor](https://opencollective.com/go-app).
11 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # demo
2 |
3 | [](https://hello.murlok.io)
4 |
5 | Example that showcases a styled hello world, context menu and navigation.
6 |
7 | ## Contribute
8 |
9 | Help to develop the [go-app](https://github.com/maxence-charriere/go-app) package by becoming a sponsor.
10 |
[Become a sponsor](https://opencollective.com/go-app).
11 |
--------------------------------------------------------------------------------
/docs/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/maxence-charriere/go-app/v7/pkg/app"
7 | )
8 |
9 | func main() {
10 | err := app.GenerateStaticWebsite("", &app.Handler{
11 | Name: "Github Pages Hello",
12 | Title: "Github Pages Hello",
13 | })
14 |
15 | if err != nil {
16 | fmt.Println(err)
17 | return
18 | }
19 |
20 | fmt.Println("static website generated")
21 | }
22 |
--------------------------------------------------------------------------------
/hello-local/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 |
7 | "github.com/maxence-charriere/go-app/v6/pkg/app"
8 | )
9 |
10 | func main() {
11 | fmt.Println("starting local server")
12 |
13 | h := &app.Handler{
14 | Title: "Hello Demo",
15 | Author: "Maxence Charriere",
16 | }
17 |
18 | if err := http.ListenAndServe(":7000", h); err != nil {
19 | panic(err)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 | *.wasm
8 | hello-local/hello-local
9 | luck/luck
10 | demo/demo
11 |
12 | # Test binary, built with `go test -c`
13 | *.test
14 |
15 | # Output of the go coverage tool, specifically when used with LiteIDE
16 | *.out
17 |
18 | # Dependency directories (remove the comment below to include it)
19 | # vendor/
20 | .firebaserc
21 |
--------------------------------------------------------------------------------
/hello-docker/dockerfile:
--------------------------------------------------------------------------------
1 | # Set the latest golang base image:
2 | FROM golang:latest
3 |
4 | # Set the Current Working Directory inside the container
5 | WORKDIR /app
6 |
7 | # Build server:
8 | COPY ./ ./
9 | RUN go mod download
10 | RUN go build -o app .
11 |
12 | # Expose server port:
13 | EXPOSE 7000
14 |
15 | # App version (uncomment if the image is for non-development ends):
16 | # ENV APP_VERSION "YOUR_VERSION"
17 |
18 | # Run the server:
19 | CMD ["./app"]
--------------------------------------------------------------------------------
/hello-docker/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "os"
7 |
8 | "github.com/maxence-charriere/go-app/v6/pkg/app"
9 | )
10 |
11 | func main() {
12 | fmt.Println("starting docker server")
13 |
14 | h := &app.Handler{
15 | Title: "Hello Demo from Docker",
16 | Author: "Maxence Charriere",
17 | Version: os.Getenv("APP_VERSION"),
18 | }
19 |
20 | if err := http.ListenAndServe(":7000", h); err != nil {
21 | panic(err)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/hello-local-external-root/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 |
7 | "github.com/maxence-charriere/go-app/v6/pkg/app"
8 | )
9 |
10 | func main() {
11 | fmt.Println("starting local server with external root")
12 |
13 | h := &app.Handler{
14 | Title: "Hello Demo with external root",
15 | Author: "Maxence Charriere",
16 | RootDir: "../hello-local",
17 | }
18 |
19 | if err := http.ListenAndServe(":7000", h); err != nil {
20 | panic(err)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/hello-gcloud-func/makefile:
--------------------------------------------------------------------------------
1 | deploy:
2 | @cd ../hello && make build
3 | @cp ../hello/app.wasm .
4 | @gsutil \
5 | -h "Cache-Control:no-cache,max-age=0" \
6 | -h "Content-Type:application/wasm" \
7 | cp ./app.wasm gs://goapp-gcloud-function/app.wasm
8 | @gcloud functions deploy Hello --runtime go113 --trigger-http --project go-app-demo-42
9 | @cd ./infra/firebase && firebase deploy
10 |
11 | run:
12 | @open https://go-app-demo-42.firebaseapp.com
13 |
14 | clean:
15 | @go clean
16 | @-rm app.wasm
--------------------------------------------------------------------------------
/hello-gcloud-func/hello.go:
--------------------------------------------------------------------------------
1 | package hello
2 |
3 | import (
4 | "net/http"
5 | "os"
6 |
7 | "github.com/maxence-charriere/go-app/v6/pkg/app"
8 | )
9 |
10 | var handler = &app.Handler{
11 | Title: "Hello Google Cloud Function",
12 | Author: "Maxence Charriere",
13 | RootDir: "https://storage.googleapis.com/goapp-gcloud-function",
14 | Version: os.Getenv("K_REVISION"),
15 | }
16 |
17 | // Hello is the Google Cloud Function implementation.
18 | func Hello(w http.ResponseWriter, r *http.Request) {
19 | handler.ServeHTTP(w, r)
20 | }
21 |
--------------------------------------------------------------------------------
/docs/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Github Pages Hello",
3 | "name": "Github Pages Hello",
4 | "icons": [
5 | {
6 | "src": "https://storage.googleapis.com/murlok-github/icon-192.png",
7 | "type": "image/png",
8 | "sizes": "192x192"
9 | },
10 | {
11 | "src": "https://storage.googleapis.com/murlok-github/icon-512.png",
12 | "type": "image/png",
13 | "sizes": "512x512"
14 | }
15 | ],
16 | "start_url": "/",
17 | "background_color": "#2d2c2c",
18 | "display": "standalone",
19 | "theme_color": "#2d2c2c"
20 | }
21 |
--------------------------------------------------------------------------------
/demo/web/city.css:
--------------------------------------------------------------------------------
1 | .city {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | width: 100%;
6 | height: 100%;
7 | overflow: hidden;
8 |
9 | display: flex;
10 | flex-direction: column;
11 | justify-content: center;
12 | align-items: center;
13 |
14 | background-size: cover;
15 | background-position: center;
16 | }
17 |
18 | .city-title {
19 | font-size: 56pt;
20 | font-weight: 200;
21 | text-align: center;
22 | }
23 |
24 | .city-description {
25 | max-width: 480px;
26 | text-align: justify;
27 | }
28 |
29 | .city-links {
30 | margin-top: 12px;
31 | text-align: center;
32 | }
33 |
--------------------------------------------------------------------------------
/hello-gcloud-func/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | # If you would like to upload your .git directory, .gitignore file or files
11 | # from your .gitignore file, remove the corresponding line
12 | # below:
13 | .git
14 | .gitignore
15 |
16 | node_modules
17 | #!include:.gitignore
18 |
--------------------------------------------------------------------------------
/hello-gcloud-appengine/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 | "os"
6 |
7 | "github.com/maxence-charriere/go-app/v6/pkg/app"
8 | "github.com/maxence-charriere/go-app/v6/pkg/log"
9 | )
10 |
11 | func main() {
12 | addr := ":" + os.Getenv("PORT")
13 | version := os.Getenv("GAE_VERSION")
14 |
15 | log.Info("stating app engine server").
16 | T("addr", addr).
17 | T("version", version).
18 | T("exec", os.Args[0])
19 |
20 | h := &app.Handler{
21 | Title: "Hello Google App Engine",
22 | Author: "Maxence Charriere",
23 | Version: version,
24 | }
25 |
26 | if err := http.ListenAndServe(addr, h); err != nil {
27 | panic(err)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | update:
2 | @cd hello && \
3 | go get -u ./... && \
4 | go mod tidy && \
5 | GOARCH=wasm GOOS=js go build -o app.wasm
6 | @cd hello-docker && \
7 | go get -u ./... && \
8 | go mod tidy
9 | @cd hello-gcloud-appengine && \
10 | go get -u ./... && \
11 | go mod tidy
12 | @cd hello-gcloud-func && \
13 | go get -u ./... && \
14 | go mod tidy
15 | @cd hello-local && \
16 | go get -u ./... && \
17 | go mod tidy
18 | @cd hello-local-external-root && \
19 | go get -u ./... && \
20 | go mod tidy
21 | @cd luck && \
22 | go get -u ./... && \
23 | go mod tidy
24 | @cd demo && \
25 | go get -u ./... && \
26 | go mod tidy
27 |
28 | clean:
29 | @-rm -r */app.wasm
30 | @-rm ./luck/luck
31 | @-rm ./demo/demo
32 | go clean ./...
--------------------------------------------------------------------------------
/demo/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | # If you would like to upload your .git directory, .gitignore file or files
11 | # from your .gitignore file, remove the corresponding line
12 | # below:
13 | .git
14 | .gitignore
15 |
16 | # Binaries for programs and plugins
17 | *.exe
18 | *.exe~
19 | *.dll
20 | *.so
21 | *.dylib
22 | # Test binary, build with `go test -c`
23 | *.test
24 | # Output of the go coverage tool, specifically when used with LiteIDE
25 | *.out
26 | demo
27 | app
--------------------------------------------------------------------------------
/hello-gcloud-appengine/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | # If you would like to upload your .git directory, .gitignore file or files
11 | # from your .gitignore file, remove the corresponding line
12 | # below:
13 | .git
14 | .gitignore
15 |
16 | # Binaries for programs and plugins
17 | *.exe
18 | *.exe~
19 | *.dll
20 | *.so
21 | *.dylib
22 | # Test binary, build with `go test -c`
23 | *.test
24 | # Output of the go coverage tool, specifically when used with LiteIDE
25 | *.out
--------------------------------------------------------------------------------
/luck/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | # If you would like to upload your .git directory, .gitignore file or files
11 | # from your .gitignore file, remove the corresponding line
12 | # below:
13 | .git
14 | .gitignore
15 |
16 | # Binaries for programs and plugins
17 | *.exe
18 | *.exe~
19 | *.dll
20 | *.so
21 | *.dylib
22 | # Test binary, build with `go test -c`
23 | *.test
24 | # Output of the go coverage tool, specifically when used with LiteIDE
25 | *.out
26 | luck
27 | app
--------------------------------------------------------------------------------
/hello/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/maxence-charriere/go-app/v6/pkg/app"
5 | )
6 |
7 | type hello struct {
8 | app.Compo
9 | name string
10 | }
11 |
12 | func (h *hello) Render() app.UI {
13 | return app.Div().Body(
14 | app.Main().Body(
15 | app.H1().Body(
16 | app.Text("Hello, "),
17 | app.If(h.name != "",
18 | app.Text(h.name),
19 | ).Else(
20 | app.Text("World"),
21 | ),
22 | ),
23 | app.Input().
24 | Value(h.name).
25 | Placeholder("What is your name?").
26 | AutoFocus(true).
27 | OnChange(h.OnInputChange),
28 | ),
29 | )
30 | }
31 |
32 | func (h *hello) OnInputChange(src app.Value, e app.Event) {
33 | h.name = src.Get("value").String()
34 | h.Update()
35 | }
36 |
37 | func main() {
38 | app.Route("/", &hello{})
39 | app.Run()
40 | }
41 |
--------------------------------------------------------------------------------
/hello/README.md:
--------------------------------------------------------------------------------
1 | # hello
2 |
3 | hello is a demo that shows how to use the [go-app package](https://github.com/maxence-charriere/go-app) to build a GUI.
4 |
5 | ## Build
6 |
7 | Go to the hello directory:
8 |
9 | ```sh
10 | cd $GOPATH/src/github.com/maxence-charriere/go-app-demo/hello
11 | ```
12 |
13 | ```sh
14 | GOARCH=wasm GOOS=js go build -o app.wasm
15 | ```
16 |
17 | Note that `app.wasm` binary requires to be moved at the server location that will serve it. See the other hello examples:
18 |
19 | - [hello-docker](https://github.com/maxence-charriere/go-app-demo/tree/v6/hello-docker)
20 | - [hello-local](https://github.com/maxence-charriere/go-app-demo/tree/v6/hello-local)
21 |
22 | ## Contribute
23 |
24 | Help to develop the [go-app](https://github.com/maxence-charriere/go-app) package by becoming a sponsor.
25 |
[Become a sponsor](https://opencollective.com/go-app).
26 |
--------------------------------------------------------------------------------
/docs/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 | github.com/maxence-charriere/go-app v1.3.6 h1:ivoXYI+Wf11vrmgoew5hcFDw4djFin2HzwBGjs8yV+4=
3 | github.com/maxence-charriere/go-app/v7 v7.0.0-20200626193706-6701325e7b21 h1:X2Eyf6dWw5UvNkMpybZnYMAlq3DJ+w+oxNcJdFGvBfo=
4 | github.com/maxence-charriere/go-app/v7 v7.0.0-20200626193706-6701325e7b21/go.mod h1:JTs+/Taw1Qz+NDOQsA0mQS0QuoEtD7kZuSpviWRKsjk=
5 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
6 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
10 |
--------------------------------------------------------------------------------
/demo/web/hello.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: black;
3 | color: white;
4 | }
5 |
6 | .hello {
7 | position: fixed;
8 | top: 0;
9 | left: 0;
10 | width: 100%;
11 | height: 100%;
12 | overflow: hidden;
13 |
14 | display: flex;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 |
19 | background-image: url("/web/space.jpg");
20 | background-size: cover;
21 | background-position: center;
22 | }
23 |
24 | .hello-title {
25 | max-width: 480px;
26 | font-size: 56pt;
27 | font-weight: 200;
28 | }
29 |
30 | .hello-input {
31 | max-width: 480px;
32 | font-size: 11pt;
33 | font-weight: 200;
34 | }
35 |
36 | .menu-button {
37 | position: fixed;
38 | left: 0;
39 | top: 0;
40 | padding: 12px;
41 | margin: 0 12px 12px;
42 | border: 0;
43 | z-index: 1;
44 |
45 | font-size: 24px;
46 | font-weight: 200;
47 | color: currentColor;
48 | cursor: pointer;
49 | }
50 |
--------------------------------------------------------------------------------
/demo/server/main.go:
--------------------------------------------------------------------------------
1 | // +build !wasm
2 |
3 | package main
4 |
5 | import (
6 | "net/http"
7 | "os"
8 |
9 | "github.com/maxence-charriere/go-app/v6/pkg/app"
10 | "github.com/maxence-charriere/go-app/v6/pkg/log"
11 | )
12 |
13 | func main() {
14 | port := os.Getenv("PORT")
15 | if port == "" {
16 | port = "7777"
17 | }
18 |
19 | version := os.Getenv("GAE_VERSION")
20 |
21 | log.Info("starting server").
22 | T("port", port).
23 | T("version", version)
24 |
25 | err := http.ListenAndServe(":"+port, &app.Handler{
26 | Title: "App Demo",
27 | Styles: []string{
28 | "/web/hello.css",
29 | "/web/city.css",
30 | },
31 | CacheableResources: []string{
32 | "/web/space.jpg",
33 | "/web/beijing.jpg",
34 | "/web/paris.jpg",
35 | "/web/sf.jpg",
36 | },
37 | // UseMinimalDefaultStyles: true,
38 | Version: version,
39 | })
40 |
41 | if err != nil {
42 | log.Error("server crashed").T("error", err)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 maxence-charriere
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/luck/server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 | "os"
6 |
7 | "github.com/maxence-charriere/go-app/v6/pkg/app"
8 | "github.com/maxence-charriere/go-app/v6/pkg/log"
9 | )
10 |
11 | func main() {
12 | port := os.Getenv("PORT")
13 | if port == "" {
14 | port = "9000"
15 | }
16 | addr := ":" + port
17 |
18 | version := os.Getenv("GAE_VERSION")
19 |
20 | log.Info("starting server").T("addr", addr)
21 |
22 | if err := http.ListenAndServe(addr, &app.Handler{
23 | Name: "Luck",
24 | Author: "Maxence Charriere",
25 | Description: "Lottery numbers generator.",
26 | Icon: app.Icon{
27 | Default: "/web/icon.png",
28 | },
29 | Keywords: []string{
30 | "lottery",
31 | "EuroMillions",
32 | "Loto",
33 | "MEGA Millions",
34 | "Powerball",
35 | "SuperLotto Plus",
36 | },
37 | ThemeColor: "#000000",
38 | BackgroundColor: "#000000",
39 | Styles: []string{
40 | "/web/luck.css",
41 | },
42 | CacheableResources: []string{
43 | "/web/bg.jpg",
44 | },
45 | Version: version,
46 | }); err != nil {
47 | log.Error("listening and serving http requests failed").
48 | T("reason", err).
49 | T("addr", addr).
50 | T("version", version).
51 | Panic()
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/hello-local/README.md:
--------------------------------------------------------------------------------
1 | # hello-local
2 |
3 | hello-local is a demo that shows how to run a progressive web app created with the [go-app package](https://github.com/maxence-charriere/go-app) on your local machine.
4 |
5 | ## TLDR
6 |
7 | ```sh
8 | cd $GOPATH/src/github.com/maxence-charriere/go-app-demo/hello-local
9 | make run
10 | ```
11 |
12 | ## Build and run
13 |
14 | Go to the hello-local directory:
15 |
16 | ```sh
17 | cd $GOPATH/src/github.com/maxence-charriere/go-app-demo/hello-local
18 | ```
19 |
20 | Make sure the `hello` directory is built:
21 |
22 | ```sh
23 | cd ../hello && make build && cd -
24 | ```
25 |
26 | Copy the hello wasm binary:
27 |
28 | ```sh
29 | cp ../hello/app.wasm .
30 | ```
31 |
32 | Build the server:
33 |
34 | ```sh
35 | go build
36 | ```
37 |
38 | The current directory should look like the following:
39 |
40 | ```sh
41 | # github.com/maxence-charriere/go-app-demo/hello-local
42 | .
43 | ├── README.md
44 | ├── app.wasm
45 | ├── go.mod
46 | ├── go.sum
47 | ├── hello-local
48 | └── main.go
49 | ```
50 |
51 | Run the server:
52 |
53 | ```sh
54 | ./hello-local
55 | ```
56 |
57 | ## Contribute
58 |
59 | Help to develop the [go-app](https://github.com/maxence-charriere/go-app) package by becoming a sponsor.
60 |
[Become a sponsor](https://opencollective.com/go-app).
61 |
--------------------------------------------------------------------------------
/docs/app-worker.js:
--------------------------------------------------------------------------------
1 | const cacheName = "app-" + "286b5034b87c94b59b608e7ae260f7599b794b79";
2 |
3 | self.addEventListener("install", event => {
4 | console.log("installing app worker 286b5034b87c94b59b608e7ae260f7599b794b79");
5 | self.skipWaiting();
6 |
7 | event.waitUntil(
8 | caches.open(cacheName).then(cache => {
9 | return cache.addAll([
10 | "/",
11 | "/app.css",
12 | "/app.js",
13 | "/manifest.json",
14 | "/wasm_exec.js",
15 | "/web/app.wasm",
16 | "https://storage.googleapis.com/murlok-github/icon-192.png",
17 | "https://storage.googleapis.com/murlok-github/icon-512.png",
18 |
19 | ]);
20 | })
21 | );
22 | });
23 |
24 | self.addEventListener("activate", event => {
25 | event.waitUntil(
26 | caches.keys().then(keyList => {
27 | return Promise.all(
28 | keyList.map(key => {
29 | if (key !== cacheName) {
30 | return caches.delete(key);
31 | }
32 | })
33 | );
34 | })
35 | );
36 | console.log("app worker 286b5034b87c94b59b608e7ae260f7599b794b79 is activated");
37 | });
38 |
39 | self.addEventListener("fetch", event => {
40 | event.respondWith(
41 | caches.match(event.request).then(response => {
42 | return response || fetch(event.request);
43 | })
44 | );
45 | });
46 |
--------------------------------------------------------------------------------
/hello-local-external-root/README.md:
--------------------------------------------------------------------------------
1 | # hello-local-external-root
2 |
3 | hello-local is a demo that shows how to run a progressive web app created with the [go-app package](https://github.com/maxence-charriere/go-app) on your local machine. It use the static files of the `hello-local` directory.
4 |
5 | ## TLDR
6 |
7 | ```sh
8 | cd $GOPATH/src/github.com/maxence-charriere/go-app-demo/hello-local-external-root
9 | make run
10 | ```
11 |
12 | ## Build and run
13 |
14 | Go to the hello-local-external-root directory:
15 |
16 | ```sh
17 | cd $GOPATH/src/github.com/maxence-charriere/go-app-demo/hello-local-external-root
18 | ```
19 |
20 | Make sure the `hello-local` directory is built:
21 |
22 | ```sh
23 | cd ../hello-local && make build && cd -
24 | ```
25 |
26 | Build the server:
27 |
28 | ```sh
29 | go build
30 | ```
31 |
32 | The current directory should look like the following:
33 |
34 | ```sh
35 | # github.com/maxence-charriere/go-app-demo/hello-local-external-root
36 | .
37 | ├── README.md
38 | ├── go.mod
39 | ├── go.sum
40 | ├── hello-local-external-root
41 | └── main.go
42 | ```
43 |
44 | Run the server:
45 |
46 | ```sh
47 | ./hello-local-external-root
48 | ```
49 |
50 | ## Contribute
51 |
52 | Help to develop the [go-app](https://github.com/maxence-charriere/go-app) package by becoming a sponsor.
53 |
[Become a sponsor](https://opencollective.com/go-app).
54 |
--------------------------------------------------------------------------------
/hello-gcloud-func/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | firebase-debug.log*
8 |
9 | # Firebase cache
10 | .firebase/
11 |
12 | # Firebase config
13 |
14 | # Uncomment this if you'd like others to create their own Firebase project.
15 | # For a team working on the same Firebase project(s), it is recommended to leave
16 | # it commented so all members can deploy to the same project(s) in .firebaserc.
17 | # .firebaserc
18 |
19 | # Runtime data
20 | pids
21 | *.pid
22 | *.seed
23 | *.pid.lock
24 |
25 | # Directory for instrumented libs generated by jscoverage/JSCover
26 | lib-cov
27 |
28 | # Coverage directory used by tools like istanbul
29 | coverage
30 |
31 | # nyc test coverage
32 | .nyc_output
33 |
34 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
35 | .grunt
36 |
37 | # Bower dependency directory (https://bower.io/)
38 | bower_components
39 |
40 | # node-waf configuration
41 | .lock-wscript
42 |
43 | # Compiled binary addons (http://nodejs.org/api/addons.html)
44 | build/Release
45 |
46 | # Dependency directories
47 | node_modules/
48 |
49 | # Optional npm cache directory
50 | .npm
51 |
52 | # Optional eslint cache
53 | .eslintcache
54 |
55 | # Optional REPL history
56 | .node_repl_history
57 |
58 | # Output of 'npm pack'
59 | *.tgz
60 |
61 | # Yarn Integrity file
62 | .yarn-integrity
63 |
64 | # dotenv environment variables file
65 | .env
66 |
--------------------------------------------------------------------------------
/hello-gcloud-func/infra/firebase/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | firebase-debug.log*
8 |
9 | # Firebase cache
10 | .firebase/
11 |
12 | # Firebase config
13 |
14 | # Uncomment this if you'd like others to create their own Firebase project.
15 | # For a team working on the same Firebase project(s), it is recommended to leave
16 | # it commented so all members can deploy to the same project(s) in .firebaserc.
17 | # .firebaserc
18 |
19 | # Runtime data
20 | pids
21 | *.pid
22 | *.seed
23 | *.pid.lock
24 |
25 | # Directory for instrumented libs generated by jscoverage/JSCover
26 | lib-cov
27 |
28 | # Coverage directory used by tools like istanbul
29 | coverage
30 |
31 | # nyc test coverage
32 | .nyc_output
33 |
34 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
35 | .grunt
36 |
37 | # Bower dependency directory (https://bower.io/)
38 | bower_components
39 |
40 | # node-waf configuration
41 | .lock-wscript
42 |
43 | # Compiled binary addons (http://nodejs.org/api/addons.html)
44 | build/Release
45 |
46 | # Dependency directories
47 | node_modules/
48 |
49 | # Optional npm cache directory
50 | .npm
51 |
52 | # Optional eslint cache
53 | .eslintcache
54 |
55 | # Optional REPL history
56 | .node_repl_history
57 |
58 | # Output of 'npm pack'
59 | *.tgz
60 |
61 | # Yarn Integrity file
62 | .yarn-integrity
63 |
64 | # dotenv environment variables file
65 | .env
66 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 | Loading 24 |
25 |You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!
38 | Open Hosting Documentation 39 |Firebase SDK Loading…
41 | 42 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /docs/app.css: -------------------------------------------------------------------------------- 1 | /* Loader */ 2 | .goapp-app-info { 3 | position: fixed; 4 | top: 0; 5 | left: 0; 6 | width: 100%; 7 | height: 100%; 8 | overflow: hidden; 9 | 10 | display: flex; 11 | flex-direction: column; 12 | justify-content: center; 13 | align-items: center; 14 | 15 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, 16 | Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 17 | font-size: 13px; 18 | font-weight: 400; 19 | color: white; 20 | background-color: #2d2c2c; 21 | } 22 | 23 | @media (prefers-color-scheme: light) { 24 | .goapp-app-info { 25 | color: black; 26 | background-color: #f6f6f6; 27 | } 28 | } 29 | 30 | .goapp-logo { 31 | max-width: 100px; 32 | max-height: 100px; 33 | user-select: none; 34 | -moz-user-select: none; 35 | -webkit-user-drag: none; 36 | -webkit-user-select: none; 37 | -ms-user-select: none; 38 | } 39 | 40 | .goapp-label { 41 | margin-top: 12px; 42 | font-size: 21px; 43 | font-weight: 100; 44 | letter-spacing: 1px; 45 | max-width: 480px; 46 | text-align: center; 47 | text-transform: lowercase; 48 | } 49 | 50 | .goapp-spin { 51 | animation: goapp-spin-frames 1.21s infinite linear; 52 | } 53 | 54 | @keyframes goapp-spin-frames { 55 | from { 56 | transform: rotate(0deg); 57 | } 58 | 59 | to { 60 | transform: rotate(360deg); 61 | } 62 | } 63 | 64 | /* Not found */ 65 | 66 | .goapp-notfound-title { 67 | display: flex; 68 | justify-content: center; 69 | align-items: center; 70 | font-size: 65pt; 71 | font-weight: 100; 72 | } 73 | 74 | /* Menu */ 75 | #app-contextmenu-background { 76 | position: fixed; 77 | width: 100%; 78 | height: 100%; 79 | overflow: hidden; 80 | left: 0; 81 | top: 0; 82 | z-index: 42000; 83 | } 84 | 85 | .goapp-contextmenu { 86 | position: fixed; 87 | min-width: 150px; 88 | max-width: 480px; 89 | padding: 6px 0; 90 | border-radius: 6px; 91 | border: solid 1px rgba(255, 255, 255, 0.1); 92 | background-color: rgba(40, 38, 37, 0.97); 93 | color: white; 94 | -webkit-box-shadow: -1px 12px 38px 0px rgba(0, 0, 0, 0.6); 95 | -moz-box-shadow: -1px 12px 38px 0px rgba(0, 0, 0, 0.6); 96 | box-shadow: -1px 12px 38px 0px rgba(0, 0, 0, 0.6); 97 | } 98 | 99 | @media (prefers-color-scheme: light) { 100 | .goapp-contextmenu { 101 | color: black; 102 | background-color: rgba(221, 221, 221, 0.97); 103 | border: solid 1px rgba(0, 0, 0, 0.2); 104 | } 105 | } 106 | 107 | .goapp-contextmenu-hidden { 108 | display: none; 109 | } 110 | 111 | .goapp-contextmenu-visible { 112 | display: block; 113 | } 114 | 115 | .goapp-menuitem { 116 | display: flex; 117 | align-items: center; 118 | padding: 3px 24px; 119 | margin: 0; 120 | border: none; 121 | width: 100%; 122 | cursor: pointer; 123 | outline: inherit; 124 | background-color: transparent; 125 | text-align: left; 126 | color: currentColor; 127 | } 128 | 129 | .goapp-menuitem:hover { 130 | background-color: deepskyblue; 131 | } 132 | 133 | .goapp-menuitem:disabled { 134 | opacity: 0.15; 135 | background-color: transparent; 136 | } 137 | 138 | .goapp-menuitem-separator { 139 | width: 100%; 140 | height: 0; 141 | margin: 6px 0; 142 | border-top: solid 1px rgba(255, 255, 255, 0.1); 143 | } 144 | 145 | @media (prefers-color-scheme: light) { 146 | .goapp-menuitem-separator { 147 | border-top: solid 1px rgba(0, 0, 0, 0.2); 148 | } 149 | } 150 | 151 | .goapp-menuitem-label { 152 | user-select: none; 153 | flex-grow: 1; 154 | } 155 | 156 | .goapp-menuitem-keys { 157 | flex-grow: 0; 158 | margin-left: 12px; 159 | text-transform: capitalize; 160 | } 161 | 162 | .goapp-menuitem-icon { 163 | width: 18px; 164 | height: 18px; 165 | margin-right: 12px; 166 | } 167 | -------------------------------------------------------------------------------- /demo/app/city.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | 7 | "github.com/maxence-charriere/go-app/v6/pkg/app" 8 | ) 9 | 10 | type cityData struct { 11 | name string 12 | description string 13 | image string 14 | } 15 | 16 | var cityStore = map[string]cityData{ 17 | "paris": { 18 | name: "Paris", 19 | image: "/web/paris.jpg", 20 | description: ` 21 | Paris, France's capital, is a major European city and a global center for art, 22 | fashion, gastronomy and culture. Its 19th-century cityscape is crisscrossed by 23 | wide boulevards and the River Seine. Beyond such landmarks as the Eiffel Tower 24 | and the 12th-century, Gothic Notre-Dame cathedral, the city is known for its 25 | cafe culture and designer boutiques along the Rue du Faubourg Saint-Honoré. 26 | `, 27 | }, 28 | "sf": { 29 | name: "San Francisco", 30 | image: "/web/sf.jpg", 31 | description: ` 32 | San Francisco, officially City and County of San Francisco and colloquially 33 | known as SF, San Fran or "The City", is a city in—and the cultural, commercial, 34 | and financial center of—Northern California. 35 | `, 36 | }, 37 | "beijing": { 38 | name: "北京市", 39 | image: "/web/beijing.jpg", 40 | description: ` 41 | Beijing, China’s sprawling capital, has history stretching back 3 millennia. Yet 42 | it’s known as much for modern architecture as its ancient sites such as the 43 | grand Forbidden City complex, the imperial palace during the Ming and Qing 44 | dynasties. Nearby, the massive Tiananmen Square pedestrian plaza is the site of 45 | Mao Zedong’s mausoleum and the National Museum of China, displaying a vast 46 | collection of cultural relics. 47 | `, 48 | }, 49 | } 50 | 51 | type city struct { 52 | app.Compo 53 | 54 | data cityData 55 | } 56 | 57 | func (c *city) OnNav(u *url.URL) { 58 | key := u.Query().Get("city") 59 | if key == "" { 60 | key = "paris" 61 | } 62 | 63 | data, ok := cityStore[key] 64 | if !ok { 65 | app.Navigate("/notfound") 66 | return 67 | } 68 | c.data = data 69 | c.Update() 70 | } 71 | 72 | func (c *city) Render() app.UI { 73 | return app.Div(). 74 | Body( 75 | app.Div(). 76 | Class("menu-button"). 77 | OnClick(c.OnMenuClick). 78 | Body( 79 | app.Text("☰"), 80 | ), 81 | app.Main(). 82 | Class("city"). 83 | Style("background-image", fmt.Sprintf("url('%s')", c.data.image)). 84 | Body( 85 | app.H1(). 86 | Class("city-title"). 87 | Body( 88 | app.Text(c.data.name), 89 | ), 90 | app.P(). 91 | Class("city-description"). 92 | Body( 93 | app.Text(c.data.description), 94 | ), 95 | app.P(). 96 | Class("city-links"). 97 | Body( 98 | app.A(). 99 | Class("app-button"). 100 | Href("/city?city=beijing"). 101 | Body( 102 | app.Text(cityStore["beijing"].name), 103 | ), 104 | app.A(). 105 | Class("app-button"). 106 | Href("/city?city=paris"). 107 | Body( 108 | app.Text(cityStore["paris"].name), 109 | ), 110 | app.A(). 111 | Class("app-button"). 112 | Href("/city?city=sf"). 113 | Body( 114 | app.Text(cityStore["sf"].name), 115 | ), 116 | ), 117 | ), 118 | ) 119 | } 120 | 121 | func (c *city) OnMenuClick(src app.Value, e app.Event) { 122 | app.NewContextMenu( 123 | app.MenuItem(). 124 | Label("Reload"). 125 | Keys("cmdorctrl+r"). 126 | OnClick(func(src app.Value, e app.Event) { 127 | app.Reload() 128 | }), 129 | app.MenuItem().Separator(), 130 | app.MenuItem(). 131 | Label("Hello demo"). 132 | OnClick(func(src app.Value, e app.Event) { 133 | app.Navigate("/") 134 | }), 135 | app.MenuItem().Separator(), 136 | app.MenuItem(). 137 | Icon(icon). 138 | Label("Go to repository"). 139 | OnClick(func(src app.Value, e app.Event) { 140 | app.Navigate("https://github.com/maxence-charriere/go-app") 141 | }), 142 | app.MenuItem(). 143 | Icon(icon). 144 | Label("Demo sources"). 145 | OnClick(func(src app.Value, e app.Event) { 146 | app.Navigate("https://github.com/maxence-charriere/go-app-demo/tree/v6/demo") 147 | }), 148 | ) 149 | } 150 | -------------------------------------------------------------------------------- /luck/app/game.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sort" 7 | "strings" 8 | 9 | "github.com/maxence-charriere/go-app/v6/pkg/app" 10 | "github.com/maxence-charriere/go-app/v6/pkg/log" 11 | ) 12 | 13 | type game struct { 14 | ID string 15 | Name string 16 | Location string 17 | Enabled bool 18 | NotSorted bool 19 | Numbers []numberConfig 20 | } 21 | 22 | func (g game) draw(n int) string { 23 | r := rand.New(rand.NewSource(int64(n))) 24 | w := strings.Builder{} 25 | 26 | for i, cfg := range g.Numbers { 27 | if i != 0 { 28 | fmt.Fprint(&w, " - ") 29 | } 30 | 31 | numbers := make([]int, 0, cfg.Count) 32 | cache := make(map[int]struct{}, cfg.Count) 33 | 34 | for len(numbers) < cfg.Count { 35 | n := r.Intn(cfg.Max) + 1 36 | if _, ok := cache[n]; ok { 37 | continue 38 | } 39 | cache[n] = struct{}{} 40 | numbers = append(numbers, n) 41 | } 42 | 43 | sort.Ints(numbers) 44 | 45 | for _, n := range numbers { 46 | if n < 10 { 47 | fmt.Fprintf(&w, "0%v ", n) 48 | } else { 49 | fmt.Fprintf(&w, "%v ", n) 50 | } 51 | } 52 | } 53 | 54 | return strings.TrimSpace(w.String()) 55 | } 56 | 57 | type numberConfig struct { 58 | Count int 59 | Max int 60 | } 61 | 62 | var ( 63 | games = map[string]game{ 64 | "powerball": { 65 | ID: "powerball", 66 | Name: "Powerball", 67 | Location: "USA", 68 | Enabled: true, 69 | Numbers: []numberConfig{ 70 | { 71 | Count: 5, 72 | Max: 69, 73 | }, 74 | { 75 | Count: 1, 76 | Max: 26, 77 | }, 78 | }, 79 | }, 80 | "megamillions": { 81 | ID: "megamillions", 82 | Name: "MEGA Millions", 83 | Location: "USA", 84 | Numbers: []numberConfig{ 85 | { 86 | Count: 5, 87 | Max: 70, 88 | }, 89 | { 90 | Count: 1, 91 | Max: 25, 92 | }, 93 | }, 94 | }, 95 | "superlottoplus": { 96 | ID: "superlottoplus", 97 | Name: "SuperLotto Plus", 98 | Location: "USA", 99 | Numbers: []numberConfig{ 100 | { 101 | Count: 5, 102 | Max: 47, 103 | }, 104 | { 105 | Count: 1, 106 | Max: 27, 107 | }, 108 | }, 109 | }, 110 | "fantasy5": { 111 | ID: "fantasy5", 112 | Name: "Fantasy 5", 113 | Location: "USA", 114 | Numbers: []numberConfig{ 115 | { 116 | Count: 5, 117 | Max: 39, 118 | }, 119 | }, 120 | }, 121 | "daily3": { 122 | ID: "daily3", 123 | Name: "Daily 3", 124 | Location: "USA", 125 | NotSorted: true, 126 | Numbers: []numberConfig{ 127 | { 128 | Count: 3, 129 | Max: 9, 130 | }, 131 | }, 132 | }, 133 | "daily4": { 134 | ID: "daily4", 135 | Name: "Daily 4", 136 | Location: "USA", 137 | NotSorted: true, 138 | Numbers: []numberConfig{ 139 | { 140 | Count: 4, 141 | Max: 9, 142 | }, 143 | }, 144 | }, 145 | "euromillions": { 146 | ID: "euromillions", 147 | Name: "EuroMillions", 148 | Location: "Europe", 149 | Enabled: true, 150 | Numbers: []numberConfig{ 151 | { 152 | Count: 5, 153 | Max: 50, 154 | }, 155 | { 156 | Count: 2, 157 | Max: 12, 158 | }, 159 | }, 160 | }, 161 | "loto": { 162 | ID: "loto", 163 | Name: "Loto", 164 | Location: "France", 165 | Numbers: []numberConfig{ 166 | { 167 | Count: 5, 168 | Max: 49, 169 | }, 170 | { 171 | Count: 1, 172 | Max: 10, 173 | }, 174 | }, 175 | }, 176 | "loto6": { 177 | ID: "loto6", 178 | Name: "Loto 6", 179 | Location: "Japan", 180 | Enabled: true, 181 | Numbers: []numberConfig{ 182 | { 183 | Count: 6, 184 | Max: 43, 185 | }, 186 | }, 187 | }, 188 | "loto7": { 189 | ID: "loto7", 190 | Name: "Loto 7", 191 | Location: "Japan", 192 | Numbers: []numberConfig{ 193 | { 194 | Count: 7, 195 | Max: 37, 196 | }, 197 | }, 198 | }, 199 | } 200 | 201 | myGames map[string]game 202 | ) 203 | 204 | func init() { 205 | g, err := loadMyGames() 206 | if err != nil { 207 | g = games 208 | log.Error("loading my games failed").T("error", err) 209 | } 210 | 211 | myGames = g 212 | } 213 | 214 | func loadMyGames() (map[string]game, error) { 215 | myGames := make(map[string]game, len(games)) 216 | if err := app.LocalStorage.Get("myGames", &games); err != nil { 217 | return nil, err 218 | } 219 | 220 | for k := range myGames { 221 | if _, ok := games[k]; !ok { 222 | delete(myGames, k) 223 | } 224 | } 225 | 226 | for k, v := range games { 227 | if old, ok := myGames[k]; ok { 228 | v.Enabled = old.Enabled 229 | } 230 | myGames[k] = v 231 | } 232 | 233 | return myGames, nil 234 | } 235 | 236 | func saveMyGames(g map[string]game) error { 237 | return app.LocalStorage.Set("myGames", g) 238 | } 239 | 240 | func gameList(games map[string]game) []game { 241 | l := make([]game, 0, len(games)) 242 | for _, g := range games { 243 | l = append(l, g) 244 | } 245 | return l 246 | } 247 | 248 | func sortGameList(games []game) { 249 | sort.Slice(games, func(i, j int) bool { 250 | return strings.Compare(games[i].Name, games[j].Name) <= 0 251 | }) 252 | } 253 | 254 | func filterGameList(games []game, filter string) []game { 255 | var f []game 256 | for _, g := range games { 257 | if filter == "" || 258 | strings.Contains( 259 | strings.ToLower(g.Name), 260 | strings.ToLower(filter), 261 | ) || 262 | strings.Contains( 263 | strings.ToLower(g.Location), 264 | strings.ToLower(filter), 265 | ) { 266 | f = append(f, g) 267 | } 268 | } 269 | return f 270 | } 271 | -------------------------------------------------------------------------------- /hello-gcloud-func/README.md: -------------------------------------------------------------------------------- 1 | # hello-gcloud-func 2 | 3 | hello-gcloud-func is a demo that shows how to run a progressive web app created with the [app package](https://github.com/maxence-charriere/go-app) on a [Google Cloud Function](https://cloud.google.com/functions). 4 | 5 | ## Prerequisites 6 | 7 | - Go to the hello-gcloud-function directory: 8 | 9 | ```sh 10 | cd $GOPATH/src/github.com/maxence-charriere/go-app/demo/hello-gcloud-function 11 | ``` 12 | 13 | - [Google Cloud SDK](https://cloud.google.com/sdk) installed on your machine 14 | - A [Google Cloud project](https://console.cloud.google.com/cloud-resource-manager) 15 | - A public [Storage bucket](https://console.cloud.google.com/storage/browser) for hosting static files: 16 | 17 | 1. Create a bucket 18 | 2. Go to `Permissions` tab 19 | 3. Click on `Add members` 20 | 4. In the `New members` input, type `allUsers` 21 | 5. In the `Select a Role` dropdown, choose `Storage/Storage Object Viewer` 22 | 6. Click on `Save` 23 | 7. Click on `ALLOW PUBLIC ACCESS` 24 | 8. In a terminal, set the bucket CORS policies: 25 | 26 | ```sh 27 | gsutil cors set ./infra/google-cloud/cors.json gs://YOUR_BUCKET_NAME 28 | 29 | ``` 30 | 31 | 9. In `hello.go`, replace the handler `RootDir` by your bucket root: 32 | ```go 33 | RootDir: "https://storage.googleapis.com/YOUR_BUCKET_NAME", 34 | ``` 35 | 36 | - [Firebase CLI](https://firebase.google.com/docs/cli) installed on your machine 37 | - Set up Firebase project. Firebase is required in order to have the function operates under a single host and avoid CORS issues. 38 | 39 | 1. Go in `./infra/firebase` 40 | 41 | ```sh 42 | cd ./infra/firebase 43 | 44 | ``` 45 | 46 | 2. Remove all the files 47 | ```sh 48 | rm -r * 49 | ``` 50 | 3. Create a Firebase project: 51 | 52 | ```sh 53 | firebase init 54 | ``` 55 | 56 | When it ask for `associate this project directory with a Firebase project ... Please select an option`, choose either: 57 | 58 | - Add Firebase to an existing Google platform project 59 | - Use an existing project 60 | 61 | See the output below for other questions: 62 | 63 | ``` 64 | hello-gcloud-func/infra/firebase 65 | ▶ firebase init 66 | 67 | ######## #### ######## ######## ######## ### ###### ######## 68 | ## ## ## ## ## ## ## ## ## ## ## 69 | ###### ## ######## ###### ######## ######### ###### ###### 70 | ## ## ## ## ## ## ## ## ## ## ## 71 | ## #### ## ## ######## ######## ## ## ###### ######## 72 | 73 | You're about to initialize a Firebase project in this directory: 74 | 75 | /Users/maxence/dev/src/github.com/maxence-charriere/go-app-demo/hello-gcloud-func/infra/firebase 76 | 77 | ? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your 78 | choices. Hosting: Configure and deploy Firebase Hosting sites 79 | 80 | === Project Setup 81 | 82 | First, let's associate this project directory with a Firebase project. 83 | You can create multiple project aliases by running firebase use --add, 84 | but for now we'll just set up a default project. 85 | 86 | ? Please select an option: Use an existing project 87 | ? Select a default Firebase project for this directory: go-app-demo-42 (go-app-demo) 88 | i Using project go-app-demo-42 (go-app-demo) 89 | 90 | === Hosting Setup 91 | 92 | Your public directory is the folder (relative to your project directory) that 93 | will contain Hosting assets to be uploaded with firebase deploy. If you 94 | have a build process for your assets, use your build's output directory. 95 | 96 | ? What do you want to use as your public directory? public 97 | ? Configure as a single-page app (rewrite all urls to /index.html)? Yes 98 | ✔ Wrote public/index.html 99 | 100 | i Writing configuration info to firebase.json... 101 | i Writing project information to .firebaserc... 102 | i Writing gitignore file to .gitignore... 103 | 104 | ✔ Firebase initialization complete! 105 | ``` 106 | 107 | 4. In `firebase.json`, change the rewrite to make in point to your function: 108 | 109 | ```json 110 | { 111 | "hosting": { 112 | "public": "public", 113 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], 114 | "rewrites": [ 115 | { 116 | "source": "**", 117 | "function": "Hello" 118 | } 119 | ] 120 | } 121 | } 122 | ``` 123 | 124 | 5. Rename `./public/index.html` to `./pubic/index2.html` (hack to make firebase redirect `/`): 125 | 126 | ```sh 127 | mv ./public/index.html ./pubic/index2.html 128 | ``` 129 | 130 | ## Build 131 | 132 | 1. Go back to the hello-gcloud-function directory: 133 | 134 | ```sh 135 | cd $GOPATH/src/github.com/maxence-charriere/go-app/demo/hello-gcloud-function 136 | ``` 137 | 138 | 2. Make sure the `hello` directory is built: 139 | 140 | ```sh 141 | cd ../hello && make build && cd - 142 | ``` 143 | 144 | 3. Copy the hello wasm binary: 145 | 146 | ```sh 147 | cp ../hello/app.wasm . 148 | ``` 149 | 150 | ## Deploy 151 | 152 | The current directory should look like the following: 153 | 154 | ```sh 155 | # github.com/maxence-charriere/go-app/demo/hello-gcloud-func 156 | . 157 | ├── README.md 158 | ├── go.mod 159 | ├── go.sum 160 | ├── hello.go 161 | └── infra 162 | ├── firebase 163 | │ ├── firebase.json 164 | │ └── public 165 | │ └── index2.html 166 | └── google-cloud 167 | └── cors.json 168 | ``` 169 | 170 | 1. Deploy `app.wasm` to the Google Cloud bucket: 171 | 172 | ``` 173 | gsutil \ 174 | -h "Cache-Control:no-cache,max-age=0" \ 175 | -h "Content-Type:application/wasm" \ 176 | cp ./app.wasm gs://YOUR_BUCKET_NAME/app.wasm 177 | ``` 178 | 179 | Setting the `Cache-Control` metadata will prevent Google Cloud Storage to store a version of the file for an hour in its cache. Forgetting to set this will make your PWA stuck with the same app.wasm version for a whole hour. 180 | 181 | The Content-Type metadata is to avoid the default `application/octet-stream` given by Google Cloud Storage. Browsers can't load a `.wasm` file if their mime-type is not `application/wasm`. 182 | 183 | 2. Deploy the Google Cloud Function: 184 | 185 | ```sh 186 | gcloud functions deploy Hello --runtime go113 --trigger-http --project YOUR_PROJECT_ID 187 | ``` 188 | 189 | Answer `y` if it asks for: 190 | 191 | ```sh 192 | API [cloudfunctions.googleapis.com] not enabled on project 193 | [xxx]. Would you like to enable and retry (this will take a 194 | few minutes)? (y/N)? 195 | ``` 196 | 197 | Answer `y` if it asks for: 198 | 199 | ```sh 200 | Allow unauthenticated invocations of new function [Hello]? (y/N)? 201 | ``` 202 | 203 | 3. Deploy Firebase project: 204 | 205 | ```sh 206 | cd ./infra/firebase && firebase deploy && cd - 207 | ``` 208 | 209 | ## Firebase 210 | 211 | Trying to reach the function as it is will result in CORS errors. 212 | You need to use [Firebase](https://firebase.google.com) in order to provide the function under a single host. 213 | 214 | The app should be now be accessible at your Firebase project URL available in the [Firebase consoler](https://console.firebase.google.com) in your project hosting section. 215 | 216 | See the [live demo](https://go-app-demo-42.firebaseapp.com/). 217 | 218 | ## Contribute 219 | 220 | Help to develop the [go-app](https://github.com/maxence-charriere/go-app) package by becoming a sponsor. 221 |