Skip to content

Commit 0fd7e40

Browse files
Merge pull request #1 from kevincobain2000/feature/api
(docs) adds frontend LP
2 parents 44ad89d + efeed65 commit 0fd7e40

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+9062
-190
lines changed

.air.toml

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# .air.conf
2+
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
3+
4+
# Working directory
5+
# . or absolute path, please note that the directories following must be under root.
6+
root = "."
7+
tmp_dir = "tmp"
8+
9+
[build]
10+
# Just plain old shell command. You could use `make` as well.
11+
cmd = "go mod tidy && go build -o ./tmp/main api/main.go"
12+
# Binary file yields from `cmd`.
13+
bin = "tmp/main"
14+
# Customize binary.
15+
# allow cors for astro
16+
full_bin = "PP_USER=air ./tmp/main --cors=4321"
17+
# Watch these filename extensions.
18+
include_ext = ["go", "tpl", "tmpl", "html", "env", "conf"]
19+
# Ignore these filename extensions or directories.
20+
exclude_dir = ["assets", "tmp", "vendor", "dist", "api/pkg/frontend"]
21+
# Watch these directories if you specified.
22+
include_dir = []
23+
# Exclude files.
24+
exclude_file = []
25+
# It's not necessary to trigger build each time file changes if it's too frequent.
26+
delay = 1000 # ms
27+
# Stop to run old binary when build errors occur.
28+
stop_on_error = true
29+
# This log file places in your tmp_dir.
30+
log = "air_errors.log"
31+
32+
[log]
33+
# Show log time
34+
time = false
35+
36+
[color]
37+
# Customize each part's color. If no color found, use the raw app log.
38+
main = "magenta"
39+
watcher = "cyan"
40+
build = "yellow"
41+
runner = "green"
42+
43+
[misc]
44+
# Delete tmp directory on exit
45+
clean_on_exit = true

.github/workflows/coveritup.yml

+18
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ jobs:
2222
- uses: kevincobain2000/action-gobrew@v2
2323
with:
2424
version: ${{ matrix.go-version }}
25+
- name: Setup Node.js ${{ matrix.node-versions }}
26+
uses: actions/setup-node@v2
27+
with:
28+
node-version: 20
2529

2630
- name: Install Tools
2731
run: |
@@ -31,6 +35,20 @@ jobs:
3135
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
3236
curl -sLk https://raw.githubusercontent.com/kevincobain2000/cover-totalizer/master/install.sh | sh
3337
38+
- name: NPM Install
39+
uses: kevincobain2000/action-coveritup@v2
40+
with:
41+
type: npm-install-time
42+
command: cd api/pkg/frontend; npm install
43+
record: runtime
44+
45+
- name: NPM Build
46+
uses: kevincobain2000/action-coveritup@v2
47+
with:
48+
type: npm-build-time
49+
command: cd api/pkg/frontend; npm run build
50+
record: runtime
51+
3452
- run: go mod tidy
3553
- name: Lint Errors
3654
uses: kevincobain2000/action-coveritup@v2

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ bin/
2121
main
2222
.DS_Store
2323
output.svg
24+
node_modules/

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<h1 align="center">
2-
SVG - Circle & Bar Progress generator
2+
SVG - Circle, Bar & Battery progress generator
33
<br>
44
in Golang.
55
<br>
@@ -24,6 +24,8 @@
2424

2525
**Bar Progress:** Generate pure SVG bar progress bar.
2626

27+
**Battery Progress:** Generate pure SVG battery progress bar.
28+
2729
**Supports Captions:** Add captions horizontally or vertically.
2830

