43 lines
1.3 KiB
TypeScript
43 lines
1.3 KiB
TypeScript
export function imageContentDisposition(displayName: string, fallbackName: string): string {
|
|
const safeDisplayName = displayName.trim() || fallbackName;
|
|
const fallback = safeDisplayName
|
|
.normalize("NFKD")
|
|
.replace(/[^a-z0-9]+/giu, "-")
|
|
.replace(/^-|-$/gu, "") || fallbackName;
|
|
const encoded = encodeURIComponent(`${safeDisplayName}.png`).replace(
|
|
/['()*]/gu,
|
|
(character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`,
|
|
);
|
|
return `attachment; filename="${fallback}.png"; filename*=UTF-8''${encoded}`;
|
|
}
|
|
|
|
export interface ConstellationChartRow {
|
|
level: number;
|
|
percent: number;
|
|
isGreat: boolean;
|
|
widthPercent: number;
|
|
}
|
|
|
|
export function constellationChartRows(
|
|
rows: ReadonlyArray<{
|
|
level: number;
|
|
cumulativePercent: string;
|
|
isGreat: boolean;
|
|
}>,
|
|
): ConstellationChartRow[] {
|
|
const values = [
|
|
...rows.map((row) => ({
|
|
level: row.level,
|
|
percent: Number(row.cumulativePercent),
|
|
isGreat: row.isGreat,
|
|
})),
|
|
{ level: 0, percent: 100, isGreat: false },
|
|
].sort((left, right) => right.level - left.level);
|
|
const maximum = Math.max(100, ...values.map((row) => row.percent));
|
|
|
|
return values.map((row) => ({
|
|
...row,
|
|
widthPercent: Math.max(0, Math.min(100, (row.percent / maximum) * 100)),
|
|
}));
|
|
}
|