volleyballsimtypes 0.0.527 → 0.0.528
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/src/api/index.d.ts +3 -1
- package/dist/cjs/src/data/init-models.js +5 -0
- package/dist/cjs/src/data/models/index.d.ts +1 -0
- package/dist/cjs/src/data/models/index.js +1 -0
- package/dist/cjs/src/data/models/team-badge.d.ts +20 -0
- package/dist/cjs/src/data/models/team-badge.js +38 -0
- package/dist/cjs/src/data/models/team.d.ts +3 -1
- package/dist/cjs/src/data/transformers/team.js +4 -1
- package/dist/cjs/src/service/team/badge.d.ts +301 -0
- package/dist/cjs/src/service/team/badge.js +93 -0
- package/dist/cjs/src/service/team/index.d.ts +1 -0
- package/dist/cjs/src/service/team/index.js +1 -0
- package/dist/cjs/src/service/team/jersey-defaults.js +3 -1
- package/dist/cjs/src/service/team/jersey.d.ts +2 -0
- package/dist/cjs/src/service/team/jersey.js +14 -2
- package/dist/cjs/src/service/team/schemas/team.z.d.ts +98 -0
- package/dist/cjs/src/service/team/schemas/team.z.js +3 -1
- package/dist/cjs/src/service/team/team.d.ts +2 -0
- package/dist/cjs/src/service/team/team.js +2 -1
- package/dist/esm/src/api/index.d.ts +3 -1
- package/dist/esm/src/data/init-models.js +6 -1
- package/dist/esm/src/data/models/index.d.ts +1 -0
- package/dist/esm/src/data/models/index.js +1 -0
- package/dist/esm/src/data/models/team-badge.d.ts +20 -0
- package/dist/esm/src/data/models/team-badge.js +34 -0
- package/dist/esm/src/data/models/team.d.ts +3 -1
- package/dist/esm/src/data/transformers/team.js +4 -1
- package/dist/esm/src/service/team/badge.d.ts +301 -0
- package/dist/esm/src/service/team/badge.js +90 -0
- package/dist/esm/src/service/team/index.d.ts +1 -0
- package/dist/esm/src/service/team/index.js +1 -0
- package/dist/esm/src/service/team/jersey-defaults.js +3 -1
- package/dist/esm/src/service/team/jersey.d.ts +2 -0
- package/dist/esm/src/service/team/jersey.js +14 -2
- package/dist/esm/src/service/team/schemas/team.z.d.ts +98 -0
- package/dist/esm/src/service/team/schemas/team.z.js +3 -1
- package/dist/esm/src/service/team/team.d.ts +2 -0
- package/dist/esm/src/service/team/team.js +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// 6-digit hex (#rrggbb) or 8-digit hex with alpha (#rrggbbaa), the same convention as the jersey colours (the
|
|
3
|
+
// 8-digit form comes from the UI's opacity-enabled colour pickers; SVG fills render both).
|
|
4
|
+
const hexColor = z.string().regex(/^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/, 'INVALID_HEX_COLOR');
|
|
5
|
+
// The badge canvas is a fixed square coordinate space. Layer x/y are the layer's centre in canvas units and
|
|
6
|
+
// `size` is the layer's height in the same units; positions may overhang the canvas a little (clipped at render).
|
|
7
|
+
export const BADGE_CANVAS = 200;
|
|
8
|
+
// Curated FontAwesome icon names offered as badge layers (owner decision 2026-08-31: curated set, not a full
|
|
9
|
+
// catalog). The UI maps each name to its solid-icon path data (view/badge/badge-icons.ts, a Record keyed by this
|
|
10
|
+
// type so the two lists cannot drift); this list is what the API validates against.
|
|
11
|
+
export const BADGE_ICONS = [
|
|
12
|
+
'star', 'crown', 'bolt', 'fire', 'heart', 'gem', 'skull', 'ghost', 'anchor', 'compass',
|
|
13
|
+
'sun', 'moon', 'snowflake', 'leaf', 'seedling', 'tree', 'mountain', 'water', 'wind', 'meteor',
|
|
14
|
+
'rocket', 'bell', 'flag', 'feather', 'shield-halved', 'chess-knight', 'chess-rook', 'hammer', 'crosshairs',
|
|
15
|
+
'medal', 'trophy', 'award', 'volleyball', 'dragon', 'cat', 'crow', 'turtle', 'unicorn', 'horse', 'dove',
|
|
16
|
+
'fish', 'paw', 'spider', 'otter', 'frog', 'dog'
|
|
17
|
+
];
|
|
18
|
+
// Text layers offer the same 20 faces as the jersey number editor (JERSEY_FONT_ALL): five generic stacks, then
|
|
19
|
+
// the fifteen display families. The jersey renders its number from GENERATED DIGIT GLYPHS because it lives in a
|
|
20
|
+
// data-uri <img> where @font-face does not load; the badge canvas is inline SVG in the document, so it uses the
|
|
21
|
+
// real webfonts instead, which also means badge text is not limited to the digits those glyph sets cover.
|
|
22
|
+
export const BADGE_TEXT_FONTS = [
|
|
23
|
+
'sans', 'wide', 'mono', 'serif', 'block',
|
|
24
|
+
'permanentMarker', 'kaushanScript', 'russoOne', 'teko', 'saira', 'michroma', 'zillaSlab', 'changaOne',
|
|
25
|
+
'stardosStencil', 'wallpoet', 'orbitron', 'tourney', 'bebasNeue', 'anton', 'jersey25'
|
|
26
|
+
];
|
|
27
|
+
// Basic geometric shapes (VolleyballSimUI/public/shapes), extracted from the two source sets 2026-08-31. The
|
|
28
|
+
// crest sets are positional (shield-a01, ribbon-07), but these are named, so the vocabulary is spelled out
|
|
29
|
+
// rather than pattern-matched: this list IS the allow list, and every entry has a file of the same name.
|
|
30
|
+
// `-outline` is the hollow cut, whose interior is a real hole in the path (so layers underneath show through,
|
|
31
|
+
// no transparent fill slot needed). Order is the picker order, grouped by family.
|
|
32
|
+
// The rounded-corner cut of every shape, plus the split square and the pie, were dropped by the owner
|
|
33
|
+
// 2026-08-31; only the sharp cuts ship.
|
|
34
|
+
export const BADGE_SHAPES = [
|
|
35
|
+
'star5-solid', 'star5-slim-solid', 'star6-solid', 'cross-solid',
|
|
36
|
+
'star5-outline', 'star5-slim-outline', 'star6-outline', 'cross-outline',
|
|
37
|
+
'pentagon-solid', 'hexagon-solid', 'octagon-solid',
|
|
38
|
+
'pentagon-outline', 'hexagon-outline', 'octagon-outline',
|
|
39
|
+
'square-solid', 'triangle-solid', 'diamond-solid',
|
|
40
|
+
'square-outline', 'triangle-outline', 'diamond-outline',
|
|
41
|
+
'rectangle-solid', 'burst-solid', 'trapezoid-solid',
|
|
42
|
+
'rectangle-outline', 'burst-outline', 'trapezoid-outline',
|
|
43
|
+
'circle-solid', 'heptagon-solid', 'nonagon-solid', 'ellipse-solid', 'parallelogram-solid',
|
|
44
|
+
'heart-solid', 'moon-solid', 'semicircle-solid', 'triangle-right-solid', 'triangle-tall-solid',
|
|
45
|
+
'trapezoid-tall-solid', 'kite-solid'
|
|
46
|
+
];
|
|
47
|
+
// The extracted vector sets in VolleyballSimUI/public/shields + public/ribbons + public/shapes:
|
|
48
|
+
// shield-a01..a17 / shield-b01..b16, each -solid|-bordered|-outline; ribbon-01..ribbon-49; and shape-<name>
|
|
49
|
+
// for every name in BADGE_SHAPES.
|
|
50
|
+
const CREST_ID = /^(shield-(a(0[1-9]|1[0-7])|b(0[1-9]|1[0-6]))-(solid|bordered|outline)|ribbon-(0[1-9]|[1-4][0-9]))$/;
|
|
51
|
+
const BASIC_ID = new RegExp(`^shape-(${BADGE_SHAPES.join('|')})$`);
|
|
52
|
+
const shapeId = z.string().refine(v => CREST_ID.test(v) || BASIC_ID.test(v), 'INVALID_BADGE_SHAPE');
|
|
53
|
+
const layerBase = {
|
|
54
|
+
x: z.number().min(-100).max(300),
|
|
55
|
+
y: z.number().min(-100).max(300),
|
|
56
|
+
size: z.number().min(4).max(400),
|
|
57
|
+
rotation: z.number().min(-180).max(180)
|
|
58
|
+
};
|
|
59
|
+
// One colour per DISTINCT fill in the source art (solid shields 1, bordered 3, ribbons up to 4, basic shapes 1),
|
|
60
|
+
// applied in the order the fills first appear in the file. Extra entries are ignored at render; missing ones
|
|
61
|
+
// fall back to the source colour.
|
|
62
|
+
const shapeLayer = z.object({
|
|
63
|
+
type: z.literal('shape'),
|
|
64
|
+
shape: shapeId,
|
|
65
|
+
colors: z.array(hexColor).min(1).max(6),
|
|
66
|
+
...layerBase
|
|
67
|
+
});
|
|
68
|
+
const iconLayer = z.object({
|
|
69
|
+
type: z.literal('icon'),
|
|
70
|
+
icon: z.enum(BADGE_ICONS),
|
|
71
|
+
color: hexColor,
|
|
72
|
+
...layerBase
|
|
73
|
+
});
|
|
74
|
+
const textLayer = z.object({
|
|
75
|
+
type: z.literal('text'),
|
|
76
|
+
text: z.string().min(1).max(24),
|
|
77
|
+
font: z.enum(BADGE_TEXT_FONTS),
|
|
78
|
+
color: hexColor,
|
|
79
|
+
...layerBase
|
|
80
|
+
});
|
|
81
|
+
export const BadgeLayerSchema = z.discriminatedUnion('type', [shapeLayer, iconLayer, textLayer]);
|
|
82
|
+
// The most layers one badge may stack. Not a technical ceiling (25 layers is under 3 KB of jsonb and a trivial
|
|
83
|
+
// number of SVG paths): past roughly a dozen you cannot tell the elements apart at the size a crest is shown,
|
|
84
|
+
// and the one-step-per-click reordering gets tedious. Exported so the editor gates on the SAME number the save
|
|
85
|
+
// validates against, rather than keeping its own copy that can drift.
|
|
86
|
+
export const BADGE_MAX_LAYERS = 25;
|
|
87
|
+
// The full team badge: an ordered stack of layers (index 0 renders first, i.e. at the back).
|
|
88
|
+
export const BadgeSchema = z.object({
|
|
89
|
+
layers: z.array(BadgeLayerSchema).min(1).max(BADGE_MAX_LAYERS)
|
|
90
|
+
});
|
|
@@ -67,6 +67,8 @@ export declare const JerseySchema: z.ZodObject<{
|
|
|
67
67
|
}>>;
|
|
68
68
|
brandColor1: z.ZodDefault<z.ZodString>;
|
|
69
69
|
brandColor2: z.ZodDefault<z.ZodString>;
|
|
70
|
+
brandSize: z.ZodDefault<z.ZodNumber>;
|
|
71
|
+
badgeSize: z.ZodDefault<z.ZodNumber>;
|
|
70
72
|
}, z.core.$strip>;
|
|
71
73
|
export type JerseyConfig = z.infer<typeof JerseySchema>;
|
|
72
74
|
export type JerseyClothing = JerseyConfig['clothing'];
|
|
@@ -26,10 +26,18 @@ export const JerseySchema = z.object({
|
|
|
26
26
|
// configs saved before it stay valid.
|
|
27
27
|
brand: z.enum(['none', 'sigma', 'person-soccer', 'feather-pointed', 'paw-claws', 'narwhal', 'horseshoe', 'spider-black-widow', 'wreath-laurel', 'omega', 'trillium']).default('none'),
|
|
28
28
|
brandColor1: hexColor.default('#ffffff'),
|
|
29
|
-
brandColor2: hexColor.default('#1e293b')
|
|
29
|
+
brandColor2: hexColor.default('#1e293b'),
|
|
30
|
+
// Chest-element heights in avatar-svg units, on the y=297 chest line. The brand sits at x=90 and the team badge
|
|
31
|
+
// at x=191, with the (non-editable) champion badge between them at x=140.5 spanning 116.5..164.5, so either one
|
|
32
|
+
// starts touching it past about 52. The range allows more than that on purpose: most teams have no champion
|
|
33
|
+
// badge, and the editor preview shows the overlap for the ones that do. Defaulted to the sizes both were fixed
|
|
34
|
+
// at before, so configs saved earlier stay valid and look unchanged.
|
|
35
|
+
brandSize: z.number().min(16).max(64).default(29),
|
|
36
|
+
badgeSize: z.number().min(16).max(64).default(48)
|
|
30
37
|
});
|
|
31
38
|
// The alternate (libero) kit stores only the fields the premium editor allows changing. Locked fields (clothing,
|
|
32
|
-
// font, brand icon, numberSpacing, numberSize) are always inherited from the main kit at
|
|
39
|
+
// font, brand icon, numberSpacing, numberSize, brandSize, badgeSize) are always inherited from the main kit at
|
|
40
|
+
// render time.
|
|
33
41
|
export const AlternateJerseySchema = z.object({
|
|
34
42
|
pattern: JerseySchema.shape.pattern,
|
|
35
43
|
colors: JerseySchema.shape.colors,
|
|
@@ -120,6 +128,8 @@ export function computeComplementaryJersey(main) {
|
|
|
120
128
|
brand: main.brand,
|
|
121
129
|
numberSpacing: main.numberSpacing,
|
|
122
130
|
numberSize: main.numberSize,
|
|
131
|
+
brandSize: main.brandSize,
|
|
132
|
+
badgeSize: main.badgeSize,
|
|
123
133
|
// Editable fields: complementary-derived
|
|
124
134
|
pattern: main.pattern,
|
|
125
135
|
colors: compColors,
|
|
@@ -139,6 +149,8 @@ export function mergeAlternateJersey(main, alt) {
|
|
|
139
149
|
brand: main.brand,
|
|
140
150
|
numberSpacing: main.numberSpacing,
|
|
141
151
|
numberSize: main.numberSize,
|
|
152
|
+
brandSize: main.brandSize,
|
|
153
|
+
badgeSize: main.badgeSize,
|
|
142
154
|
pattern: alt.pattern,
|
|
143
155
|
colors: alt.colors,
|
|
144
156
|
numberColor: alt.numberColor,
|
|
@@ -413,6 +413,8 @@ export declare const TeamInputSchema: z.ZodObject<{
|
|
|
413
413
|
}>>;
|
|
414
414
|
brandColor1: z.ZodDefault<z.ZodString>;
|
|
415
415
|
brandColor2: z.ZodDefault<z.ZodString>;
|
|
416
|
+
brandSize: z.ZodDefault<z.ZodNumber>;
|
|
417
|
+
badgeSize: z.ZodDefault<z.ZodNumber>;
|
|
416
418
|
}, z.core.$strip>>;
|
|
417
419
|
alternateJerseyConfig: z.ZodOptional<z.ZodObject<{
|
|
418
420
|
pattern: z.ZodEnum<{
|
|
@@ -438,5 +440,101 @@ export declare const TeamInputSchema: z.ZodObject<{
|
|
|
438
440
|
brandColor1: z.ZodDefault<z.ZodString>;
|
|
439
441
|
brandColor2: z.ZodDefault<z.ZodString>;
|
|
440
442
|
}, z.core.$strip>>;
|
|
443
|
+
badgeConfig: z.ZodOptional<z.ZodObject<{
|
|
444
|
+
layers: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
445
|
+
x: z.ZodNumber;
|
|
446
|
+
y: z.ZodNumber;
|
|
447
|
+
size: z.ZodNumber;
|
|
448
|
+
rotation: z.ZodNumber;
|
|
449
|
+
type: z.ZodLiteral<"shape">;
|
|
450
|
+
shape: z.ZodString;
|
|
451
|
+
colors: z.ZodArray<z.ZodString>;
|
|
452
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
453
|
+
x: z.ZodNumber;
|
|
454
|
+
y: z.ZodNumber;
|
|
455
|
+
size: z.ZodNumber;
|
|
456
|
+
rotation: z.ZodNumber;
|
|
457
|
+
type: z.ZodLiteral<"icon">;
|
|
458
|
+
icon: z.ZodEnum<{
|
|
459
|
+
star: "star";
|
|
460
|
+
crown: "crown";
|
|
461
|
+
bolt: "bolt";
|
|
462
|
+
fire: "fire";
|
|
463
|
+
heart: "heart";
|
|
464
|
+
gem: "gem";
|
|
465
|
+
skull: "skull";
|
|
466
|
+
ghost: "ghost";
|
|
467
|
+
anchor: "anchor";
|
|
468
|
+
compass: "compass";
|
|
469
|
+
sun: "sun";
|
|
470
|
+
moon: "moon";
|
|
471
|
+
snowflake: "snowflake";
|
|
472
|
+
leaf: "leaf";
|
|
473
|
+
seedling: "seedling";
|
|
474
|
+
tree: "tree";
|
|
475
|
+
mountain: "mountain";
|
|
476
|
+
water: "water";
|
|
477
|
+
wind: "wind";
|
|
478
|
+
meteor: "meteor";
|
|
479
|
+
rocket: "rocket";
|
|
480
|
+
bell: "bell";
|
|
481
|
+
flag: "flag";
|
|
482
|
+
feather: "feather";
|
|
483
|
+
"shield-halved": "shield-halved";
|
|
484
|
+
"chess-knight": "chess-knight";
|
|
485
|
+
"chess-rook": "chess-rook";
|
|
486
|
+
hammer: "hammer";
|
|
487
|
+
crosshairs: "crosshairs";
|
|
488
|
+
medal: "medal";
|
|
489
|
+
trophy: "trophy";
|
|
490
|
+
award: "award";
|
|
491
|
+
volleyball: "volleyball";
|
|
492
|
+
dragon: "dragon";
|
|
493
|
+
cat: "cat";
|
|
494
|
+
crow: "crow";
|
|
495
|
+
turtle: "turtle";
|
|
496
|
+
unicorn: "unicorn";
|
|
497
|
+
horse: "horse";
|
|
498
|
+
dove: "dove";
|
|
499
|
+
fish: "fish";
|
|
500
|
+
paw: "paw";
|
|
501
|
+
spider: "spider";
|
|
502
|
+
otter: "otter";
|
|
503
|
+
frog: "frog";
|
|
504
|
+
dog: "dog";
|
|
505
|
+
}>;
|
|
506
|
+
color: z.ZodString;
|
|
507
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
508
|
+
x: z.ZodNumber;
|
|
509
|
+
y: z.ZodNumber;
|
|
510
|
+
size: z.ZodNumber;
|
|
511
|
+
rotation: z.ZodNumber;
|
|
512
|
+
type: z.ZodLiteral<"text">;
|
|
513
|
+
text: z.ZodString;
|
|
514
|
+
font: z.ZodEnum<{
|
|
515
|
+
block: "block";
|
|
516
|
+
sans: "sans";
|
|
517
|
+
wide: "wide";
|
|
518
|
+
mono: "mono";
|
|
519
|
+
serif: "serif";
|
|
520
|
+
permanentMarker: "permanentMarker";
|
|
521
|
+
kaushanScript: "kaushanScript";
|
|
522
|
+
russoOne: "russoOne";
|
|
523
|
+
teko: "teko";
|
|
524
|
+
saira: "saira";
|
|
525
|
+
michroma: "michroma";
|
|
526
|
+
zillaSlab: "zillaSlab";
|
|
527
|
+
changaOne: "changaOne";
|
|
528
|
+
stardosStencil: "stardosStencil";
|
|
529
|
+
wallpoet: "wallpoet";
|
|
530
|
+
orbitron: "orbitron";
|
|
531
|
+
tourney: "tourney";
|
|
532
|
+
bebasNeue: "bebasNeue";
|
|
533
|
+
anton: "anton";
|
|
534
|
+
jersey25: "jersey25";
|
|
535
|
+
}>;
|
|
536
|
+
color: z.ZodString;
|
|
537
|
+
}, z.core.$strip>], "type">>;
|
|
538
|
+
}, z.core.$strip>>;
|
|
441
539
|
}, z.core.$strip>;
|
|
442
540
|
export type TeamInput = z.infer<typeof TeamInputSchema>;
|
|
@@ -3,6 +3,7 @@ import { Player } from '../../player';
|
|
|
3
3
|
import { Country } from '../../country';
|
|
4
4
|
import { TacticsInputSchema } from './tactics.z';
|
|
5
5
|
import { JerseySchema, AlternateJerseySchema } from '../jersey';
|
|
6
|
+
import { BadgeSchema } from '../badge';
|
|
6
7
|
const playerInstanceSchema = z.custom((v) => v instanceof Player, {
|
|
7
8
|
message: 'INVALID_PLAYER_INSTANCE'
|
|
8
9
|
});
|
|
@@ -20,7 +21,8 @@ export const TeamInputSchema = z.object({
|
|
|
20
21
|
legacyFlagCountry: countrySchema.optional(),
|
|
21
22
|
tactics: TacticsInputSchema.optional(),
|
|
22
23
|
jerseyConfig: JerseySchema.optional(),
|
|
23
|
-
alternateJerseyConfig: AlternateJerseySchema.optional()
|
|
24
|
+
alternateJerseyConfig: AlternateJerseySchema.optional(),
|
|
25
|
+
badgeConfig: BadgeSchema.optional()
|
|
24
26
|
}).superRefine((data, ctx) => {
|
|
25
27
|
const ids = data.roster.map(p => p.id);
|
|
26
28
|
if (new Set(ids).size !== ids.length) {
|
|
@@ -2,6 +2,7 @@ import { Player } from '../player';
|
|
|
2
2
|
import { Country } from '../country';
|
|
3
3
|
import { Tactics } from './tactics';
|
|
4
4
|
import type { JerseyConfig, AlternateJerseyConfig } from './jersey';
|
|
5
|
+
import type { BadgeConfig } from './badge';
|
|
5
6
|
export declare class Team {
|
|
6
7
|
readonly id: string;
|
|
7
8
|
readonly roster: Player[];
|
|
@@ -13,6 +14,7 @@ export declare class Team {
|
|
|
13
14
|
readonly legacyFlagCountry?: Country;
|
|
14
15
|
readonly jerseyConfig?: JerseyConfig;
|
|
15
16
|
readonly alternateJerseyConfig?: AlternateJerseyConfig;
|
|
17
|
+
readonly badgeConfig?: BadgeConfig;
|
|
16
18
|
private _rating;
|
|
17
19
|
static create(input: unknown): Team;
|
|
18
20
|
private constructor();
|
|
@@ -16,7 +16,7 @@ export class Team {
|
|
|
16
16
|
tactics: result.data.tactics != null ? Tactics.create(result.data.tactics) : undefined
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
constructor({ id, rating, name, shortName, divisionId, country, legacyFlagCountry, roster, tactics, jerseyConfig, alternateJerseyConfig }) {
|
|
19
|
+
constructor({ id, rating, name, shortName, divisionId, country, legacyFlagCountry, roster, tactics, jerseyConfig, alternateJerseyConfig, badgeConfig }) {
|
|
20
20
|
this.id = id;
|
|
21
21
|
this._rating = rating;
|
|
22
22
|
this.roster = roster;
|
|
@@ -28,6 +28,7 @@ export class Team {
|
|
|
28
28
|
this.legacyFlagCountry = legacyFlagCountry;
|
|
29
29
|
this.jerseyConfig = jerseyConfig;
|
|
30
30
|
this.alternateJerseyConfig = alternateJerseyConfig;
|
|
31
|
+
this.badgeConfig = badgeConfig;
|
|
31
32
|
}
|
|
32
33
|
get rating() {
|
|
33
34
|
return this._rating;
|