@johnmorrisdotca/taisen-brackets 0.9.0 → 0.11.0
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/CHANGELOG.md +26 -0
- package/README.md +16 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/judo-road.d.ts +53 -0
- package/dist/judo-road.js +207 -0
- package/dist/judo-sheets.d.ts +20 -0
- package/dist/judo-sheets.js +12 -11
- package/dist/locales.js +10 -0
- package/dist/rank-kit.d.ts +90 -0
- package/dist/rank-kit.js +124 -0
- package/dist/ranking.d.ts +95 -0
- package/dist/ranking.js +391 -0
- package/dist/types.d.ts +19 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the ranking lists, the medal table and the results boards share: the sizes, the frame (size, theme, language, flags), the stylesheet with its light and dark palettes, the
|
|
3
|
+
* wrapper that makes the SVG, and the small shapes (a movement arrow, a pill, a rank badge). Every board is a static SVG for a given state, a pure function of its input.
|
|
4
|
+
*/
|
|
5
|
+
import type { DrawOptions, Locale, Words } from "./types.ts";
|
|
6
|
+
import { bw, clampN, fitSize } from "./judo-board.ts";
|
|
7
|
+
import { type Voice } from "./locales.ts";
|
|
8
|
+
import { type MarkContext } from "./marks.ts";
|
|
9
|
+
export { bw, clampN, fitSize };
|
|
10
|
+
export type BoardSizeName = "tv" | "tablet" | "tablet-tall" | "phone" | "square" | "portrait";
|
|
11
|
+
/** The sizes of a board: a TV's 1920 by 1080, a tablet on its side (1280 by 800) and upright (800 by 1280), a phone's 600 by 1300, and the social-card shapes, square (1080) and 4:5 (1080 by 1350). */
|
|
12
|
+
export declare const BOARD_SIZES: Readonly<Record<BoardSizeName, {
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
}>>;
|
|
16
|
+
/** What every board takes. */
|
|
17
|
+
export interface BoardOptions {
|
|
18
|
+
/** One of `BOARD_SIZES` (`tv` by default), or a size of your own, `{ width, height }`, at least 200 each way. */
|
|
19
|
+
size?: BoardSizeName | {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
/** `auto` (the default) follows the page's light or dark, `light` and `dark` fix it. */
|
|
24
|
+
theme?: "auto" | "light" | "dark";
|
|
25
|
+
/** Draws a flag from its code, as for `drawBracket`: a synchronous function from a code (`CA-BC`, `JP`) and `{ shape, size, theme }` to an SVG string, such as one made from `@johnmorrisdotca/hata`. */
|
|
26
|
+
flags?: DrawOptions["flags"];
|
|
27
|
+
/** The address of a flag as a picture to load, tried where `flags` gives none. */
|
|
28
|
+
flagHref?: DrawOptions["flagHref"];
|
|
29
|
+
/** `round` (the default) or `square`: the shape a flag is asked for and drawn in. */
|
|
30
|
+
flagShape?: "round" | "square";
|
|
31
|
+
/** The language: `en`, `fr`, `ja`, `es`, `de` or a `Locale`. */
|
|
32
|
+
locale?: string | Locale;
|
|
33
|
+
words?: Partial<Words>;
|
|
34
|
+
/** The `<title>` of the drawing. Default: the board's own heading. */
|
|
35
|
+
title?: string;
|
|
36
|
+
/** Prefix for the drawing's ids. Default: a hash of the state and the options. */
|
|
37
|
+
id?: string;
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface BoardFrame {
|
|
41
|
+
W: number;
|
|
42
|
+
H: number;
|
|
43
|
+
v: Voice;
|
|
44
|
+
scope: string;
|
|
45
|
+
theme: "auto" | "light" | "dark";
|
|
46
|
+
ctx: MarkContext;
|
|
47
|
+
options: BoardOptions;
|
|
48
|
+
}
|
|
49
|
+
export declare const rect: (x: number, y: number, w: number, h: number, cls: string, rx?: number, extra?: string) => string;
|
|
50
|
+
export declare const label: (x: number, y: number, size: number, content: string, cls: string, anchor?: "start" | "middle" | "end", weight?: number, extra?: string) => string;
|
|
51
|
+
/** The size, theme and language a board is drawn with, checked; `seed` is whatever the drawing depends on, for the hash of the ids. */
|
|
52
|
+
export declare function boardFrame(options: BoardOptions, seed: unknown): BoardFrame;
|
|
53
|
+
export interface BoardPalette {
|
|
54
|
+
bg: string;
|
|
55
|
+
ink: string;
|
|
56
|
+
sub: string;
|
|
57
|
+
accent: string;
|
|
58
|
+
accentInk: string;
|
|
59
|
+
row: string;
|
|
60
|
+
rowAlt: string;
|
|
61
|
+
edge: string;
|
|
62
|
+
head: string;
|
|
63
|
+
headInk: string;
|
|
64
|
+
up: string;
|
|
65
|
+
down: string;
|
|
66
|
+
upRow: string;
|
|
67
|
+
downRow: string;
|
|
68
|
+
pill: string;
|
|
69
|
+
pillInk: string;
|
|
70
|
+
/** Gold, silver, bronze: the two ends of the row's gradient, the edge and the numeral. */
|
|
71
|
+
gold: readonly [string, string, string, string];
|
|
72
|
+
silver: readonly [string, string, string, string];
|
|
73
|
+
bronze: readonly [string, string, string, string];
|
|
74
|
+
}
|
|
75
|
+
export declare const BOARD_LIGHT: BoardPalette;
|
|
76
|
+
export declare const BOARD_DARK: BoardPalette;
|
|
77
|
+
/** The rules for one palette, scoped, with `before` ahead of every selector (empty, or the dark-mode root selector). */
|
|
78
|
+
export declare function boardRules(p: BoardPalette, scope: string, before: string, extra?: (sel: (s: string, body: string) => string, v: (name: string, value: string) => string) => string[]): string;
|
|
79
|
+
/** The whole stylesheet: the light palette, the dark one under the page's dark mode (for `auto`) or on its own, and the fixed rules. */
|
|
80
|
+
export declare function boardStyle(scope: string, theme: "auto" | "light" | "dark", extra?: Parameters<typeof boardRules>[3], fixed?: string): string;
|
|
81
|
+
/** The medal gradients a board's rows use: one for gold, silver and bronze, by id. */
|
|
82
|
+
export declare function medalDefs(scope: string): string;
|
|
83
|
+
export declare function boardWrap(f: BoardFrame, title: string, desc: string, body: string[], kind: string, extra?: Parameters<typeof boardRules>[3], fixed?: string, defs?: string): string;
|
|
84
|
+
/** A movement arrow, a triangle `s` high centred at (cx, cy), up or down. */
|
|
85
|
+
export declare function arrow(cx: number, cy: number, s: number, up: boolean): string;
|
|
86
|
+
/** A pill with centred text in it, as wide as the text needs (never wider than `maxW`). Returns the pieces and the width. */
|
|
87
|
+
export declare function pill(x: number, cy: number, h: number, content: string, maxW: number, cls?: string, inkCls?: string, anchor?: "start" | "end"): {
|
|
88
|
+
svg: string;
|
|
89
|
+
w: number;
|
|
90
|
+
};
|
package/dist/rank-kit.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { bw, clampN, fitSize, FONT } from "./judo-board.js";
|
|
2
|
+
import { voiceOf } from "./locales.js";
|
|
3
|
+
import { markDefs } from "./marks.js";
|
|
4
|
+
import { esc, fit, hash, num } from "./text.js";
|
|
5
|
+
export { bw, clampN, fitSize };
|
|
6
|
+
/** The sizes of a board: a TV's 1920 by 1080, a tablet on its side (1280 by 800) and upright (800 by 1280), a phone's 600 by 1300, and the social-card shapes, square (1080) and 4:5 (1080 by 1350). */
|
|
7
|
+
export const BOARD_SIZES = Object.freeze({
|
|
8
|
+
tv: { width: 1920, height: 1080 },
|
|
9
|
+
tablet: { width: 1280, height: 800 },
|
|
10
|
+
"tablet-tall": { width: 800, height: 1280 },
|
|
11
|
+
phone: { width: 600, height: 1300 },
|
|
12
|
+
square: { width: 1080, height: 1080 },
|
|
13
|
+
portrait: { width: 1080, height: 1350 },
|
|
14
|
+
});
|
|
15
|
+
export const rect = (x, y, w, h, cls, rx = 0, extra = "") => `<rect class="${cls}" x="${num(x)}" y="${num(y)}" width="${num(w)}" height="${num(h)}"${rx ? ` rx="${num(rx)}"` : ""}${extra}/>`;
|
|
16
|
+
export const label = (x, y, size, content, cls, anchor = "start", weight = 800, extra = "") => `<text class="${cls}" x="${num(x)}" y="${num(y)}" font-size="${num(size)}" font-weight="${weight}" text-anchor="${anchor}"${extra}>${esc(content)}</text>`;
|
|
17
|
+
/** An id for the drawing's classes and ids, made safe: letters, digits, `_` and `-` only (anything else becomes `-`), and a letter first. `undefined` stays `undefined`. */
|
|
18
|
+
const safeId = (id) => (id === undefined ? undefined : /^[A-Za-z]/.test(id) ? id.replace(/[^\w-]/g, "-") : `rk-${id.replace(/[^\w-]/g, "-")}`);
|
|
19
|
+
/** The size, theme and language a board is drawn with, checked; `seed` is whatever the drawing depends on, for the hash of the ids. */
|
|
20
|
+
export function boardFrame(options, seed) {
|
|
21
|
+
const v = voiceOf(options);
|
|
22
|
+
const size = typeof options.size === "string" ? BOARD_SIZES[options.size] : options.size ?? BOARD_SIZES.tv;
|
|
23
|
+
if (!size || !(size.width >= 200) || !(size.height >= 200))
|
|
24
|
+
throw new RangeError(`taisen-brackets: a size is ${Object.keys(BOARD_SIZES).map((k) => `"${k}"`).join(", ")} or { width, height } of 200 or more, not ${JSON.stringify(options.size)}`);
|
|
25
|
+
const theme = options.theme ?? "auto";
|
|
26
|
+
if (theme !== "auto" && theme !== "light" && theme !== "dark")
|
|
27
|
+
throw new RangeError(`taisen-brackets: a theme is "auto", "light" or "dark", not ${JSON.stringify(theme)}`);
|
|
28
|
+
const shape = options.flagShape ?? "round";
|
|
29
|
+
if (shape !== "round" && shape !== "square")
|
|
30
|
+
throw new RangeError(`taisen-brackets: a flag shape is "round" or "square", not ${JSON.stringify(options.flagShape)}`);
|
|
31
|
+
const scope = safeId(options.id) ?? `rk-${hash(JSON.stringify([seed, options.size, theme, shape, v.locale.code, options.flags ? 1 : 0, options.flagHref ? 1 : 0, options.title]))}`;
|
|
32
|
+
const ctx = { radii: new Set(), symbols: new Map(), prefix: scope, shape, theme: "inherit", flagCache: new Map(), ...(options.flags ? { flags: options.flags } : {}), ...(options.flagHref ? { flagHref: options.flagHref } : {}) };
|
|
33
|
+
return { W: size.width, H: size.height, v, scope, theme, ctx, options };
|
|
34
|
+
}
|
|
35
|
+
export const BOARD_LIGHT = {
|
|
36
|
+
bg: "#eceff4", ink: "#131822", sub: "#566071", accent: "#2457c5", accentInk: "#ffffff",
|
|
37
|
+
row: "#ffffff", rowAlt: "#f6f8fb", edge: "#d3d9e3", head: "#16233f", headInk: "#ffffff",
|
|
38
|
+
up: "#0f8a46", down: "#c3302a", upRow: "#e0f4e8", downRow: "#fbe3e1",
|
|
39
|
+
pill: "#e3e8f1", pillInk: "#2a3345",
|
|
40
|
+
gold: ["#f8e9b5", "#fdf6dc", "#d4a929", "#7d5d00"], silver: ["#e4e8ee", "#f3f5f8", "#a9b2c0", "#4f586a"], bronze: ["#f2d5ba", "#faeadb", "#c98650", "#82451a"],
|
|
41
|
+
};
|
|
42
|
+
export const BOARD_DARK = {
|
|
43
|
+
bg: "#0b0f17", ink: "#f0f3f9", sub: "#98a3b8", accent: "#6ea2ff", accentInk: "#0b0f17",
|
|
44
|
+
row: "#161d2b", rowAlt: "#121826", edge: "#27324a", head: "#1b2742", headInk: "#f0f3f9",
|
|
45
|
+
up: "#4fdc8b", down: "#ff7b72", upRow: "#123724", downRow: "#451d1d",
|
|
46
|
+
pill: "#25304a", pillInk: "#dfe6f5",
|
|
47
|
+
gold: ["#5a4813", "#2c2512", "#d0aa3a", "#f5d263"], silver: ["#434c60", "#232a38", "#9ba6bb", "#e3e8f2"], bronze: ["#58341b", "#2b1d14", "#c4854f", "#f3a96f"],
|
|
48
|
+
};
|
|
49
|
+
const MEDALS = ["gold", "silver", "bronze"];
|
|
50
|
+
/** The rules for one palette, scoped, with `before` ahead of every selector (empty, or the dark-mode root selector). */
|
|
51
|
+
export function boardRules(p, scope, before, extra) {
|
|
52
|
+
const sel = (s, body) => `${before}.${scope} ${s}{${body}}`;
|
|
53
|
+
const v = (name, value) => `var(--rk-${name}, ${value})`;
|
|
54
|
+
const out = [
|
|
55
|
+
sel(".rk-bg", `fill:${v("bg", p.bg)}`),
|
|
56
|
+
sel(".rk-ink", `fill:${v("ink", p.ink)}`),
|
|
57
|
+
sel(".rk-sub", `fill:${v("sub", p.sub)}`),
|
|
58
|
+
sel(".rk-accent", `fill:${v("accent", p.accent)}`),
|
|
59
|
+
sel(".rk-accentink", `fill:${v("accent-ink", p.accentInk)}`),
|
|
60
|
+
sel(".rk-head", `fill:${v("head", p.head)}`),
|
|
61
|
+
sel(".rk-headink", `fill:${v("head-ink", p.headInk)}`),
|
|
62
|
+
sel(".rk-row", `fill:${v("row", p.row)};stroke:${v("edge", p.edge)};stroke-width:1.5`),
|
|
63
|
+
sel(".rk-row.rk-alt", `fill:${v("row-alt", p.rowAlt)}`),
|
|
64
|
+
sel(".rk-sep", `stroke:${v("edge", p.edge)};stroke-width:1.5`),
|
|
65
|
+
sel(".rk-up", `fill:${v("up", p.up)}`),
|
|
66
|
+
sel(".rk-down", `fill:${v("down", p.down)}`),
|
|
67
|
+
sel(".rk-row.rk-mup", `fill:${v("up-row", p.upRow)}`),
|
|
68
|
+
sel(".rk-row.rk-mdown", `fill:${v("down-row", p.downRow)}`),
|
|
69
|
+
sel(".rk-pill", `fill:${v("pill", p.pill)}`),
|
|
70
|
+
sel(".rk-pillink", `fill:${v("pill-ink", p.pillInk)}`),
|
|
71
|
+
sel(".rk-nr", `fill:${v("accent", p.accent)}`),
|
|
72
|
+
sel(".rk-nrink", `fill:${v("accent-ink", p.accentInk)}`),
|
|
73
|
+
sel(".tb-ring", `fill:none;stroke:rgba(0,0,0,.28);stroke-width:1.5`),
|
|
74
|
+
sel(".tb-plain", `fill:${v("pill", p.pill)}`),
|
|
75
|
+
sel(".tb-initials", `fill:${v("pill-ink", p.pillInk)}`),
|
|
76
|
+
];
|
|
77
|
+
MEDALS.forEach((m, i) => {
|
|
78
|
+
const c = p[m];
|
|
79
|
+
out.push(sel(`.rk-ga${i + 1}`, `stop-color:${c[0]}`), sel(`.rk-gb${i + 1}`, `stop-color:${c[1]}`), sel(`.rk-medal${i + 1}`, `stroke:${c[2]};stroke-width:2`), sel(`.rk-num${i + 1}`, `fill:${c[3]}`), sel(`.rk-bar${i + 1}`, `fill:${c[2]}`));
|
|
80
|
+
});
|
|
81
|
+
if (extra)
|
|
82
|
+
out.push(...extra(sel, v));
|
|
83
|
+
return out.join("\n");
|
|
84
|
+
}
|
|
85
|
+
/** The whole stylesheet: the light palette, the dark one under the page's dark mode (for `auto`) or on its own, and the fixed rules. */
|
|
86
|
+
export function boardStyle(scope, theme, extra, fixed = "") {
|
|
87
|
+
const tail = [`.${scope} text{font-family:var(--rk-font, ${FONT});font-variant-numeric:tabular-nums}`, fixed.replaceAll("$S", `.${scope}`)].filter(Boolean).join("\n");
|
|
88
|
+
if (theme === "light")
|
|
89
|
+
return `${boardRules(BOARD_LIGHT, scope, "", extra)}\n${tail}`;
|
|
90
|
+
if (theme === "dark")
|
|
91
|
+
return `${boardRules(BOARD_DARK, scope, "", extra)}\n${tail}`;
|
|
92
|
+
return `${boardRules(BOARD_LIGHT, scope, "", extra)}\n@media (prefers-color-scheme: dark){\n${boardRules(BOARD_DARK, scope, ':root:not([data-theme="light"]) ', extra)}\n}\n${boardRules(BOARD_DARK, scope, ':root[data-theme="dark"] ', extra)}\n${tail}`;
|
|
93
|
+
}
|
|
94
|
+
/** The medal gradients a board's rows use: one for gold, silver and bronze, by id. */
|
|
95
|
+
export function medalDefs(scope) {
|
|
96
|
+
return MEDALS.map((_, i) => `<linearGradient id="${esc(scope)}-g${i + 1}" x1="0" x2="1" y1="0" y2="0"><stop class="rk-ga${i + 1}" offset="0"/><stop class="rk-gb${i + 1}" offset="1"/></linearGradient>`).join("");
|
|
97
|
+
}
|
|
98
|
+
export function boardWrap(f, title, desc, body, kind, extra, fixed = "", defs = "") {
|
|
99
|
+
const marks = markDefs(f.ctx);
|
|
100
|
+
return [
|
|
101
|
+
`<svg xmlns="http://www.w3.org/2000/svg" lang="${esc(f.v.locale.code)}" class="taisen taisen-board ${esc(f.scope)}${f.options.className ? ` ${esc(f.options.className)}` : ""}" viewBox="0 0 ${num(f.W)} ${num(f.H)}" width="${num(f.W)}" height="${num(f.H)}" style="max-width:100%;height:auto" role="img" aria-labelledby="${esc(f.scope)}-t ${esc(f.scope)}-d" data-board="${kind}">`,
|
|
102
|
+
`<title id="${esc(f.scope)}-t">${esc(title)}</title><desc id="${esc(f.scope)}-d">${esc(desc)}</desc>`,
|
|
103
|
+
`<style>${boardStyle(f.scope, f.theme, extra, fixed)}</style>`,
|
|
104
|
+
`<defs>${medalDefs(f.scope)}${defs}${marks}</defs>`,
|
|
105
|
+
`<rect class="rk-bg" width="${num(f.W)}" height="${num(f.H)}"/>`,
|
|
106
|
+
...body,
|
|
107
|
+
"</svg>",
|
|
108
|
+
].join("\n");
|
|
109
|
+
}
|
|
110
|
+
// ------------------------------------------------------------------------------------------------ small shapes
|
|
111
|
+
/** A movement arrow, a triangle `s` high centred at (cx, cy), up or down. */
|
|
112
|
+
export function arrow(cx, cy, s, up) {
|
|
113
|
+
const w = s * 1.1, h = s * 0.9;
|
|
114
|
+
const pts = up ? [[cx, cy - h / 2], [cx + w / 2, cy + h / 2], [cx - w / 2, cy + h / 2]] : [[cx - w / 2, cy - h / 2], [cx + w / 2, cy - h / 2], [cx, cy + h / 2]];
|
|
115
|
+
return `<polygon class="${up ? "rk-up" : "rk-down"}" points="${pts.map(([x, y]) => `${num(x)},${num(y)}`).join(" ")}"/>`;
|
|
116
|
+
}
|
|
117
|
+
/** A pill with centred text in it, as wide as the text needs (never wider than `maxW`). Returns the pieces and the width. */
|
|
118
|
+
export function pill(x, cy, h, content, maxW, cls = "rk-pill", inkCls = "rk-pillink", anchor = "start") {
|
|
119
|
+
const size = h * 0.56;
|
|
120
|
+
const fs = fitSize(content, size, maxW - h * 0.7, 0.6);
|
|
121
|
+
const w = Math.min(maxW, bw(content, fs) + h * 0.7);
|
|
122
|
+
const x0 = anchor === "start" ? x : x - w;
|
|
123
|
+
return { svg: `${rect(x0, cy - h / 2, w, h, cls, h / 2)}${label(x0 + w / 2, cy + fs * 0.36, fs, fit(content, fs, w, bw), inkCls, "middle", 800, ' letter-spacing=".03em"')}`, w };
|
|
124
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ranking lists for any ranked sport, drawn from the caller's data (a provincial or club feed, a federation's list): a title and a category, then the entries as a podium (the top
|
|
3
|
+
* three in gold, silver and bronze rows) above a compact list, as one featured row above two columns, or as a plain list. Text first: rank, flag, name, club, points and the
|
|
4
|
+
* movement since the last list, with no photo slot to leave empty. A champion row ("C"), an interim champion, newly ranked athletes ("NR"), tied ranks and paging are in.
|
|
5
|
+
* Static SVG for a given state, like every drawing here.
|
|
6
|
+
*/
|
|
7
|
+
import { type BoardOptions } from "./rank-kit.ts";
|
|
8
|
+
/** A name in two parts: the family name is written in capitals and first by default (`SURNAME Given`, as judo and the IJF write it). */
|
|
9
|
+
export interface RankingName {
|
|
10
|
+
given?: string;
|
|
11
|
+
surname: string;
|
|
12
|
+
}
|
|
13
|
+
/** One line of a ranking. Only `name` is needed. */
|
|
14
|
+
export interface RankingEntry {
|
|
15
|
+
/** The name as it is to be written, or its two parts (set by `nameStyle`). */
|
|
16
|
+
name: string | RankingName;
|
|
17
|
+
/** The rank. Left out, the position in the list, with equal points sharing a rank (`ties`). A champion has none. */
|
|
18
|
+
rank?: number;
|
|
19
|
+
/** A number (shown to `precision` decimals) or text (shown as it is). */
|
|
20
|
+
points?: number | string;
|
|
21
|
+
club?: string;
|
|
22
|
+
/** The country's or region's name, written under the name in a podium row. */
|
|
23
|
+
country?: string;
|
|
24
|
+
/** The country's three letters (`CAN`), written in the compact rows. */
|
|
25
|
+
code?: string;
|
|
26
|
+
/** A code for the `flags` renderer: a country (`JP`) or a Canadian province or territory (`CA-BC`). */
|
|
27
|
+
flag?: string;
|
|
28
|
+
/** A mark of your own (an image address or inline SVG) in place of a flag: a club's emblem. */
|
|
29
|
+
mark?: string;
|
|
30
|
+
/** This athlete's category ("U18 · -60 kg"), written in the second line when `categories` is on: for a list that mixes categories. */
|
|
31
|
+
category?: string;
|
|
32
|
+
/** The movement since the last list: whole places up (positive) or down (negative), `0` for none, `"new"` for newly ranked ("NR"). */
|
|
33
|
+
change?: number | "new";
|
|
34
|
+
/** The champion of the division: a row marked "C" above the ranks (`"interim"` for an interim champion). */
|
|
35
|
+
champion?: boolean | "interim";
|
|
36
|
+
}
|
|
37
|
+
export interface RankingSource {
|
|
38
|
+
/** The heading. Default: the language's word for ranking. */
|
|
39
|
+
title?: string;
|
|
40
|
+
/** The category as a line under the heading ("U18 · Men -60 kg"; `rankingCategoryLabel` writes one). */
|
|
41
|
+
category?: string;
|
|
42
|
+
/** The date or period of the list, at the right of the heading ("October 2026"). */
|
|
43
|
+
date?: string;
|
|
44
|
+
/** Where the list comes from, small at the foot ("Source: BC Judo"). */
|
|
45
|
+
source?: string;
|
|
46
|
+
entries: readonly RankingEntry[];
|
|
47
|
+
}
|
|
48
|
+
export interface RankingOptions extends BoardOptions {
|
|
49
|
+
/** `podium` (the default): the top three as big rows, tinted gold, silver and bronze, above the compact rest. `featured`: one big row above two columns. `list`: every row compact. */
|
|
50
|
+
style?: "podium" | "list" | "featured";
|
|
51
|
+
/** How many rows, from the top, are big (0 to 3). Default by `style`. Only on the first page. */
|
|
52
|
+
big?: number;
|
|
53
|
+
/** One column or two for the compact rows (the first column runs down before the second starts). Default 1, and 2 for `featured`. */
|
|
54
|
+
columns?: 1 | 2;
|
|
55
|
+
/** The most entries drawn, from the first of the page. Default: as many as fit at a readable size. */
|
|
56
|
+
rows?: number;
|
|
57
|
+
/** Which page of `rows` entries (0 is the first). The header says which entries are shown. */
|
|
58
|
+
page?: number;
|
|
59
|
+
/** On a wide board (at least 3:2) the big rows go in a panel on the left and the compact ones beside them, in place of one above the other. Default true; `false` stacks them. */
|
|
60
|
+
split?: boolean;
|
|
61
|
+
/** Tint the rows of ranks 1 to 3 gold, silver and bronze. Default: on for `podium` and `featured` (off when the list has a champion row), off for `list`. */
|
|
62
|
+
medals?: boolean;
|
|
63
|
+
/** How movement is shown: `arrow` (an arrow and the number of places, the default), `row` (the row tinted green or red), `both`, or `none`. */
|
|
64
|
+
movement?: "arrow" | "row" | "both" | "none";
|
|
65
|
+
/** `surname-first` (the default: `SURNAME Given`), `given-first` (`Given SURNAME`) or `as-is`, for a `name` given in two parts. */
|
|
66
|
+
nameStyle?: "surname-first" | "given-first" | "as-is";
|
|
67
|
+
/** `plain` (`10`, the default) or `hash` (`#10`). */
|
|
68
|
+
rankStyle?: "plain" | "hash";
|
|
69
|
+
/** Decimals for numeric points (`2` writes `91.60` and `50.00`). Default: as many as the number has, up to three. */
|
|
70
|
+
precision?: number;
|
|
71
|
+
/** Equal points share a rank where an entry names none (`1, 2, 2, 4`). Default true. */
|
|
72
|
+
ties?: boolean;
|
|
73
|
+
/** `given` (the default) keeps the order of the entries; `points` puts the most points first. */
|
|
74
|
+
sort?: "given" | "points";
|
|
75
|
+
/** Write each entry's own `category` in the second line. */
|
|
76
|
+
categories?: boolean;
|
|
77
|
+
/** Draw a club's (or the athlete's) initials on a badge for an entry with no flag or mark, even where no entry has one. Default: only where some entry has a flag or mark. */
|
|
78
|
+
badge?: boolean;
|
|
79
|
+
}
|
|
80
|
+
/** The ranks of a list, in order: an entry's own `rank`, else its position, with equal points sharing a rank; `null` for a champion row. Pure; takes the list as it is ordered. */
|
|
81
|
+
export declare function rankingRanks(entries: readonly RankingEntry[], options?: {
|
|
82
|
+
ties?: boolean;
|
|
83
|
+
}): (number | null)[];
|
|
84
|
+
/** A category as a heading ("U18 · Men -60 kg"): an age group, a sex and a weight, any of them, joined by a dot. A weight is `-60` or `+100` (kg) or any text. */
|
|
85
|
+
export declare function rankingCategoryLabel(category: {
|
|
86
|
+
age?: string;
|
|
87
|
+
sex?: "men" | "women" | "open";
|
|
88
|
+
weight?: string;
|
|
89
|
+
}, locale?: string): string;
|
|
90
|
+
/** The ranking as a sentence, the drawing's description. */
|
|
91
|
+
export declare function describeRanking(source: RankingSource, options?: Pick<RankingOptions, "locale" | "words" | "nameStyle" | "precision" | "ties" | "sort" | "rankStyle" | "rows" | "page">): string;
|
|
92
|
+
/**
|
|
93
|
+
* The ranking list as an SVG. Throws a `RangeError` for an entry with no name, a rank or change that is not a whole number, an option that is not one of its values, or a bad size or theme.
|
|
94
|
+
*/
|
|
95
|
+
export declare function rankingList(source: RankingSource, options?: RankingOptions): string;
|