Spaces:
Running
Running
upload slice
Browse files- backend/handlers/caption.go +65 -0
- backend/handlers/metadata.go +26 -0
- backend/handlers/upload.go +11 -6
- backend/internal/captioner/stub.go +16 -0
- backend/main.go +23 -6
- backend/migrations/0003_placeholder.sql +22 -0
- frontend/package-lock.json +543 -25
- frontend/package.json +3 -2
- frontend/src/App.tsx +2 -1
- frontend/src/pages/ReviewPage.tsx +33 -0
- frontend/src/pages/UploadPage.tsx +233 -118
- frontend/vite.config.ts +15 -2
backend/handlers/caption.go
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package handlers
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"time"
|
| 5 |
+
"net/http"
|
| 6 |
+
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
"github.com/google/uuid"
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
// POST /api/maps/:id/caption
|
| 12 |
+
func (d *UploadDeps) CreateCaption(c *gin.Context) {
|
| 13 |
+
ctx := c.Request.Context()
|
| 14 |
+
mapID := c.Param("id")
|
| 15 |
+
|
| 16 |
+
// 1) look up the map’s file key
|
| 17 |
+
var key string
|
| 18 |
+
if err := d.DB.QueryRowContext(ctx,
|
| 19 |
+
`SELECT file_key FROM maps WHERE map_id = $1`, mapID).Scan(&key); err != nil {
|
| 20 |
+
c.JSON(http.StatusNotFound, gin.H{"error": "map not found"})
|
| 21 |
+
return
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
// 2) generate placeholder caption
|
| 25 |
+
text, model := d.Cap.Generate(ctx, key)
|
| 26 |
+
|
| 27 |
+
// 3) insert caption row
|
| 28 |
+
capID := uuid.New()
|
| 29 |
+
if _, err := d.DB.ExecContext(ctx, `
|
| 30 |
+
INSERT INTO captions (cap_id, map_id, generated, model, raw_json, created_at)
|
| 31 |
+
VALUES ($1,$2,$3,$4,$5,NOW())`,
|
| 32 |
+
capID, mapID, text, model, []byte("{}")); err != nil {
|
| 33 |
+
c.JSON(http.StatusInternalServerError, gin.H{"error": "db insert failed"})
|
| 34 |
+
return
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// 4) respond to the front‑end
|
| 38 |
+
c.JSON(http.StatusOK, gin.H{
|
| 39 |
+
"captionId": capID,
|
| 40 |
+
"generated": text,
|
| 41 |
+
})
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
func (d *UploadDeps) GetCaption(c *gin.Context) {
|
| 45 |
+
ctx := c.Request.Context()
|
| 46 |
+
capID := c.Param("id")
|
| 47 |
+
|
| 48 |
+
var key, text string
|
| 49 |
+
if err := d.DB.QueryRowContext(ctx, `
|
| 50 |
+
SELECT m.file_key, c.generated
|
| 51 |
+
FROM captions c
|
| 52 |
+
JOIN maps m ON c.map_id = m.id
|
| 53 |
+
WHERE c.id = $1`, capID).Scan(&key, &text); err != nil {
|
| 54 |
+
c.JSON(http.StatusNotFound, gin.H{"error": "caption not found"})
|
| 55 |
+
return
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
// turn object key into a 24‑hour presigned URL
|
| 59 |
+
url, _ := d.Storage.Link(ctx, key, 24*time.Hour)
|
| 60 |
+
|
| 61 |
+
c.JSON(http.StatusOK, gin.H{
|
| 62 |
+
"imageUrl": url,
|
| 63 |
+
"generated": text,
|
| 64 |
+
})
|
| 65 |
+
}
|
backend/handlers/metadata.go
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package handlers
|
| 2 |
+
|
| 3 |
+
import "github.com/gin-gonic/gin"
|
| 4 |
+
|
| 5 |
+
// PUT /api/maps/:id/metadata
|
| 6 |
+
func (d *UploadDeps) UpdateMapMetadata(c *gin.Context) {
|
| 7 |
+
mapID := c.Param("id")
|
| 8 |
+
var req struct {
|
| 9 |
+
Source string `json:"source"`
|
| 10 |
+
Region string `json:"region"`
|
| 11 |
+
Category string `json:"category"`
|
| 12 |
+
}
|
| 13 |
+
if err := c.BindJSON(&req); err != nil {
|
| 14 |
+
c.JSON(400, gin.H{"error": "invalid json"})
|
| 15 |
+
return
|
| 16 |
+
}
|
| 17 |
+
_, err := d.DB.Exec(`UPDATE maps
|
| 18 |
+
SET source=$1, region=$2, category=$3
|
| 19 |
+
WHERE id=$4`,
|
| 20 |
+
req.Source, req.Region, req.Category, mapID)
|
| 21 |
+
if err != nil {
|
| 22 |
+
c.JSON(500, gin.H{"error": "db update failed"})
|
| 23 |
+
return
|
| 24 |
+
}
|
| 25 |
+
c.Status(204)
|
| 26 |
+
}
|
backend/handlers/upload.go
CHANGED
|
@@ -6,6 +6,7 @@ import (
|
|
| 6 |
"database/sql"
|
| 7 |
"encoding/hex"
|
| 8 |
"io"
|
|
|
|
| 9 |
"net/http"
|
| 10 |
"time"
|
| 11 |
|
|
@@ -13,6 +14,7 @@ import (
|
|
| 13 |
"github.com/google/uuid"
|
| 14 |
"github.com/lib/pq"
|
| 15 |
"github.com/SCGR-1/promptaid-backend/internal/storage"
|
|
|
|
| 16 |
)
|
| 17 |
|
| 18 |
|
|
@@ -21,8 +23,8 @@ type UploadDeps struct {
|
|
| 21 |
DB *sql.DB
|
| 22 |
Storage storage.ObjectStore
|
| 23 |
Bucket string
|
| 24 |
-
RegionOK map[string]bool
|
| 25 |
-
|
| 26 |
}
|
| 27 |
|
| 28 |
func (d *UploadDeps) UploadMap(c *gin.Context) {
|
|
@@ -79,22 +81,25 @@ func (d *UploadDeps) UploadMap(c *gin.Context) {
|
|
| 79 |
|
| 80 |
// ---- 5. Insert into maps -------------------------------------------
|
| 81 |
mapID := uuid.New()
|
| 82 |
-
|
| 83 |
INSERT INTO maps
|
| 84 |
-
(
|
| 85 |
VALUES ($1,$2,$3,$4,$5,$6,NOW())`,
|
| 86 |
mapID, objKey, shaHex,
|
| 87 |
params.Source, params.Region, params.Category,
|
| 88 |
)
|
| 89 |
if err != nil {
|
| 90 |
-
|
|
|
|
| 91 |
return
|
| 92 |
}
|
|
|
|
|
|
|
| 93 |
|
| 94 |
// ---- 6. Insert any countries ---------------------------------------
|
| 95 |
if len(params.Countries) > 0 {
|
| 96 |
_, err = d.DB.Exec(`
|
| 97 |
-
INSERT INTO map_countries (map_id,
|
| 98 |
SELECT $1, UNNEST($2::char(2)[])
|
| 99 |
ON CONFLICT DO NOTHING`,
|
| 100 |
mapID, pq.Array(params.Countries),
|
|
|
|
| 6 |
"database/sql"
|
| 7 |
"encoding/hex"
|
| 8 |
"io"
|
| 9 |
+
"log"
|
| 10 |
"net/http"
|
| 11 |
"time"
|
| 12 |
|
|
|
|
| 14 |
"github.com/google/uuid"
|
| 15 |
"github.com/lib/pq"
|
| 16 |
"github.com/SCGR-1/promptaid-backend/internal/storage"
|
| 17 |
+
"github.com/SCGR-1/promptaid-backend/internal/captioner"
|
| 18 |
)
|
| 19 |
|
| 20 |
|
|
|
|
| 23 |
DB *sql.DB
|
| 24 |
Storage storage.ObjectStore
|
| 25 |
Bucket string
|
| 26 |
+
RegionOK map[string]bool
|
| 27 |
+
Cap captioner.Captioner
|
| 28 |
}
|
| 29 |
|
| 30 |
func (d *UploadDeps) UploadMap(c *gin.Context) {
|
|
|
|
| 81 |
|
| 82 |
// ---- 5. Insert into maps -------------------------------------------
|
| 83 |
mapID := uuid.New()
|
| 84 |
+
res, err := d.DB.Exec(`
|
| 85 |
INSERT INTO maps
|
| 86 |
+
(map_id, file_key, sha256, source, region, category, created_at)
|
| 87 |
VALUES ($1,$2,$3,$4,$5,$6,NOW())`,
|
| 88 |
mapID, objKey, shaHex,
|
| 89 |
params.Source, params.Region, params.Category,
|
| 90 |
)
|
| 91 |
if err != nil {
|
| 92 |
+
log.Printf("🔴 maps INSERT error: %v", err)
|
| 93 |
+
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
| 94 |
return
|
| 95 |
}
|
| 96 |
+
rows, _ := res.RowsAffected()
|
| 97 |
+
log.Printf("🟢 maps INSERT succeeded, rows affected: %d", rows)
|
| 98 |
|
| 99 |
// ---- 6. Insert any countries ---------------------------------------
|
| 100 |
if len(params.Countries) > 0 {
|
| 101 |
_, err = d.DB.Exec(`
|
| 102 |
+
INSERT INTO map_countries (map_id, c_code)
|
| 103 |
SELECT $1, UNNEST($2::char(2)[])
|
| 104 |
ON CONFLICT DO NOTHING`,
|
| 105 |
mapID, pq.Array(params.Countries),
|
backend/internal/captioner/stub.go
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package captioner
|
| 2 |
+
|
| 3 |
+
import "context"
|
| 4 |
+
|
| 5 |
+
// A pluggable captioner interface (so you can swap to GPT‑4o later).
|
| 6 |
+
type Captioner interface {
|
| 7 |
+
Generate(ctx context.Context, objectKey string) (text, model string)
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
// Minimal stub: always returns the same caption.
|
| 11 |
+
type Stub struct{}
|
| 12 |
+
|
| 13 |
+
func (Stub) Generate(_ context.Context, _ string) (string, string) {
|
| 14 |
+
return "🔧 Stub caption: replace me with GPT‑4o", "GPT‑4O"
|
| 15 |
+
}
|
| 16 |
+
|
backend/main.go
CHANGED
|
@@ -10,6 +10,7 @@ import (
|
|
| 10 |
|
| 11 |
"github.com/SCGR-1/promptaid-backend/internal/storage"
|
| 12 |
"github.com/SCGR-1/promptaid-backend/handlers"
|
|
|
|
| 13 |
)
|
| 14 |
|
| 15 |
type Config struct {
|
|
@@ -26,12 +27,17 @@ func loadConfig() Config {
|
|
| 26 |
|
| 27 |
|
| 28 |
func main() {
|
| 29 |
-
|
| 30 |
-
cfg := loadConfig()
|
| 31 |
|
| 32 |
// ---- 1. connect DB ----
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
// ---- 2. choose storage driver ----
|
| 37 |
var store storage.ObjectStore
|
|
@@ -54,8 +60,9 @@ func main() {
|
|
| 54 |
uploadDeps := handlers.UploadDeps{
|
| 55 |
DB: db,
|
| 56 |
Storage: store,
|
| 57 |
-
Bucket:
|
| 58 |
RegionOK: make(map[string]bool),
|
|
|
|
| 59 |
}
|
| 60 |
|
| 61 |
// ---- 3. build server ----
|
|
@@ -65,7 +72,17 @@ func main() {
|
|
| 65 |
r.Static("/static", l.Root()) // add Root() getter or hardcode "./uploads"
|
| 66 |
}
|
| 67 |
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
log.Fatal(r.Run(":8080"))
|
| 71 |
}
|
|
|
|
| 10 |
|
| 11 |
"github.com/SCGR-1/promptaid-backend/internal/storage"
|
| 12 |
"github.com/SCGR-1/promptaid-backend/handlers"
|
| 13 |
+
"github.com/SCGR-1/promptaid-backend/internal/captioner"
|
| 14 |
)
|
| 15 |
|
| 16 |
type Config struct {
|
|
|
|
| 27 |
|
| 28 |
|
| 29 |
func main() {
|
|
|
|
|
|
|
| 30 |
|
| 31 |
// ---- 1. connect DB ----
|
| 32 |
+
dsn := os.Getenv("DATABASE_URL")
|
| 33 |
+
if dsn == "" {
|
| 34 |
+
dsn = "postgres://promptaid:promptaid@localhost:5432/promptaid?sslmode=disable"
|
| 35 |
+
}
|
| 36 |
+
db, err := sql.Open("postgres", dsn)
|
| 37 |
+
if err != nil {
|
| 38 |
+
log.Fatal(err)
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
|
| 42 |
// ---- 2. choose storage driver ----
|
| 43 |
var store storage.ObjectStore
|
|
|
|
| 60 |
uploadDeps := handlers.UploadDeps{
|
| 61 |
DB: db,
|
| 62 |
Storage: store,
|
| 63 |
+
Bucket: os.Getenv("S3_BUCKET"),
|
| 64 |
RegionOK: make(map[string]bool),
|
| 65 |
+
Cap: captioner.Stub{},
|
| 66 |
}
|
| 67 |
|
| 68 |
// ---- 3. build server ----
|
|
|
|
| 72 |
r.Static("/static", l.Root()) // add Root() getter or hardcode "./uploads"
|
| 73 |
}
|
| 74 |
|
| 75 |
+
api := r.Group("/api")
|
| 76 |
+
|
| 77 |
+
api.POST("/maps", uploadDeps.UploadMap)
|
| 78 |
+
api.POST("/maps/:id/caption", uploadDeps.CreateCaption)
|
| 79 |
+
api.PUT ("/maps/:id/metadata", uploadDeps.UpdateMapMetadata)
|
| 80 |
+
api.GET ("/captions/:id", uploadDeps.GetCaption)
|
| 81 |
+
|
| 82 |
+
uploadDeps.RegionOK = map[string]bool{
|
| 83 |
+
"_TBD_REGION": true,
|
| 84 |
+
"AFR": true, "AMR": true, "APA": true, "EUR": true, "MENA": true,
|
| 85 |
+
}
|
| 86 |
|
| 87 |
log.Fatal(r.Run(":8080"))
|
| 88 |
}
|
backend/migrations/0003_placeholder.sql
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-- +goose Up
|
| 2 |
+
|
| 3 |
+
INSERT INTO sources (s_code, label)
|
| 4 |
+
VALUES
|
| 5 |
+
('_TBD_SOURCE', 'TBD placeholder')
|
| 6 |
+
ON CONFLICT (s_code) DO NOTHING;
|
| 7 |
+
|
| 8 |
+
INSERT INTO region (r_code, label)
|
| 9 |
+
VALUES
|
| 10 |
+
('_TBD_REGION', 'TBD placeholder')
|
| 11 |
+
ON CONFLICT (r_code) DO NOTHING;
|
| 12 |
+
|
| 13 |
+
INSERT INTO category (cat_code, label)
|
| 14 |
+
VALUES
|
| 15 |
+
('_TBD_CATEGORY', 'TBD placeholder')
|
| 16 |
+
ON CONFLICT (cat_code) DO NOTHING;
|
| 17 |
+
|
| 18 |
+
-- +goose Down
|
| 19 |
+
|
| 20 |
+
DELETE FROM category WHERE cat_code = '_TBD_CATEGORY';
|
| 21 |
+
DELETE FROM region WHERE r_code = '_TBD_REGION';
|
| 22 |
+
DELETE FROM sources WHERE s_code = '_TBD_SOURCE';
|
frontend/package-lock.json
CHANGED
|
@@ -18,8 +18,10 @@
|
|
| 18 |
"devDependencies": {
|
| 19 |
"@eslint/js": "^9.30.1",
|
| 20 |
"@tailwindcss/postcss": "^4.1.11",
|
|
|
|
| 21 |
"@types/react": "^19.1.8",
|
| 22 |
"@types/react-dom": "^19.1.6",
|
|
|
|
| 23 |
"@vitejs/plugin-react-swc": "^3.10.2",
|
| 24 |
"autoprefixer": "^10.4.21",
|
| 25 |
"eslint": "^9.30.1",
|
|
@@ -29,8 +31,7 @@
|
|
| 29 |
"postcss": "^8.5.6",
|
| 30 |
"tailwindcss": "^4.1.11",
|
| 31 |
"typescript": "~5.8.3",
|
| 32 |
-
"typescript-eslint": "^8.35.1"
|
| 33 |
-
"vite": "^7.0.4"
|
| 34 |
}
|
| 35 |
},
|
| 36 |
"node_modules/@alloc/quick-lru": {
|
|
@@ -60,6 +61,260 @@
|
|
| 60 |
"node": ">=6.0.0"
|
| 61 |
}
|
| 62 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
"node_modules/@babel/runtime": {
|
| 64 |
"version": "7.27.6",
|
| 65 |
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
|
|
@@ -81,6 +336,54 @@
|
|
| 81 |
"node": ">=6.9.0"
|
| 82 |
}
|
| 83 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
"node_modules/@esbuild/aix-ppc64": {
|
| 85 |
"version": "0.25.6",
|
| 86 |
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz",
|
|
@@ -94,6 +397,7 @@
|
|
| 94 |
"os": [
|
| 95 |
"aix"
|
| 96 |
],
|
|
|
|
| 97 |
"engines": {
|
| 98 |
"node": ">=18"
|
| 99 |
}
|
|
@@ -111,6 +415,7 @@
|
|
| 111 |
"os": [
|
| 112 |
"android"
|
| 113 |
],
|
|
|
|
| 114 |
"engines": {
|
| 115 |
"node": ">=18"
|
| 116 |
}
|
|
@@ -128,6 +433,7 @@
|
|
| 128 |
"os": [
|
| 129 |
"android"
|
| 130 |
],
|
|
|
|
| 131 |
"engines": {
|
| 132 |
"node": ">=18"
|
| 133 |
}
|
|
@@ -145,6 +451,7 @@
|
|
| 145 |
"os": [
|
| 146 |
"android"
|
| 147 |
],
|
|
|
|
| 148 |
"engines": {
|
| 149 |
"node": ">=18"
|
| 150 |
}
|
|
@@ -162,6 +469,7 @@
|
|
| 162 |
"os": [
|
| 163 |
"darwin"
|
| 164 |
],
|
|
|
|
| 165 |
"engines": {
|
| 166 |
"node": ">=18"
|
| 167 |
}
|
|
@@ -179,6 +487,7 @@
|
|
| 179 |
"os": [
|
| 180 |
"darwin"
|
| 181 |
],
|
|
|
|
| 182 |
"engines": {
|
| 183 |
"node": ">=18"
|
| 184 |
}
|
|
@@ -196,6 +505,7 @@
|
|
| 196 |
"os": [
|
| 197 |
"freebsd"
|
| 198 |
],
|
|
|
|
| 199 |
"engines": {
|
| 200 |
"node": ">=18"
|
| 201 |
}
|
|
@@ -213,6 +523,7 @@
|
|
| 213 |
"os": [
|
| 214 |
"freebsd"
|
| 215 |
],
|
|
|
|
| 216 |
"engines": {
|
| 217 |
"node": ">=18"
|
| 218 |
}
|
|
@@ -230,6 +541,7 @@
|
|
| 230 |
"os": [
|
| 231 |
"linux"
|
| 232 |
],
|
|
|
|
| 233 |
"engines": {
|
| 234 |
"node": ">=18"
|
| 235 |
}
|
|
@@ -247,6 +559,7 @@
|
|
| 247 |
"os": [
|
| 248 |
"linux"
|
| 249 |
],
|
|
|
|
| 250 |
"engines": {
|
| 251 |
"node": ">=18"
|
| 252 |
}
|
|
@@ -264,6 +577,7 @@
|
|
| 264 |
"os": [
|
| 265 |
"linux"
|
| 266 |
],
|
|
|
|
| 267 |
"engines": {
|
| 268 |
"node": ">=18"
|
| 269 |
}
|
|
@@ -281,6 +595,7 @@
|
|
| 281 |
"os": [
|
| 282 |
"linux"
|
| 283 |
],
|
|
|
|
| 284 |
"engines": {
|
| 285 |
"node": ">=18"
|
| 286 |
}
|
|
@@ -298,6 +613,7 @@
|
|
| 298 |
"os": [
|
| 299 |
"linux"
|
| 300 |
],
|
|
|
|
| 301 |
"engines": {
|
| 302 |
"node": ">=18"
|
| 303 |
}
|
|
@@ -315,6 +631,7 @@
|
|
| 315 |
"os": [
|
| 316 |
"linux"
|
| 317 |
],
|
|
|
|
| 318 |
"engines": {
|
| 319 |
"node": ">=18"
|
| 320 |
}
|
|
@@ -332,6 +649,7 @@
|
|
| 332 |
"os": [
|
| 333 |
"linux"
|
| 334 |
],
|
|
|
|
| 335 |
"engines": {
|
| 336 |
"node": ">=18"
|
| 337 |
}
|
|
@@ -349,6 +667,7 @@
|
|
| 349 |
"os": [
|
| 350 |
"linux"
|
| 351 |
],
|
|
|
|
| 352 |
"engines": {
|
| 353 |
"node": ">=18"
|
| 354 |
}
|
|
@@ -366,6 +685,7 @@
|
|
| 366 |
"os": [
|
| 367 |
"linux"
|
| 368 |
],
|
|
|
|
| 369 |
"engines": {
|
| 370 |
"node": ">=18"
|
| 371 |
}
|
|
@@ -383,6 +703,7 @@
|
|
| 383 |
"os": [
|
| 384 |
"netbsd"
|
| 385 |
],
|
|
|
|
| 386 |
"engines": {
|
| 387 |
"node": ">=18"
|
| 388 |
}
|
|
@@ -400,6 +721,7 @@
|
|
| 400 |
"os": [
|
| 401 |
"netbsd"
|
| 402 |
],
|
|
|
|
| 403 |
"engines": {
|
| 404 |
"node": ">=18"
|
| 405 |
}
|
|
@@ -417,6 +739,7 @@
|
|
| 417 |
"os": [
|
| 418 |
"openbsd"
|
| 419 |
],
|
|
|
|
| 420 |
"engines": {
|
| 421 |
"node": ">=18"
|
| 422 |
}
|
|
@@ -434,6 +757,7 @@
|
|
| 434 |
"os": [
|
| 435 |
"openbsd"
|
| 436 |
],
|
|
|
|
| 437 |
"engines": {
|
| 438 |
"node": ">=18"
|
| 439 |
}
|
|
@@ -451,6 +775,7 @@
|
|
| 451 |
"os": [
|
| 452 |
"openharmony"
|
| 453 |
],
|
|
|
|
| 454 |
"engines": {
|
| 455 |
"node": ">=18"
|
| 456 |
}
|
|
@@ -468,6 +793,7 @@
|
|
| 468 |
"os": [
|
| 469 |
"sunos"
|
| 470 |
],
|
|
|
|
| 471 |
"engines": {
|
| 472 |
"node": ">=18"
|
| 473 |
}
|
|
@@ -485,6 +811,7 @@
|
|
| 485 |
"os": [
|
| 486 |
"win32"
|
| 487 |
],
|
|
|
|
| 488 |
"engines": {
|
| 489 |
"node": ">=18"
|
| 490 |
}
|
|
@@ -502,6 +829,7 @@
|
|
| 502 |
"os": [
|
| 503 |
"win32"
|
| 504 |
],
|
|
|
|
| 505 |
"engines": {
|
| 506 |
"node": ">=18"
|
| 507 |
}
|
|
@@ -519,6 +847,7 @@
|
|
| 519 |
"os": [
|
| 520 |
"win32"
|
| 521 |
],
|
|
|
|
| 522 |
"engines": {
|
| 523 |
"node": ">=18"
|
| 524 |
}
|
|
@@ -900,7 +1229,8 @@
|
|
| 900 |
"optional": true,
|
| 901 |
"os": [
|
| 902 |
"android"
|
| 903 |
-
]
|
|
|
|
| 904 |
},
|
| 905 |
"node_modules/@rollup/rollup-android-arm64": {
|
| 906 |
"version": "4.44.2",
|
|
@@ -914,7 +1244,8 @@
|
|
| 914 |
"optional": true,
|
| 915 |
"os": [
|
| 916 |
"android"
|
| 917 |
-
]
|
|
|
|
| 918 |
},
|
| 919 |
"node_modules/@rollup/rollup-darwin-arm64": {
|
| 920 |
"version": "4.44.2",
|
|
@@ -928,7 +1259,8 @@
|
|
| 928 |
"optional": true,
|
| 929 |
"os": [
|
| 930 |
"darwin"
|
| 931 |
-
]
|
|
|
|
| 932 |
},
|
| 933 |
"node_modules/@rollup/rollup-darwin-x64": {
|
| 934 |
"version": "4.44.2",
|
|
@@ -942,7 +1274,8 @@
|
|
| 942 |
"optional": true,
|
| 943 |
"os": [
|
| 944 |
"darwin"
|
| 945 |
-
]
|
|
|
|
| 946 |
},
|
| 947 |
"node_modules/@rollup/rollup-freebsd-arm64": {
|
| 948 |
"version": "4.44.2",
|
|
@@ -956,7 +1289,8 @@
|
|
| 956 |
"optional": true,
|
| 957 |
"os": [
|
| 958 |
"freebsd"
|
| 959 |
-
]
|
|
|
|
| 960 |
},
|
| 961 |
"node_modules/@rollup/rollup-freebsd-x64": {
|
| 962 |
"version": "4.44.2",
|
|
@@ -970,7 +1304,8 @@
|
|
| 970 |
"optional": true,
|
| 971 |
"os": [
|
| 972 |
"freebsd"
|
| 973 |
-
]
|
|
|
|
| 974 |
},
|
| 975 |
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
| 976 |
"version": "4.44.2",
|
|
@@ -984,7 +1319,8 @@
|
|
| 984 |
"optional": true,
|
| 985 |
"os": [
|
| 986 |
"linux"
|
| 987 |
-
]
|
|
|
|
| 988 |
},
|
| 989 |
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
| 990 |
"version": "4.44.2",
|
|
@@ -998,7 +1334,8 @@
|
|
| 998 |
"optional": true,
|
| 999 |
"os": [
|
| 1000 |
"linux"
|
| 1001 |
-
]
|
|
|
|
| 1002 |
},
|
| 1003 |
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
| 1004 |
"version": "4.44.2",
|
|
@@ -1012,7 +1349,8 @@
|
|
| 1012 |
"optional": true,
|
| 1013 |
"os": [
|
| 1014 |
"linux"
|
| 1015 |
-
]
|
|
|
|
| 1016 |
},
|
| 1017 |
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
| 1018 |
"version": "4.44.2",
|
|
@@ -1026,7 +1364,8 @@
|
|
| 1026 |
"optional": true,
|
| 1027 |
"os": [
|
| 1028 |
"linux"
|
| 1029 |
-
]
|
|
|
|
| 1030 |
},
|
| 1031 |
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
| 1032 |
"version": "4.44.2",
|
|
@@ -1040,7 +1379,8 @@
|
|
| 1040 |
"optional": true,
|
| 1041 |
"os": [
|
| 1042 |
"linux"
|
| 1043 |
-
]
|
|
|
|
| 1044 |
},
|
| 1045 |
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
| 1046 |
"version": "4.44.2",
|
|
@@ -1054,7 +1394,8 @@
|
|
| 1054 |
"optional": true,
|
| 1055 |
"os": [
|
| 1056 |
"linux"
|
| 1057 |
-
]
|
|
|
|
| 1058 |
},
|
| 1059 |
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
| 1060 |
"version": "4.44.2",
|
|
@@ -1068,7 +1409,8 @@
|
|
| 1068 |
"optional": true,
|
| 1069 |
"os": [
|
| 1070 |
"linux"
|
| 1071 |
-
]
|
|
|
|
| 1072 |
},
|
| 1073 |
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
| 1074 |
"version": "4.44.2",
|
|
@@ -1082,7 +1424,8 @@
|
|
| 1082 |
"optional": true,
|
| 1083 |
"os": [
|
| 1084 |
"linux"
|
| 1085 |
-
]
|
|
|
|
| 1086 |
},
|
| 1087 |
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
| 1088 |
"version": "4.44.2",
|
|
@@ -1096,7 +1439,8 @@
|
|
| 1096 |
"optional": true,
|
| 1097 |
"os": [
|
| 1098 |
"linux"
|
| 1099 |
-
]
|
|
|
|
| 1100 |
},
|
| 1101 |
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
| 1102 |
"version": "4.44.2",
|
|
@@ -1110,7 +1454,8 @@
|
|
| 1110 |
"optional": true,
|
| 1111 |
"os": [
|
| 1112 |
"linux"
|
| 1113 |
-
]
|
|
|
|
| 1114 |
},
|
| 1115 |
"node_modules/@rollup/rollup-linux-x64-musl": {
|
| 1116 |
"version": "4.44.2",
|
|
@@ -1124,7 +1469,8 @@
|
|
| 1124 |
"optional": true,
|
| 1125 |
"os": [
|
| 1126 |
"linux"
|
| 1127 |
-
]
|
|
|
|
| 1128 |
},
|
| 1129 |
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
| 1130 |
"version": "4.44.2",
|
|
@@ -1138,7 +1484,8 @@
|
|
| 1138 |
"optional": true,
|
| 1139 |
"os": [
|
| 1140 |
"win32"
|
| 1141 |
-
]
|
|
|
|
| 1142 |
},
|
| 1143 |
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
| 1144 |
"version": "4.44.2",
|
|
@@ -1152,7 +1499,8 @@
|
|
| 1152 |
"optional": true,
|
| 1153 |
"os": [
|
| 1154 |
"win32"
|
| 1155 |
-
]
|
|
|
|
| 1156 |
},
|
| 1157 |
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
| 1158 |
"version": "4.44.2",
|
|
@@ -1166,7 +1514,8 @@
|
|
| 1166 |
"optional": true,
|
| 1167 |
"os": [
|
| 1168 |
"win32"
|
| 1169 |
-
]
|
|
|
|
| 1170 |
},
|
| 1171 |
"node_modules/@swc/core": {
|
| 1172 |
"version": "1.12.11",
|
|
@@ -1679,6 +2028,51 @@
|
|
| 1679 |
"@babel/runtime-corejs3": "^7.22.6"
|
| 1680 |
}
|
| 1681 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1682 |
"node_modules/@types/estree": {
|
| 1683 |
"version": "1.0.8",
|
| 1684 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
|
@@ -1693,6 +2087,16 @@
|
|
| 1693 |
"dev": true,
|
| 1694 |
"license": "MIT"
|
| 1695 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1696 |
"node_modules/@types/react": {
|
| 1697 |
"version": "19.1.8",
|
| 1698 |
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
|
|
@@ -1970,6 +2374,27 @@
|
|
| 1970 |
"url": "https://opencollective.com/typescript-eslint"
|
| 1971 |
}
|
| 1972 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1973 |
"node_modules/@vitejs/plugin-react-swc": {
|
| 1974 |
"version": "3.10.2",
|
| 1975 |
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.10.2.tgz",
|
|
@@ -1984,6 +2409,13 @@
|
|
| 1984 |
"vite": "^4 || ^5 || ^6 || ^7.0.0-beta.0"
|
| 1985 |
}
|
| 1986 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1987 |
"node_modules/acorn": {
|
| 1988 |
"version": "8.15.0",
|
| 1989 |
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
|
@@ -2246,6 +2678,13 @@
|
|
| 2246 |
"dev": true,
|
| 2247 |
"license": "MIT"
|
| 2248 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2249 |
"node_modules/core-js-pure": {
|
| 2250 |
"version": "3.44.0",
|
| 2251 |
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.44.0.tgz",
|
|
@@ -2424,6 +2863,7 @@
|
|
| 2424 |
"dev": true,
|
| 2425 |
"hasInstallScript": true,
|
| 2426 |
"license": "MIT",
|
|
|
|
| 2427 |
"bin": {
|
| 2428 |
"esbuild": "bin/esbuild"
|
| 2429 |
},
|
|
@@ -2821,10 +3261,21 @@
|
|
| 2821 |
"os": [
|
| 2822 |
"darwin"
|
| 2823 |
],
|
|
|
|
| 2824 |
"engines": {
|
| 2825 |
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
| 2826 |
}
|
| 2827 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2828 |
"node_modules/get-nonce": {
|
| 2829 |
"version": "1.0.1",
|
| 2830 |
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
|
@@ -3018,6 +3469,19 @@
|
|
| 3018 |
"js-yaml": "bin/js-yaml.js"
|
| 3019 |
}
|
| 3020 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3021 |
"node_modules/json-buffer": {
|
| 3022 |
"version": "3.0.1",
|
| 3023 |
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
|
@@ -3039,6 +3503,19 @@
|
|
| 3039 |
"dev": true,
|
| 3040 |
"license": "MIT"
|
| 3041 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3042 |
"node_modules/keyv": {
|
| 3043 |
"version": "4.5.4",
|
| 3044 |
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
|
@@ -3337,6 +3814,23 @@
|
|
| 3337 |
"loose-envify": "cli.js"
|
| 3338 |
}
|
| 3339 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3340 |
"node_modules/lucide-react": {
|
| 3341 |
"version": "0.525.0",
|
| 3342 |
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz",
|
|
@@ -3777,6 +4271,16 @@
|
|
| 3777 |
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
| 3778 |
"license": "MIT"
|
| 3779 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3780 |
"node_modules/react-remove-scroll": {
|
| 3781 |
"version": "2.7.1",
|
| 3782 |
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
|
|
@@ -3905,6 +4409,7 @@
|
|
| 3905 |
"integrity": "sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==",
|
| 3906 |
"dev": true,
|
| 3907 |
"license": "MIT",
|
|
|
|
| 3908 |
"dependencies": {
|
| 3909 |
"@types/estree": "1.0.8"
|
| 3910 |
},
|
|
@@ -4098,6 +4603,7 @@
|
|
| 4098 |
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
|
| 4099 |
"dev": true,
|
| 4100 |
"license": "MIT",
|
|
|
|
| 4101 |
"dependencies": {
|
| 4102 |
"fdir": "^6.4.4",
|
| 4103 |
"picomatch": "^4.0.2"
|
|
@@ -4115,6 +4621,7 @@
|
|
| 4115 |
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
| 4116 |
"dev": true,
|
| 4117 |
"license": "MIT",
|
|
|
|
| 4118 |
"peerDependencies": {
|
| 4119 |
"picomatch": "^3 || ^4"
|
| 4120 |
},
|
|
@@ -4130,6 +4637,7 @@
|
|
| 4130 |
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
| 4131 |
"dev": true,
|
| 4132 |
"license": "MIT",
|
|
|
|
| 4133 |
"engines": {
|
| 4134 |
"node": ">=12"
|
| 4135 |
},
|
|
@@ -4219,6 +4727,13 @@
|
|
| 4219 |
"typescript": ">=4.8.4 <5.9.0"
|
| 4220 |
}
|
| 4221 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4222 |
"node_modules/update-browserslist-db": {
|
| 4223 |
"version": "1.1.3",
|
| 4224 |
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
|
@@ -4304,11 +4819,12 @@
|
|
| 4304 |
}
|
| 4305 |
},
|
| 4306 |
"node_modules/vite": {
|
| 4307 |
-
"version": "7.0.
|
| 4308 |
-
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.
|
| 4309 |
-
"integrity": "sha512-
|
| 4310 |
"dev": true,
|
| 4311 |
"license": "MIT",
|
|
|
|
| 4312 |
"dependencies": {
|
| 4313 |
"esbuild": "^0.25.0",
|
| 4314 |
"fdir": "^6.4.6",
|
|
@@ -4384,6 +4900,7 @@
|
|
| 4384 |
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
| 4385 |
"dev": true,
|
| 4386 |
"license": "MIT",
|
|
|
|
| 4387 |
"peerDependencies": {
|
| 4388 |
"picomatch": "^3 || ^4"
|
| 4389 |
},
|
|
@@ -4399,6 +4916,7 @@
|
|
| 4399 |
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
| 4400 |
"dev": true,
|
| 4401 |
"license": "MIT",
|
|
|
|
| 4402 |
"engines": {
|
| 4403 |
"node": ">=12"
|
| 4404 |
},
|
|
|
|
| 18 |
"devDependencies": {
|
| 19 |
"@eslint/js": "^9.30.1",
|
| 20 |
"@tailwindcss/postcss": "^4.1.11",
|
| 21 |
+
"@types/node": "^24.1.0",
|
| 22 |
"@types/react": "^19.1.8",
|
| 23 |
"@types/react-dom": "^19.1.6",
|
| 24 |
+
"@vitejs/plugin-react": "^4.7.0",
|
| 25 |
"@vitejs/plugin-react-swc": "^3.10.2",
|
| 26 |
"autoprefixer": "^10.4.21",
|
| 27 |
"eslint": "^9.30.1",
|
|
|
|
| 31 |
"postcss": "^8.5.6",
|
| 32 |
"tailwindcss": "^4.1.11",
|
| 33 |
"typescript": "~5.8.3",
|
| 34 |
+
"typescript-eslint": "^8.35.1"
|
|
|
|
| 35 |
}
|
| 36 |
},
|
| 37 |
"node_modules/@alloc/quick-lru": {
|
|
|
|
| 61 |
"node": ">=6.0.0"
|
| 62 |
}
|
| 63 |
},
|
| 64 |
+
"node_modules/@babel/code-frame": {
|
| 65 |
+
"version": "7.27.1",
|
| 66 |
+
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
| 67 |
+
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
|
| 68 |
+
"dev": true,
|
| 69 |
+
"license": "MIT",
|
| 70 |
+
"dependencies": {
|
| 71 |
+
"@babel/helper-validator-identifier": "^7.27.1",
|
| 72 |
+
"js-tokens": "^4.0.0",
|
| 73 |
+
"picocolors": "^1.1.1"
|
| 74 |
+
},
|
| 75 |
+
"engines": {
|
| 76 |
+
"node": ">=6.9.0"
|
| 77 |
+
}
|
| 78 |
+
},
|
| 79 |
+
"node_modules/@babel/compat-data": {
|
| 80 |
+
"version": "7.28.0",
|
| 81 |
+
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz",
|
| 82 |
+
"integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==",
|
| 83 |
+
"dev": true,
|
| 84 |
+
"license": "MIT",
|
| 85 |
+
"engines": {
|
| 86 |
+
"node": ">=6.9.0"
|
| 87 |
+
}
|
| 88 |
+
},
|
| 89 |
+
"node_modules/@babel/core": {
|
| 90 |
+
"version": "7.28.0",
|
| 91 |
+
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
|
| 92 |
+
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
|
| 93 |
+
"dev": true,
|
| 94 |
+
"license": "MIT",
|
| 95 |
+
"dependencies": {
|
| 96 |
+
"@ampproject/remapping": "^2.2.0",
|
| 97 |
+
"@babel/code-frame": "^7.27.1",
|
| 98 |
+
"@babel/generator": "^7.28.0",
|
| 99 |
+
"@babel/helper-compilation-targets": "^7.27.2",
|
| 100 |
+
"@babel/helper-module-transforms": "^7.27.3",
|
| 101 |
+
"@babel/helpers": "^7.27.6",
|
| 102 |
+
"@babel/parser": "^7.28.0",
|
| 103 |
+
"@babel/template": "^7.27.2",
|
| 104 |
+
"@babel/traverse": "^7.28.0",
|
| 105 |
+
"@babel/types": "^7.28.0",
|
| 106 |
+
"convert-source-map": "^2.0.0",
|
| 107 |
+
"debug": "^4.1.0",
|
| 108 |
+
"gensync": "^1.0.0-beta.2",
|
| 109 |
+
"json5": "^2.2.3",
|
| 110 |
+
"semver": "^6.3.1"
|
| 111 |
+
},
|
| 112 |
+
"engines": {
|
| 113 |
+
"node": ">=6.9.0"
|
| 114 |
+
},
|
| 115 |
+
"funding": {
|
| 116 |
+
"type": "opencollective",
|
| 117 |
+
"url": "https://opencollective.com/babel"
|
| 118 |
+
}
|
| 119 |
+
},
|
| 120 |
+
"node_modules/@babel/core/node_modules/semver": {
|
| 121 |
+
"version": "6.3.1",
|
| 122 |
+
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
| 123 |
+
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
| 124 |
+
"dev": true,
|
| 125 |
+
"license": "ISC",
|
| 126 |
+
"bin": {
|
| 127 |
+
"semver": "bin/semver.js"
|
| 128 |
+
}
|
| 129 |
+
},
|
| 130 |
+
"node_modules/@babel/generator": {
|
| 131 |
+
"version": "7.28.0",
|
| 132 |
+
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
|
| 133 |
+
"integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
|
| 134 |
+
"dev": true,
|
| 135 |
+
"license": "MIT",
|
| 136 |
+
"dependencies": {
|
| 137 |
+
"@babel/parser": "^7.28.0",
|
| 138 |
+
"@babel/types": "^7.28.0",
|
| 139 |
+
"@jridgewell/gen-mapping": "^0.3.12",
|
| 140 |
+
"@jridgewell/trace-mapping": "^0.3.28",
|
| 141 |
+
"jsesc": "^3.0.2"
|
| 142 |
+
},
|
| 143 |
+
"engines": {
|
| 144 |
+
"node": ">=6.9.0"
|
| 145 |
+
}
|
| 146 |
+
},
|
| 147 |
+
"node_modules/@babel/helper-compilation-targets": {
|
| 148 |
+
"version": "7.27.2",
|
| 149 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
|
| 150 |
+
"integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
|
| 151 |
+
"dev": true,
|
| 152 |
+
"license": "MIT",
|
| 153 |
+
"dependencies": {
|
| 154 |
+
"@babel/compat-data": "^7.27.2",
|
| 155 |
+
"@babel/helper-validator-option": "^7.27.1",
|
| 156 |
+
"browserslist": "^4.24.0",
|
| 157 |
+
"lru-cache": "^5.1.1",
|
| 158 |
+
"semver": "^6.3.1"
|
| 159 |
+
},
|
| 160 |
+
"engines": {
|
| 161 |
+
"node": ">=6.9.0"
|
| 162 |
+
}
|
| 163 |
+
},
|
| 164 |
+
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
| 165 |
+
"version": "6.3.1",
|
| 166 |
+
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
| 167 |
+
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
| 168 |
+
"dev": true,
|
| 169 |
+
"license": "ISC",
|
| 170 |
+
"bin": {
|
| 171 |
+
"semver": "bin/semver.js"
|
| 172 |
+
}
|
| 173 |
+
},
|
| 174 |
+
"node_modules/@babel/helper-globals": {
|
| 175 |
+
"version": "7.28.0",
|
| 176 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
|
| 177 |
+
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
|
| 178 |
+
"dev": true,
|
| 179 |
+
"license": "MIT",
|
| 180 |
+
"engines": {
|
| 181 |
+
"node": ">=6.9.0"
|
| 182 |
+
}
|
| 183 |
+
},
|
| 184 |
+
"node_modules/@babel/helper-module-imports": {
|
| 185 |
+
"version": "7.27.1",
|
| 186 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
|
| 187 |
+
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
|
| 188 |
+
"dev": true,
|
| 189 |
+
"license": "MIT",
|
| 190 |
+
"dependencies": {
|
| 191 |
+
"@babel/traverse": "^7.27.1",
|
| 192 |
+
"@babel/types": "^7.27.1"
|
| 193 |
+
},
|
| 194 |
+
"engines": {
|
| 195 |
+
"node": ">=6.9.0"
|
| 196 |
+
}
|
| 197 |
+
},
|
| 198 |
+
"node_modules/@babel/helper-module-transforms": {
|
| 199 |
+
"version": "7.27.3",
|
| 200 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
|
| 201 |
+
"integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
|
| 202 |
+
"dev": true,
|
| 203 |
+
"license": "MIT",
|
| 204 |
+
"dependencies": {
|
| 205 |
+
"@babel/helper-module-imports": "^7.27.1",
|
| 206 |
+
"@babel/helper-validator-identifier": "^7.27.1",
|
| 207 |
+
"@babel/traverse": "^7.27.3"
|
| 208 |
+
},
|
| 209 |
+
"engines": {
|
| 210 |
+
"node": ">=6.9.0"
|
| 211 |
+
},
|
| 212 |
+
"peerDependencies": {
|
| 213 |
+
"@babel/core": "^7.0.0"
|
| 214 |
+
}
|
| 215 |
+
},
|
| 216 |
+
"node_modules/@babel/helper-plugin-utils": {
|
| 217 |
+
"version": "7.27.1",
|
| 218 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
|
| 219 |
+
"integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
|
| 220 |
+
"dev": true,
|
| 221 |
+
"license": "MIT",
|
| 222 |
+
"engines": {
|
| 223 |
+
"node": ">=6.9.0"
|
| 224 |
+
}
|
| 225 |
+
},
|
| 226 |
+
"node_modules/@babel/helper-string-parser": {
|
| 227 |
+
"version": "7.27.1",
|
| 228 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
| 229 |
+
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
| 230 |
+
"dev": true,
|
| 231 |
+
"license": "MIT",
|
| 232 |
+
"engines": {
|
| 233 |
+
"node": ">=6.9.0"
|
| 234 |
+
}
|
| 235 |
+
},
|
| 236 |
+
"node_modules/@babel/helper-validator-identifier": {
|
| 237 |
+
"version": "7.27.1",
|
| 238 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
|
| 239 |
+
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
|
| 240 |
+
"dev": true,
|
| 241 |
+
"license": "MIT",
|
| 242 |
+
"engines": {
|
| 243 |
+
"node": ">=6.9.0"
|
| 244 |
+
}
|
| 245 |
+
},
|
| 246 |
+
"node_modules/@babel/helper-validator-option": {
|
| 247 |
+
"version": "7.27.1",
|
| 248 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
|
| 249 |
+
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
|
| 250 |
+
"dev": true,
|
| 251 |
+
"license": "MIT",
|
| 252 |
+
"engines": {
|
| 253 |
+
"node": ">=6.9.0"
|
| 254 |
+
}
|
| 255 |
+
},
|
| 256 |
+
"node_modules/@babel/helpers": {
|
| 257 |
+
"version": "7.27.6",
|
| 258 |
+
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz",
|
| 259 |
+
"integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==",
|
| 260 |
+
"dev": true,
|
| 261 |
+
"license": "MIT",
|
| 262 |
+
"dependencies": {
|
| 263 |
+
"@babel/template": "^7.27.2",
|
| 264 |
+
"@babel/types": "^7.27.6"
|
| 265 |
+
},
|
| 266 |
+
"engines": {
|
| 267 |
+
"node": ">=6.9.0"
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
"node_modules/@babel/parser": {
|
| 271 |
+
"version": "7.28.0",
|
| 272 |
+
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
|
| 273 |
+
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
|
| 274 |
+
"dev": true,
|
| 275 |
+
"license": "MIT",
|
| 276 |
+
"dependencies": {
|
| 277 |
+
"@babel/types": "^7.28.0"
|
| 278 |
+
},
|
| 279 |
+
"bin": {
|
| 280 |
+
"parser": "bin/babel-parser.js"
|
| 281 |
+
},
|
| 282 |
+
"engines": {
|
| 283 |
+
"node": ">=6.0.0"
|
| 284 |
+
}
|
| 285 |
+
},
|
| 286 |
+
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
| 287 |
+
"version": "7.27.1",
|
| 288 |
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
|
| 289 |
+
"integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
|
| 290 |
+
"dev": true,
|
| 291 |
+
"license": "MIT",
|
| 292 |
+
"dependencies": {
|
| 293 |
+
"@babel/helper-plugin-utils": "^7.27.1"
|
| 294 |
+
},
|
| 295 |
+
"engines": {
|
| 296 |
+
"node": ">=6.9.0"
|
| 297 |
+
},
|
| 298 |
+
"peerDependencies": {
|
| 299 |
+
"@babel/core": "^7.0.0-0"
|
| 300 |
+
}
|
| 301 |
+
},
|
| 302 |
+
"node_modules/@babel/plugin-transform-react-jsx-source": {
|
| 303 |
+
"version": "7.27.1",
|
| 304 |
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
|
| 305 |
+
"integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
|
| 306 |
+
"dev": true,
|
| 307 |
+
"license": "MIT",
|
| 308 |
+
"dependencies": {
|
| 309 |
+
"@babel/helper-plugin-utils": "^7.27.1"
|
| 310 |
+
},
|
| 311 |
+
"engines": {
|
| 312 |
+
"node": ">=6.9.0"
|
| 313 |
+
},
|
| 314 |
+
"peerDependencies": {
|
| 315 |
+
"@babel/core": "^7.0.0-0"
|
| 316 |
+
}
|
| 317 |
+
},
|
| 318 |
"node_modules/@babel/runtime": {
|
| 319 |
"version": "7.27.6",
|
| 320 |
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
|
|
|
|
| 336 |
"node": ">=6.9.0"
|
| 337 |
}
|
| 338 |
},
|
| 339 |
+
"node_modules/@babel/template": {
|
| 340 |
+
"version": "7.27.2",
|
| 341 |
+
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
|
| 342 |
+
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
|
| 343 |
+
"dev": true,
|
| 344 |
+
"license": "MIT",
|
| 345 |
+
"dependencies": {
|
| 346 |
+
"@babel/code-frame": "^7.27.1",
|
| 347 |
+
"@babel/parser": "^7.27.2",
|
| 348 |
+
"@babel/types": "^7.27.1"
|
| 349 |
+
},
|
| 350 |
+
"engines": {
|
| 351 |
+
"node": ">=6.9.0"
|
| 352 |
+
}
|
| 353 |
+
},
|
| 354 |
+
"node_modules/@babel/traverse": {
|
| 355 |
+
"version": "7.28.0",
|
| 356 |
+
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
|
| 357 |
+
"integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
|
| 358 |
+
"dev": true,
|
| 359 |
+
"license": "MIT",
|
| 360 |
+
"dependencies": {
|
| 361 |
+
"@babel/code-frame": "^7.27.1",
|
| 362 |
+
"@babel/generator": "^7.28.0",
|
| 363 |
+
"@babel/helper-globals": "^7.28.0",
|
| 364 |
+
"@babel/parser": "^7.28.0",
|
| 365 |
+
"@babel/template": "^7.27.2",
|
| 366 |
+
"@babel/types": "^7.28.0",
|
| 367 |
+
"debug": "^4.3.1"
|
| 368 |
+
},
|
| 369 |
+
"engines": {
|
| 370 |
+
"node": ">=6.9.0"
|
| 371 |
+
}
|
| 372 |
+
},
|
| 373 |
+
"node_modules/@babel/types": {
|
| 374 |
+
"version": "7.28.1",
|
| 375 |
+
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz",
|
| 376 |
+
"integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==",
|
| 377 |
+
"dev": true,
|
| 378 |
+
"license": "MIT",
|
| 379 |
+
"dependencies": {
|
| 380 |
+
"@babel/helper-string-parser": "^7.27.1",
|
| 381 |
+
"@babel/helper-validator-identifier": "^7.27.1"
|
| 382 |
+
},
|
| 383 |
+
"engines": {
|
| 384 |
+
"node": ">=6.9.0"
|
| 385 |
+
}
|
| 386 |
+
},
|
| 387 |
"node_modules/@esbuild/aix-ppc64": {
|
| 388 |
"version": "0.25.6",
|
| 389 |
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz",
|
|
|
|
| 397 |
"os": [
|
| 398 |
"aix"
|
| 399 |
],
|
| 400 |
+
"peer": true,
|
| 401 |
"engines": {
|
| 402 |
"node": ">=18"
|
| 403 |
}
|
|
|
|
| 415 |
"os": [
|
| 416 |
"android"
|
| 417 |
],
|
| 418 |
+
"peer": true,
|
| 419 |
"engines": {
|
| 420 |
"node": ">=18"
|
| 421 |
}
|
|
|
|
| 433 |
"os": [
|
| 434 |
"android"
|
| 435 |
],
|
| 436 |
+
"peer": true,
|
| 437 |
"engines": {
|
| 438 |
"node": ">=18"
|
| 439 |
}
|
|
|
|
| 451 |
"os": [
|
| 452 |
"android"
|
| 453 |
],
|
| 454 |
+
"peer": true,
|
| 455 |
"engines": {
|
| 456 |
"node": ">=18"
|
| 457 |
}
|
|
|
|
| 469 |
"os": [
|
| 470 |
"darwin"
|
| 471 |
],
|
| 472 |
+
"peer": true,
|
| 473 |
"engines": {
|
| 474 |
"node": ">=18"
|
| 475 |
}
|
|
|
|
| 487 |
"os": [
|
| 488 |
"darwin"
|
| 489 |
],
|
| 490 |
+
"peer": true,
|
| 491 |
"engines": {
|
| 492 |
"node": ">=18"
|
| 493 |
}
|
|
|
|
| 505 |
"os": [
|
| 506 |
"freebsd"
|
| 507 |
],
|
| 508 |
+
"peer": true,
|
| 509 |
"engines": {
|
| 510 |
"node": ">=18"
|
| 511 |
}
|
|
|
|
| 523 |
"os": [
|
| 524 |
"freebsd"
|
| 525 |
],
|
| 526 |
+
"peer": true,
|
| 527 |
"engines": {
|
| 528 |
"node": ">=18"
|
| 529 |
}
|
|
|
|
| 541 |
"os": [
|
| 542 |
"linux"
|
| 543 |
],
|
| 544 |
+
"peer": true,
|
| 545 |
"engines": {
|
| 546 |
"node": ">=18"
|
| 547 |
}
|
|
|
|
| 559 |
"os": [
|
| 560 |
"linux"
|
| 561 |
],
|
| 562 |
+
"peer": true,
|
| 563 |
"engines": {
|
| 564 |
"node": ">=18"
|
| 565 |
}
|
|
|
|
| 577 |
"os": [
|
| 578 |
"linux"
|
| 579 |
],
|
| 580 |
+
"peer": true,
|
| 581 |
"engines": {
|
| 582 |
"node": ">=18"
|
| 583 |
}
|
|
|
|
| 595 |
"os": [
|
| 596 |
"linux"
|
| 597 |
],
|
| 598 |
+
"peer": true,
|
| 599 |
"engines": {
|
| 600 |
"node": ">=18"
|
| 601 |
}
|
|
|
|
| 613 |
"os": [
|
| 614 |
"linux"
|
| 615 |
],
|
| 616 |
+
"peer": true,
|
| 617 |
"engines": {
|
| 618 |
"node": ">=18"
|
| 619 |
}
|
|
|
|
| 631 |
"os": [
|
| 632 |
"linux"
|
| 633 |
],
|
| 634 |
+
"peer": true,
|
| 635 |
"engines": {
|
| 636 |
"node": ">=18"
|
| 637 |
}
|
|
|
|
| 649 |
"os": [
|
| 650 |
"linux"
|
| 651 |
],
|
| 652 |
+
"peer": true,
|
| 653 |
"engines": {
|
| 654 |
"node": ">=18"
|
| 655 |
}
|
|
|
|
| 667 |
"os": [
|
| 668 |
"linux"
|
| 669 |
],
|
| 670 |
+
"peer": true,
|
| 671 |
"engines": {
|
| 672 |
"node": ">=18"
|
| 673 |
}
|
|
|
|
| 685 |
"os": [
|
| 686 |
"linux"
|
| 687 |
],
|
| 688 |
+
"peer": true,
|
| 689 |
"engines": {
|
| 690 |
"node": ">=18"
|
| 691 |
}
|
|
|
|
| 703 |
"os": [
|
| 704 |
"netbsd"
|
| 705 |
],
|
| 706 |
+
"peer": true,
|
| 707 |
"engines": {
|
| 708 |
"node": ">=18"
|
| 709 |
}
|
|
|
|
| 721 |
"os": [
|
| 722 |
"netbsd"
|
| 723 |
],
|
| 724 |
+
"peer": true,
|
| 725 |
"engines": {
|
| 726 |
"node": ">=18"
|
| 727 |
}
|
|
|
|
| 739 |
"os": [
|
| 740 |
"openbsd"
|
| 741 |
],
|
| 742 |
+
"peer": true,
|
| 743 |
"engines": {
|
| 744 |
"node": ">=18"
|
| 745 |
}
|
|
|
|
| 757 |
"os": [
|
| 758 |
"openbsd"
|
| 759 |
],
|
| 760 |
+
"peer": true,
|
| 761 |
"engines": {
|
| 762 |
"node": ">=18"
|
| 763 |
}
|
|
|
|
| 775 |
"os": [
|
| 776 |
"openharmony"
|
| 777 |
],
|
| 778 |
+
"peer": true,
|
| 779 |
"engines": {
|
| 780 |
"node": ">=18"
|
| 781 |
}
|
|
|
|
| 793 |
"os": [
|
| 794 |
"sunos"
|
| 795 |
],
|
| 796 |
+
"peer": true,
|
| 797 |
"engines": {
|
| 798 |
"node": ">=18"
|
| 799 |
}
|
|
|
|
| 811 |
"os": [
|
| 812 |
"win32"
|
| 813 |
],
|
| 814 |
+
"peer": true,
|
| 815 |
"engines": {
|
| 816 |
"node": ">=18"
|
| 817 |
}
|
|
|
|
| 829 |
"os": [
|
| 830 |
"win32"
|
| 831 |
],
|
| 832 |
+
"peer": true,
|
| 833 |
"engines": {
|
| 834 |
"node": ">=18"
|
| 835 |
}
|
|
|
|
| 847 |
"os": [
|
| 848 |
"win32"
|
| 849 |
],
|
| 850 |
+
"peer": true,
|
| 851 |
"engines": {
|
| 852 |
"node": ">=18"
|
| 853 |
}
|
|
|
|
| 1229 |
"optional": true,
|
| 1230 |
"os": [
|
| 1231 |
"android"
|
| 1232 |
+
],
|
| 1233 |
+
"peer": true
|
| 1234 |
},
|
| 1235 |
"node_modules/@rollup/rollup-android-arm64": {
|
| 1236 |
"version": "4.44.2",
|
|
|
|
| 1244 |
"optional": true,
|
| 1245 |
"os": [
|
| 1246 |
"android"
|
| 1247 |
+
],
|
| 1248 |
+
"peer": true
|
| 1249 |
},
|
| 1250 |
"node_modules/@rollup/rollup-darwin-arm64": {
|
| 1251 |
"version": "4.44.2",
|
|
|
|
| 1259 |
"optional": true,
|
| 1260 |
"os": [
|
| 1261 |
"darwin"
|
| 1262 |
+
],
|
| 1263 |
+
"peer": true
|
| 1264 |
},
|
| 1265 |
"node_modules/@rollup/rollup-darwin-x64": {
|
| 1266 |
"version": "4.44.2",
|
|
|
|
| 1274 |
"optional": true,
|
| 1275 |
"os": [
|
| 1276 |
"darwin"
|
| 1277 |
+
],
|
| 1278 |
+
"peer": true
|
| 1279 |
},
|
| 1280 |
"node_modules/@rollup/rollup-freebsd-arm64": {
|
| 1281 |
"version": "4.44.2",
|
|
|
|
| 1289 |
"optional": true,
|
| 1290 |
"os": [
|
| 1291 |
"freebsd"
|
| 1292 |
+
],
|
| 1293 |
+
"peer": true
|
| 1294 |
},
|
| 1295 |
"node_modules/@rollup/rollup-freebsd-x64": {
|
| 1296 |
"version": "4.44.2",
|
|
|
|
| 1304 |
"optional": true,
|
| 1305 |
"os": [
|
| 1306 |
"freebsd"
|
| 1307 |
+
],
|
| 1308 |
+
"peer": true
|
| 1309 |
},
|
| 1310 |
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
| 1311 |
"version": "4.44.2",
|
|
|
|
| 1319 |
"optional": true,
|
| 1320 |
"os": [
|
| 1321 |
"linux"
|
| 1322 |
+
],
|
| 1323 |
+
"peer": true
|
| 1324 |
},
|
| 1325 |
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
| 1326 |
"version": "4.44.2",
|
|
|
|
| 1334 |
"optional": true,
|
| 1335 |
"os": [
|
| 1336 |
"linux"
|
| 1337 |
+
],
|
| 1338 |
+
"peer": true
|
| 1339 |
},
|
| 1340 |
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
| 1341 |
"version": "4.44.2",
|
|
|
|
| 1349 |
"optional": true,
|
| 1350 |
"os": [
|
| 1351 |
"linux"
|
| 1352 |
+
],
|
| 1353 |
+
"peer": true
|
| 1354 |
},
|
| 1355 |
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
| 1356 |
"version": "4.44.2",
|
|
|
|
| 1364 |
"optional": true,
|
| 1365 |
"os": [
|
| 1366 |
"linux"
|
| 1367 |
+
],
|
| 1368 |
+
"peer": true
|
| 1369 |
},
|
| 1370 |
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
| 1371 |
"version": "4.44.2",
|
|
|
|
| 1379 |
"optional": true,
|
| 1380 |
"os": [
|
| 1381 |
"linux"
|
| 1382 |
+
],
|
| 1383 |
+
"peer": true
|
| 1384 |
},
|
| 1385 |
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
| 1386 |
"version": "4.44.2",
|
|
|
|
| 1394 |
"optional": true,
|
| 1395 |
"os": [
|
| 1396 |
"linux"
|
| 1397 |
+
],
|
| 1398 |
+
"peer": true
|
| 1399 |
},
|
| 1400 |
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
| 1401 |
"version": "4.44.2",
|
|
|
|
| 1409 |
"optional": true,
|
| 1410 |
"os": [
|
| 1411 |
"linux"
|
| 1412 |
+
],
|
| 1413 |
+
"peer": true
|
| 1414 |
},
|
| 1415 |
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
| 1416 |
"version": "4.44.2",
|
|
|
|
| 1424 |
"optional": true,
|
| 1425 |
"os": [
|
| 1426 |
"linux"
|
| 1427 |
+
],
|
| 1428 |
+
"peer": true
|
| 1429 |
},
|
| 1430 |
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
| 1431 |
"version": "4.44.2",
|
|
|
|
| 1439 |
"optional": true,
|
| 1440 |
"os": [
|
| 1441 |
"linux"
|
| 1442 |
+
],
|
| 1443 |
+
"peer": true
|
| 1444 |
},
|
| 1445 |
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
| 1446 |
"version": "4.44.2",
|
|
|
|
| 1454 |
"optional": true,
|
| 1455 |
"os": [
|
| 1456 |
"linux"
|
| 1457 |
+
],
|
| 1458 |
+
"peer": true
|
| 1459 |
},
|
| 1460 |
"node_modules/@rollup/rollup-linux-x64-musl": {
|
| 1461 |
"version": "4.44.2",
|
|
|
|
| 1469 |
"optional": true,
|
| 1470 |
"os": [
|
| 1471 |
"linux"
|
| 1472 |
+
],
|
| 1473 |
+
"peer": true
|
| 1474 |
},
|
| 1475 |
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
| 1476 |
"version": "4.44.2",
|
|
|
|
| 1484 |
"optional": true,
|
| 1485 |
"os": [
|
| 1486 |
"win32"
|
| 1487 |
+
],
|
| 1488 |
+
"peer": true
|
| 1489 |
},
|
| 1490 |
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
| 1491 |
"version": "4.44.2",
|
|
|
|
| 1499 |
"optional": true,
|
| 1500 |
"os": [
|
| 1501 |
"win32"
|
| 1502 |
+
],
|
| 1503 |
+
"peer": true
|
| 1504 |
},
|
| 1505 |
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
| 1506 |
"version": "4.44.2",
|
|
|
|
| 1514 |
"optional": true,
|
| 1515 |
"os": [
|
| 1516 |
"win32"
|
| 1517 |
+
],
|
| 1518 |
+
"peer": true
|
| 1519 |
},
|
| 1520 |
"node_modules/@swc/core": {
|
| 1521 |
"version": "1.12.11",
|
|
|
|
| 2028 |
"@babel/runtime-corejs3": "^7.22.6"
|
| 2029 |
}
|
| 2030 |
},
|
| 2031 |
+
"node_modules/@types/babel__core": {
|
| 2032 |
+
"version": "7.20.5",
|
| 2033 |
+
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
| 2034 |
+
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
|
| 2035 |
+
"dev": true,
|
| 2036 |
+
"license": "MIT",
|
| 2037 |
+
"dependencies": {
|
| 2038 |
+
"@babel/parser": "^7.20.7",
|
| 2039 |
+
"@babel/types": "^7.20.7",
|
| 2040 |
+
"@types/babel__generator": "*",
|
| 2041 |
+
"@types/babel__template": "*",
|
| 2042 |
+
"@types/babel__traverse": "*"
|
| 2043 |
+
}
|
| 2044 |
+
},
|
| 2045 |
+
"node_modules/@types/babel__generator": {
|
| 2046 |
+
"version": "7.27.0",
|
| 2047 |
+
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
|
| 2048 |
+
"integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
|
| 2049 |
+
"dev": true,
|
| 2050 |
+
"license": "MIT",
|
| 2051 |
+
"dependencies": {
|
| 2052 |
+
"@babel/types": "^7.0.0"
|
| 2053 |
+
}
|
| 2054 |
+
},
|
| 2055 |
+
"node_modules/@types/babel__template": {
|
| 2056 |
+
"version": "7.4.4",
|
| 2057 |
+
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
|
| 2058 |
+
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
|
| 2059 |
+
"dev": true,
|
| 2060 |
+
"license": "MIT",
|
| 2061 |
+
"dependencies": {
|
| 2062 |
+
"@babel/parser": "^7.1.0",
|
| 2063 |
+
"@babel/types": "^7.0.0"
|
| 2064 |
+
}
|
| 2065 |
+
},
|
| 2066 |
+
"node_modules/@types/babel__traverse": {
|
| 2067 |
+
"version": "7.20.7",
|
| 2068 |
+
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz",
|
| 2069 |
+
"integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==",
|
| 2070 |
+
"dev": true,
|
| 2071 |
+
"license": "MIT",
|
| 2072 |
+
"dependencies": {
|
| 2073 |
+
"@babel/types": "^7.20.7"
|
| 2074 |
+
}
|
| 2075 |
+
},
|
| 2076 |
"node_modules/@types/estree": {
|
| 2077 |
"version": "1.0.8",
|
| 2078 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
|
|
|
| 2087 |
"dev": true,
|
| 2088 |
"license": "MIT"
|
| 2089 |
},
|
| 2090 |
+
"node_modules/@types/node": {
|
| 2091 |
+
"version": "24.1.0",
|
| 2092 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz",
|
| 2093 |
+
"integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==",
|
| 2094 |
+
"dev": true,
|
| 2095 |
+
"license": "MIT",
|
| 2096 |
+
"dependencies": {
|
| 2097 |
+
"undici-types": "~7.8.0"
|
| 2098 |
+
}
|
| 2099 |
+
},
|
| 2100 |
"node_modules/@types/react": {
|
| 2101 |
"version": "19.1.8",
|
| 2102 |
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
|
|
|
|
| 2374 |
"url": "https://opencollective.com/typescript-eslint"
|
| 2375 |
}
|
| 2376 |
},
|
| 2377 |
+
"node_modules/@vitejs/plugin-react": {
|
| 2378 |
+
"version": "4.7.0",
|
| 2379 |
+
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
| 2380 |
+
"integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
|
| 2381 |
+
"dev": true,
|
| 2382 |
+
"license": "MIT",
|
| 2383 |
+
"dependencies": {
|
| 2384 |
+
"@babel/core": "^7.28.0",
|
| 2385 |
+
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
|
| 2386 |
+
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
|
| 2387 |
+
"@rolldown/pluginutils": "1.0.0-beta.27",
|
| 2388 |
+
"@types/babel__core": "^7.20.5",
|
| 2389 |
+
"react-refresh": "^0.17.0"
|
| 2390 |
+
},
|
| 2391 |
+
"engines": {
|
| 2392 |
+
"node": "^14.18.0 || >=16.0.0"
|
| 2393 |
+
},
|
| 2394 |
+
"peerDependencies": {
|
| 2395 |
+
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
| 2396 |
+
}
|
| 2397 |
+
},
|
| 2398 |
"node_modules/@vitejs/plugin-react-swc": {
|
| 2399 |
"version": "3.10.2",
|
| 2400 |
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.10.2.tgz",
|
|
|
|
| 2409 |
"vite": "^4 || ^5 || ^6 || ^7.0.0-beta.0"
|
| 2410 |
}
|
| 2411 |
},
|
| 2412 |
+
"node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": {
|
| 2413 |
+
"version": "1.0.0-beta.27",
|
| 2414 |
+
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
| 2415 |
+
"integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
|
| 2416 |
+
"dev": true,
|
| 2417 |
+
"license": "MIT"
|
| 2418 |
+
},
|
| 2419 |
"node_modules/acorn": {
|
| 2420 |
"version": "8.15.0",
|
| 2421 |
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
|
|
|
| 2678 |
"dev": true,
|
| 2679 |
"license": "MIT"
|
| 2680 |
},
|
| 2681 |
+
"node_modules/convert-source-map": {
|
| 2682 |
+
"version": "2.0.0",
|
| 2683 |
+
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
| 2684 |
+
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
|
| 2685 |
+
"dev": true,
|
| 2686 |
+
"license": "MIT"
|
| 2687 |
+
},
|
| 2688 |
"node_modules/core-js-pure": {
|
| 2689 |
"version": "3.44.0",
|
| 2690 |
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.44.0.tgz",
|
|
|
|
| 2863 |
"dev": true,
|
| 2864 |
"hasInstallScript": true,
|
| 2865 |
"license": "MIT",
|
| 2866 |
+
"peer": true,
|
| 2867 |
"bin": {
|
| 2868 |
"esbuild": "bin/esbuild"
|
| 2869 |
},
|
|
|
|
| 3261 |
"os": [
|
| 3262 |
"darwin"
|
| 3263 |
],
|
| 3264 |
+
"peer": true,
|
| 3265 |
"engines": {
|
| 3266 |
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
| 3267 |
}
|
| 3268 |
},
|
| 3269 |
+
"node_modules/gensync": {
|
| 3270 |
+
"version": "1.0.0-beta.2",
|
| 3271 |
+
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
| 3272 |
+
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
|
| 3273 |
+
"dev": true,
|
| 3274 |
+
"license": "MIT",
|
| 3275 |
+
"engines": {
|
| 3276 |
+
"node": ">=6.9.0"
|
| 3277 |
+
}
|
| 3278 |
+
},
|
| 3279 |
"node_modules/get-nonce": {
|
| 3280 |
"version": "1.0.1",
|
| 3281 |
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
|
|
|
| 3469 |
"js-yaml": "bin/js-yaml.js"
|
| 3470 |
}
|
| 3471 |
},
|
| 3472 |
+
"node_modules/jsesc": {
|
| 3473 |
+
"version": "3.1.0",
|
| 3474 |
+
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
|
| 3475 |
+
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
|
| 3476 |
+
"dev": true,
|
| 3477 |
+
"license": "MIT",
|
| 3478 |
+
"bin": {
|
| 3479 |
+
"jsesc": "bin/jsesc"
|
| 3480 |
+
},
|
| 3481 |
+
"engines": {
|
| 3482 |
+
"node": ">=6"
|
| 3483 |
+
}
|
| 3484 |
+
},
|
| 3485 |
"node_modules/json-buffer": {
|
| 3486 |
"version": "3.0.1",
|
| 3487 |
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
|
|
|
| 3503 |
"dev": true,
|
| 3504 |
"license": "MIT"
|
| 3505 |
},
|
| 3506 |
+
"node_modules/json5": {
|
| 3507 |
+
"version": "2.2.3",
|
| 3508 |
+
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
| 3509 |
+
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
| 3510 |
+
"dev": true,
|
| 3511 |
+
"license": "MIT",
|
| 3512 |
+
"bin": {
|
| 3513 |
+
"json5": "lib/cli.js"
|
| 3514 |
+
},
|
| 3515 |
+
"engines": {
|
| 3516 |
+
"node": ">=6"
|
| 3517 |
+
}
|
| 3518 |
+
},
|
| 3519 |
"node_modules/keyv": {
|
| 3520 |
"version": "4.5.4",
|
| 3521 |
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
|
|
|
| 3814 |
"loose-envify": "cli.js"
|
| 3815 |
}
|
| 3816 |
},
|
| 3817 |
+
"node_modules/lru-cache": {
|
| 3818 |
+
"version": "5.1.1",
|
| 3819 |
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
| 3820 |
+
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
| 3821 |
+
"dev": true,
|
| 3822 |
+
"license": "ISC",
|
| 3823 |
+
"dependencies": {
|
| 3824 |
+
"yallist": "^3.0.2"
|
| 3825 |
+
}
|
| 3826 |
+
},
|
| 3827 |
+
"node_modules/lru-cache/node_modules/yallist": {
|
| 3828 |
+
"version": "3.1.1",
|
| 3829 |
+
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
| 3830 |
+
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
| 3831 |
+
"dev": true,
|
| 3832 |
+
"license": "ISC"
|
| 3833 |
+
},
|
| 3834 |
"node_modules/lucide-react": {
|
| 3835 |
"version": "0.525.0",
|
| 3836 |
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz",
|
|
|
|
| 4271 |
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
| 4272 |
"license": "MIT"
|
| 4273 |
},
|
| 4274 |
+
"node_modules/react-refresh": {
|
| 4275 |
+
"version": "0.17.0",
|
| 4276 |
+
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
|
| 4277 |
+
"integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
|
| 4278 |
+
"dev": true,
|
| 4279 |
+
"license": "MIT",
|
| 4280 |
+
"engines": {
|
| 4281 |
+
"node": ">=0.10.0"
|
| 4282 |
+
}
|
| 4283 |
+
},
|
| 4284 |
"node_modules/react-remove-scroll": {
|
| 4285 |
"version": "2.7.1",
|
| 4286 |
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
|
|
|
|
| 4409 |
"integrity": "sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==",
|
| 4410 |
"dev": true,
|
| 4411 |
"license": "MIT",
|
| 4412 |
+
"peer": true,
|
| 4413 |
"dependencies": {
|
| 4414 |
"@types/estree": "1.0.8"
|
| 4415 |
},
|
|
|
|
| 4603 |
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
|
| 4604 |
"dev": true,
|
| 4605 |
"license": "MIT",
|
| 4606 |
+
"peer": true,
|
| 4607 |
"dependencies": {
|
| 4608 |
"fdir": "^6.4.4",
|
| 4609 |
"picomatch": "^4.0.2"
|
|
|
|
| 4621 |
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
| 4622 |
"dev": true,
|
| 4623 |
"license": "MIT",
|
| 4624 |
+
"peer": true,
|
| 4625 |
"peerDependencies": {
|
| 4626 |
"picomatch": "^3 || ^4"
|
| 4627 |
},
|
|
|
|
| 4637 |
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
| 4638 |
"dev": true,
|
| 4639 |
"license": "MIT",
|
| 4640 |
+
"peer": true,
|
| 4641 |
"engines": {
|
| 4642 |
"node": ">=12"
|
| 4643 |
},
|
|
|
|
| 4727 |
"typescript": ">=4.8.4 <5.9.0"
|
| 4728 |
}
|
| 4729 |
},
|
| 4730 |
+
"node_modules/undici-types": {
|
| 4731 |
+
"version": "7.8.0",
|
| 4732 |
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
|
| 4733 |
+
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
|
| 4734 |
+
"dev": true,
|
| 4735 |
+
"license": "MIT"
|
| 4736 |
+
},
|
| 4737 |
"node_modules/update-browserslist-db": {
|
| 4738 |
"version": "1.1.3",
|
| 4739 |
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
|
|
|
| 4819 |
}
|
| 4820 |
},
|
| 4821 |
"node_modules/vite": {
|
| 4822 |
+
"version": "7.0.5",
|
| 4823 |
+
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz",
|
| 4824 |
+
"integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==",
|
| 4825 |
"dev": true,
|
| 4826 |
"license": "MIT",
|
| 4827 |
+
"peer": true,
|
| 4828 |
"dependencies": {
|
| 4829 |
"esbuild": "^0.25.0",
|
| 4830 |
"fdir": "^6.4.6",
|
|
|
|
| 4900 |
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
| 4901 |
"dev": true,
|
| 4902 |
"license": "MIT",
|
| 4903 |
+
"peer": true,
|
| 4904 |
"peerDependencies": {
|
| 4905 |
"picomatch": "^3 || ^4"
|
| 4906 |
},
|
|
|
|
| 4916 |
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
| 4917 |
"dev": true,
|
| 4918 |
"license": "MIT",
|
| 4919 |
+
"peer": true,
|
| 4920 |
"engines": {
|
| 4921 |
"node": ">=12"
|
| 4922 |
},
|
frontend/package.json
CHANGED
|
@@ -12,8 +12,10 @@
|
|
| 12 |
"devDependencies": {
|
| 13 |
"@eslint/js": "^9.30.1",
|
| 14 |
"@tailwindcss/postcss": "^4.1.11",
|
|
|
|
| 15 |
"@types/react": "^19.1.8",
|
| 16 |
"@types/react-dom": "^19.1.6",
|
|
|
|
| 17 |
"@vitejs/plugin-react-swc": "^3.10.2",
|
| 18 |
"autoprefixer": "^10.4.21",
|
| 19 |
"eslint": "^9.30.1",
|
|
@@ -23,8 +25,7 @@
|
|
| 23 |
"postcss": "^8.5.6",
|
| 24 |
"tailwindcss": "^4.1.11",
|
| 25 |
"typescript": "~5.8.3",
|
| 26 |
-
"typescript-eslint": "^8.35.1"
|
| 27 |
-
"vite": "^7.0.4"
|
| 28 |
},
|
| 29 |
"dependencies": {
|
| 30 |
"@ifrc-go/icons": "^2.0.1",
|
|
|
|
| 12 |
"devDependencies": {
|
| 13 |
"@eslint/js": "^9.30.1",
|
| 14 |
"@tailwindcss/postcss": "^4.1.11",
|
| 15 |
+
"@types/node": "^24.1.0",
|
| 16 |
"@types/react": "^19.1.8",
|
| 17 |
"@types/react-dom": "^19.1.6",
|
| 18 |
+
"@vitejs/plugin-react": "^4.7.0",
|
| 19 |
"@vitejs/plugin-react-swc": "^3.10.2",
|
| 20 |
"autoprefixer": "^10.4.21",
|
| 21 |
"eslint": "^9.30.1",
|
|
|
|
| 25 |
"postcss": "^8.5.6",
|
| 26 |
"tailwindcss": "^4.1.11",
|
| 27 |
"typescript": "~5.8.3",
|
| 28 |
+
"typescript-eslint": "^8.35.1"
|
|
|
|
| 29 |
},
|
| 30 |
"dependencies": {
|
| 31 |
"@ifrc-go/icons": "^2.0.1",
|
frontend/src/App.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
-
/* src/App.tsx */
|
| 2 |
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
| 3 |
import RootLayout from './layouts/RootLayout';
|
| 4 |
import UploadPage from './pages/UploadPage';
|
|
|
|
| 5 |
import AnalyticsPage from './pages/AnalyticsPage';
|
| 6 |
import ExplorePage from './pages/ExplorePage';
|
| 7 |
import HelpPage from './pages/HelpPage';
|
|
@@ -12,6 +12,7 @@ const router = createBrowserRouter([
|
|
| 12 |
children: [
|
| 13 |
{ path: '/', element: <UploadPage /> },
|
| 14 |
{ path: '/upload', element: <UploadPage /> },
|
|
|
|
| 15 |
{ path: '/analytics', element: <AnalyticsPage /> },
|
| 16 |
{ path: '/explore', element: <ExplorePage /> },
|
| 17 |
{ path: '/help', element: <HelpPage /> },
|
|
|
|
|
|
|
| 1 |
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
| 2 |
import RootLayout from './layouts/RootLayout';
|
| 3 |
import UploadPage from './pages/UploadPage';
|
| 4 |
+
import ReviewPage from './pages/ReviewPage';
|
| 5 |
import AnalyticsPage from './pages/AnalyticsPage';
|
| 6 |
import ExplorePage from './pages/ExplorePage';
|
| 7 |
import HelpPage from './pages/HelpPage';
|
|
|
|
| 12 |
children: [
|
| 13 |
{ path: '/', element: <UploadPage /> },
|
| 14 |
{ path: '/upload', element: <UploadPage /> },
|
| 15 |
+
{ path: '/review/:id', element: <ReviewPage /> },
|
| 16 |
{ path: '/analytics', element: <AnalyticsPage /> },
|
| 17 |
{ path: '/explore', element: <ExplorePage /> },
|
| 18 |
{ path: '/help', element: <HelpPage /> },
|
frontend/src/pages/ReviewPage.tsx
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// src/pages/ReviewPage.tsx
|
| 2 |
+
import { useParams } from "react-router-dom";
|
| 3 |
+
import { useEffect, useState } from "react";
|
| 4 |
+
|
| 5 |
+
export default function ReviewPage() {
|
| 6 |
+
const { id } = useParams(); // captionId
|
| 7 |
+
const [data, setData] = useState<any>(null);
|
| 8 |
+
const [draft, setDraft] = useState("");
|
| 9 |
+
|
| 10 |
+
useEffect(() => {
|
| 11 |
+
(async () => {
|
| 12 |
+
const res = await fetch(`/api/captions/${id}`);
|
| 13 |
+
const json = await res.json();
|
| 14 |
+
setData(json);
|
| 15 |
+
setDraft(json.generated || "");
|
| 16 |
+
})();
|
| 17 |
+
}, [id]);
|
| 18 |
+
|
| 19 |
+
if (!data) return <p className="p-6">Loading…</p>;
|
| 20 |
+
|
| 21 |
+
return (
|
| 22 |
+
<main className="p-6 space-y-6">
|
| 23 |
+
<img src={data.imageUrl} className="max-w-full rounded-xl shadow" />
|
| 24 |
+
<textarea
|
| 25 |
+
value={draft}
|
| 26 |
+
onChange={e => setDraft(e.target.value)}
|
| 27 |
+
className="w-full border rounded p-3 font-mono" rows={5}
|
| 28 |
+
/>
|
| 29 |
+
{/* sliders for accuracy/context/usability */}
|
| 30 |
+
{/* Save button calls PUT /api/captions/{id} */}
|
| 31 |
+
</main>
|
| 32 |
+
);
|
| 33 |
+
}
|
frontend/src/pages/UploadPage.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import { useCallback, useState } from 'react';
|
| 2 |
import type { DragEvent } from 'react';
|
| 3 |
import {
|
| 4 |
PageContainer, Heading, Button,
|
|
@@ -12,14 +12,24 @@ import {
|
|
| 12 |
import { Link, useNavigate } from 'react-router-dom';
|
| 13 |
|
| 14 |
export default function UploadPage() {
|
|
|
|
|
|
|
| 15 |
/* ---------------- local state ----------------- */
|
| 16 |
const navigate = useNavigate();
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
const [file, setFile] = useState<File | null>(null);
|
| 19 |
-
const [source, setSource] = useState('');
|
| 20 |
-
const [region, setRegion] = useState('');
|
| 21 |
-
const [category, setCategory] = useState('');
|
|
|
|
|
|
|
|
|
|
| 22 |
const [countries, setCountries] = useState<string[]>([]);
|
|
|
|
| 23 |
|
| 24 |
// Wrapper functions to handle OptionKey to string conversion
|
| 25 |
const handleSourceChange = (value: any) => setSource(String(value));
|
|
@@ -27,6 +37,13 @@ export default function UploadPage() {
|
|
| 27 |
const handleCategoryChange = (value: any) => setCategory(String(value));
|
| 28 |
const handleCountriesChange = (value: any) => setCountries(Array.isArray(value) ? value.map(String) : []);
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
/* ---- drag-and-drop + file-picker handlers -------------------------- */
|
| 31 |
const onDrop = useCallback((e: DragEvent<HTMLDivElement>) => {
|
| 32 |
e.preventDefault();
|
|
@@ -38,6 +55,27 @@ export default function UploadPage() {
|
|
| 38 |
if (file) setFile(file);
|
| 39 |
}, []);
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
/* ---- generate handler --------------------------------------------- */
|
| 42 |
async function handleGenerate() {
|
| 43 |
if (!file) return;
|
|
@@ -50,12 +88,24 @@ export default function UploadPage() {
|
|
| 50 |
countries.forEach((c) => fd.append('countries', c));
|
| 51 |
|
| 52 |
try {
|
| 53 |
-
|
| 54 |
-
const
|
| 55 |
-
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
} catch (err) {
|
| 58 |
-
// basic alert for now; replace with toast later
|
| 59 |
alert((err as Error).message);
|
| 60 |
}
|
| 61 |
}
|
|
@@ -65,121 +115,186 @@ export default function UploadPage() {
|
|
| 65 |
<PageContainer>
|
| 66 |
<div className="mx-auto max-w-3xl text-center px-4 py-10">
|
| 67 |
{/* Title & intro copy */}
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
>
|
| 82 |
-
|
| 83 |
-
</Link>
|
| 84 |
-
</div>
|
| 85 |
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
/>
|
|
|
|
| 145 |
</div>
|
|
|
|
|
|
|
| 146 |
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
Selected file: {file.name}
|
| 158 |
-
</p>
|
| 159 |
-
) : (
|
| 160 |
-
<>
|
| 161 |
-
<p className="text-sm text-gray-600">Drag & Drop a file here</p>
|
| 162 |
-
<p className="text-xs text-gray-500">or</p>
|
| 163 |
-
|
| 164 |
-
{/* File-picker button */}
|
| 165 |
-
<RawFileInput name="file" accept="image/*" onChange={onFileChange}>
|
| 166 |
-
<Button name="upload" size={1}>
|
| 167 |
-
Upload
|
| 168 |
-
</Button>
|
| 169 |
-
</RawFileInput>
|
| 170 |
-
</>
|
| 171 |
-
)}
|
| 172 |
-
</div>
|
| 173 |
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
</div>
|
| 184 |
</PageContainer>
|
| 185 |
);
|
|
|
|
| 1 |
+
import { useCallback, useState, useEffect } from 'react';
|
| 2 |
import type { DragEvent } from 'react';
|
| 3 |
import {
|
| 4 |
PageContainer, Heading, Button,
|
|
|
|
| 12 |
import { Link, useNavigate } from 'react-router-dom';
|
| 13 |
|
| 14 |
export default function UploadPage() {
|
| 15 |
+
const [step, setStep] = useState<1 | 2>(1);
|
| 16 |
+
const [preview, setPreview] = useState<string | null>(null);
|
| 17 |
/* ---------------- local state ----------------- */
|
| 18 |
const navigate = useNavigate();
|
| 19 |
|
| 20 |
+
const PH_SOURCE = "_TBD_SOURCE";
|
| 21 |
+
const PH_REGION = "_TBD_REGION";
|
| 22 |
+
const PH_CATEGORY = "_TBD_CATEGORY";
|
| 23 |
+
|
| 24 |
const [file, setFile] = useState<File | null>(null);
|
| 25 |
+
//const [source, setSource] = useState('');
|
| 26 |
+
//const [region, setRegion] = useState('');
|
| 27 |
+
//const [category, setCategory] = useState('');
|
| 28 |
+
const [source, setSource] = useState(PH_SOURCE);
|
| 29 |
+
const [region, setRegion] = useState(PH_REGION);
|
| 30 |
+
const [category, setCategory] = useState(PH_CATEGORY);
|
| 31 |
const [countries, setCountries] = useState<string[]>([]);
|
| 32 |
+
const [captionId, setCaptionId] = useState<string | null>(null);
|
| 33 |
|
| 34 |
// Wrapper functions to handle OptionKey to string conversion
|
| 35 |
const handleSourceChange = (value: any) => setSource(String(value));
|
|
|
|
| 37 |
const handleCategoryChange = (value: any) => setCategory(String(value));
|
| 38 |
const handleCountriesChange = (value: any) => setCountries(Array.isArray(value) ? value.map(String) : []);
|
| 39 |
|
| 40 |
+
const [draft, setDraft] = useState('');
|
| 41 |
+
const [scores, setScores] = useState({
|
| 42 |
+
accuracy: 50,
|
| 43 |
+
context: 50,
|
| 44 |
+
usability: 50,
|
| 45 |
+
});
|
| 46 |
+
|
| 47 |
/* ---- drag-and-drop + file-picker handlers -------------------------- */
|
| 48 |
const onDrop = useCallback((e: DragEvent<HTMLDivElement>) => {
|
| 49 |
e.preventDefault();
|
|
|
|
| 55 |
if (file) setFile(file);
|
| 56 |
}, []);
|
| 57 |
|
| 58 |
+
// blob URL / preview
|
| 59 |
+
useEffect(() => {
|
| 60 |
+
if (!file) {
|
| 61 |
+
setPreview(null);
|
| 62 |
+
return;
|
| 63 |
+
}
|
| 64 |
+
const url = URL.createObjectURL(file);
|
| 65 |
+
setPreview(url);
|
| 66 |
+
return () => URL.revokeObjectURL(url);
|
| 67 |
+
}, [file]);
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
async function readJsonSafely(res: Response): Promise<any> {
|
| 71 |
+
const text = await res.text(); // get raw body
|
| 72 |
+
try {
|
| 73 |
+
return text ? JSON.parse(text) : {}; // valid JSON or empty object
|
| 74 |
+
} catch {
|
| 75 |
+
return { error: text }; // plain text fallback
|
| 76 |
+
}
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
/* ---- generate handler --------------------------------------------- */
|
| 80 |
async function handleGenerate() {
|
| 81 |
if (!file) return;
|
|
|
|
| 88 |
countries.forEach((c) => fd.append('countries', c));
|
| 89 |
|
| 90 |
try {
|
| 91 |
+
/* 1) upload */
|
| 92 |
+
const mapRes = await fetch('/api/maps', { method: 'POST', body: fd });
|
| 93 |
+
const mapJson = await readJsonSafely(mapRes);
|
| 94 |
+
if (!mapRes.ok) throw new Error(mapJson.error || 'Upload failed');
|
| 95 |
+
|
| 96 |
+
/* 2) caption */
|
| 97 |
+
const capRes = await fetch(
|
| 98 |
+
`/api/maps/${mapJson.mapId}/caption`,
|
| 99 |
+
{ method: 'POST' },
|
| 100 |
+
);
|
| 101 |
+
const capJson = await readJsonSafely(capRes);
|
| 102 |
+
if (!capRes.ok) throw new Error(capJson.error || 'Caption failed');
|
| 103 |
+
|
| 104 |
+
/* 3) continue workflow */
|
| 105 |
+
setCaptionId(capJson.captionId);
|
| 106 |
+
setDraft(capJson.generated);
|
| 107 |
+
setStep(2);
|
| 108 |
} catch (err) {
|
|
|
|
| 109 |
alert((err as Error).message);
|
| 110 |
}
|
| 111 |
}
|
|
|
|
| 115 |
<PageContainer>
|
| 116 |
<div className="mx-auto max-w-3xl text-center px-4 py-10">
|
| 117 |
{/* Title & intro copy */}
|
| 118 |
+
{step === 1 && <>
|
| 119 |
+
<Heading level={2}>Upload Your Crisis Map</Heading>
|
| 120 |
+
<p className="mt-3 text-gray-700 leading-relaxed">
|
| 121 |
+
This app evaluates how well multimodal AI models turn emergency maps
|
| 122 |
+
into meaningful text. Upload your map, let the AI generate a
|
| 123 |
+
description, then review and rate the result based on your expertise.
|
| 124 |
+
</p>
|
| 125 |
+
{/* “More »” link */}
|
| 126 |
+
<div className="mt-2">
|
| 127 |
+
<Link
|
| 128 |
+
to="/help"
|
| 129 |
+
className="text-ifrcRed text-xs hover:underline flex items-center gap-1"
|
| 130 |
+
>
|
| 131 |
+
More <ArrowRightLineIcon className="w-3 h-3" />
|
| 132 |
+
</Link>
|
| 133 |
+
</div>
|
| 134 |
+
</>}
|
| 135 |
+
|
| 136 |
+
{/* Show uploaded image in step 2 */}
|
| 137 |
+
{step === 2 && preview &&(
|
| 138 |
+
<div className="mt-6 flex justify-center">
|
| 139 |
+
<img
|
| 140 |
+
src={preview}
|
| 141 |
+
alt="Uploaded map preview"
|
| 142 |
+
className="max-h-80 rounded shadow"
|
| 143 |
+
/>
|
| 144 |
+
</div>
|
| 145 |
+
)}
|
| 146 |
+
|
| 147 |
+
{/* Drop-zone */}
|
| 148 |
+
{step === 1 && (
|
| 149 |
+
<div
|
| 150 |
+
className="mt-10 border-2 border-dashed border-gray-300 bg-gray-50 rounded-xl p-10 flex flex-col items-center gap-4 hover:bg-gray-100 transition-colors"
|
| 151 |
+
onDragOver={(e) => e.preventDefault()}
|
| 152 |
+
onDrop={onDrop}
|
| 153 |
>
|
| 154 |
+
<UploadCloudLineIcon className="w-10 h-10 text-ifrcRed" />
|
|
|
|
|
|
|
| 155 |
|
| 156 |
+
{file ? (
|
| 157 |
+
<p className="text-sm font-medium text-gray-800">
|
| 158 |
+
Selected file: {file.name}
|
| 159 |
+
</p>
|
| 160 |
+
) : (
|
| 161 |
+
<>
|
| 162 |
+
<p className="text-sm text-gray-600">Drag & Drop a file here</p>
|
| 163 |
+
<p className="text-xs text-gray-500">or</p>
|
| 164 |
+
|
| 165 |
+
{/* File-picker button */}
|
| 166 |
+
<RawFileInput name="file" accept="image/*" onChange={onFileChange}>
|
| 167 |
+
<Button name="upload" size={1}>
|
| 168 |
+
Upload
|
| 169 |
+
</Button>
|
| 170 |
+
</RawFileInput>
|
| 171 |
+
</>
|
| 172 |
+
)}
|
| 173 |
+
</div>
|
| 174 |
+
)}
|
| 175 |
+
|
| 176 |
+
{/* Generate button */}
|
| 177 |
+
{step === 1 && (
|
| 178 |
+
<Button
|
| 179 |
+
name="generate"
|
| 180 |
+
className="mt-8"
|
| 181 |
+
disabled={!file}
|
| 182 |
+
onClick={handleGenerate}
|
| 183 |
+
>
|
| 184 |
+
Generate
|
| 185 |
+
</Button>
|
| 186 |
+
)}
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
{step === 2 && (
|
| 190 |
+
<div className="space-y-10">
|
| 191 |
+
{/* ────── METADATA FORM ────── */}
|
| 192 |
+
<div className="grid gap-4 text-left sm:grid-cols-2">
|
| 193 |
+
<SelectInput
|
| 194 |
+
label="Source"
|
| 195 |
+
name="source"
|
| 196 |
+
value={source}
|
| 197 |
+
onChange={handleSourceChange}
|
| 198 |
+
options={[
|
| 199 |
+
{ value: 'UNOSAT', label: 'UNOSAT' },
|
| 200 |
+
{ value: 'FIELD', label: 'Field HQ' },
|
| 201 |
+
]}
|
| 202 |
+
keySelector={(o) => o.value}
|
| 203 |
+
labelSelector={(o) => o.label}
|
| 204 |
+
required
|
| 205 |
+
/>
|
| 206 |
+
<SelectInput
|
| 207 |
+
label="Region"
|
| 208 |
+
name="region"
|
| 209 |
+
value={region}
|
| 210 |
+
onChange={handleRegionChange}
|
| 211 |
+
options={[
|
| 212 |
+
{ value: 'AFR', label: 'Africa' },
|
| 213 |
+
{ value: 'AMR', label: 'Americas' },
|
| 214 |
+
{ value: 'APA', label: 'Asia‑Pacific' },
|
| 215 |
+
{ value: 'EUR', label: 'Europe' },
|
| 216 |
+
{ value: 'MENA', label: 'Middle East & N Africa' },
|
| 217 |
+
]}
|
| 218 |
+
keySelector={(o) => o.value}
|
| 219 |
+
labelSelector={(o) => o.label}
|
| 220 |
+
required
|
| 221 |
+
/>
|
| 222 |
+
<SelectInput
|
| 223 |
+
label="Category"
|
| 224 |
+
name="category"
|
| 225 |
+
value={category}
|
| 226 |
+
onChange={handleCategoryChange}
|
| 227 |
+
options={[
|
| 228 |
+
{ value: 'FLOOD', label: 'Flood' },
|
| 229 |
+
{ value: 'WILDFIRE', label: 'Wildfire' },
|
| 230 |
+
{ value: 'EARTHQUAKE', label: 'Earthquake' },
|
| 231 |
+
]}
|
| 232 |
+
keySelector={(o) => o.value}
|
| 233 |
+
labelSelector={(o) => o.label}
|
| 234 |
+
required
|
| 235 |
+
/>
|
| 236 |
+
<MultiSelectInput
|
| 237 |
+
label="Countries (optional)"
|
| 238 |
+
name="countries"
|
| 239 |
+
value={countries}
|
| 240 |
+
onChange={handleCountriesChange}
|
| 241 |
+
options={[
|
| 242 |
+
{ value: 'PH', label: 'Philippines' },
|
| 243 |
+
{ value: 'ID', label: 'Indonesia' },
|
| 244 |
+
{ value: 'VN', label: 'Vietnam' },
|
| 245 |
+
]}
|
| 246 |
+
keySelector={(o) => o.value}
|
| 247 |
+
labelSelector={(o) => o.label}
|
| 248 |
+
placeholder="Select one or more"
|
| 249 |
+
/>
|
| 250 |
+
</div>
|
| 251 |
+
|
| 252 |
+
{/* ────── RATING SLIDERS ────── */}
|
| 253 |
+
<div className="text-left">
|
| 254 |
+
<Heading level={3}>How well did the AI perform on the task?</Heading>
|
| 255 |
+
{(['accuracy', 'context', 'usability'] as const).map((k) => (
|
| 256 |
+
<div key={k} className="mt-6 flex items-center gap-4">
|
| 257 |
+
<label className="block text-sm font-medium capitalize w-28">{k}</label>
|
| 258 |
+
<input
|
| 259 |
+
type="range"
|
| 260 |
+
min={0}
|
| 261 |
+
max={100}
|
| 262 |
+
value={scores[k]}
|
| 263 |
+
onChange={(e) =>
|
| 264 |
+
setScores((s) => ({ ...s, [k]: Number(e.target.value) }))
|
| 265 |
+
}
|
| 266 |
+
className="w-full accent-ifrcRed"
|
| 267 |
/>
|
| 268 |
+
<span className="ml-2 w-10 text-right tabular-nums">{scores[k]}</span>
|
| 269 |
</div>
|
| 270 |
+
))}
|
| 271 |
+
</div>
|
| 272 |
|
| 273 |
+
{/* ────── AI‑GENERATED CAPTION ────── */}
|
| 274 |
+
<div className="text-left">
|
| 275 |
+
<Heading level={3}>AI‑Generated Caption</Heading>
|
| 276 |
+
<textarea
|
| 277 |
+
className="w-full border rounded p-3 font-mono mt-2"
|
| 278 |
+
rows={5}
|
| 279 |
+
value={draft}
|
| 280 |
+
onChange={(e) => setDraft(e.target.value)}
|
| 281 |
+
/>
|
| 282 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
|
| 284 |
+
{/* ────── SUBMIT BUTTON ────── */}
|
| 285 |
+
<Button
|
| 286 |
+
name="submit"
|
| 287 |
+
className="mt-10"
|
| 288 |
+
onClick={() =>
|
| 289 |
+
alert('Stub saved – wire PUT /api/captions/:id later')
|
| 290 |
+
}
|
| 291 |
+
>
|
| 292 |
+
Submit
|
| 293 |
+
</Button>
|
| 294 |
+
</div>
|
| 295 |
+
)}
|
| 296 |
+
|
| 297 |
+
|
| 298 |
</div>
|
| 299 |
</PageContainer>
|
| 300 |
);
|
frontend/vite.config.ts
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
|
|
|
|
|
| 1 |
import { defineConfig } from 'vite'
|
| 2 |
-
import react from '@vitejs/plugin-react
|
| 3 |
|
| 4 |
-
// https://vite.dev/config/
|
| 5 |
export default defineConfig({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
plugins: [react()],
|
| 7 |
})
|
|
|
|
|
|
|
|
|
| 1 |
+
console.log('⚙️ VITE CONFIG LOADED')
|
| 2 |
+
|
| 3 |
import { defineConfig } from 'vite'
|
| 4 |
+
import react from '@vitejs/plugin-react'
|
| 5 |
|
|
|
|
| 6 |
export default defineConfig({
|
| 7 |
+
server: {
|
| 8 |
+
port: 5173,
|
| 9 |
+
proxy: {
|
| 10 |
+
'/api': {
|
| 11 |
+
target: 'http://localhost:8080',
|
| 12 |
+
changeOrigin: true,
|
| 13 |
+
secure: false,
|
| 14 |
+
},
|
| 15 |
+
},
|
| 16 |
+
},
|
| 17 |
plugins: [react()],
|
| 18 |
})
|
| 19 |
+
|
| 20 |
+
|