This commit is contained in:
Tomas Dvorak
2025-10-22 20:35:22 +02:00
parent e47059385c
commit e6bc2eedb3
55 changed files with 1751 additions and 1378 deletions
Binary file not shown.
+3
View File
@@ -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
+8
View File
@@ -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=
+65 -12
View File
@@ -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 == "" {
+67 -10
View File
@@ -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
+1
View File
@@ -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)
}
}
+1
View File
@@ -15,6 +15,7 @@
<a href="/" class="text-2xl font-bold gradient-text">🇨🇿 České Kluby Loga</a>
<div class="flex gap-4">
<a href="/" class="nav-link px-4 py-2 rounded-lg hover:bg-dark-border transition-smooth">Domů</a>
<a href="/logos.html" class="nav-link px-4 py-2 rounded-lg hover:bg-dark-border transition-smooth">Všechna Loga</a>
<a href="/api-docs.html" class="nav-link px-4 py-2 rounded-lg hover:bg-dark-border transition-smooth">API Docs</a>
<a href="/admin.html" class="nav-link px-4 py-2 rounded-lg hover:bg-dark-border transition-smooth">Admin</a>
</div>
+67
View File
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="cs" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Všechna Loga - České Kluby Loga API</title>
<link rel="stylesheet" href="/src/style.css">
</head>
<body class="bg-dark-bg text-white min-h-screen">
<nav class="border-b border-dark-border bg-dark-card/50 backdrop-blur-sm sticky top-0 z-50">
<div class="container mx-auto px-6 py-4">
<div class="flex items-center justify-between">
<a href="/" class="text-2xl font-bold gradient-text">České Kluby Loga</a>
<div class="flex gap-4">
<a href="/" class="nav-link px-4 py-2 rounded-lg hover:bg-dark-border transition-smooth">Domů</a>
<a href="/logos.html" class="nav-link px-4 py-2 rounded-lg bg-accent-blue/20 transition-smooth">Všechna Loga</a>
<a href="/api-docs.html" class="nav-link px-4 py-2 rounded-lg hover:bg-dark-border transition-smooth">API Docs</a>
<a href="/admin.html" class="nav-link px-4 py-2 rounded-lg hover:bg-dark-border transition-smooth">Admin</a>
</div>
</div>
</div>
</nav>
<header class="border-b border-dark-border bg-dark-card">
<div class="container mx-auto px-6 py-8">
<h1 class="text-3xl font-bold gradient-text mb-2">Všechna Loga</h1>
<p class="text-gray-400">Procházejte všechna dostupná loga, vyhledávejte a spravujte</p>
</div>
</header>
<main class="container mx-auto px-6 py-12">
<div class="mb-6 flex flex-col md:flex-row gap-3 md:items-center">
<input
type="text"
id="allLogoSearch"
placeholder="Hledat mezi všemi logy..."
class="w-full md:max-w-lg bg-dark-card border border-dark-border rounded-lg px-4 py-3 text-white focus:outline-none focus:border-accent-blue transition-smooth"
>
<div class="text-xs text-gray-500">20 log na stránku • řazeno: nejnovější</div>
</div>
<div id="allLoading" class="text-center py-12">
<div class="spinner mx-auto"></div>
<p class="mt-4 text-gray-400">Načítání log...</p>
</div>
<div id="allEmpty" class="text-center py-16 hidden">
<div class="text-6xl mb-4"></div>
<p class="text-xl text-gray-400 mb-4">Žádná loga nenalezena</p>
</div>
<div id="allLogoGrid" class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6 gap-6"></div>
<div class="text-center mt-10">
<button id="loadMoreBtn" class="px-6 py-3 bg-dark-card border border-dark-border rounded-lg hover:bg-dark-border transition-smooth hidden">Načíst další</button>
</div>
</main>
<footer class="border-t border-dark-border mt-20">
<div class="container mx-auto px-6 py-8 text-center text-gray-400">
<p>🇨🇿 České Kluby Loga API</p>
</div>
</footer>
<script type="module" src="/src/logos.js"></script>
</body>
</html>
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+15 -15
View File
@@ -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).
+7 -7
View File
@@ -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.
+11 -11
View File
@@ -1,11 +1,11 @@
A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
[![NPM](https://nodei.co/npm/color-name.png?mini=true)](https://nodei.co/npm/color-name/)
```js
var colors = require('color-name');
colors.red //[255,0,0]
```
<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
[![NPM](https://nodei.co/npm/color-name.png?mini=true)](https://nodei.co/npm/color-name/)
```js
var colors = require('color-name');
colors.red //[255,0,0]
```
<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
+152 -152
View File
@@ -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]
};
+28 -28
View File
@@ -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 <dfcreative@gmail.com>",
"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 <dfcreative@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/colorjs/color-name/issues"
},
"homepage": "https://github.com/colorjs/color-name"
}
+60 -60
View File
@@ -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;
}
+46 -46
View File
@@ -1,46 +1,46 @@
# read-cache [![Build Status](https://travis-ci.org/TrySound/read-cache.svg?branch=master)](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 [![Build Status](https://travis-ci.org/TrySound/read-cache.svg?branch=master)](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)
+78 -78
View File
@@ -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);
};
+70 -70
View File
@@ -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;
+77 -77
View File
@@ -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;
+26 -31
View File
@@ -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 = `
<div class="col-span-full text-center py-16">
<p class="text-xl text-gray-400">No logos found matching "${query}"</p>
</div>
`
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 = `
<div class="col-span-full text-center py-16">
<p class="text-xl text-gray-400">No logos found matching "${q}"</p>
</div>
`
}
} 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(() => {
+132
View File
@@ -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 `
<div class="logo-card bg-dark-card rounded-xl p-4 border border-dark-border hover:border-accent-blue transition-smooth group" data-id="${logo.id}">
<div class="aspect-square bg-dark-bg rounded-lg flex items-center justify-center mb-3 overflow-hidden cursor-pointer">
<img src="${logoUrl}" alt="${logo.club_name}" class="max-w-full max-h-full object-contain p-2 group-hover:scale-110 transition-transform duration-300" loading="lazy" onerror="this.parentElement.innerHTML='<svg class=\'w-8 h-8 text-gray-500\' fill=\'none\' stroke=\'currentColor\' viewBox=\'0 0 24 24\'><path stroke-linecap=\'round\' stroke-linejoin=\'round\' stroke-width=\'2\' d=\'M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\'></path></svg>'">
</div>
<div class="flex items-center gap-3">
<div class="flex-1 min-w-0 cursor-pointer">
<h3 class="font-semibold text-sm truncate mb-0.5">${logo.club_name}</h3>
<p class="text-xs text-gray-400 truncate">${logo.club_type || 'fotbal'}</p>
</div>
<button class="delete-logo px-3 py-1.5 text-xs bg-red-600 rounded hover:bg-red-500 transition-smooth">Smazat</button>
</div>
</div>
`
}).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)
+2 -1
View File
@@ -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')
}
}
}
+5
View File
@@ -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
)
+6
View File
@@ -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=
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+17 -17
View File
@@ -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" %*
+7 -7
View File
@@ -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.
+11 -11
View File
@@ -1,11 +1,11 @@
A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
[![NPM](https://nodei.co/npm/color-name.png?mini=true)](https://nodei.co/npm/color-name/)
```js
var colors = require('color-name');
colors.red //[255,0,0]
```
<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
[![NPM](https://nodei.co/npm/color-name.png?mini=true)](https://nodei.co/npm/color-name/)
```js
var colors = require('color-name');
colors.red //[255,0,0]
```
<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
+152 -152
View File
@@ -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]
};
+28 -28
View File
@@ -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 <dfcreative@gmail.com>",
"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 <dfcreative@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/colorjs/color-name/issues"
},
"homepage": "https://github.com/colorjs/color-name"
}
+53 -53
View File
@@ -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;
+46 -2
View File
@@ -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':
+1 -1
View File
@@ -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",
+118 -118
View File
@@ -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, youll have a FAČR-aware logo CDN that anyone can integrate into websites, apps, or your SportCreative projects.