diff --git a/backend/czech-clubs-logos-api b/backend/czech-clubs-logos-api
new file mode 100644
index 0000000..8adbcf6
Binary files /dev/null and b/backend/czech-clubs-logos-api differ
diff --git a/backend/go.mod b/backend/go.mod
index 6927aeb..5f36217 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -7,6 +7,8 @@ require (
github.com/gin-gonic/gin v1.9.1
github.com/google/uuid v1.5.0
github.com/mattn/go-sqlite3 v1.14.19
+ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
+ github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
)
require (
@@ -31,6 +33,7 @@ require (
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
+ golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
diff --git a/backend/go.sum b/backend/go.sum
index e54c855..a7210f5 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -63,6 +63,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
+github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
+github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
+github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -82,14 +86,18 @@ golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
+golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
diff --git a/backend/handlers.go b/backend/handlers.go
index 37f7f2a..e593146 100644
--- a/backend/handlers.go
+++ b/backend/handlers.go
@@ -7,6 +7,7 @@ import (
"net/http"
"os"
"path/filepath"
+ "strconv"
"strings"
"time"
@@ -369,13 +370,43 @@ func getLogoWithMetadata(c *gin.Context) {
// List all logos
func listLogos(c *gin.Context) {
- rows, err := db.Query(`
- SELECT id, club_name, club_city, club_type, club_website,
- has_svg, has_png, primary_format,
- created_at, updated_at
- FROM logos
- ORDER BY club_name
- `)
+ q := strings.TrimSpace(c.Query("q"))
+ sortParam := c.DefaultQuery("sort", "name")
+ limitStr := c.Query("limit")
+ pageStr := c.Query("page")
+
+ base := "SELECT id, club_name, club_city, club_type, club_website, has_svg, has_png, primary_format, created_at, updated_at FROM logos"
+ where := ""
+ args := []interface{}{}
+ if q != "" {
+ where = " WHERE LOWER(club_name) LIKE ? OR LOWER(club_city) LIKE ? OR id LIKE ?"
+ like := "%" + strings.ToLower(q) + "%"
+ args = append(args, like, like, "%"+q+"%")
+ }
+ order := " ORDER BY club_name"
+ if sortParam == "recent" {
+ order = " ORDER BY datetime(updated_at) DESC, datetime(created_at) DESC"
+ }
+ limitClause := ""
+ if limitStr != "" {
+ if limit, err := strconv.Atoi(limitStr); err == nil && limit > 0 {
+ limitClause = " LIMIT ?"
+ args = append(args, limit)
+ if pageStr != "" {
+ if page, err := strconv.Atoi(pageStr); err == nil {
+ if page < 1 {
+ page = 1
+ }
+ offset := (page - 1) * limit
+ limitClause += " OFFSET ?"
+ args = append(args, offset)
+ }
+ }
+ }
+ }
+
+ query := base + where + order + limitClause
+ rows, err := db.Query(query, args...)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
return
@@ -392,8 +423,7 @@ func listLogos(c *gin.Context) {
for rows.Next() {
var logo LogoMetadata
var hasSVG, hasPNG int
-
- err := rows.Scan(
+ if err := rows.Scan(
&logo.ID,
&logo.ClubName,
&logo.ClubCity,
@@ -404,14 +434,12 @@ func listLogos(c *gin.Context) {
&logo.PrimaryFormat,
&logo.CreatedAt,
&logo.UpdatedAt,
- )
- if err != nil {
+ ); err != nil {
continue
}
logo.HasSVG = hasSVG == 1
logo.HasPNG = hasPNG == 1
-
if logo.HasPNG {
logo.LogoURL = fmt.Sprintf("%s/logos/%s?format=png", baseURL, logo.ID)
} else if logo.HasSVG {
@@ -424,6 +452,31 @@ func listLogos(c *gin.Context) {
c.JSON(http.StatusOK, logos)
}
+func deleteLogo(c *gin.Context) {
+ id := c.Param("id")
+ if id == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "logo ID is required"})
+ return
+ }
+ if _, err := uuid.Parse(id); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "invalid UUID format"})
+ return
+ }
+
+ _, err := db.Exec("DELETE FROM logos WHERE id = ?", id)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
+ return
+ }
+
+ pngPath := filepath.Join("./logos/png", id+".png")
+ svgPath := filepath.Join("./logos/svg", id+".svg")
+ os.Remove(pngPath)
+ os.Remove(svgPath)
+
+ c.JSON(http.StatusOK, gin.H{"success": true, "id": id})
+}
+
func uploadLogo(c *gin.Context) {
id := c.Param("id")
if id == "" {
diff --git a/backend/image_converter.go b/backend/image_converter.go
index b8dc958..610c693 100644
--- a/backend/image_converter.go
+++ b/backend/image_converter.go
@@ -9,6 +9,9 @@ import (
"os"
"os/exec"
"path/filepath"
+
+ "github.com/srwiley/oksvg"
+ "github.com/srwiley/rasterx"
)
// ConvertSVGToPNG converts an SVG file to PNG format
@@ -24,8 +27,12 @@ func ConvertSVGToPNG(svgPath, pngPath string, width int) error {
return nil
}
- // If no converter available, copy SVG as fallback and log warning
- return fmt.Errorf("no SVG converter available (install ImageMagick or Inkscape)")
+ // Try pure-Go conversion
+ if err := convertWithGoRenderer(svgPath, pngPath, width); err == nil {
+ return nil
+ }
+
+ return fmt.Errorf("no SVG converter available (install ImageMagick or Inkscape, or ensure Go renderer deps)")
}
// ConvertPDFToPNG converts a PDF file to PNG format
@@ -39,14 +46,14 @@ func ConvertPDFToPNG(pdfPath, pngPath string, width int) error {
fmt.Sprintf("%s[0]", pdfPath), // Only first page
pngPath,
)
-
+
var stderr bytes.Buffer
cmd.Stderr = &stderr
-
+
if err := cmd.Run(); err != nil {
return fmt.Errorf("PDF conversion failed (install ImageMagick and Ghostscript): %v - %s", err, stderr.String())
}
-
+
return nil
}
@@ -58,14 +65,14 @@ func convertWithImageMagick(svgPath, pngPath string, width int) error {
svgPath,
pngPath,
)
-
+
var stderr bytes.Buffer
cmd.Stderr = &stderr
-
+
if err := cmd.Run(); err != nil {
return fmt.Errorf("imagemagick conversion failed: %v - %s", err, stderr.String())
}
-
+
return nil
}
@@ -76,10 +83,10 @@ func convertWithInkscape(svgPath, pngPath string, width int) error {
fmt.Sprintf("--export-width=%d", width),
svgPath,
)
-
+
var stderr bytes.Buffer
cmd.Stderr = &stderr
-
+
if err := cmd.Run(); err != nil {
return fmt.Errorf("inkscape conversion failed: %v - %s", err, stderr.String())
}
@@ -87,6 +94,56 @@ func convertWithInkscape(svgPath, pngPath string, width int) error {
return nil
}
+func convertWithGoRenderer(svgPath, pngPath string, width int) error {
+ f, err := os.Open(svgPath)
+ if err != nil {
+ return fmt.Errorf("open svg: %w", err)
+ }
+ defer f.Close()
+
+ icon, err := oksvg.ReadIconStream(f)
+ if err != nil {
+ return fmt.Errorf("parse svg: %w", err)
+ }
+
+ vb := icon.ViewBox
+ targetW := width
+ if targetW <= 0 {
+ targetW = int(vb.W)
+ if targetW <= 0 {
+ targetW = 512
+ }
+ }
+ var targetH int
+ if vb.W != 0 {
+ targetH = int(float64(targetW) * (vb.H / vb.W))
+ } else {
+ targetH = targetW
+ }
+ if targetH <= 0 {
+ targetH = targetW
+ }
+
+ icon.SetTarget(0, 0, float64(targetW), float64(targetH))
+
+ rgba := image.NewRGBA(image.Rect(0, 0, targetW, targetH))
+ scanner := rasterx.NewScannerGV(targetW, targetH, rgba, rgba.Bounds())
+ raster := rasterx.NewDasher(targetW, targetH, scanner)
+ icon.Draw(raster, 1.0)
+
+ out, err := os.Create(pngPath)
+ if err != nil {
+ return fmt.Errorf("create png: %w", err)
+ }
+ defer out.Close()
+
+ if err := png.Encode(out, rgba); err != nil {
+ os.Remove(pngPath)
+ return fmt.Errorf("encode png: %w", err)
+ }
+ return nil
+}
+
// OptimizePNG optimizes a PNG file (basic implementation)
func OptimizePNG(pngPath string) error {
// Open the file
diff --git a/backend/main.go b/backend/main.go
index 941b0f6..161358a 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -88,6 +88,7 @@ func setupRoutes(r *gin.Engine) {
logos.GET("/:id", getLogo)
logos.GET("/:id/json", getLogoWithMetadata)
logos.POST("/:id", uploadLogo)
+ logos.DELETE("/:id", deleteLogo)
}
}
diff --git a/frontend/index.html b/frontend/index.html
index 281ed7b..b0e3632 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -15,6 +15,7 @@
🇨🇿 České Kluby Loga
diff --git a/frontend/logos.html b/frontend/logos.html
new file mode 100644
index 0000000..1e8ec96
--- /dev/null
+++ b/frontend/logos.html
@@ -0,0 +1,67 @@
+
+
+
+
+
+ Všechna Loga - České Kluby Loga API
+
+
+
+
+
+
+
+
+
+
+
20 log na stránku • řazeno: nejnovější
+
+
+
+
+
+
⚽
+
Žádná loga nenalezena
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/node_modules/.bin/autoprefixer.cmd b/frontend/node_modules/.bin/autoprefixer.cmd
index 7ed417d..4bb03e2 100644
--- a/frontend/node_modules/.bin/autoprefixer.cmd
+++ b/frontend/node_modules/.bin/autoprefixer.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\autoprefixer\bin\autoprefixer" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\autoprefixer\bin\autoprefixer" %*
diff --git a/frontend/node_modules/.bin/baseline-browser-mapping.cmd b/frontend/node_modules/.bin/baseline-browser-mapping.cmd
index 7db3642..e8ced87 100644
--- a/frontend/node_modules/.bin/baseline-browser-mapping.cmd
+++ b/frontend/node_modules/.bin/baseline-browser-mapping.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\baseline-browser-mapping\dist\cli.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\baseline-browser-mapping\dist\cli.js" %*
diff --git a/frontend/node_modules/.bin/browserslist.cmd b/frontend/node_modules/.bin/browserslist.cmd
index f93c251..e2a0d3f 100644
--- a/frontend/node_modules/.bin/browserslist.cmd
+++ b/frontend/node_modules/.bin/browserslist.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\browserslist\cli.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\browserslist\cli.js" %*
diff --git a/frontend/node_modules/.bin/cssesc.cmd b/frontend/node_modules/.bin/cssesc.cmd
index b560b42..a79d95b 100644
--- a/frontend/node_modules/.bin/cssesc.cmd
+++ b/frontend/node_modules/.bin/cssesc.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\cssesc\bin\cssesc" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\cssesc\bin\cssesc" %*
diff --git a/frontend/node_modules/.bin/esbuild.cmd b/frontend/node_modules/.bin/esbuild.cmd
index cc920c5..d368539 100644
--- a/frontend/node_modules/.bin/esbuild.cmd
+++ b/frontend/node_modules/.bin/esbuild.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\esbuild\bin\esbuild" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\esbuild\bin\esbuild" %*
diff --git a/frontend/node_modules/.bin/glob.cmd b/frontend/node_modules/.bin/glob.cmd
index 3c1d48a..2acbf75 100644
--- a/frontend/node_modules/.bin/glob.cmd
+++ b/frontend/node_modules/.bin/glob.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\glob\dist\esm\bin.mjs" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\glob\dist\esm\bin.mjs" %*
diff --git a/frontend/node_modules/.bin/jiti.cmd b/frontend/node_modules/.bin/jiti.cmd
index e54ba7d..e947fc6 100644
--- a/frontend/node_modules/.bin/jiti.cmd
+++ b/frontend/node_modules/.bin/jiti.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\jiti\bin\jiti.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\jiti\bin\jiti.js" %*
diff --git a/frontend/node_modules/.bin/nanoid.cmd b/frontend/node_modules/.bin/nanoid.cmd
index 9c40107..601a2c8 100644
--- a/frontend/node_modules/.bin/nanoid.cmd
+++ b/frontend/node_modules/.bin/nanoid.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nanoid\bin\nanoid.cjs" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nanoid\bin\nanoid.cjs" %*
diff --git a/frontend/node_modules/.bin/node-which.cmd b/frontend/node_modules/.bin/node-which.cmd
index 8738aed..7eeb316 100644
--- a/frontend/node_modules/.bin/node-which.cmd
+++ b/frontend/node_modules/.bin/node-which.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\which\bin\node-which" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\which\bin\node-which" %*
diff --git a/frontend/node_modules/.bin/resolve.cmd b/frontend/node_modules/.bin/resolve.cmd
index 1a017c4..6358238 100644
--- a/frontend/node_modules/.bin/resolve.cmd
+++ b/frontend/node_modules/.bin/resolve.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\resolve\bin\resolve" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\resolve\bin\resolve" %*
diff --git a/frontend/node_modules/.bin/rollup.cmd b/frontend/node_modules/.bin/rollup.cmd
index b3f110b..d9a0a35 100644
--- a/frontend/node_modules/.bin/rollup.cmd
+++ b/frontend/node_modules/.bin/rollup.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rollup\dist\bin\rollup" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rollup\dist\bin\rollup" %*
diff --git a/frontend/node_modules/.bin/sucrase-node.cmd b/frontend/node_modules/.bin/sucrase-node.cmd
index 7319f3a..60bf079 100644
--- a/frontend/node_modules/.bin/sucrase-node.cmd
+++ b/frontend/node_modules/.bin/sucrase-node.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\sucrase\bin\sucrase-node" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\sucrase\bin\sucrase-node" %*
diff --git a/frontend/node_modules/.bin/sucrase.cmd b/frontend/node_modules/.bin/sucrase.cmd
index 3cd8928..359672c 100644
--- a/frontend/node_modules/.bin/sucrase.cmd
+++ b/frontend/node_modules/.bin/sucrase.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\sucrase\bin\sucrase" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\sucrase\bin\sucrase" %*
diff --git a/frontend/node_modules/.bin/tailwind.cmd b/frontend/node_modules/.bin/tailwind.cmd
index 338176a..e341631 100644
--- a/frontend/node_modules/.bin/tailwind.cmd
+++ b/frontend/node_modules/.bin/tailwind.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\tailwindcss\lib\cli.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\tailwindcss\lib\cli.js" %*
diff --git a/frontend/node_modules/.bin/tailwindcss.cmd b/frontend/node_modules/.bin/tailwindcss.cmd
index 338176a..e341631 100644
--- a/frontend/node_modules/.bin/tailwindcss.cmd
+++ b/frontend/node_modules/.bin/tailwindcss.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\tailwindcss\lib\cli.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\tailwindcss\lib\cli.js" %*
diff --git a/frontend/node_modules/.bin/update-browserslist-db.cmd b/frontend/node_modules/.bin/update-browserslist-db.cmd
index 2e14905..d5176c7 100644
--- a/frontend/node_modules/.bin/update-browserslist-db.cmd
+++ b/frontend/node_modules/.bin/update-browserslist-db.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\update-browserslist-db\cli.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\update-browserslist-db\cli.js" %*
diff --git a/frontend/node_modules/.bin/vite.cmd b/frontend/node_modules/.bin/vite.cmd
index f62e966..e824f3a 100644
--- a/frontend/node_modules/.bin/vite.cmd
+++ b/frontend/node_modules/.bin/vite.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vite\bin\vite.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vite\bin\vite.js" %*
diff --git a/frontend/node_modules/.bin/yaml.cmd b/frontend/node_modules/.bin/yaml.cmd
index f76090f..2ef9758 100644
--- a/frontend/node_modules/.bin/yaml.cmd
+++ b/frontend/node_modules/.bin/yaml.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\yaml\bin.mjs" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\yaml\bin.mjs" %*
diff --git a/frontend/node_modules/@types/estree/README.md b/frontend/node_modules/@types/estree/README.md
index 3a8c041..2af760b 100644
--- a/frontend/node_modules/@types/estree/README.md
+++ b/frontend/node_modules/@types/estree/README.md
@@ -1,15 +1,15 @@
-# Installation
-> `npm install --save @types/estree`
-
-# Summary
-This package contains type definitions for estree (https://github.com/estree/estree).
-
-# Details
-Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/estree.
-
-### Additional Details
- * Last updated: Fri, 06 Jun 2025 00:04:33 GMT
- * Dependencies: none
-
-# Credits
-These definitions were written by [RReverser](https://github.com/RReverser).
+# Installation
+> `npm install --save @types/estree`
+
+# Summary
+This package contains type definitions for estree (https://github.com/estree/estree).
+
+# Details
+Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/estree.
+
+### Additional Details
+ * Last updated: Fri, 06 Jun 2025 00:04:33 GMT
+ * Dependencies: none
+
+# Credits
+These definitions were written by [RReverser](https://github.com/RReverser).
diff --git a/frontend/node_modules/color-name/LICENSE b/frontend/node_modules/color-name/LICENSE
index 4d9802a..c6b1001 100644
--- a/frontend/node_modules/color-name/LICENSE
+++ b/frontend/node_modules/color-name/LICENSE
@@ -1,8 +1,8 @@
-The MIT License (MIT)
-Copyright (c) 2015 Dmitry Ivanov
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
+The MIT License (MIT)
+Copyright (c) 2015 Dmitry Ivanov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/frontend/node_modules/color-name/README.md b/frontend/node_modules/color-name/README.md
index 3611a6b..932b979 100644
--- a/frontend/node_modules/color-name/README.md
+++ b/frontend/node_modules/color-name/README.md
@@ -1,11 +1,11 @@
-A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
-
-[](https://nodei.co/npm/color-name/)
-
-
-```js
-var colors = require('color-name');
-colors.red //[255,0,0]
-```
-
-
+A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
+
+[](https://nodei.co/npm/color-name/)
+
+
+```js
+var colors = require('color-name');
+colors.red //[255,0,0]
+```
+
+
diff --git a/frontend/node_modules/color-name/index.js b/frontend/node_modules/color-name/index.js
index e42aa68..b7c198a 100644
--- a/frontend/node_modules/color-name/index.js
+++ b/frontend/node_modules/color-name/index.js
@@ -1,152 +1,152 @@
-'use strict'
-
-module.exports = {
- "aliceblue": [240, 248, 255],
- "antiquewhite": [250, 235, 215],
- "aqua": [0, 255, 255],
- "aquamarine": [127, 255, 212],
- "azure": [240, 255, 255],
- "beige": [245, 245, 220],
- "bisque": [255, 228, 196],
- "black": [0, 0, 0],
- "blanchedalmond": [255, 235, 205],
- "blue": [0, 0, 255],
- "blueviolet": [138, 43, 226],
- "brown": [165, 42, 42],
- "burlywood": [222, 184, 135],
- "cadetblue": [95, 158, 160],
- "chartreuse": [127, 255, 0],
- "chocolate": [210, 105, 30],
- "coral": [255, 127, 80],
- "cornflowerblue": [100, 149, 237],
- "cornsilk": [255, 248, 220],
- "crimson": [220, 20, 60],
- "cyan": [0, 255, 255],
- "darkblue": [0, 0, 139],
- "darkcyan": [0, 139, 139],
- "darkgoldenrod": [184, 134, 11],
- "darkgray": [169, 169, 169],
- "darkgreen": [0, 100, 0],
- "darkgrey": [169, 169, 169],
- "darkkhaki": [189, 183, 107],
- "darkmagenta": [139, 0, 139],
- "darkolivegreen": [85, 107, 47],
- "darkorange": [255, 140, 0],
- "darkorchid": [153, 50, 204],
- "darkred": [139, 0, 0],
- "darksalmon": [233, 150, 122],
- "darkseagreen": [143, 188, 143],
- "darkslateblue": [72, 61, 139],
- "darkslategray": [47, 79, 79],
- "darkslategrey": [47, 79, 79],
- "darkturquoise": [0, 206, 209],
- "darkviolet": [148, 0, 211],
- "deeppink": [255, 20, 147],
- "deepskyblue": [0, 191, 255],
- "dimgray": [105, 105, 105],
- "dimgrey": [105, 105, 105],
- "dodgerblue": [30, 144, 255],
- "firebrick": [178, 34, 34],
- "floralwhite": [255, 250, 240],
- "forestgreen": [34, 139, 34],
- "fuchsia": [255, 0, 255],
- "gainsboro": [220, 220, 220],
- "ghostwhite": [248, 248, 255],
- "gold": [255, 215, 0],
- "goldenrod": [218, 165, 32],
- "gray": [128, 128, 128],
- "green": [0, 128, 0],
- "greenyellow": [173, 255, 47],
- "grey": [128, 128, 128],
- "honeydew": [240, 255, 240],
- "hotpink": [255, 105, 180],
- "indianred": [205, 92, 92],
- "indigo": [75, 0, 130],
- "ivory": [255, 255, 240],
- "khaki": [240, 230, 140],
- "lavender": [230, 230, 250],
- "lavenderblush": [255, 240, 245],
- "lawngreen": [124, 252, 0],
- "lemonchiffon": [255, 250, 205],
- "lightblue": [173, 216, 230],
- "lightcoral": [240, 128, 128],
- "lightcyan": [224, 255, 255],
- "lightgoldenrodyellow": [250, 250, 210],
- "lightgray": [211, 211, 211],
- "lightgreen": [144, 238, 144],
- "lightgrey": [211, 211, 211],
- "lightpink": [255, 182, 193],
- "lightsalmon": [255, 160, 122],
- "lightseagreen": [32, 178, 170],
- "lightskyblue": [135, 206, 250],
- "lightslategray": [119, 136, 153],
- "lightslategrey": [119, 136, 153],
- "lightsteelblue": [176, 196, 222],
- "lightyellow": [255, 255, 224],
- "lime": [0, 255, 0],
- "limegreen": [50, 205, 50],
- "linen": [250, 240, 230],
- "magenta": [255, 0, 255],
- "maroon": [128, 0, 0],
- "mediumaquamarine": [102, 205, 170],
- "mediumblue": [0, 0, 205],
- "mediumorchid": [186, 85, 211],
- "mediumpurple": [147, 112, 219],
- "mediumseagreen": [60, 179, 113],
- "mediumslateblue": [123, 104, 238],
- "mediumspringgreen": [0, 250, 154],
- "mediumturquoise": [72, 209, 204],
- "mediumvioletred": [199, 21, 133],
- "midnightblue": [25, 25, 112],
- "mintcream": [245, 255, 250],
- "mistyrose": [255, 228, 225],
- "moccasin": [255, 228, 181],
- "navajowhite": [255, 222, 173],
- "navy": [0, 0, 128],
- "oldlace": [253, 245, 230],
- "olive": [128, 128, 0],
- "olivedrab": [107, 142, 35],
- "orange": [255, 165, 0],
- "orangered": [255, 69, 0],
- "orchid": [218, 112, 214],
- "palegoldenrod": [238, 232, 170],
- "palegreen": [152, 251, 152],
- "paleturquoise": [175, 238, 238],
- "palevioletred": [219, 112, 147],
- "papayawhip": [255, 239, 213],
- "peachpuff": [255, 218, 185],
- "peru": [205, 133, 63],
- "pink": [255, 192, 203],
- "plum": [221, 160, 221],
- "powderblue": [176, 224, 230],
- "purple": [128, 0, 128],
- "rebeccapurple": [102, 51, 153],
- "red": [255, 0, 0],
- "rosybrown": [188, 143, 143],
- "royalblue": [65, 105, 225],
- "saddlebrown": [139, 69, 19],
- "salmon": [250, 128, 114],
- "sandybrown": [244, 164, 96],
- "seagreen": [46, 139, 87],
- "seashell": [255, 245, 238],
- "sienna": [160, 82, 45],
- "silver": [192, 192, 192],
- "skyblue": [135, 206, 235],
- "slateblue": [106, 90, 205],
- "slategray": [112, 128, 144],
- "slategrey": [112, 128, 144],
- "snow": [255, 250, 250],
- "springgreen": [0, 255, 127],
- "steelblue": [70, 130, 180],
- "tan": [210, 180, 140],
- "teal": [0, 128, 128],
- "thistle": [216, 191, 216],
- "tomato": [255, 99, 71],
- "turquoise": [64, 224, 208],
- "violet": [238, 130, 238],
- "wheat": [245, 222, 179],
- "white": [255, 255, 255],
- "whitesmoke": [245, 245, 245],
- "yellow": [255, 255, 0],
- "yellowgreen": [154, 205, 50]
-};
+'use strict'
+
+module.exports = {
+ "aliceblue": [240, 248, 255],
+ "antiquewhite": [250, 235, 215],
+ "aqua": [0, 255, 255],
+ "aquamarine": [127, 255, 212],
+ "azure": [240, 255, 255],
+ "beige": [245, 245, 220],
+ "bisque": [255, 228, 196],
+ "black": [0, 0, 0],
+ "blanchedalmond": [255, 235, 205],
+ "blue": [0, 0, 255],
+ "blueviolet": [138, 43, 226],
+ "brown": [165, 42, 42],
+ "burlywood": [222, 184, 135],
+ "cadetblue": [95, 158, 160],
+ "chartreuse": [127, 255, 0],
+ "chocolate": [210, 105, 30],
+ "coral": [255, 127, 80],
+ "cornflowerblue": [100, 149, 237],
+ "cornsilk": [255, 248, 220],
+ "crimson": [220, 20, 60],
+ "cyan": [0, 255, 255],
+ "darkblue": [0, 0, 139],
+ "darkcyan": [0, 139, 139],
+ "darkgoldenrod": [184, 134, 11],
+ "darkgray": [169, 169, 169],
+ "darkgreen": [0, 100, 0],
+ "darkgrey": [169, 169, 169],
+ "darkkhaki": [189, 183, 107],
+ "darkmagenta": [139, 0, 139],
+ "darkolivegreen": [85, 107, 47],
+ "darkorange": [255, 140, 0],
+ "darkorchid": [153, 50, 204],
+ "darkred": [139, 0, 0],
+ "darksalmon": [233, 150, 122],
+ "darkseagreen": [143, 188, 143],
+ "darkslateblue": [72, 61, 139],
+ "darkslategray": [47, 79, 79],
+ "darkslategrey": [47, 79, 79],
+ "darkturquoise": [0, 206, 209],
+ "darkviolet": [148, 0, 211],
+ "deeppink": [255, 20, 147],
+ "deepskyblue": [0, 191, 255],
+ "dimgray": [105, 105, 105],
+ "dimgrey": [105, 105, 105],
+ "dodgerblue": [30, 144, 255],
+ "firebrick": [178, 34, 34],
+ "floralwhite": [255, 250, 240],
+ "forestgreen": [34, 139, 34],
+ "fuchsia": [255, 0, 255],
+ "gainsboro": [220, 220, 220],
+ "ghostwhite": [248, 248, 255],
+ "gold": [255, 215, 0],
+ "goldenrod": [218, 165, 32],
+ "gray": [128, 128, 128],
+ "green": [0, 128, 0],
+ "greenyellow": [173, 255, 47],
+ "grey": [128, 128, 128],
+ "honeydew": [240, 255, 240],
+ "hotpink": [255, 105, 180],
+ "indianred": [205, 92, 92],
+ "indigo": [75, 0, 130],
+ "ivory": [255, 255, 240],
+ "khaki": [240, 230, 140],
+ "lavender": [230, 230, 250],
+ "lavenderblush": [255, 240, 245],
+ "lawngreen": [124, 252, 0],
+ "lemonchiffon": [255, 250, 205],
+ "lightblue": [173, 216, 230],
+ "lightcoral": [240, 128, 128],
+ "lightcyan": [224, 255, 255],
+ "lightgoldenrodyellow": [250, 250, 210],
+ "lightgray": [211, 211, 211],
+ "lightgreen": [144, 238, 144],
+ "lightgrey": [211, 211, 211],
+ "lightpink": [255, 182, 193],
+ "lightsalmon": [255, 160, 122],
+ "lightseagreen": [32, 178, 170],
+ "lightskyblue": [135, 206, 250],
+ "lightslategray": [119, 136, 153],
+ "lightslategrey": [119, 136, 153],
+ "lightsteelblue": [176, 196, 222],
+ "lightyellow": [255, 255, 224],
+ "lime": [0, 255, 0],
+ "limegreen": [50, 205, 50],
+ "linen": [250, 240, 230],
+ "magenta": [255, 0, 255],
+ "maroon": [128, 0, 0],
+ "mediumaquamarine": [102, 205, 170],
+ "mediumblue": [0, 0, 205],
+ "mediumorchid": [186, 85, 211],
+ "mediumpurple": [147, 112, 219],
+ "mediumseagreen": [60, 179, 113],
+ "mediumslateblue": [123, 104, 238],
+ "mediumspringgreen": [0, 250, 154],
+ "mediumturquoise": [72, 209, 204],
+ "mediumvioletred": [199, 21, 133],
+ "midnightblue": [25, 25, 112],
+ "mintcream": [245, 255, 250],
+ "mistyrose": [255, 228, 225],
+ "moccasin": [255, 228, 181],
+ "navajowhite": [255, 222, 173],
+ "navy": [0, 0, 128],
+ "oldlace": [253, 245, 230],
+ "olive": [128, 128, 0],
+ "olivedrab": [107, 142, 35],
+ "orange": [255, 165, 0],
+ "orangered": [255, 69, 0],
+ "orchid": [218, 112, 214],
+ "palegoldenrod": [238, 232, 170],
+ "palegreen": [152, 251, 152],
+ "paleturquoise": [175, 238, 238],
+ "palevioletred": [219, 112, 147],
+ "papayawhip": [255, 239, 213],
+ "peachpuff": [255, 218, 185],
+ "peru": [205, 133, 63],
+ "pink": [255, 192, 203],
+ "plum": [221, 160, 221],
+ "powderblue": [176, 224, 230],
+ "purple": [128, 0, 128],
+ "rebeccapurple": [102, 51, 153],
+ "red": [255, 0, 0],
+ "rosybrown": [188, 143, 143],
+ "royalblue": [65, 105, 225],
+ "saddlebrown": [139, 69, 19],
+ "salmon": [250, 128, 114],
+ "sandybrown": [244, 164, 96],
+ "seagreen": [46, 139, 87],
+ "seashell": [255, 245, 238],
+ "sienna": [160, 82, 45],
+ "silver": [192, 192, 192],
+ "skyblue": [135, 206, 235],
+ "slateblue": [106, 90, 205],
+ "slategray": [112, 128, 144],
+ "slategrey": [112, 128, 144],
+ "snow": [255, 250, 250],
+ "springgreen": [0, 255, 127],
+ "steelblue": [70, 130, 180],
+ "tan": [210, 180, 140],
+ "teal": [0, 128, 128],
+ "thistle": [216, 191, 216],
+ "tomato": [255, 99, 71],
+ "turquoise": [64, 224, 208],
+ "violet": [238, 130, 238],
+ "wheat": [245, 222, 179],
+ "white": [255, 255, 255],
+ "whitesmoke": [245, 245, 245],
+ "yellow": [255, 255, 0],
+ "yellowgreen": [154, 205, 50]
+};
diff --git a/frontend/node_modules/color-name/package.json b/frontend/node_modules/color-name/package.json
index 7acc902..782dd82 100644
--- a/frontend/node_modules/color-name/package.json
+++ b/frontend/node_modules/color-name/package.json
@@ -1,28 +1,28 @@
-{
- "name": "color-name",
- "version": "1.1.4",
- "description": "A list of color names and its values",
- "main": "index.js",
- "files": [
- "index.js"
- ],
- "scripts": {
- "test": "node test.js"
- },
- "repository": {
- "type": "git",
- "url": "git@github.com:colorjs/color-name.git"
- },
- "keywords": [
- "color-name",
- "color",
- "color-keyword",
- "keyword"
- ],
- "author": "DY ",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/colorjs/color-name/issues"
- },
- "homepage": "https://github.com/colorjs/color-name"
-}
+{
+ "name": "color-name",
+ "version": "1.1.4",
+ "description": "A list of color names and its values",
+ "main": "index.js",
+ "files": [
+ "index.js"
+ ],
+ "scripts": {
+ "test": "node test.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:colorjs/color-name.git"
+ },
+ "keywords": [
+ "color-name",
+ "color",
+ "color-keyword",
+ "keyword"
+ ],
+ "author": "DY ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/colorjs/color-name/issues"
+ },
+ "homepage": "https://github.com/colorjs/color-name"
+}
diff --git a/frontend/node_modules/fraction.js/fraction.d.ts b/frontend/node_modules/fraction.js/fraction.d.ts
index 8a11b3a..e62cfe1 100644
--- a/frontend/node_modules/fraction.js/fraction.d.ts
+++ b/frontend/node_modules/fraction.js/fraction.d.ts
@@ -1,60 +1,60 @@
-declare module 'Fraction';
-
-export interface NumeratorDenominator {
- n: number;
- d: number;
-}
-
-type FractionConstructor = {
- (fraction: Fraction): Fraction;
- (num: number | string): Fraction;
- (numerator: number, denominator: number): Fraction;
- (numbers: [number | string, number | string]): Fraction;
- (fraction: NumeratorDenominator): Fraction;
- (firstValue: Fraction | number | string | [number | string, number | string] | NumeratorDenominator, secondValue?: number): Fraction;
-};
-
-export default class Fraction {
- constructor (fraction: Fraction);
- constructor (num: number | string);
- constructor (numerator: number, denominator: number);
- constructor (numbers: [number | string, number | string]);
- constructor (fraction: NumeratorDenominator);
- constructor (firstValue: Fraction | number | string | [number | string, number | string] | NumeratorDenominator, secondValue?: number);
-
- s: number;
- n: number;
- d: number;
-
- abs(): Fraction;
- neg(): Fraction;
-
- add: FractionConstructor;
- sub: FractionConstructor;
- mul: FractionConstructor;
- div: FractionConstructor;
- pow: FractionConstructor;
- gcd: FractionConstructor;
- lcm: FractionConstructor;
-
- mod(n?: number | string | Fraction): Fraction;
-
- ceil(places?: number): Fraction;
- floor(places?: number): Fraction;
- round(places?: number): Fraction;
-
- inverse(): Fraction;
-
- simplify(eps?: number): Fraction;
-
- equals(n: number | string | Fraction): boolean;
- compare(n: number | string | Fraction): number;
- divisible(n: number | string | Fraction): boolean;
-
- valueOf(): number;
- toString(decimalPlaces?: number): string;
- toLatex(excludeWhole?: boolean): string;
- toFraction(excludeWhole?: boolean): string;
- toContinued(): number[];
- clone(): Fraction;
-}
+declare module 'Fraction';
+
+export interface NumeratorDenominator {
+ n: number;
+ d: number;
+}
+
+type FractionConstructor = {
+ (fraction: Fraction): Fraction;
+ (num: number | string): Fraction;
+ (numerator: number, denominator: number): Fraction;
+ (numbers: [number | string, number | string]): Fraction;
+ (fraction: NumeratorDenominator): Fraction;
+ (firstValue: Fraction | number | string | [number | string, number | string] | NumeratorDenominator, secondValue?: number): Fraction;
+};
+
+export default class Fraction {
+ constructor (fraction: Fraction);
+ constructor (num: number | string);
+ constructor (numerator: number, denominator: number);
+ constructor (numbers: [number | string, number | string]);
+ constructor (fraction: NumeratorDenominator);
+ constructor (firstValue: Fraction | number | string | [number | string, number | string] | NumeratorDenominator, secondValue?: number);
+
+ s: number;
+ n: number;
+ d: number;
+
+ abs(): Fraction;
+ neg(): Fraction;
+
+ add: FractionConstructor;
+ sub: FractionConstructor;
+ mul: FractionConstructor;
+ div: FractionConstructor;
+ pow: FractionConstructor;
+ gcd: FractionConstructor;
+ lcm: FractionConstructor;
+
+ mod(n?: number | string | Fraction): Fraction;
+
+ ceil(places?: number): Fraction;
+ floor(places?: number): Fraction;
+ round(places?: number): Fraction;
+
+ inverse(): Fraction;
+
+ simplify(eps?: number): Fraction;
+
+ equals(n: number | string | Fraction): boolean;
+ compare(n: number | string | Fraction): number;
+ divisible(n: number | string | Fraction): boolean;
+
+ valueOf(): number;
+ toString(decimalPlaces?: number): string;
+ toLatex(excludeWhole?: boolean): string;
+ toFraction(excludeWhole?: boolean): string;
+ toContinued(): number[];
+ clone(): Fraction;
+}
diff --git a/frontend/node_modules/read-cache/README.md b/frontend/node_modules/read-cache/README.md
index 25b7a6a..16a5c36 100644
--- a/frontend/node_modules/read-cache/README.md
+++ b/frontend/node_modules/read-cache/README.md
@@ -1,46 +1,46 @@
-# read-cache [](https://travis-ci.org/TrySound/read-cache)
-
-Reads and caches the entire contents of a file until it is modified.
-
-
-## Install
-
-```
-$ npm i read-cache
-```
-
-
-## Usage
-
-```js
-// foo.js
-var readCache = require('read-cache');
-
-readCache('foo.js').then(function (contents) {
- console.log(contents);
-});
-```
-
-
-## API
-
-### readCache(path[, encoding])
-
-Returns a promise that resolves with the file's contents.
-
-### readCache.sync(path[, encoding])
-
-Returns the content of the file.
-
-### readCache.get(path[, encoding])
-
-Returns the content of cached file or null.
-
-### readCache.clear()
-
-Clears the contents of the cache.
-
-
-## License
-
-MIT © [Bogdan Chadkin](mailto:trysound@yandex.ru)
+# read-cache [](https://travis-ci.org/TrySound/read-cache)
+
+Reads and caches the entire contents of a file until it is modified.
+
+
+## Install
+
+```
+$ npm i read-cache
+```
+
+
+## Usage
+
+```js
+// foo.js
+var readCache = require('read-cache');
+
+readCache('foo.js').then(function (contents) {
+ console.log(contents);
+});
+```
+
+
+## API
+
+### readCache(path[, encoding])
+
+Returns a promise that resolves with the file's contents.
+
+### readCache.sync(path[, encoding])
+
+Returns the content of the file.
+
+### readCache.get(path[, encoding])
+
+Returns the content of cached file or null.
+
+### readCache.clear()
+
+Clears the contents of the cache.
+
+
+## License
+
+MIT © [Bogdan Chadkin](mailto:trysound@yandex.ru)
diff --git a/frontend/node_modules/read-cache/index.js b/frontend/node_modules/read-cache/index.js
index a35bb66..b5263e6 100644
--- a/frontend/node_modules/read-cache/index.js
+++ b/frontend/node_modules/read-cache/index.js
@@ -1,78 +1,78 @@
-var fs = require('fs');
-var path = require('path');
-var pify = require('pify');
-
-var stat = pify(fs.stat);
-var readFile = pify(fs.readFile);
-var resolve = path.resolve;
-
-var cache = Object.create(null);
-
-function convert(content, encoding) {
- if (Buffer.isEncoding(encoding)) {
- return content.toString(encoding);
- }
- return content;
-}
-
-module.exports = function (path, encoding) {
- path = resolve(path);
-
- return stat(path).then(function (stats) {
- var item = cache[path];
-
- if (item && item.mtime.getTime() === stats.mtime.getTime()) {
- return convert(item.content, encoding);
- }
-
- return readFile(path).then(function (data) {
- cache[path] = {
- mtime: stats.mtime,
- content: data
- };
-
- return convert(data, encoding);
- });
- }).catch(function (err) {
- cache[path] = null;
- return Promise.reject(err);
- });
-};
-
-module.exports.sync = function (path, encoding) {
- path = resolve(path);
-
- try {
- var stats = fs.statSync(path);
- var item = cache[path];
-
- if (item && item.mtime.getTime() === stats.mtime.getTime()) {
- return convert(item.content, encoding);
- }
-
- var data = fs.readFileSync(path);
-
- cache[path] = {
- mtime: stats.mtime,
- content: data
- };
-
- return convert(data, encoding);
- } catch (err) {
- cache[path] = null;
- throw err;
- }
-
-};
-
-module.exports.get = function (path, encoding) {
- path = resolve(path);
- if (cache[path]) {
- return convert(cache[path].content, encoding);
- }
- return null;
-};
-
-module.exports.clear = function () {
- cache = Object.create(null);
-};
+var fs = require('fs');
+var path = require('path');
+var pify = require('pify');
+
+var stat = pify(fs.stat);
+var readFile = pify(fs.readFile);
+var resolve = path.resolve;
+
+var cache = Object.create(null);
+
+function convert(content, encoding) {
+ if (Buffer.isEncoding(encoding)) {
+ return content.toString(encoding);
+ }
+ return content;
+}
+
+module.exports = function (path, encoding) {
+ path = resolve(path);
+
+ return stat(path).then(function (stats) {
+ var item = cache[path];
+
+ if (item && item.mtime.getTime() === stats.mtime.getTime()) {
+ return convert(item.content, encoding);
+ }
+
+ return readFile(path).then(function (data) {
+ cache[path] = {
+ mtime: stats.mtime,
+ content: data
+ };
+
+ return convert(data, encoding);
+ });
+ }).catch(function (err) {
+ cache[path] = null;
+ return Promise.reject(err);
+ });
+};
+
+module.exports.sync = function (path, encoding) {
+ path = resolve(path);
+
+ try {
+ var stats = fs.statSync(path);
+ var item = cache[path];
+
+ if (item && item.mtime.getTime() === stats.mtime.getTime()) {
+ return convert(item.content, encoding);
+ }
+
+ var data = fs.readFileSync(path);
+
+ cache[path] = {
+ mtime: stats.mtime,
+ content: data
+ };
+
+ return convert(data, encoding);
+ } catch (err) {
+ cache[path] = null;
+ throw err;
+ }
+
+};
+
+module.exports.get = function (path, encoding) {
+ path = resolve(path);
+ if (cache[path]) {
+ return convert(cache[path].content, encoding);
+ }
+ return null;
+};
+
+module.exports.clear = function () {
+ cache = Object.create(null);
+};
diff --git a/frontend/node_modules/rollup/dist/bin/rollup b/frontend/node_modules/rollup/dist/bin/rollup
index 1a2a326..dc82f91 100644
--- a/frontend/node_modules/rollup/dist/bin/rollup
+++ b/frontend/node_modules/rollup/dist/bin/rollup
@@ -1246,76 +1246,76 @@ yargsParser.camelCase = camelCase;
yargsParser.decamelize = decamelize;
yargsParser.looksLikeNumber = looksLikeNumber;
-/******************************************************************************
-Copyright (c) Microsoft Corporation.
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-***************************************************************************** */
-/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
-
-
-function __addDisposableResource(env, value, async) {
- if (value !== null && value !== void 0) {
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
- var dispose, inner;
- if (async) {
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
- dispose = value[Symbol.asyncDispose];
- }
- if (dispose === void 0) {
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
- dispose = value[Symbol.dispose];
- if (async) inner = dispose;
- }
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
- if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
- env.stack.push({ value: value, dispose: dispose, async: async });
- }
- else if (async) {
- env.stack.push({ async: true });
- }
- return value;
-
-}
-
-var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
- var e = new Error(message);
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
-};
-
-function __disposeResources(env) {
- function fail(e) {
- env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
- env.hasError = true;
- }
- var r, s = 0;
- function next() {
- while (r = env.stack.pop()) {
- try {
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
- if (r.dispose) {
- var result = r.dispose.call(r.value);
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
- }
- else s |= 1;
- }
- catch (e) {
- fail(e);
- }
- }
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
- if (env.hasError) throw env.error;
- }
- return next();
+/******************************************************************************
+Copyright (c) Microsoft Corporation.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+***************************************************************************** */
+/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
+
+
+function __addDisposableResource(env, value, async) {
+ if (value !== null && value !== void 0) {
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
+ var dispose, inner;
+ if (async) {
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
+ dispose = value[Symbol.asyncDispose];
+ }
+ if (dispose === void 0) {
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
+ dispose = value[Symbol.dispose];
+ if (async) inner = dispose;
+ }
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
+ env.stack.push({ value: value, dispose: dispose, async: async });
+ }
+ else if (async) {
+ env.stack.push({ async: true });
+ }
+ return value;
+
+}
+
+var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
+ var e = new Error(message);
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
+};
+
+function __disposeResources(env) {
+ function fail(e) {
+ env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
+ env.hasError = true;
+ }
+ var r, s = 0;
+ function next() {
+ while (r = env.stack.pop()) {
+ try {
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
+ if (r.dispose) {
+ var result = r.dispose.call(r.value);
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
+ }
+ else s |= 1;
+ }
+ catch (e) {
+ fail(e);
+ }
+ }
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
+ if (env.hasError) throw env.error;
+ }
+ return next();
}
const toZeroIfInfinity = value => Number.isFinite(value) ? value : 0;
diff --git a/frontend/node_modules/vite/dist/node/chunks/dep-YkMKzX4u.js b/frontend/node_modules/vite/dist/node/chunks/dep-YkMKzX4u.js
index 65c8945..b3943a8 100644
--- a/frontend/node_modules/vite/dist/node/chunks/dep-YkMKzX4u.js
+++ b/frontend/node_modules/vite/dist/node/chunks/dep-YkMKzX4u.js
@@ -263,83 +263,83 @@ pify$1.all = pify$1;
var pifyExports = pify$2.exports;
-var fs = require$$0__default;
-var path$3 = require$$0;
-var pify = pifyExports;
-
-var stat = pify(fs.stat);
-var readFile = pify(fs.readFile);
-var resolve = path$3.resolve;
-
-var cache = Object.create(null);
-
-function convert(content, encoding) {
- if (Buffer.isEncoding(encoding)) {
- return content.toString(encoding);
- }
- return content;
-}
-
-readCache$1.exports = function (path, encoding) {
- path = resolve(path);
-
- return stat(path).then(function (stats) {
- var item = cache[path];
-
- if (item && item.mtime.getTime() === stats.mtime.getTime()) {
- return convert(item.content, encoding);
- }
-
- return readFile(path).then(function (data) {
- cache[path] = {
- mtime: stats.mtime,
- content: data
- };
-
- return convert(data, encoding);
- });
- }).catch(function (err) {
- cache[path] = null;
- return Promise.reject(err);
- });
-};
-
-readCache$1.exports.sync = function (path, encoding) {
- path = resolve(path);
-
- try {
- var stats = fs.statSync(path);
- var item = cache[path];
-
- if (item && item.mtime.getTime() === stats.mtime.getTime()) {
- return convert(item.content, encoding);
- }
-
- var data = fs.readFileSync(path);
-
- cache[path] = {
- mtime: stats.mtime,
- content: data
- };
-
- return convert(data, encoding);
- } catch (err) {
- cache[path] = null;
- throw err;
- }
-
-};
-
-readCache$1.exports.get = function (path, encoding) {
- path = resolve(path);
- if (cache[path]) {
- return convert(cache[path].content, encoding);
- }
- return null;
-};
-
-readCache$1.exports.clear = function () {
- cache = Object.create(null);
+var fs = require$$0__default;
+var path$3 = require$$0;
+var pify = pifyExports;
+
+var stat = pify(fs.stat);
+var readFile = pify(fs.readFile);
+var resolve = path$3.resolve;
+
+var cache = Object.create(null);
+
+function convert(content, encoding) {
+ if (Buffer.isEncoding(encoding)) {
+ return content.toString(encoding);
+ }
+ return content;
+}
+
+readCache$1.exports = function (path, encoding) {
+ path = resolve(path);
+
+ return stat(path).then(function (stats) {
+ var item = cache[path];
+
+ if (item && item.mtime.getTime() === stats.mtime.getTime()) {
+ return convert(item.content, encoding);
+ }
+
+ return readFile(path).then(function (data) {
+ cache[path] = {
+ mtime: stats.mtime,
+ content: data
+ };
+
+ return convert(data, encoding);
+ });
+ }).catch(function (err) {
+ cache[path] = null;
+ return Promise.reject(err);
+ });
+};
+
+readCache$1.exports.sync = function (path, encoding) {
+ path = resolve(path);
+
+ try {
+ var stats = fs.statSync(path);
+ var item = cache[path];
+
+ if (item && item.mtime.getTime() === stats.mtime.getTime()) {
+ return convert(item.content, encoding);
+ }
+
+ var data = fs.readFileSync(path);
+
+ cache[path] = {
+ mtime: stats.mtime,
+ content: data
+ };
+
+ return convert(data, encoding);
+ } catch (err) {
+ cache[path] = null;
+ throw err;
+ }
+
+};
+
+readCache$1.exports.get = function (path, encoding) {
+ path = resolve(path);
+ if (cache[path]) {
+ return convert(cache[path].content, encoding);
+ }
+ return null;
+};
+
+readCache$1.exports.clear = function () {
+ cache = Object.create(null);
};
var readCacheExports = readCache$1.exports;
diff --git a/frontend/src/home.js b/frontend/src/home.js
index 0d8cefe..d8391fd 100644
--- a/frontend/src/home.js
+++ b/frontend/src/home.js
@@ -44,27 +44,19 @@ const browseBtn = document.getElementById('browseBtn')
let allLogos = []
-// Load logos
-async function loadLogos() {
+async function loadRecentLogos() {
try {
- const response = await fetch(`${API_BASE_URL}/logos`)
-
- if (!response.ok) {
- throw new Error('Failed to fetch logos')
- }
-
+ const response = await fetch(`${API_BASE_URL}/logos?sort=recent&limit=8`)
+ if (!response.ok) throw new Error('Failed to fetch recent logos')
allLogos = await response.json()
-
loadingState.classList.add('hidden')
-
if (allLogos.length === 0) {
emptyState.classList.remove('hidden')
} else {
displayLogos(allLogos)
}
-
} catch (error) {
- console.error('Error loading logos:', error)
+ console.error('Error loading recent logos:', error)
loadingState.classList.add('hidden')
emptyState.classList.remove('hidden')
}
@@ -116,20 +108,26 @@ function displayLogos(logos) {
}
// Filter logos
-function filterLogos(query) {
- const filtered = allLogos.filter(logo =>
- logo.club_name.toLowerCase().includes(query.toLowerCase()) ||
- (logo.club_city && logo.club_city.toLowerCase().includes(query.toLowerCase()))
- )
-
- displayLogos(filtered)
-
- if (filtered.length === 0 && query) {
- logoGrid.innerHTML = `
-
-
No logos found matching "${query}"
-
- `
+async function filterLogos(query) {
+ const q = query.trim()
+ if (!q) {
+ displayLogos(allLogos)
+ return
+ }
+ try {
+ const resp = await fetch(`${API_BASE_URL}/logos?q=${encodeURIComponent(q)}&limit=50`)
+ if (!resp.ok) throw new Error('Search failed')
+ const results = await resp.json()
+ displayLogos(results)
+ if (results.length === 0) {
+ logoGrid.innerHTML = `
+
+
No logos found matching "${q}"
+
+ `
+ }
+ } catch (e) {
+ console.warn('Search error:', e.message)
}
}
@@ -158,10 +156,7 @@ if (gallerySearch) {
// Browse button - scroll to gallery
if (browseBtn) {
browseBtn.addEventListener('click', () => {
- document.getElementById('logoGallery').scrollIntoView({
- behavior: 'smooth',
- block: 'start'
- })
+ window.location.href = '/logos.html'
})
}
@@ -202,7 +197,7 @@ console.log('🇨🇿 Czech Clubs Logos API - Home')
console.log('Backend API:', API_BASE_URL)
// Load logos on page load
-loadLogos()
+loadRecentLogos()
// Show welcome notification
setTimeout(() => {
diff --git a/frontend/src/logos.js b/frontend/src/logos.js
new file mode 100644
index 0000000..bc62406
--- /dev/null
+++ b/frontend/src/logos.js
@@ -0,0 +1,132 @@
+import './style.css'
+
+const API_BASE_URL = '/api'
+
+const grid = document.getElementById('allLogoGrid')
+const loading = document.getElementById('allLoading')
+const empty = document.getElementById('allEmpty')
+const loadMoreBtn = document.getElementById('loadMoreBtn')
+const searchInput = document.getElementById('allLogoSearch')
+
+let page = 1
+const limit = 20
+let query = ''
+let isLoading = false
+let hasMore = true
+
+async function loadPage(reset = false) {
+ if (isLoading) return
+ if (reset) {
+ page = 1
+ hasMore = true
+ grid.innerHTML = ''
+ empty.classList.add('hidden')
+ loading.classList.remove('hidden')
+ } else {
+ loadMoreBtn.disabled = true
+ loadMoreBtn.textContent = 'Načítání...'
+ }
+
+ isLoading = true
+ try {
+ const url = new URL(`${API_BASE_URL}/logos`, window.location.origin)
+ url.searchParams.set('sort', 'recent')
+ url.searchParams.set('limit', String(limit))
+ url.searchParams.set('page', String(page))
+ if (query) url.searchParams.set('q', query)
+
+ const resp = await fetch(url.toString().replace(window.location.origin, ''))
+ if (!resp.ok) throw new Error('Failed to fetch logos')
+ const data = await resp.json()
+
+ if (reset) loading.classList.add('hidden')
+
+ if (Array.isArray(data) && data.length > 0) {
+ appendCards(data)
+ page += 1
+ if (data.length < limit) {
+ hasMore = false
+ loadMoreBtn.classList.add('hidden')
+ } else {
+ loadMoreBtn.classList.remove('hidden')
+ }
+ } else {
+ if (reset) empty.classList.remove('hidden')
+ hasMore = false
+ loadMoreBtn.classList.add('hidden')
+ }
+ } catch (_) {
+ if (reset) {
+ loading.classList.add('hidden')
+ empty.classList.remove('hidden')
+ }
+ } finally {
+ isLoading = false
+ loadMoreBtn.disabled = false
+ loadMoreBtn.textContent = 'Načíst další'
+ }
+}
+
+function appendCards(items) {
+ const html = items.map(logo => {
+ const logoUrl = `${API_BASE_URL}/logos/${logo.id}`
+ return `
+
+
+

+
+
+
+
${logo.club_name}
+
${logo.club_type || 'fotbal'}
+
+
+
+
+ `
+ }).join('')
+ grid.insertAdjacentHTML('beforeend', html)
+}
+
+grid.addEventListener('click', async (e) => {
+ const delBtn = e.target.closest('.delete-logo')
+ if (delBtn) {
+ const card = delBtn.closest('.logo-card')
+ const id = card.dataset.id
+ const ok = confirm('Smazat toto logo?')
+ if (!ok) return
+ delBtn.disabled = true
+ delBtn.textContent = 'Mazání...'
+ try {
+ const resp = await fetch(`${API_BASE_URL}/logos/${id}`, { method: 'DELETE' })
+ if (!resp.ok) throw new Error('Delete failed')
+ card.remove()
+ if (!grid.children.length) empty.classList.remove('hidden')
+ } catch (_) {
+ delBtn.textContent = 'Smazat'
+ delBtn.disabled = false
+ alert('Mazání selhalo')
+ }
+ return
+ }
+ const card = e.target.closest('.logo-card')
+ if (card && !e.target.closest('.delete-logo')) {
+ const id = card.dataset.id
+ window.location.href = `/logo.html?id=${id}`
+ }
+})
+
+let searchTimer
+searchInput.addEventListener('input', () => {
+ clearTimeout(searchTimer)
+ searchTimer = setTimeout(() => {
+ query = searchInput.value.trim()
+ loadPage(true)
+ }, 300)
+})
+
+loadMoreBtn.addEventListener('click', () => {
+ if (hasMore) loadPage(false)
+})
+
+loadPage(true)
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
index 0859caa..af2a884 100644
--- a/frontend/vite.config.js
+++ b/frontend/vite.config.js
@@ -22,7 +22,8 @@ export default defineConfig({
main: resolve(__dirname, 'index.html'),
admin: resolve(__dirname, 'admin.html'),
apiDocs: resolve(__dirname, 'api-docs.html'),
- logo: resolve(__dirname, 'logo.html')
+ logo: resolve(__dirname, 'logo.html'),
+ logos: resolve(__dirname, 'logos.html')
}
}
}
diff --git a/go.mod b/go.mod
index 51be996..da4570e 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,8 @@
module club
go 1.25.1
+
+require (
+ github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
+ golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..93f2971
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,6 @@
+github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
+github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
+golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
+golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/scripts/node_modules/.bin/nodemon.cmd b/scripts/node_modules/.bin/nodemon.cmd
index 55acf8a..98e1b95 100644
--- a/scripts/node_modules/.bin/nodemon.cmd
+++ b/scripts/node_modules/.bin/nodemon.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nodemon\bin\nodemon.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nodemon\bin\nodemon.js" %*
diff --git a/scripts/node_modules/.bin/nodetouch.cmd b/scripts/node_modules/.bin/nodetouch.cmd
index 8298b91..426bfc3 100644
--- a/scripts/node_modules/.bin/nodetouch.cmd
+++ b/scripts/node_modules/.bin/nodetouch.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\touch\bin\nodetouch.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\touch\bin\nodetouch.js" %*
diff --git a/scripts/node_modules/.bin/prebuild-install.cmd b/scripts/node_modules/.bin/prebuild-install.cmd
index 21ff904..c01b2c3 100644
--- a/scripts/node_modules/.bin/prebuild-install.cmd
+++ b/scripts/node_modules/.bin/prebuild-install.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\prebuild-install\bin.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\prebuild-install\bin.js" %*
diff --git a/scripts/node_modules/.bin/rc.cmd b/scripts/node_modules/.bin/rc.cmd
index be16b73..22dbe46 100644
--- a/scripts/node_modules/.bin/rc.cmd
+++ b/scripts/node_modules/.bin/rc.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rc\cli.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rc\cli.js" %*
diff --git a/scripts/node_modules/.bin/semver.cmd b/scripts/node_modules/.bin/semver.cmd
index 9913fa9..7d4c104 100644
--- a/scripts/node_modules/.bin/semver.cmd
+++ b/scripts/node_modules/.bin/semver.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\semver\bin\semver.js" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\semver\bin\semver.js" %*
diff --git a/scripts/node_modules/.bin/svgo.cmd b/scripts/node_modules/.bin/svgo.cmd
index 3624a53..922d764 100644
--- a/scripts/node_modules/.bin/svgo.cmd
+++ b/scripts/node_modules/.bin/svgo.cmd
@@ -1,17 +1,17 @@
-@ECHO off
-GOTO start
-:find_dp0
-SET dp0=%~dp0
-EXIT /b
-:start
-SETLOCAL
-CALL :find_dp0
-
-IF EXIST "%dp0%\node.exe" (
- SET "_prog=%dp0%\node.exe"
-) ELSE (
- SET "_prog=node"
- SET PATHEXT=%PATHEXT:;.JS;=;%
-)
-
-endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\svgo\bin\svgo" %*
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\svgo\bin\svgo" %*
diff --git a/scripts/node_modules/color-name/LICENSE b/scripts/node_modules/color-name/LICENSE
index 4d9802a..c6b1001 100644
--- a/scripts/node_modules/color-name/LICENSE
+++ b/scripts/node_modules/color-name/LICENSE
@@ -1,8 +1,8 @@
-The MIT License (MIT)
-Copyright (c) 2015 Dmitry Ivanov
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
+The MIT License (MIT)
+Copyright (c) 2015 Dmitry Ivanov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/scripts/node_modules/color-name/README.md b/scripts/node_modules/color-name/README.md
index 3611a6b..932b979 100644
--- a/scripts/node_modules/color-name/README.md
+++ b/scripts/node_modules/color-name/README.md
@@ -1,11 +1,11 @@
-A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
-
-[](https://nodei.co/npm/color-name/)
-
-
-```js
-var colors = require('color-name');
-colors.red //[255,0,0]
-```
-
-
+A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
+
+[](https://nodei.co/npm/color-name/)
+
+
+```js
+var colors = require('color-name');
+colors.red //[255,0,0]
+```
+
+
diff --git a/scripts/node_modules/color-name/index.js b/scripts/node_modules/color-name/index.js
index e42aa68..b7c198a 100644
--- a/scripts/node_modules/color-name/index.js
+++ b/scripts/node_modules/color-name/index.js
@@ -1,152 +1,152 @@
-'use strict'
-
-module.exports = {
- "aliceblue": [240, 248, 255],
- "antiquewhite": [250, 235, 215],
- "aqua": [0, 255, 255],
- "aquamarine": [127, 255, 212],
- "azure": [240, 255, 255],
- "beige": [245, 245, 220],
- "bisque": [255, 228, 196],
- "black": [0, 0, 0],
- "blanchedalmond": [255, 235, 205],
- "blue": [0, 0, 255],
- "blueviolet": [138, 43, 226],
- "brown": [165, 42, 42],
- "burlywood": [222, 184, 135],
- "cadetblue": [95, 158, 160],
- "chartreuse": [127, 255, 0],
- "chocolate": [210, 105, 30],
- "coral": [255, 127, 80],
- "cornflowerblue": [100, 149, 237],
- "cornsilk": [255, 248, 220],
- "crimson": [220, 20, 60],
- "cyan": [0, 255, 255],
- "darkblue": [0, 0, 139],
- "darkcyan": [0, 139, 139],
- "darkgoldenrod": [184, 134, 11],
- "darkgray": [169, 169, 169],
- "darkgreen": [0, 100, 0],
- "darkgrey": [169, 169, 169],
- "darkkhaki": [189, 183, 107],
- "darkmagenta": [139, 0, 139],
- "darkolivegreen": [85, 107, 47],
- "darkorange": [255, 140, 0],
- "darkorchid": [153, 50, 204],
- "darkred": [139, 0, 0],
- "darksalmon": [233, 150, 122],
- "darkseagreen": [143, 188, 143],
- "darkslateblue": [72, 61, 139],
- "darkslategray": [47, 79, 79],
- "darkslategrey": [47, 79, 79],
- "darkturquoise": [0, 206, 209],
- "darkviolet": [148, 0, 211],
- "deeppink": [255, 20, 147],
- "deepskyblue": [0, 191, 255],
- "dimgray": [105, 105, 105],
- "dimgrey": [105, 105, 105],
- "dodgerblue": [30, 144, 255],
- "firebrick": [178, 34, 34],
- "floralwhite": [255, 250, 240],
- "forestgreen": [34, 139, 34],
- "fuchsia": [255, 0, 255],
- "gainsboro": [220, 220, 220],
- "ghostwhite": [248, 248, 255],
- "gold": [255, 215, 0],
- "goldenrod": [218, 165, 32],
- "gray": [128, 128, 128],
- "green": [0, 128, 0],
- "greenyellow": [173, 255, 47],
- "grey": [128, 128, 128],
- "honeydew": [240, 255, 240],
- "hotpink": [255, 105, 180],
- "indianred": [205, 92, 92],
- "indigo": [75, 0, 130],
- "ivory": [255, 255, 240],
- "khaki": [240, 230, 140],
- "lavender": [230, 230, 250],
- "lavenderblush": [255, 240, 245],
- "lawngreen": [124, 252, 0],
- "lemonchiffon": [255, 250, 205],
- "lightblue": [173, 216, 230],
- "lightcoral": [240, 128, 128],
- "lightcyan": [224, 255, 255],
- "lightgoldenrodyellow": [250, 250, 210],
- "lightgray": [211, 211, 211],
- "lightgreen": [144, 238, 144],
- "lightgrey": [211, 211, 211],
- "lightpink": [255, 182, 193],
- "lightsalmon": [255, 160, 122],
- "lightseagreen": [32, 178, 170],
- "lightskyblue": [135, 206, 250],
- "lightslategray": [119, 136, 153],
- "lightslategrey": [119, 136, 153],
- "lightsteelblue": [176, 196, 222],
- "lightyellow": [255, 255, 224],
- "lime": [0, 255, 0],
- "limegreen": [50, 205, 50],
- "linen": [250, 240, 230],
- "magenta": [255, 0, 255],
- "maroon": [128, 0, 0],
- "mediumaquamarine": [102, 205, 170],
- "mediumblue": [0, 0, 205],
- "mediumorchid": [186, 85, 211],
- "mediumpurple": [147, 112, 219],
- "mediumseagreen": [60, 179, 113],
- "mediumslateblue": [123, 104, 238],
- "mediumspringgreen": [0, 250, 154],
- "mediumturquoise": [72, 209, 204],
- "mediumvioletred": [199, 21, 133],
- "midnightblue": [25, 25, 112],
- "mintcream": [245, 255, 250],
- "mistyrose": [255, 228, 225],
- "moccasin": [255, 228, 181],
- "navajowhite": [255, 222, 173],
- "navy": [0, 0, 128],
- "oldlace": [253, 245, 230],
- "olive": [128, 128, 0],
- "olivedrab": [107, 142, 35],
- "orange": [255, 165, 0],
- "orangered": [255, 69, 0],
- "orchid": [218, 112, 214],
- "palegoldenrod": [238, 232, 170],
- "palegreen": [152, 251, 152],
- "paleturquoise": [175, 238, 238],
- "palevioletred": [219, 112, 147],
- "papayawhip": [255, 239, 213],
- "peachpuff": [255, 218, 185],
- "peru": [205, 133, 63],
- "pink": [255, 192, 203],
- "plum": [221, 160, 221],
- "powderblue": [176, 224, 230],
- "purple": [128, 0, 128],
- "rebeccapurple": [102, 51, 153],
- "red": [255, 0, 0],
- "rosybrown": [188, 143, 143],
- "royalblue": [65, 105, 225],
- "saddlebrown": [139, 69, 19],
- "salmon": [250, 128, 114],
- "sandybrown": [244, 164, 96],
- "seagreen": [46, 139, 87],
- "seashell": [255, 245, 238],
- "sienna": [160, 82, 45],
- "silver": [192, 192, 192],
- "skyblue": [135, 206, 235],
- "slateblue": [106, 90, 205],
- "slategray": [112, 128, 144],
- "slategrey": [112, 128, 144],
- "snow": [255, 250, 250],
- "springgreen": [0, 255, 127],
- "steelblue": [70, 130, 180],
- "tan": [210, 180, 140],
- "teal": [0, 128, 128],
- "thistle": [216, 191, 216],
- "tomato": [255, 99, 71],
- "turquoise": [64, 224, 208],
- "violet": [238, 130, 238],
- "wheat": [245, 222, 179],
- "white": [255, 255, 255],
- "whitesmoke": [245, 245, 245],
- "yellow": [255, 255, 0],
- "yellowgreen": [154, 205, 50]
-};
+'use strict'
+
+module.exports = {
+ "aliceblue": [240, 248, 255],
+ "antiquewhite": [250, 235, 215],
+ "aqua": [0, 255, 255],
+ "aquamarine": [127, 255, 212],
+ "azure": [240, 255, 255],
+ "beige": [245, 245, 220],
+ "bisque": [255, 228, 196],
+ "black": [0, 0, 0],
+ "blanchedalmond": [255, 235, 205],
+ "blue": [0, 0, 255],
+ "blueviolet": [138, 43, 226],
+ "brown": [165, 42, 42],
+ "burlywood": [222, 184, 135],
+ "cadetblue": [95, 158, 160],
+ "chartreuse": [127, 255, 0],
+ "chocolate": [210, 105, 30],
+ "coral": [255, 127, 80],
+ "cornflowerblue": [100, 149, 237],
+ "cornsilk": [255, 248, 220],
+ "crimson": [220, 20, 60],
+ "cyan": [0, 255, 255],
+ "darkblue": [0, 0, 139],
+ "darkcyan": [0, 139, 139],
+ "darkgoldenrod": [184, 134, 11],
+ "darkgray": [169, 169, 169],
+ "darkgreen": [0, 100, 0],
+ "darkgrey": [169, 169, 169],
+ "darkkhaki": [189, 183, 107],
+ "darkmagenta": [139, 0, 139],
+ "darkolivegreen": [85, 107, 47],
+ "darkorange": [255, 140, 0],
+ "darkorchid": [153, 50, 204],
+ "darkred": [139, 0, 0],
+ "darksalmon": [233, 150, 122],
+ "darkseagreen": [143, 188, 143],
+ "darkslateblue": [72, 61, 139],
+ "darkslategray": [47, 79, 79],
+ "darkslategrey": [47, 79, 79],
+ "darkturquoise": [0, 206, 209],
+ "darkviolet": [148, 0, 211],
+ "deeppink": [255, 20, 147],
+ "deepskyblue": [0, 191, 255],
+ "dimgray": [105, 105, 105],
+ "dimgrey": [105, 105, 105],
+ "dodgerblue": [30, 144, 255],
+ "firebrick": [178, 34, 34],
+ "floralwhite": [255, 250, 240],
+ "forestgreen": [34, 139, 34],
+ "fuchsia": [255, 0, 255],
+ "gainsboro": [220, 220, 220],
+ "ghostwhite": [248, 248, 255],
+ "gold": [255, 215, 0],
+ "goldenrod": [218, 165, 32],
+ "gray": [128, 128, 128],
+ "green": [0, 128, 0],
+ "greenyellow": [173, 255, 47],
+ "grey": [128, 128, 128],
+ "honeydew": [240, 255, 240],
+ "hotpink": [255, 105, 180],
+ "indianred": [205, 92, 92],
+ "indigo": [75, 0, 130],
+ "ivory": [255, 255, 240],
+ "khaki": [240, 230, 140],
+ "lavender": [230, 230, 250],
+ "lavenderblush": [255, 240, 245],
+ "lawngreen": [124, 252, 0],
+ "lemonchiffon": [255, 250, 205],
+ "lightblue": [173, 216, 230],
+ "lightcoral": [240, 128, 128],
+ "lightcyan": [224, 255, 255],
+ "lightgoldenrodyellow": [250, 250, 210],
+ "lightgray": [211, 211, 211],
+ "lightgreen": [144, 238, 144],
+ "lightgrey": [211, 211, 211],
+ "lightpink": [255, 182, 193],
+ "lightsalmon": [255, 160, 122],
+ "lightseagreen": [32, 178, 170],
+ "lightskyblue": [135, 206, 250],
+ "lightslategray": [119, 136, 153],
+ "lightslategrey": [119, 136, 153],
+ "lightsteelblue": [176, 196, 222],
+ "lightyellow": [255, 255, 224],
+ "lime": [0, 255, 0],
+ "limegreen": [50, 205, 50],
+ "linen": [250, 240, 230],
+ "magenta": [255, 0, 255],
+ "maroon": [128, 0, 0],
+ "mediumaquamarine": [102, 205, 170],
+ "mediumblue": [0, 0, 205],
+ "mediumorchid": [186, 85, 211],
+ "mediumpurple": [147, 112, 219],
+ "mediumseagreen": [60, 179, 113],
+ "mediumslateblue": [123, 104, 238],
+ "mediumspringgreen": [0, 250, 154],
+ "mediumturquoise": [72, 209, 204],
+ "mediumvioletred": [199, 21, 133],
+ "midnightblue": [25, 25, 112],
+ "mintcream": [245, 255, 250],
+ "mistyrose": [255, 228, 225],
+ "moccasin": [255, 228, 181],
+ "navajowhite": [255, 222, 173],
+ "navy": [0, 0, 128],
+ "oldlace": [253, 245, 230],
+ "olive": [128, 128, 0],
+ "olivedrab": [107, 142, 35],
+ "orange": [255, 165, 0],
+ "orangered": [255, 69, 0],
+ "orchid": [218, 112, 214],
+ "palegoldenrod": [238, 232, 170],
+ "palegreen": [152, 251, 152],
+ "paleturquoise": [175, 238, 238],
+ "palevioletred": [219, 112, 147],
+ "papayawhip": [255, 239, 213],
+ "peachpuff": [255, 218, 185],
+ "peru": [205, 133, 63],
+ "pink": [255, 192, 203],
+ "plum": [221, 160, 221],
+ "powderblue": [176, 224, 230],
+ "purple": [128, 0, 128],
+ "rebeccapurple": [102, 51, 153],
+ "red": [255, 0, 0],
+ "rosybrown": [188, 143, 143],
+ "royalblue": [65, 105, 225],
+ "saddlebrown": [139, 69, 19],
+ "salmon": [250, 128, 114],
+ "sandybrown": [244, 164, 96],
+ "seagreen": [46, 139, 87],
+ "seashell": [255, 245, 238],
+ "sienna": [160, 82, 45],
+ "silver": [192, 192, 192],
+ "skyblue": [135, 206, 235],
+ "slateblue": [106, 90, 205],
+ "slategray": [112, 128, 144],
+ "slategrey": [112, 128, 144],
+ "snow": [255, 250, 250],
+ "springgreen": [0, 255, 127],
+ "steelblue": [70, 130, 180],
+ "tan": [210, 180, 140],
+ "teal": [0, 128, 128],
+ "thistle": [216, 191, 216],
+ "tomato": [255, 99, 71],
+ "turquoise": [64, 224, 208],
+ "violet": [238, 130, 238],
+ "wheat": [245, 222, 179],
+ "white": [255, 255, 255],
+ "whitesmoke": [245, 245, 245],
+ "yellow": [255, 255, 0],
+ "yellowgreen": [154, 205, 50]
+};
diff --git a/scripts/node_modules/color-name/package.json b/scripts/node_modules/color-name/package.json
index 7acc902..782dd82 100644
--- a/scripts/node_modules/color-name/package.json
+++ b/scripts/node_modules/color-name/package.json
@@ -1,28 +1,28 @@
-{
- "name": "color-name",
- "version": "1.1.4",
- "description": "A list of color names and its values",
- "main": "index.js",
- "files": [
- "index.js"
- ],
- "scripts": {
- "test": "node test.js"
- },
- "repository": {
- "type": "git",
- "url": "git@github.com:colorjs/color-name.git"
- },
- "keywords": [
- "color-name",
- "color",
- "color-keyword",
- "keyword"
- ],
- "author": "DY ",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/colorjs/color-name/issues"
- },
- "homepage": "https://github.com/colorjs/color-name"
-}
+{
+ "name": "color-name",
+ "version": "1.1.4",
+ "description": "A list of color names and its values",
+ "main": "index.js",
+ "files": [
+ "index.js"
+ ],
+ "scripts": {
+ "test": "node test.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:colorjs/color-name.git"
+ },
+ "keywords": [
+ "color-name",
+ "color",
+ "color-keyword",
+ "keyword"
+ ],
+ "author": "DY ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/colorjs/color-name/issues"
+ },
+ "homepage": "https://github.com/colorjs/color-name"
+}
diff --git a/scripts/node_modules/simple-update-notifier/build/index.js b/scripts/node_modules/simple-update-notifier/build/index.js
index 090f9df..d7c3cde 100644
--- a/scripts/node_modules/simple-update-notifier/build/index.js
+++ b/scripts/node_modules/simple-update-notifier/build/index.js
@@ -7,59 +7,59 @@ var path = require('path');
var fs = require('fs');
var https = require('https');
-/******************************************************************************
-Copyright (c) Microsoft Corporation.
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-***************************************************************************** */
-/* global Reflect, Promise */
-
-
-function __awaiter(thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-}
-
-function __generator(thisArg, body) {
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
- function verb(n) { return function (v) { return step([n, v]); }; }
- function step(op) {
- if (f) throw new TypeError("Generator is already executing.");
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
- if (y = 0, t) op = [op[0] & 2, t.value];
- switch (op[0]) {
- case 0: case 1: t = op; break;
- case 4: _.label++; return { value: op[1], done: false };
- case 5: _.label++; y = op[1]; op = [0]; continue;
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
- default:
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
- if (t[2]) _.ops.pop();
- _.trys.pop(); continue;
- }
- op = body.call(thisArg, _);
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
- }
+/******************************************************************************
+Copyright (c) Microsoft Corporation.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+***************************************************************************** */
+/* global Reflect, Promise */
+
+
+function __awaiter(thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+}
+
+function __generator(thisArg, body) {
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
+ function verb(n) { return function (v) { return step([n, v]); }; }
+ function step(op) {
+ if (f) throw new TypeError("Generator is already executing.");
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
+ if (y = 0, t) op = [op[0] & 2, t.value];
+ switch (op[0]) {
+ case 0: case 1: t = op; break;
+ case 4: _.label++; return { value: op[1], done: false };
+ case 5: _.label++; y = op[1]; op = [0]; continue;
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
+ default:
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
+ if (t[2]) _.ops.pop();
+ _.trys.pop(); continue;
+ }
+ op = body.call(thisArg, _);
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
+ }
}
var packageJson = process$1.env.npm_package_json;
diff --git a/scripts/optimize-assets.js b/scripts/optimize-assets.js
index 2840bab..745d79a 100644
--- a/scripts/optimize-assets.js
+++ b/scripts/optimize-assets.js
@@ -34,6 +34,7 @@ const CONFIG = {
},
// Directories to scan (relative to project root)
scanDirs: [
+ 'backend/logos',
'data/logos',
'frontend/dist',
],
@@ -74,7 +75,7 @@ async function getFileSize(filePath) {
*/
async function optimizeSvgFile(filePath) {
const svg = await fs.readFile(filePath, 'utf8');
- const result = optimize(svg, {
+ const result = optimizeSvg(svg, {
path: filePath,
multipass: true,
plugins: [
@@ -100,6 +101,45 @@ async function optimizeSvgFile(filePath) {
return true;
}
+async function convertSvgToPng(svgPath) {
+ try {
+ const normalized = path.normalize(svgPath);
+ let pngPath = normalized.replace(/\.svg$/i, '.png');
+
+ const mappings = [
+ {
+ from: path.join(path.sep, 'data', 'logos', 'svg') + path.sep,
+ to: path.join(path.sep, 'data', 'logos', 'png') + path.sep,
+ },
+ {
+ from: path.join(path.sep, 'backend', 'logos', 'svg') + path.sep,
+ to: path.join(path.sep, 'backend', 'logos', 'png') + path.sep,
+ },
+ ];
+
+ for (const { from, to } of mappings) {
+ if (normalized.includes(from)) {
+ pngPath = normalized.replace(from, to).replace(/\.svg$/i, '.png');
+ break;
+ }
+ }
+
+ await fs.mkdir(path.dirname(pngPath), { recursive: true });
+
+ const image = sharp(svgPath, { density: 300 });
+ await image
+ .resize({ width: 512, fit: 'inside', withoutEnlargement: true })
+ .png({ quality: CONFIG.compression.png.quality, effort: CONFIG.compression.png.effort })
+ .toFile(pngPath);
+
+ console.log(chalk.green(` ✓ Converted to PNG: ${pngPath}`));
+ return true;
+ } catch (error) {
+ console.warn(chalk.yellow(` ⚠️ SVG to PNG conversion skipped: ${error.message}`));
+ return false;
+ }
+}
+
/**
* Optimize PNG/JPG file
*/
@@ -195,7 +235,11 @@ async function processFile(filePath) {
// Optimize based on file type
switch (ext) {
case 'svg':
- optimized = await optimizeSvgFile(filePath);
+ {
+ const didOptimize = await optimizeSvgFile(filePath);
+ const didConvert = await convertSvgToPng(filePath);
+ optimized = didOptimize || didConvert;
+ }
break;
case 'png':
case 'jpg':
diff --git a/scripts/package.json b/scripts/package.json
index 7cf7d03..8578f1b 100644
--- a/scripts/package.json
+++ b/scripts/package.json
@@ -5,7 +5,7 @@
"main": "optimize-assets.js",
"scripts": {
"optimize": "node optimize-assets.js",
- "optimize:watch": "nodemon --watch ../data --watch ../frontend/dist -e svg,png,pdf --exec npm run optimize"
+ "optimize:watch": "nodemon --watch ../backend/logos --watch ../data --watch ../frontend/dist -e svg,pdf --exec npm run optimize"
},
"dependencies": {
"chalk": "^4.1.2",
diff --git a/vision.md b/vision.md
index 4b39b3c..6e00f04 100644
--- a/vision.md
+++ b/vision.md
@@ -1,119 +1,119 @@
-🇨🇿 Czech Clubs Logos API
-
-A fullstack project for serving high-quality, transparent background logos of Czech football & futsal clubs.
-Logos are mapped by FAČR UUIDs (from facr.tdvorak.dev
-) to ensure consistency across projects.
-
-✨ Features
-
-⚽ Fetch Czech clubs metadata from FAČR Scraper API.
-
-🖼️ Upload & store full-quality transparent logos (SVG/PNG).
-
-🔄 Reuse FAČR UUID as a unique identifier.
-
-🌐 Serve logos through a simple CDN-style API.
-
-📝 Optional metadata (club name, city, colors, competition).
-
-📦 Self-hosted with Go backend + CDN storage.
-
-🔧 Tech Stack
-
-Backend: Golang (Gin or Fiber)
-
-Storage:
-
-Local /logos/{id}.svg
-
-Or cloud (Supabase / Cloudflare R2 / S3)
-
-Database: SQLite/Postgres (to link UUID ↔ metadata ↔ logo file)
-
-External API: facr.tdvorak.dev
-
-📂 Project Structure
-czech-clubs-logos-api/
-│── backend/
-│ ├── main.go # Go API entrypoint
-│ ├── routes.go # API routes
-│ ├── facr_client.go # Client for facr.tdvorak.dev
-│ ├── handlers/
-│ │ ├── upload.go # Handle logo upload
-│ │ ├── logos.go # Serve logos
-│ │ └── clubs.go # Proxy FAČR API
-│ └── storage/
-│ └── local.go # Logo saving/loading
-│── logos/ # Stored club logos (UUID.svg/png)
-│── frontend/ # (optional, for admin upload UI)
-│── db.sqlite # Database (UUID ↔ metadata)
-│── go.mod
-│── README.md
-
-🚀 API Endpoints
-Search clubs
-
-Proxy FAČR search to help find correct UUID:
-
-GET /clubs/search?q=sparta
-→ proxies facr.tdvorak.dev/club/search?q=sparta
-
-Get club info
-GET /clubs/:id
-→ proxies facr.tdvorak.dev/club/{id}
-
-Upload logo
-
-Upload a full-quality SVG/PNG logo mapped to a FAČR UUID:
-
-POST /logos/:id
-FormData: file=@slavia.svg
-→ Saves to ./logos/{id}.svg
-→ Stores metadata in DB
-
-Get logo
-
-Serve logo by FAČR UUID:
-
-GET /logos/:id
-→ returns {id}.svg/png
-
-Get logo with metadata
-GET /logos/:id/json
-{
- "id": "00000000-0000-0000-0000-000000000000",
- "club": "AC Sparta Praha",
- "type": "football",
- "logo_url": "https://cdn.example.com/logos/00000000-0000-0000-0000-000000000000.svg"
-}
-
-📊 Example Workflow
-
-Search for a club:
-
-GET /clubs/search?q=Slavia
-→ returns UUID: 11111111-2222-3333-4444-555555555555
-
-
-Upload logo for club:
-
-POST /logos/11111111-2222-3333-4444-555555555555
-file=@slavia.svg
-
-
-Get logo:
-
-GET /logos/11111111-2222-3333-4444-555555555555
-→ returns full quality transparent SVG
-
-🔮 Future Ideas
-
-✍️ Web admin panel for uploading logos.
-
-🎨 Auto background remover (e.g., remove.bg API).
-
-🔎 Logo search by club name (maps internally to UUID).
-
-📦 Publish as NPM package (@czech-football/logos) or Go module.
-
+🇨🇿 Czech Clubs Logos API
+
+A fullstack project for serving high-quality, transparent background logos of Czech football & futsal clubs.
+Logos are mapped by FAČR UUIDs (from facr.tdvorak.dev
+) to ensure consistency across projects.
+
+✨ Features
+
+⚽ Fetch Czech clubs metadata from FAČR Scraper API.
+
+🖼️ Upload & store full-quality transparent logos (SVG/PNG).
+
+🔄 Reuse FAČR UUID as a unique identifier.
+
+🌐 Serve logos through a simple CDN-style API.
+
+📝 Optional metadata (club name, city, colors, competition).
+
+📦 Self-hosted with Go backend + CDN storage.
+
+🔧 Tech Stack
+
+Backend: Golang (Gin or Fiber)
+
+Storage:
+
+Local /logos/{id}.svg
+
+Or cloud (Supabase / Cloudflare R2 / S3)
+
+Database: SQLite/Postgres (to link UUID ↔ metadata ↔ logo file)
+
+External API: facr.tdvorak.dev
+
+📂 Project Structure
+czech-clubs-logos-api/
+│── backend/
+│ ├── main.go # Go API entrypoint
+│ ├── routes.go # API routes
+│ ├── facr_client.go # Client for facr.tdvorak.dev
+│ ├── handlers/
+│ │ ├── upload.go # Handle logo upload
+│ │ ├── logos.go # Serve logos
+│ │ └── clubs.go # Proxy FAČR API
+│ └── storage/
+│ └── local.go # Logo saving/loading
+│── logos/ # Stored club logos (UUID.svg/png)
+│── frontend/ # (optional, for admin upload UI)
+│── db.sqlite # Database (UUID ↔ metadata)
+│── go.mod
+│── README.md
+
+🚀 API Endpoints
+Search clubs
+
+Proxy FAČR search to help find correct UUID:
+
+GET /clubs/search?q=sparta
+→ proxies facr.tdvorak.dev/club/search?q=sparta
+
+Get club info
+GET /clubs/:id
+→ proxies facr.tdvorak.dev/club/{id}
+
+Upload logo
+
+Upload a full-quality SVG/PNG logo mapped to a FAČR UUID:
+
+POST /logos/:id
+FormData: file=@slavia.svg
+→ Saves to ./logos/{id}.svg
+→ Stores metadata in DB
+
+Get logo
+
+Serve logo by FAČR UUID:
+
+GET /logos/:id
+→ returns {id}.svg/png
+
+Get logo with metadata
+GET /logos/:id/json
+{
+ "id": "00000000-0000-0000-0000-000000000000",
+ "club": "AC Sparta Praha",
+ "type": "football",
+ "logo_url": "https://cdn.example.com/logos/00000000-0000-0000-0000-000000000000.svg"
+}
+
+📊 Example Workflow
+
+Search for a club:
+
+GET /clubs/search?q=Slavia
+→ returns UUID: 11111111-2222-3333-4444-555555555555
+
+
+Upload logo for club:
+
+POST /logos/11111111-2222-3333-4444-555555555555
+file=@slavia.svg
+
+
+Get logo:
+
+GET /logos/11111111-2222-3333-4444-555555555555
+→ returns full quality transparent SVG
+
+🔮 Future Ideas
+
+✍️ Web admin panel for uploading logos.
+
+🎨 Auto background remover (e.g., remove.bg API).
+
+🔎 Logo search by club name (maps internally to UUID).
+
+📦 Publish as NPM package (@czech-football/logos) or Go module.
+
👉 This way, you’ll have a FAČR-aware logo CDN that anyone can integrate into websites, apps, or your SportCreative projects.
\ No newline at end of file