Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(docs) adds frontend LP #1

Merged
merged 2 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# .air.conf
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format

# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"

[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go mod tidy && go build -o ./tmp/main api/main.go"
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary.
# allow cors for astro
full_bin = "PP_USER=air ./tmp/main --cors=4321"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html", "env", "conf"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor", "dist", "api/pkg/frontend"]
# Watch these directories if you specified.
include_dir = []
# Exclude files.
exclude_file = []
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop to run old binary when build errors occur.
stop_on_error = true
# This log file places in your tmp_dir.
log = "air_errors.log"

[log]
# Show log time
time = false

[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

[misc]
# Delete tmp directory on exit
clean_on_exit = true
18 changes: 18 additions & 0 deletions .github/workflows/coveritup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ jobs:
- uses: kevincobain2000/action-gobrew@v2
with:
version: ${{ matrix.go-version }}
- name: Setup Node.js ${{ matrix.node-versions }}
uses: actions/setup-node@v2
with:
node-version: 20

- name: Install Tools
run: |
Expand All @@ -31,6 +35,20 @@ jobs:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
curl -sLk https://raw.githubusercontent.com/kevincobain2000/cover-totalizer/master/install.sh | sh

- name: NPM Install
uses: kevincobain2000/action-coveritup@v2
with:
type: npm-install-time
command: cd api/pkg/frontend; npm install
record: runtime

- name: NPM Build
uses: kevincobain2000/action-coveritup@v2
with:
type: npm-build-time
command: cd api/pkg/frontend; npm run build
record: runtime

- run: go mod tidy
- name: Lint Errors
uses: kevincobain2000/action-coveritup@v2
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ bin/
main
.DS_Store
output.svg
node_modules/
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<h1 align="center">
SVG - Circle & Bar Progress generator
SVG - Circle, Bar & Battery progress generator
<br>
in Golang.
<br>
Expand All @@ -24,6 +24,8 @@

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

**Battery Progress:** Generate pure SVG battery progress bar.

**Supports Captions:** Add captions horizontally or vertically.

**Customizable:** Customize with various color, width, height, background and caption options.
Expand Down Expand Up @@ -66,14 +68,13 @@ import (
func main() {
circular, _ := gps.NewCircular(func(o *gps.CircularOptions) error {
o.Progress = 97
o.Size = 200
o.CircleSize = 200
o.CircleWidth = 16
o.ProgressWidth = 16
o.CircleColor = "#e0e0e0"
o.ProgressColor = "#76e5b1"
o.TextColor = "#6bdba7"
o.TextSize = 52
o.ShowPercentage = true
o.TextSize = 52true
o.BackgroundColor = ""
o.Caption = ""
o.CaptionPos = "bottom"
Expand Down Expand Up @@ -104,8 +105,7 @@ func main() {
o.Height = 50
o.ProgressColor = "#76e5b1"
o.TextColor = "#6bdba7"
o.TextSize = 20
o.ShowPercentage = true
o.TextSize = 20true
o.Caption = ""
o.CaptionSize = 16
o.CaptionColor = "#000000"
Expand Down
30 changes: 30 additions & 0 deletions api/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"flag"

"github.com/kevincobain2000/go-progress-svg/api/pkg"
)

type Flags struct {
host string
port string
cors string
baseUrl string
}

var f Flags

func main() {
SetupFlags()
pkg.StartEcho(pkg.NewEcho(f.baseUrl, f.cors), f.host, f.port)
}

func SetupFlags() {
flag.StringVar(&f.host, "host", "localhost", "host to serve")
flag.StringVar(&f.port, "port", "3003", "port to serve")
flag.StringVar(&f.cors, "cors", "", "cors port to allow")
flag.StringVar(&f.baseUrl, "base-url", "/", "base url with slash")
flag.Parse()

}
134 changes: 134 additions & 0 deletions api/pkg/api_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package pkg

import (
"net/http"

gps "github.com/kevincobain2000/go-progress-svg"
"github.com/labstack/echo/v4"
"github.com/mcuadros/go-defaults"
)

type APIHandler struct {
}

func NewAPIHandler() *APIHandler {
return &APIHandler{}
}

type APIRequest struct {
Style string `json:"style" query:"style" default:"circle" validate:"required,ascii,oneof=circle battery bar" message:"style is required"`

// common on all styles
Progress int `json:"progress" query:"progress" default:"1" validate:"required,min=0,max=100" message:"progress is required"`

// only circle style
CircleSize int `json:"size" query:"size" default:"100" validate:"required,min=50,max=500" message:"size is required"`
CircleWidth int `json:"circle_width" query:"circle_width" default:"15" validate:"required,min=1,max=200" message:"circle_width is required"`
ProgressWidth int `json:"progress_width" query:"progress_width" default:"15" validate:"required,min=1,max=50" message:"progress_width is required"`
CircleColor string `json:"circle_color" query:"circle_color" default:"e0e0e0" validate:"required" message:"circle_color is required"`

// circle style
ProgressColor string `json:"progress_color" query:"progress_color" default:"76e5b1" validate:"required" message:"progress_color is required"`
TextColor string `json:"text_color" query:"text_color" default:"6bdba7" validate:"required" message:"text_color is required"`
TextSize int `json:"text_size" query:"text_size" default:"52" validate:"required,min=10,max=100" message:"text_size is required"`

BackgroundColor string `json:"background_color" query:"background_color" default:"e0e0e0" validate:"required" message:"background_color is required"`
CaptionSize int `json:"caption_size" query:"caption_size" default:"25" validate:"required,min=2,max=100" message:"caption_size is required"`
CaptionColor string `json:"caption_color" query:"caption_color" default:"000000" validate:"required" message:"caption_color is required"`
SegmentCount int `json:"segment_count" query:"segment_count" default:"1" validate:"min=0,max=100" message:"segment_count min 0 and max 100"`
SegmentGap int `json:"segment_gap" query:"segment_gap" default:"0" validate:"min=0,max=10" message:"segment_gap min 0 and max 10"`
Caption string `json:"caption" query:"caption" default:"" validate:"ascii,min=0,max=20" message:"caption min 0 and max 20"`
CornerRadius int `json:"corner_radius" query:"corner_radius" default:"10" validate:"required,min=1,max=50" message:"corner_radius is required"`

// only bar style
Width int `json:"width" query:"width" default:"200" validate:"required,min=50,max=500" message:"width is required"`
Height int `json:"height" query:"height" default:"20" validate:"required,min=20,max=500" message:"height is required"`
}

func (h *APIHandler) Get(c echo.Context) error {
req := new(APIRequest)
if err := BindRequest(c, req); err != nil {
return echo.NewHTTPError(http.StatusUnprocessableEntity, err)
}
defaults.SetDefaults(req)
msgs, err := ValidateRequest(req)
if err != nil {
return echo.NewHTTPError(http.StatusUnprocessableEntity, msgs)
}

if req.Style == "circle" {
circular, err := gps.NewCircular(func(o *gps.CircularOptions) error {
o.Progress = req.Progress
o.CircleSize = req.CircleSize
o.CircleWidth = req.CircleWidth
o.ProgressWidth = req.ProgressWidth
o.CircleColor = "#" + req.CircleColor
o.ProgressColor = "#" + req.ProgressColor
o.TextColor = "#" + req.TextColor
o.TextSize = req.TextSize
o.BackgroundColor = "#" + req.BackgroundColor
o.Caption = req.Caption
o.CaptionSize = req.CaptionSize
o.CaptionColor = "#" + req.CaptionColor
o.SegmentCount = req.SegmentCount
o.SegmentGap = float64(req.SegmentGap)

return nil
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
content := circular.SVG()
SetHeadersResponseSvg(c.Response().Header())
return c.Blob(http.StatusOK, "image/svg+xml", []byte(content))
}

if req.Style == "bar" {
bar, err := gps.NewBar(func(o *gps.BarOptions) error {
o.Progress = req.Progress
o.Caption = req.Caption
o.Width = req.Width
o.Height = req.Height
o.ProgressColor = "#" + req.ProgressColor
o.TextColor = "#" + req.TextColor
o.TextSize = req.TextSize
o.Caption = req.Caption
o.CaptionSize = req.CaptionSize
o.CaptionColor = "#" + req.CaptionColor
o.BackgroundColor = "#" + req.BackgroundColor
o.CornerRadius = req.CornerRadius
return nil
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
content := bar.SVG()
SetHeadersResponseSvg(c.Response().Header())
return c.Blob(http.StatusOK, "image/svg+xml", []byte(content))
}

if req.Style == "battery" {
battery, err := gps.NewBattery(func(o *gps.BatteryOptions) error {
o.Progress = req.Progress
o.Caption = req.Caption
o.Width = req.Width
o.Height = req.Height
o.ProgressColor = "#" + req.ProgressColor
o.TextColor = "#" + req.TextColor
o.TextSize = req.TextSize
o.Caption = req.Caption
o.CaptionSize = req.CaptionSize
o.CaptionColor = "#" + req.CaptionColor
o.BackgroundColor = "#" + req.BackgroundColor
o.CornerRadius = req.CornerRadius
return nil
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
content := battery.SVG()
SetHeadersResponseSvg(c.Response().Header())
return c.Blob(http.StatusOK, "image/svg+xml", []byte(content))
}
return nil
}
49 changes: 49 additions & 0 deletions api/pkg/assets_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package pkg

import (
"embed"
"fmt"
"net/http"
"os"

"github.com/labstack/echo/v4"
)

type AssetsHandler struct {
filename string
publicDir embed.FS
}

func NewAssetsHandler(publicDir embed.FS, filename string) *AssetsHandler {
return &AssetsHandler{
publicDir: publicDir,
filename: filename,
}
}

func (h *AssetsHandler) GetPlain(c echo.Context) error {
filename := fmt.Sprintf("%s/%s", DIST_DIR, h.filename)
content, err := h.publicDir.ReadFile(filename)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, "Not Found")
}
return ResponsePlain(c, content, "0")
}
func (h *AssetsHandler) GetICO(c echo.Context) error {
filename := fmt.Sprintf("%s/%s", DIST_DIR, h.filename)
content, err := h.publicDir.ReadFile(filename)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, "Not Found")
}
SetHeadersResponsePNG(c.Response().Header())
return c.Blob(http.StatusOK, "image/x-icon", content)
}

func (h *AssetsHandler) GetHTML(c echo.Context) error {
filename := fmt.Sprintf("%s/%s", DIST_DIR, h.filename)
content, err := h.publicDir.ReadFile(filename)
if err != nil {
return c.String(http.StatusOK, os.Getenv("VERSION"))
}
return ResponseHTML(c, content, "0")
}
Loading
Loading