feat: enhance learn-number with dynamic SVG icons, multi-page support, and modular UI
Build and Push Docker Image / build (push) Successful in 2m26s
Build and Push Docker Image / build (push) Successful in 2m26s
This commit is contained in:
@@ -1,41 +1,77 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Icon struct {
|
||||
Name string
|
||||
Paths []string
|
||||
}
|
||||
|
||||
// 升级版:更卡通、更饱满的简笔画
|
||||
var CountingIcons = []Icon{
|
||||
{Name: "Bear", Paths: []string{
|
||||
"M 512 800 C 300 800 200 700 200 500 C 200 300 350 200 512 200 C 674 200 824 300 824 500 C 824 700 724 800 512 800 Z", // Body
|
||||
"M 300 300 m -50 0 a 50 50 0 1 0 100 0 a 50 50 0 1 0 -100 0", // Ear L
|
||||
"M 724 300 m -50 0 a 50 50 0 1 0 100 0 a 50 50 0 1 0 -100 0", // Ear R
|
||||
"M 400 450 m -20 0 a 20 20 0 1 0 40 0 a 20 20 0 1 0 -40 0", // Eye L
|
||||
"M 624 450 m -20 0 a 20 20 0 1 0 40 0 a 20 20 0 1 0 -40 0", // Eye R
|
||||
"M 512 550 Q 512 650 400 650 M 512 550 Q 512 650 624 650", // Mouth
|
||||
}},
|
||||
{Name: "Cat", Paths: []string{
|
||||
"M 200 800 L 300 400 L 400 200 L 512 350 L 624 200 L 724 400 L 824 800 Z", // Head
|
||||
"M 400 550 m -15 0 a 15 15 0 1 0 30 0 a 15 15 0 1 0 -30 0", // Eye L
|
||||
"M 624 550 m -15 0 a 15 15 0 1 0 30 0 a 15 15 0 1 0 -30 0", // Eye R
|
||||
"M 512 650 L 450 700 M 512 650 L 574 700", // Nose
|
||||
}},
|
||||
{Name: "Car", Paths: []string{
|
||||
"M 100 700 L 100 500 Q 100 400 300 400 L 700 400 Q 900 400 900 500 L 900 700 Z", // Body
|
||||
"M 250 700 m -60 0 a 60 60 0 1 0 120 0 a 60 60 0 1 0 -120 0", // Wheel L
|
||||
"M 750 700 m -60 0 a 60 60 0 1 0 120 0 a 60 60 0 1 0 -120 0", // Wheel R
|
||||
"M 300 400 L 400 250 L 624 250 L 724 400", // Roof
|
||||
}},
|
||||
{Name: "Bird", Paths: []string{
|
||||
"M 512 512 m -300 0 a 300 300 0 1 0 600 0 a 300 300 0 1 0 -600 0", // Body
|
||||
"M 812 512 L 950 450 L 812 400 Z", // Beak
|
||||
"M 400 400 m -20 0 a 20 20 0 1 0 40 0 a 20 20 0 1 0 -40 0", // Eye
|
||||
"M 212 512 Q 100 400 212 300", // Wing
|
||||
}},
|
||||
{Name: "Rocket", Paths: []string{
|
||||
"M 512 100 Q 700 400 700 800 L 324 800 Q 324 400 512 100 Z", // Body
|
||||
"M 512 400 m -50 0 a 50 50 0 1 0 100 0 a 50 50 0 1 0 -100 0", // Window
|
||||
"M 324 800 L 200 950 L 324 900 M 700 800 L 824 950 L 700 900", // Fins
|
||||
}},
|
||||
var IconCategories = map[string][]Icon{
|
||||
"shapes": {
|
||||
{Name: "Circle", Paths: []string{"M 512 112 C 291 112 112 291 112 512 C 112 733 291 912 512 912 C 733 912 912 733 912 512 C 912 291 733 112 512 112 Z"}},
|
||||
{Name: "Square", Paths: []string{"M 150 150 L 874 150 L 874 874 L 150 874 Z"}},
|
||||
{Name: "Rectangle", Paths: []string{"M 100 300 L 924 300 L 924 724 L 100 724 Z"}},
|
||||
{Name: "Triangle", Paths: []string{"M 512 150 L 900 850 L 124 850 Z"}},
|
||||
{Name: "Star", Paths: []string{"M 512 100 L 612 400 L 924 400 L 674 600 L 774 900 L 512 700 L 250 900 L 350 600 L 100 400 L 412 400 Z"}},
|
||||
{Name: "Heart", Paths: []string{"M 512 900 C 200 700 100 500 100 300 C 100 100 400 100 512 250 C 624 100 924 100 924 300 C 924 500 824 700 512 900 Z"}},
|
||||
{Name: "Diamond", Paths: []string{"M 512 100 L 900 512 L 512 924 L 124 512 Z"}},
|
||||
{Name: "Oval", Paths: []string{"M 512 350 C 200 350 100 420 100 512 C 100 604 200 674 512 674 C 824 674 924 604 924 512 C 924 420 824 350 512 350 Z"}},
|
||||
{Name: "Trapezoid", Paths: []string{"M 300 200 L 724 200 L 924 800 L 100 800 Z"}},
|
||||
{Name: "Hexagon", Paths: []string{"M 512 100 L 858 300 L 858 724 L 512 924 L 166 724 L 166 300 Z"}},
|
||||
},
|
||||
"fruits": {},
|
||||
}
|
||||
|
||||
type SVG struct {
|
||||
Groups []G `xml:"g"`
|
||||
}
|
||||
|
||||
type G struct {
|
||||
ID string `xml:"id,attr"`
|
||||
Groups []G `xml:"g"`
|
||||
Paths []Path `xml:"path"`
|
||||
}
|
||||
|
||||
type Path struct {
|
||||
D string `xml:"d,attr"`
|
||||
}
|
||||
|
||||
func LoadIcons(filePath string) error {
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil { return err }
|
||||
var svg SVG
|
||||
if err := xml.Unmarshal(data, &svg); err != nil { return err }
|
||||
var objectsG *G
|
||||
for i := range svg.Groups {
|
||||
if svg.Groups[i].ID == "objects" { objectsG = &svg.Groups[i]; break }
|
||||
}
|
||||
if objectsG == nil { return nil }
|
||||
var fruitIcons []Icon
|
||||
for i, g := range objectsG.Groups {
|
||||
paths := collectPaths(g)
|
||||
if len(paths) > 0 {
|
||||
fruitIcons = append(fruitIcons, Icon{
|
||||
Name: fmt.Sprintf("Item %d", i+1),
|
||||
Paths: paths,
|
||||
})
|
||||
}
|
||||
}
|
||||
IconCategories["fruits"] = fruitIcons
|
||||
return nil
|
||||
}
|
||||
|
||||
func collectPaths(g G) []string {
|
||||
var paths []string
|
||||
for _, p := range g.Paths {
|
||||
d := strings.TrimSpace(p.D)
|
||||
if d != "" { paths = append(paths, d) }
|
||||
}
|
||||
for _, subG := range g.Groups { paths = append(paths, collectPaths(subG)...) }
|
||||
return paths
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user