2931
**Customizable:** Customize with various color, width, height, background and caption options.
@@ -66,14 +68,13 @@ import (
6668
func main() {
6769
circular, _ := gps.NewCircular(func(o *gps.CircularOptions) error {
6870
o.Progress = 97
69-
o.Size = 200
71+
o.CircleSize = 200
7072
o.CircleWidth = 16
7173
o.ProgressWidth = 16
7274
o.CircleColor = "#e0e0e0"
7375
o.ProgressColor = "#76e5b1"
7476
o.TextColor = "#6bdba7"
75-
o.TextSize = 52
76-
o.ShowPercentage = true
77+
o.TextSize = 52true
7778
o.BackgroundColor = ""
7879
o.Caption = ""
7980
o.CaptionPos = "bottom"
@@ -104,8 +105,7 @@ func main() {
104105
o.Height = 50
105106
o.ProgressColor = "#76e5b1"
106107
o.TextColor = "#6bdba7"
107-
o.TextSize = 20
108-
o.ShowPercentage = true
108+
o.TextSize = 20true
109109
o.Caption = ""
110110
o.CaptionSize = 16
111111
o.CaptionColor = "#000000"

api/main.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
6+
"github.com/kevincobain2000/go-progress-svg/api/pkg"
7+
)
8+
9+
type Flags struct {
10+
host string
11+
port string
12+
cors string
13+
baseUrl string
14+
}
15+
16+
var f Flags
17+
18+
func main() {
19+
SetupFlags()
20+
pkg.StartEcho(pkg.NewEcho(f.baseUrl, f.cors), f.host, f.port)
21+
}
22+
23+
func SetupFlags() {
24+
flag.StringVar(&f.host, "host", "localhost", "host to serve")
25+
flag.StringVar(&f.port, "port", "3003", "port to serve")
26+
flag.StringVar(&f.cors, "cors", "", "cors port to allow")
27+
flag.StringVar(&f.baseUrl, "base-url", "/", "base url with slash")
28+
flag.Parse()
29+
30+
}

api/pkg/api_handler.go

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package pkg
2+
3+
import (
4+
"net/http"
5+
6+
gps "github.com/kevincobain2000/go-progress-svg"
7+
"github.com/labstack/echo/v4"
8+
"github.com/mcuadros/go-defaults"
9+
)
10+
11+
type APIHandler struct {
12+
}
13+
14+
func NewAPIHandler() *APIHandler {
15+
return &APIHandler{}
16+
}
17+
18+
type APIRequest struct {
19+
Style string `json:"style" query:"style" default:"circle" validate:"required,ascii,oneof=circle battery bar" message:"style is required"`
20+
21+
// common on all styles
22+
Progress int `json:"progress" query:"progress" default:"1" validate:"required,min=0,max=100" message:"progress is required"`
23+
24+
// only circle style
25+
CircleSize int `json:"size" query:"size" default:"100" validate:"required,min=50,max=500" message:"size is required"`
26+
CircleWidth int `json:"circle_width" query:"circle_width" default:"15" validate:"required,min=1,max=200" message:"circle_width is required"`
27+
ProgressWidth int `json:"progress_width" query:"progress_width" default:"15" validate:"required,min=1,max=50" message:"progress_width is required"`
28+
CircleColor string `json:"circle_color" query:"circle_color" default:"e0e0e0" validate:"required" message:"circle_color is required"`
29+
30+
// circle style
31+
ProgressColor string `json:"progress_color" query:"progress_color" default:"76e5b1" validate:"required" message:"progress_color is required"`
32+
TextColor string `json:"text_color" query:"text_color" default:"6bdba7" validate:"required" message:"text_color is required"`
33+
TextSize int `json:"text_size" query:"text_size" default:"52" validate:"required,min=10,max=100" message:"text_size is required"`
34+
35+
BackgroundColor string `json:"background_color" query:"background_color" default:"e0e0e0" validate:"required" message:"background_color is required"`
36+
CaptionSize int `json:"caption_size" query:"caption_size" default:"25" validate:"required,min=2,max=100" message:"caption_size is required"`
37+
CaptionColor string `json:"caption_color" query:"caption_color" default:"000000" validate:"required" message:"caption_color is required"`
38+
SegmentCount int `json:"segment_count" query:"segment_count" default:"1" validate:"min=0,max=100" message:"segment_count min 0 and max 100"`
39+
SegmentGap int `json:"segment_gap" query:"segment_gap" default:"0" validate:"min=0,max=10" message:"segment_gap min 0 and max 10"`
40+
Caption string `json:"caption" query:"caption" default:"" validate:"ascii,min=0,max=20" message:"caption min 0 and max 20"`
41+
CornerRadius int `json:"corner_radius" query:"corner_radius" default:"10" validate:"required,min=1,max=50" message:"corner_radius is required"`
42+
43+
// only bar style
44+
Width int `json:"width" query:"width" default:"200" validate:"required,min=50,max=500" message:"width is required"`
45+
Height int `json:"height" query:"height" default:"20" validate:"required,min=20,max=500" message:"height is required"`
46+
}
47+
48+
func (h *APIHandler) Get(c echo.Context) error {
49+
req := new(APIRequest)
50+
if err := BindRequest(c, req); err != nil {
51+
return echo.NewHTTPError(http.StatusUnprocessableEntity, err)
52+
}
53+
defaults.SetDefaults(req)
54+
msgs, err := ValidateRequest(req)
55+
if err != nil {
56+
return echo.NewHTTPError(http.StatusUnprocessableEntity, msgs)
57+
}
58+
59+
if req.Style == "circle" {
60+
circular, err := gps.NewCircular(func(o *gps.CircularOptions) error {
61+
o.Progress = req.Progress
62+
o.CircleSize = req.CircleSize
63+
o.CircleWidth = req.CircleWidth
64+
o.ProgressWidth = req.ProgressWidth
65+
o.CircleColor = "#" + req.CircleColor
66+
o.ProgressColor = "#" + req.ProgressColor
67+
o.TextColor = "#" + req.TextColor
68+
o.TextSize = req.TextSize
69+
o.BackgroundColor = "#" + req.BackgroundColor
70+
o.Caption = req.Caption
71+
o.CaptionSize = req.CaptionSize
72+
o.CaptionColor = "#" + req.CaptionColor
73+
o.SegmentCount = req.SegmentCount
74+
o.SegmentGap = float64(req.SegmentGap)
75+
76+
return nil
77+
})
78+
if err != nil {
79+
return echo.NewHTTPError(http.StatusInternalServerError, err)
80+
}
81+
content := circular.SVG()
82+
SetHeadersResponseSvg(c.Response().Header())
83+
return c.Blob(http.StatusOK, "image/svg+xml", []byte(content))
84+
}
85+
86+
if req.Style == "bar" {
87+
bar, err := gps.NewBar(func(o *gps.BarOptions) error {
88+
o.Progress = req.Progress
89+
o.Caption = req.Caption
90+
o.Width = req.Width
91+
o.Height = req.Height
92+
o.ProgressColor = "#" + req.ProgressColor
93+
o.TextColor = "#" + req.TextColor
94+
o.TextSize = req.TextSize
95+
o.Caption = req.Caption
96+
o.CaptionSize = req.CaptionSize
97+
o.CaptionColor = "#" + req.CaptionColor
98+
o.BackgroundColor = "#" + req.BackgroundColor
99+
o.CornerRadius = req.CornerRadius
100+
return nil
101+
})
102+
if err != nil {
103+
return echo.NewHTTPError(http.StatusInternalServerError, err)
104+
}
105+
content := bar.SVG()
106+
SetHeadersResponseSvg(c.Response().Header())
107+
return c.Blob(http.StatusOK, "image/svg+xml", []byte(content))
108+
}
109+
110+
if req.Style == "battery" {
111+
battery, err := gps.NewBattery(func(o *gps.BatteryOptions) error {
112+
o.Progress = req.Progress
113+
o.Caption = req.Caption
114+
o.Width = req.Width
115+
o.Height = req.Height
116+
o.ProgressColor = "#" + req.ProgressColor
117+
o.TextColor = "#" + req.TextColor
118+
o.TextSize = req.TextSize
119+
o.Caption = req.Caption
120+
o.CaptionSize = req.CaptionSize
121+
o.CaptionColor = "#" + req.CaptionColor
122+
o.BackgroundColor = "#" + req.BackgroundColor
123+
o.CornerRadius = req.CornerRadius
124+
return nil
125+
})
126+
if err != nil {
127+
return echo.NewHTTPError(http.StatusInternalServerError, err)
128+
}
129+
content := battery.SVG()
130+
SetHeadersResponseSvg(c.Response().Header())
131+
return c.Blob(http.StatusOK, "image/svg+xml", []byte(content))
132+
}
133+
return nil
134+
}

api/pkg/assets_handler.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package pkg
2+
3+
import (
4+
"embed"
5+
"fmt"
6+
"net/http"
7+
"os"
8+
9+
"github.com/labstack/echo/v4"
10+
)
11+
12+
type AssetsHandler struct {
13+
filename string
14+
publicDir embed.FS
15+
}
16+
17+
func NewAssetsHandler(publicDir embed.FS, filename string) *AssetsHandler {
18+
return &AssetsHandler{
19+
publicDir: publicDir,
20+
filename: filename,
21+
}
22+
}
23+
24+
func (h *AssetsHandler) GetPlain(c echo.Context) error {
25+
filename := fmt.Sprintf("%s/%s", DIST_DIR, h.filename)
26+
content, err := h.publicDir.ReadFile(filename)
27+
if err != nil {
28+
return echo.NewHTTPError(http.StatusNotFound, "Not Found")
29+
}
30+
return ResponsePlain(c, content, "0")
31+
}
32+
func (h *AssetsHandler) GetICO(c echo.Context) error {
33+
filename := fmt.Sprintf("%s/%s", DIST_DIR, h.filename)
34+
content, err := h.publicDir.ReadFile(filename)
35+
if err != nil {
36+
return echo.NewHTTPError(http.StatusNotFound, "Not Found")
37+
}
38+
SetHeadersResponsePNG(c.Response().Header())
39+
return c.Blob(http.StatusOK, "image/x-icon", content)
40+
}
41+
42+
func (h *AssetsHandler) GetHTML(c echo.Context) error {
43+
filename := fmt.Sprintf("%s/%s", DIST_DIR, h.filename)
44+
content, err := h.publicDir.ReadFile(filename)
45+
if err != nil {
46+
return c.String(http.StatusOK, os.Getenv("VERSION"))
47+
}
48+
return ResponseHTML(c, content, "0")
49+
}

0 commit comments

Comments
 (0)