mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: satori and resvg for rendering
This commit is contained in:
1 parent
e48ea4c307
commit
c834f4f966
34 files changed
+670
-501
No files matched your search
Vendored
+1
@@ -4,6 +4,7 @@
|
||||
"accountinfo",
|
||||
"kranvagn",
|
||||
"ownedtanks",
|
||||
"Resvg",
|
||||
"searchplayers",
|
||||
"Smri",
|
||||
"strvk",
|
||||
|
||||
+5
-4
@@ -5,27 +5,28 @@
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"pw": "playwright install && playwright install-deps",
|
||||
"install": "playwright install",
|
||||
"start": "vite-node src/index.ts --script",
|
||||
"lint": "tsc"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@resvg/resvg-js": "^2.4.1",
|
||||
"discord.js": "^14.9.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"fuzzysort": "^2.0.4",
|
||||
"lodash.startcase": "^4.4.0",
|
||||
"markdown-escape": "^2.0.0",
|
||||
"node-fetch": "^3.3.1"
|
||||
"node-fetch": "^3.3.1",
|
||||
"react": "^18.2.0",
|
||||
"satori": "^0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.34.2",
|
||||
"@total-typescript/ts-reset": "^0.4.2",
|
||||
"@types/escape-html": "^1.0.2",
|
||||
"@types/lodash.startcase": "^4.4.7",
|
||||
"@types/markdown-escape": "^1.1.0",
|
||||
"@types/node": "^20.2.1",
|
||||
"@types/react": "^18.2.7",
|
||||
"typescript": "^5.0.4",
|
||||
"vite-node": "^0.31.1"
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,6 @@ import {
|
||||
ButtonBuilder,
|
||||
SlashCommandBuilder,
|
||||
} from 'discord.js';
|
||||
import escapeHTML from 'escape-html';
|
||||
import GenericStats from '../components/GenericStats/index.js';
|
||||
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
|
||||
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||
@@ -19,7 +18,7 @@ import getBlitzStarsAccount from '../core/blitzstars/getBlitzStarsAccount.js';
|
||||
import cmdName from '../core/interaction/cmdName.js';
|
||||
import addUsernameOption from '../core/options/addUsernameOption.js';
|
||||
import { args } from '../core/process/args.js';
|
||||
import screenshotHTML from '../core/ui/screenshotHTML.js';
|
||||
import render from '../core/ui/render.js';
|
||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
||||
import { PlayerClanData } from '../types/playerClanData.js';
|
||||
@@ -118,22 +117,27 @@ export default {
|
||||
}
|
||||
if (!stats) return;
|
||||
|
||||
const screenshot = await screenshotHTML(
|
||||
Wrapper(
|
||||
TitleBar(
|
||||
escapeHTML(blitzStarsAccount.nickname),
|
||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
||||
clanData[id]?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||
: undefined,
|
||||
`${periodNames[period]} • ${new Date().toDateString()} • ${
|
||||
BLITZ_SERVERS[server]
|
||||
}`,
|
||||
),
|
||||
const image = await render(
|
||||
<Wrapper>
|
||||
<TitleBar
|
||||
name={blitzStarsAccount.nickname}
|
||||
nameDiscriminator={
|
||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : undefined
|
||||
}
|
||||
image={
|
||||
clanData[id]?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||
: undefined
|
||||
}
|
||||
description={`${
|
||||
periodNames[period]
|
||||
} • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`}
|
||||
/>
|
||||
|
||||
stats.all.battles === 0
|
||||
? NoBattlesInPeriod()
|
||||
: GenericStats([
|
||||
{stats.all.battles === 0 && <NoBattlesInPeriod />}
|
||||
{stats.all.battles > 0 && (
|
||||
<GenericStats
|
||||
stats={[
|
||||
[
|
||||
'Winrate',
|
||||
`${(100 * (stats.all.wins / stats.all.battles)).toFixed(2)}%`,
|
||||
@@ -183,10 +187,12 @@ export default {
|
||||
(stats.all.battles - stats.all.survived_battles)
|
||||
).toFixed(2),
|
||||
],
|
||||
]),
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
PoweredByBlitzStars(),
|
||||
),
|
||||
<PoweredByBlitzStars />
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
const actionRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
@@ -195,7 +201,7 @@ export default {
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
files: [screenshot],
|
||||
files: [image],
|
||||
components: [actionRow],
|
||||
});
|
||||
|
||||
@@ -3,8 +3,7 @@ import {
|
||||
ButtonBuilder,
|
||||
SlashCommandBuilder,
|
||||
} from 'discord.js';
|
||||
import escapeHTML from 'escape-html';
|
||||
import Breakdown from '../components/Breakdown.js';
|
||||
import * as Breakdown from '../components/Breakdown/index.js';
|
||||
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
|
||||
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||
import TitleBar from '../components/TitleBar.js';
|
||||
@@ -21,7 +20,7 @@ import { tankopedia } from '../core/blitzstars/tankopedia.js';
|
||||
import cmdName from '../core/interaction/cmdName.js';
|
||||
import addUsernameOption from '../core/options/addUsernameOption.js';
|
||||
import { args } from '../core/process/args.js';
|
||||
import screenshotHTML from '../core/ui/screenshotHTML.js';
|
||||
import render from '../core/ui/render.js';
|
||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
||||
import { PlayerClanData } from '../types/playerClanData.js';
|
||||
@@ -30,7 +29,7 @@ import resolveTankName from '../utilities/resolveTankName.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inDevelopment: false,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
@@ -72,43 +71,51 @@ export default {
|
||||
([tankId, tankStats]) => {
|
||||
const career = careerStats[tankId as unknown as number];
|
||||
|
||||
return Breakdown.Row(
|
||||
resolveTankName({
|
||||
tank_id: tankId as unknown as number,
|
||||
name: tankopedia.data[tankId as unknown as number].name,
|
||||
}),
|
||||
tankStats.wins / tankStats.battles,
|
||||
career.wins / career.battles,
|
||||
-Infinity,
|
||||
-Infinity,
|
||||
tankStats.damage_dealt / tankStats.battles,
|
||||
career.damage_dealt / career.battles,
|
||||
tankStats.survived_battles / tankStats.battles,
|
||||
career.survived_battles / career.battles,
|
||||
tankStats.battles,
|
||||
career.battles,
|
||||
tankopedia.data[tankId as unknown as number].images.normal,
|
||||
return (
|
||||
<Breakdown.Row
|
||||
key={tankId}
|
||||
name={resolveTankName({
|
||||
tank_id: tankId as unknown as number,
|
||||
name: tankopedia.data[tankId as unknown as number].name,
|
||||
})}
|
||||
winrate={tankStats.wins / tankStats.battles}
|
||||
careerWinrate={career.wins / career.battles}
|
||||
WN8={-Infinity}
|
||||
careerWN8={-Infinity}
|
||||
damage={tankStats.damage_dealt / tankStats.battles}
|
||||
careerDamage={career.damage_dealt / career.battles}
|
||||
survival={tankStats.survived_battles / tankStats.battles}
|
||||
careerSurvival={career.survived_battles / career.battles}
|
||||
battles={tankStats.battles}
|
||||
careerBattles={career.battles}
|
||||
icon={tankopedia.data[tankId as unknown as number].images.normal}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const screenshot = await screenshotHTML(
|
||||
Wrapper(
|
||||
TitleBar(
|
||||
escapeHTML(accountInfo[id].nickname),
|
||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
||||
clanData[id]?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||
: undefined,
|
||||
`Today's breakdown • ${new Date().toDateString()} • ${
|
||||
const image = await render(
|
||||
<Wrapper>
|
||||
<TitleBar
|
||||
name={accountInfo[id].nickname}
|
||||
nameDiscriminator={
|
||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : undefined
|
||||
}
|
||||
image={
|
||||
clanData[id]?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||
: undefined
|
||||
}
|
||||
description={`Today's breakdown • ${new Date().toDateString()} • ${
|
||||
BLITZ_SERVERS[server]
|
||||
}`,
|
||||
),
|
||||
}`}
|
||||
/>
|
||||
|
||||
rows.length === 0 ? NoBattlesInPeriod() : Breakdown.Root(...rows),
|
||||
{rows.length === 0 && <NoBattlesInPeriod />}
|
||||
{rows.length > 0 && <Breakdown.Root>{rows}</Breakdown.Root>}
|
||||
|
||||
PoweredByBlitzStars(),
|
||||
),
|
||||
<PoweredByBlitzStars />
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
const actionRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
@@ -117,7 +124,7 @@ export default {
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
files: [screenshot],
|
||||
files: [image],
|
||||
components: [actionRow],
|
||||
});
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
import Children from './Children.js';
|
||||
|
||||
const Breakdown = {
|
||||
Root(...children: string[]) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown">
|
||||
${Children(children)}
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
|
||||
Row(
|
||||
name: string,
|
||||
winrate: number,
|
||||
careerWinrate: number,
|
||||
wn8: number,
|
||||
careerWn8: number,
|
||||
averageDamage: number,
|
||||
careerAverageDamage: number,
|
||||
survival: number,
|
||||
careerSurvival: number,
|
||||
battles: number,
|
||||
careerBattles: number,
|
||||
icon?: string,
|
||||
) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown-row">
|
||||
${this.RowDiscriminator(name, icon)}
|
||||
${this.RowStat(
|
||||
'Winrate',
|
||||
`${(winrate * 100).toFixed(2)}%`,
|
||||
`${(careerWinrate * 100).toFixed(2)}%`,
|
||||
winrate - careerWinrate,
|
||||
)}
|
||||
${this.RowStat(
|
||||
'Damage',
|
||||
averageDamage.toFixed(2),
|
||||
careerAverageDamage.toFixed(2),
|
||||
averageDamage - careerAverageDamage,
|
||||
)}
|
||||
${this.RowStat(
|
||||
'Survival',
|
||||
`${(survival * 100).toFixed(2)}%`,
|
||||
`${(careerSurvival * 100).toFixed(2)}%`,
|
||||
survival - careerSurvival,
|
||||
)}
|
||||
${this.RowStat('Battles', battles.toFixed(0), careerBattles.toFixed(0))}
|
||||
</div>
|
||||
`;
|
||||
|
||||
/*
|
||||
${this.RowStat(
|
||||
'WN8',
|
||||
wn8.toFixed(0),
|
||||
careerWn8.toFixed(0),
|
||||
wn8 - careerWn8,
|
||||
)}
|
||||
*/
|
||||
},
|
||||
|
||||
RowDiscriminator(name: string, icon?: string) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown-row-discriminator {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
width: 0px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.breakdown-row-discriminator-icon {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.breakdown-row-discriminator-name {
|
||||
color: #A0A0A0;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown-row-discriminator">
|
||||
${
|
||||
icon
|
||||
? `<img src="${icon}" class="breakdown-row-discriminator-icon" />`
|
||||
: ''
|
||||
}
|
||||
<span class="breakdown-row-discriminator-name">${name}</span>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
|
||||
RowStat(name: string, value: string, career: string, delta?: number) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown-row-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-career {
|
||||
color: #A0A0A0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-name {
|
||||
color: #A0A0A0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-value {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-value-delta {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-value-text {
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown-row-stat">
|
||||
<span class="breakdown-row-stat-career">${career}</span>
|
||||
|
||||
<div class="breakdown-row-stat-value">
|
||||
${
|
||||
delta
|
||||
? `<img src="${
|
||||
(delta ?? 0) > 0
|
||||
? 'https://i.imgur.com/qbjiXa1.png'
|
||||
: 'https://i.imgur.com/3uyNhun.png'
|
||||
}" class="breakdown-row-stat-value-delta" />`
|
||||
: ''
|
||||
}
|
||||
|
||||
<span class="breakdown-row-stat-value-text">${value}</span>
|
||||
</div>
|
||||
|
||||
<span class="breakdown-row-stat-name">${name}</span>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
};
|
||||
|
||||
export default Breakdown;
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface RootProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function Root({ children }: RootProps) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { RowDiscriminator } from './RowDiscriminator.js';
|
||||
import { RowStat } from './RowStat.js';
|
||||
|
||||
export interface RowProps {
|
||||
name: string;
|
||||
winrate: number;
|
||||
careerWinrate: number;
|
||||
WN8: number;
|
||||
careerWN8: number;
|
||||
damage: number;
|
||||
careerDamage: number;
|
||||
survival: number;
|
||||
careerSurvival: number;
|
||||
battles: number;
|
||||
careerBattles: number;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
export function Row({
|
||||
name,
|
||||
winrate,
|
||||
careerWinrate,
|
||||
WN8,
|
||||
careerWN8,
|
||||
damage: averageDamage,
|
||||
careerDamage: careerAverageDamage,
|
||||
survival,
|
||||
careerSurvival,
|
||||
battles,
|
||||
careerBattles,
|
||||
icon,
|
||||
}: RowProps) {
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 16 }}>
|
||||
<RowDiscriminator name={name} icon={icon} />
|
||||
<RowStat
|
||||
name="Winrate"
|
||||
value={`${(winrate * 100).toFixed(2)}%`}
|
||||
career={`${(careerWinrate * 100).toFixed(2)}%`}
|
||||
delta={winrate - careerWinrate}
|
||||
/>
|
||||
<RowStat
|
||||
name="Damage"
|
||||
value={averageDamage.toFixed(2)}
|
||||
career={careerAverageDamage.toFixed(2)}
|
||||
delta={averageDamage - careerAverageDamage}
|
||||
/>
|
||||
<RowStat
|
||||
name="Survival"
|
||||
value={`${(survival * 100).toFixed(2)}%`}
|
||||
career={`${(careerSurvival * 100).toFixed(2)}%`}
|
||||
delta={survival - careerSurvival}
|
||||
/>
|
||||
<RowStat
|
||||
name="Battles"
|
||||
value={battles.toFixed(0)}
|
||||
career={careerBattles.toFixed(0)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
export interface RowDiscriminatorProps {
|
||||
name: string;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
export function RowDiscriminator({ name, icon }: RowDiscriminatorProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
boxSizing: 'border-box',
|
||||
width: 0,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{icon && (
|
||||
<img
|
||||
src={icon}
|
||||
style={{ width: '100%', flex: 1, objectFit: 'cover' }}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
color: '#A0A0A0',
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
display: 'block',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: '100%',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
export interface RowStatProps {
|
||||
name: string;
|
||||
value: string;
|
||||
career: string;
|
||||
delta?: number;
|
||||
}
|
||||
|
||||
export function RowStat({ name, value, career, delta }: RowStatProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 4,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<span style={{ color: '#A0A0A0', fontSize: 12 }}>{career}</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: 4,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{delta && (
|
||||
<img
|
||||
src={
|
||||
(delta ?? 0) > 0
|
||||
? 'https://i.imgur.com/qbjiXa1.png'
|
||||
: 'https://i.imgur.com/3uyNhun.png'
|
||||
}
|
||||
style={{ width: 12, height: 12 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<span style={{ color: 'white', fontSize: 16, fontWeight: 'bold' }}>
|
||||
{value}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span style={{ color: '#A0A0A0', fontSize: 12 }}>{name}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './components/Root.js';
|
||||
export * from './components/Row.js';
|
||||
export * from './components/RowDiscriminator.js';
|
||||
export * from './components/RowStat.js';
|
||||
@@ -1,5 +0,0 @@
|
||||
export type ChildrenArgument = string | string[];
|
||||
|
||||
export default function Children(children: string[]) {
|
||||
return children.join('\n');
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Stat } from '../index.js';
|
||||
import GenericStatsRow from './GenericStatsRow.js';
|
||||
|
||||
export default function GenericStatsColumn(stats: Stat[]) {
|
||||
return `
|
||||
<style>
|
||||
.generic-stats-column {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="generic-stats-column">
|
||||
${stats.map((stat) => GenericStatsRow(stat)).join('\n')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Stat } from '../index.js';
|
||||
import GenericStatsRow from './GenericStatsRow.js';
|
||||
|
||||
export interface GenericStatsColumnProps {
|
||||
stats: Stat[];
|
||||
}
|
||||
|
||||
export default function GenericStatsColumn({ stats }: GenericStatsColumnProps) {
|
||||
return (
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
{stats.map((stat) => (
|
||||
<GenericStatsRow key={stat[0]} stat={stat} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Stat } from '../index.js';
|
||||
|
||||
export default function GenericStatsRow(stat: Stat) {
|
||||
return `
|
||||
<style>
|
||||
.generic-stats-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.generic-stats-label {
|
||||
color: #A0A0A0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.generic-stats-value {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="generic-stats-row">
|
||||
<span class="generic-stats-label">${stat[0]}</span>
|
||||
<span class="generic-stats-value">${stat[1]}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Stat } from '../index.js';
|
||||
|
||||
export interface GenericStatsRowProps {
|
||||
stat: Stat;
|
||||
}
|
||||
|
||||
export default function GenericStatsRow({ stat }: GenericStatsRowProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<span style={{ color: '#A0A0A0', fontSize: 16 }}>{stat[0]}</span>
|
||||
<span style={{ color: 'white', fontWeight: 'bold', fontSize: 16 }}>
|
||||
{stat[1]}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,15 @@ import GenericStatsColumn from './components/GenericStatsColumn.js';
|
||||
|
||||
export type Stat = [string, string | number];
|
||||
|
||||
export default function GenericStats(stats: Stat[], columnCount = 2) {
|
||||
export interface GenericStatsProps {
|
||||
stats: Stat[];
|
||||
columnCount?: number;
|
||||
}
|
||||
|
||||
export default function GenericStats({
|
||||
stats,
|
||||
columnCount = 2,
|
||||
}: GenericStatsProps) {
|
||||
const itemsPerRow = Math.ceil(stats.length / columnCount);
|
||||
const columns: Stat[][] = [];
|
||||
|
||||
@@ -12,16 +20,14 @@ export default function GenericStats(stats: Stat[], columnCount = 2) {
|
||||
columns[column].push(stat);
|
||||
});
|
||||
|
||||
return `
|
||||
<style>
|
||||
.generic-stats {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="generic-stats">
|
||||
${columns.map((column) => GenericStatsColumn(column)).join('\n')}
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 32 }}>
|
||||
{columns.map((stats) => (
|
||||
<GenericStatsColumn
|
||||
key={stats.map((stat) => stat[0]).join('-')}
|
||||
stats={stats}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
`;
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
export default function NoBattlesInPeriod() {
|
||||
return `
|
||||
<style>
|
||||
.no-battles-in-period {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.no-battles-in-period-text {
|
||||
font-size: 16px;
|
||||
color: #A0A0A0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="no-battles-in-period">
|
||||
<span class="no-battles-in-period-text">No battles played in this period</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export default function NoBattlesInPeriod() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 16, color: '#A0A0A0' }}>
|
||||
No battles played in this period
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
export default function PoweredByBlitzStars() {
|
||||
return `
|
||||
<style>
|
||||
.powered-by-blitz-stars {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.powered-by-blitz-stars-icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.powered-by-blitz-stars-text {
|
||||
font-size: 16px;
|
||||
color: #A0A0A0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="powered-by-blitz-stars">
|
||||
<img class="powered-by-blitz-stars-icon" src="https://www.blitzstars.com/assets/images/4b4cb591.TankyMcPewpew.png" />
|
||||
<span class="powered-by-blitz-stars-text">Powered by BlitzStars</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
export default function PoweredByBlitzStars() {
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
|
||||
<img
|
||||
src="https://www.blitzstars.com/assets/images/4b4cb591.TankyMcPewpew.png"
|
||||
style={{ height: 16, width: 16 }}
|
||||
/>
|
||||
<span style={{ color: '#A0A0A0', fontSize: 16 }}>
|
||||
Powered by BlitzStars
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import Children from './Children.js';
|
||||
|
||||
export default function Root(...children: string[]) {
|
||||
return `
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto+Flex:[email protected]');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:[email protected]');
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Roboto Flex', sans-serif;
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="root">
|
||||
${Children(children)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
export default function TitleBar(
|
||||
name: string,
|
||||
nameDiscriminator: string,
|
||||
image?: string,
|
||||
description?: string,
|
||||
) {
|
||||
return `
|
||||
<style>
|
||||
.title-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title-bar-info {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.title-bar-avatar {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.title-bar-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.title-bar-name {
|
||||
font-size: 32px;
|
||||
color: white;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.title-bar-discriminator {
|
||||
color: #A0A0A0;
|
||||
}
|
||||
|
||||
.title-bar-description {
|
||||
color: #A0A0A0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.title-bar-blitzkrieg {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="title-bar">
|
||||
<div class="title-bar-info">
|
||||
${image ? `<img class="title-bar-avatar" src="${image}" />` : ''}
|
||||
|
||||
<div class="title-bar-text">
|
||||
<span class="title-bar-name">
|
||||
${name}
|
||||
<span class="title-bar-discriminator">${nameDiscriminator}</span>
|
||||
</span>
|
||||
|
||||
<span class="title-bar-description">${description}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img class="title-bar-blitzkrieg" src="https://i.imgur.com/35phKIu.png" />
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
export interface TitleBarProps {
|
||||
name: string;
|
||||
nameDiscriminator?: string;
|
||||
image?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export default function TitleBar({
|
||||
name,
|
||||
nameDiscriminator,
|
||||
image,
|
||||
description,
|
||||
}: TitleBarProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
{image && <img style={{ width: 64, height: 64 }} src={image} />}
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 32,
|
||||
color: 'white',
|
||||
fontWeight: 900,
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
{nameDiscriminator && (
|
||||
<span style={{ color: '#A0A0A0' }}>{nameDiscriminator}</span>
|
||||
)}
|
||||
</span>
|
||||
|
||||
<span style={{ color: '#A0A0A0', fontSize: 16 }}>{description}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img
|
||||
style={{ width: 64, height: 64 }}
|
||||
src="https://i.imgur.com/35phKIu.png"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import Children from './Children.js';
|
||||
|
||||
export default function Wrapper(...children: string[]) {
|
||||
return `
|
||||
<style>
|
||||
#wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 32px;
|
||||
width: 640px;
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="wrapper">
|
||||
${Children(children)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface WrapperProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default function Wrapper({ children }: WrapperProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: 16,
|
||||
gap: 32,
|
||||
width: 640,
|
||||
background: 'black',
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Resvg } from '@resvg/resvg-js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { ReactNode } from 'react';
|
||||
import satori from 'satori';
|
||||
|
||||
const robotoFlex = readFileSync('src/assets/fonts/Roboto.ttf');
|
||||
const robotoFlexBold = readFileSync('src/assets/fonts/Roboto-Bold.ttf');
|
||||
const robotoFlexBlack = readFileSync('src/assets/fonts/Roboto-Black.ttf');
|
||||
|
||||
export default async function render(element: ReactNode) {
|
||||
const svg = await satori(element, {
|
||||
width: 640,
|
||||
fonts: [
|
||||
{ data: robotoFlex, name: 'Roboto Flex', weight: 400 },
|
||||
{ data: robotoFlexBold, name: 'Roboto Flex', weight: 700 },
|
||||
{ data: robotoFlexBlack, name: 'Roboto Flex', weight: 900 },
|
||||
],
|
||||
});
|
||||
const png = new Resvg(svg).render().asPng();
|
||||
|
||||
return png;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import Root from '../../components/Root.js';
|
||||
import { browser } from '../../index.js';
|
||||
|
||||
export default async function screenshotHTML(children: string) {
|
||||
const page = await browser.newPage();
|
||||
await page.setViewportSize({ width: 640, height: 1 });
|
||||
await page.setContent(Root(children));
|
||||
const screenshot = await page
|
||||
.locator('#root')
|
||||
.screenshot({ omitBackground: true, scale: 'css' });
|
||||
await page.close();
|
||||
|
||||
return screenshot;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { chromium } from '@playwright/test';
|
||||
import { Client, GatewayIntentBits } from 'discord.js';
|
||||
import { args } from './core/process/args.js';
|
||||
import { registerErrorHandlers } from './events/error.js';
|
||||
@@ -17,5 +16,3 @@ client
|
||||
.on('guildMemberAdd', guildMemberAdd)
|
||||
.on('interactionCreate', interactionCreate)
|
||||
.login(args['discord-token']);
|
||||
|
||||
export const browser = await chromium.launch();
|
||||
File renamed without changes.
+2
-1
@@ -8,6 +8,7 @@
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
}
|
||||
@@ -156,15 +156,83 @@
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061"
|
||||
integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==
|
||||
|
||||
"@playwright/test@^1.34.2":
|
||||
version "1.34.2"
|
||||
resolved "https://registry.npmjs.org/@playwright/test/-/test-1.34.2.tgz"
|
||||
integrity sha512-v/LBnwzD0225q8xEv3t9DmNPX61yvNnEbiA8PoNk1fbkxApJFCWYLPpQbdVWzHaARdZD9g1PYBoOvnffortfKw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
playwright-core "1.34.2"
|
||||
"@resvg/resvg-js-android-arm-eabi@2.4.1":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.4.1.tgz#49dc9722f95096f8aff70186deae8e148d60dce5"
|
||||
integrity sha512-AA6f7hS0FAPpvQMhBCf6f1oD1LdlqNXKCxAAPpKh6tR11kqV0YIB9zOlIYgITM14mq2YooLFl6XIbbvmY+jwUw==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.4.1.tgz#fdb7c9362ea27a228831d047cfd1ea240daed780"
|
||||
integrity sha512-/QleoRdPfsEuH9jUjilYcDtKK/BkmWcK+1LXM8L2nsnf/CI8EnFyv7ZzCj4xAIvZGAy9dTYr/5NZBcTwxG2HQg==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.4.1.tgz#5ef093f1276149340b9f5a5c487717c4de87bee7"
|
||||
integrity sha512-U1oMNhea+kAXgiEXgzo7EbFGCD1Edq5aSlQoe6LMly6UjHzgx2W3N5kEXCwU/CgN5FiQhZr7PlSJSlcr7mdhfg==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.4.1.tgz#18dd758184f4877be1f6ac80d2f37999581c998c"
|
||||
integrity sha512-avyVh6DpebBfHHtTQTZYSr6NG1Ur6TEilk1+H0n7V+g4F7x7WPOo8zL00ZhQCeRQ5H4f8WXNWIEKL8fwqcOkYw==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.4.1.tgz#eee8f8166763aacc935a53e223e7b9c31b10c94a"
|
||||
integrity sha512-isY/mdKoBWH4VB5v621co+8l101jxxYjuTkwOLsbW+5RK9EbLciPlCB02M99ThAHzI2MYxIUjXNmNgOW8btXvw==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.4.1.tgz#826569e1ee08f07879ce32850822ede2ee1192ef"
|
||||
integrity sha512-uY5voSCrFI8TH95vIYBm5blpkOtltLxLRODyhKJhGfskOI7XkRw5/t1u0sWAGYD8rRSNX+CA+np86otKjubrNg==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.4.1.tgz#faf63d873666078ca74604454d40e4fecc22beb4"
|
||||
integrity sha512-6mT0+JBCsermKMdi/O2mMk3m7SqOjwi9TKAwSngRZ/nQoL3Z0Z5zV+572ztgbWr0GODB422uD8e9R9zzz38dRQ==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.4.1.tgz#37b4c16c488aac3834a069c3725f017285d94b1e"
|
||||
integrity sha512-60KnrscLj6VGhkYOJEmmzPlqqfcw1keDh6U+vMcNDjPhV3B5vRSkpP/D/a8sfokyeh4VEacPSYkWGezvzS2/mg==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.4.1.tgz#6099cf57c958832549b0671991246e06bb44df27"
|
||||
integrity sha512-0AMyZSICC1D7ge115cOZQW8Pcad6PjWuZkBFF3FJuSxC6Dgok0MQnLTs2MfMdKBlAcwO9dXsf3bv9tJZj8pATA==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.4.1.tgz#10c9472a20198a218d8c3b6d8fbb3fcba213b670"
|
||||
integrity sha512-76XDFOFSa3d0QotmcNyChh2xHwk+JTFiEQBVxMlHpHMeq7hNrQJ1IpE1zcHSQvrckvkdfLboKRrlGB86B10Qjw==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.4.1.tgz#bfc1d37ed485d72ca5717138b99ba40788fa2720"
|
||||
integrity sha512-odyVFGrEWZIzzJ89KdaFtiYWaIJh9hJRW/frcEcG3agJ464VXkN/2oEVF5ulD+5mpGlug9qJg7htzHcKxDN8sg==
|
||||
|
||||
"@resvg/[email protected]":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.4.1.tgz#83cae82dfe27121f85492eb4dc03f6fe33d8a703"
|
||||
integrity sha512-vY4kTLH2S3bP+puU5x7hlAxHv+ulFgcK6Zn3efKSr0M0KnZ9A3qeAjZteIpkowEFfUeMPNg2dvvoFRJA9zqxSw==
|
||||
|
||||
"@resvg/resvg-js@^2.4.1":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@resvg/resvg-js/-/resvg-js-2.4.1.tgz#07e9cd57f3c925a5fb075a313a0640fc74cba4a2"
|
||||
integrity sha512-wTOf1zerZX8qYcMmLZw3czR4paI4hXqPjShNwJRh5DeHxvgffUS5KM7XwxtbIheUW6LVYT5fhT2AJiP6mU7U4A==
|
||||
optionalDependencies:
|
||||
fsevents "2.3.2"
|
||||
"@resvg/resvg-js-android-arm-eabi" "2.4.1"
|
||||
"@resvg/resvg-js-android-arm64" "2.4.1"
|
||||
"@resvg/resvg-js-darwin-arm64" "2.4.1"
|
||||
"@resvg/resvg-js-darwin-x64" "2.4.1"
|
||||
"@resvg/resvg-js-linux-arm-gnueabihf" "2.4.1"
|
||||
"@resvg/resvg-js-linux-arm64-gnu" "2.4.1"
|
||||
"@resvg/resvg-js-linux-arm64-musl" "2.4.1"
|
||||
"@resvg/resvg-js-linux-x64-gnu" "2.4.1"
|
||||
"@resvg/resvg-js-linux-x64-musl" "2.4.1"
|
||||
"@resvg/resvg-js-win32-arm64-msvc" "2.4.1"
|
||||
"@resvg/resvg-js-win32-ia32-msvc" "2.4.1"
|
||||
"@resvg/resvg-js-win32-x64-msvc" "2.4.1"
|
||||
|
||||
"@sapphire/async-queue@^1.5.0":
|
||||
version "1.5.0"
|
||||
@@ -184,6 +252,14 @@
|
||||
resolved "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.4.2.tgz"
|
||||
integrity sha512-KJwlv5gkGjs1uFV7/xx81n3tqgBwBJvH94n1xDyH3q+JSmtsMeSleJffarEBfG2yAFeJiFA4BnGOK6FFPHc19g==
|
||||
|
||||
"@shuding/[email protected]":
|
||||
version "1.4.0-beta.0"
|
||||
resolved "https://registry.yarnpkg.com/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz#5d1e7e9e056f546aad41df1c5043f8f85d39e24b"
|
||||
integrity sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==
|
||||
dependencies:
|
||||
fflate "^0.7.3"
|
||||
string.prototype.codepointat "^0.2.1"
|
||||
|
||||
"@tokenizer/token@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz"
|
||||
@@ -226,6 +302,25 @@
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz"
|
||||
integrity sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
|
||||
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
||||
|
||||
"@types/react@^18.2.7":
|
||||
version "18.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.7.tgz#dfb4518042a3117a045b8c222316f83414a783b3"
|
||||
integrity sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
|
||||
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
|
||||
|
||||
"@types/ws@^8.5.4":
|
||||
version "8.5.4"
|
||||
resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz"
|
||||
@@ -238,6 +333,11 @@ acorn@^8.8.2:
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz"
|
||||
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
||||
|
||||
[email protected]:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
|
||||
integrity sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==
|
||||
|
||||
busboy@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz"
|
||||
@@ -250,6 +350,45 @@ cac@^6.7.14:
|
||||
resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz"
|
||||
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
||||
|
||||
camelize@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
|
||||
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
|
||||
|
||||
color-name@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
css-background-parser@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/css-background-parser/-/css-background-parser-0.1.0.tgz#48a17f7fe6d4d4f1bca3177ddf16c5617950741b"
|
||||
integrity sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==
|
||||
|
||||
[email protected]:
|
||||
version "1.0.0-3"
|
||||
resolved "https://registry.yarnpkg.com/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz#9eaeb7140947bf5d649fc49a19e4bbaa5f602713"
|
||||
integrity sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==
|
||||
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||
integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
|
||||
|
||||
css-to-react-native@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32"
|
||||
integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==
|
||||
dependencies:
|
||||
camelize "^1.0.0"
|
||||
css-color-keywords "^1.0.0"
|
||||
postcss-value-parser "^4.0.2"
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz"
|
||||
@@ -286,6 +425,11 @@ discord.js@^14.9.0:
|
||||
undici "^5.21.0"
|
||||
ws "^8.13.0"
|
||||
|
||||
emoji-regex@^10.2.1:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f"
|
||||
integrity sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==
|
||||
|
||||
esbuild@^0.17.5:
|
||||
version "0.17.19"
|
||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz"
|
||||
@@ -332,6 +476,11 @@ fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
fflate@^0.7.3:
|
||||
version "0.7.4"
|
||||
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.4.tgz#61587e5d958fdabb5a9368a302c25363f4f69f50"
|
||||
integrity sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==
|
||||
|
||||
file-type@^18.2.1:
|
||||
version "18.2.1"
|
||||
resolved "https://registry.npmjs.org/file-type/-/file-type-18.2.1.tgz"
|
||||
@@ -348,7 +497,7 @@ formdata-polyfill@^4.0.10:
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
[email protected], fsevents@~2.3.2:
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
@@ -358,6 +507,11 @@ fuzzysort@^2.0.4:
|
||||
resolved "https://registry.npmjs.org/fuzzysort/-/fuzzysort-2.0.4.tgz"
|
||||
integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==
|
||||
|
||||
hex-rgb@^4.1.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776"
|
||||
integrity sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==
|
||||
|
||||
ieee754@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
|
||||
@@ -368,11 +522,24 @@ inherits@^2.0.3:
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
||||
jsonc-parser@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz"
|
||||
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
|
||||
|
||||
linebreak@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/linebreak/-/linebreak-1.1.0.tgz#831cf378d98bced381d8ab118f852bd50d81e46b"
|
||||
integrity sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==
|
||||
dependencies:
|
||||
base64-js "0.0.8"
|
||||
unicode-trie "^2.0.0"
|
||||
|
||||
lodash.snakecase@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz"
|
||||
@@ -388,6 +555,13 @@ lodash@^4.17.21:
|
||||
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
loose-envify@^1.1.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
markdown-escape@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/markdown-escape/-/markdown-escape-2.0.0.tgz"
|
||||
@@ -427,6 +601,19 @@ node-fetch@^3.3.1:
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
pako@^0.2.5:
|
||||
version "0.2.9"
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
|
||||
integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==
|
||||
|
||||
parse-css-color@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/parse-css-color/-/parse-css-color-0.2.1.tgz#b687a583f2e42e66ffdfce80a570706966e807c9"
|
||||
integrity sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==
|
||||
dependencies:
|
||||
color-name "^1.1.4"
|
||||
hex-rgb "^4.1.0"
|
||||
|
||||
pathe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz"
|
||||
@@ -451,10 +638,10 @@ pkg-types@^1.0.3:
|
||||
mlly "^1.2.0"
|
||||
pathe "^1.1.0"
|
||||
|
||||
p[email protected]4.2:
|
||||
version "1.34.2"
|
||||
resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.34.2.tgz"
|
||||
integrity sha512-MrkgGWLANc5qthXduvIY1a/tuafROyTORVd86fwKwgoYrmnBooN/GgeZSBm7ljTLV2FCWNSXV3se7qeScKn83g==
|
||||
postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss@^8.4.23:
|
||||
version "8.4.23"
|
||||
@@ -465,6 +652,13 @@ postcss@^8.4.23:
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
react@^18.2.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
readable-stream@^3.6.0:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz"
|
||||
@@ -493,6 +687,21 @@ safe-buffer@~5.2.0:
|
||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
satori@^0.9.1:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/satori/-/satori-0.9.1.tgz#59380f59be44ff825e58b5e2c8d0598240e15365"
|
||||
integrity sha512-2ggMOiY8O8rIxQ6vywiw3LlBheWHbsOzu5hZdMXTDFKzE9sDHUOtJegGmGE+e9aRSO1ttttgXrcHVsHPKYU2GQ==
|
||||
dependencies:
|
||||
"@shuding/opentype.js" "1.4.0-beta.0"
|
||||
css-background-parser "^0.1.0"
|
||||
css-box-shadow "1.0.0-3"
|
||||
css-to-react-native "^3.0.0"
|
||||
emoji-regex "^10.2.1"
|
||||
linebreak "^1.1.0"
|
||||
parse-css-color "^0.2.1"
|
||||
postcss-value-parser "^4.2.0"
|
||||
yoga-wasm-web "^0.3.3"
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||
@@ -503,6 +712,11 @@ streamsearch@^1.1.0:
|
||||
resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
|
||||
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
|
||||
|
||||
string.prototype.codepointat@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc"
|
||||
integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==
|
||||
|
||||
string_decoder@^1.1.1:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
|
||||
@@ -518,6 +732,11 @@ strtok3@^7.0.0:
|
||||
"@tokenizer/token" "^0.3.0"
|
||||
peek-readable "^5.0.0"
|
||||
|
||||
tiny-inflate@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4"
|
||||
integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==
|
||||
|
||||
token-types@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz"
|
||||
@@ -553,6 +772,14 @@ undici@^5.21.0:
|
||||
dependencies:
|
||||
busboy "^1.6.0"
|
||||
|
||||
unicode-trie@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unicode-trie/-/unicode-trie-2.0.0.tgz#8fd8845696e2e14a8b67d78fa9e0dd2cad62fec8"
|
||||
integrity sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==
|
||||
dependencies:
|
||||
pako "^0.2.5"
|
||||
tiny-inflate "^1.0.0"
|
||||
|
||||
util-deprecate@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||
@@ -590,3 +817,8 @@ ws@^8.13.0:
|
||||
version "8.13.0"
|
||||
resolved "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz"
|
||||
integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
|
||||
|
||||
yoga-wasm-web@^0.3.3:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz#eb8e9fcb18e5e651994732f19a220cb885d932ba"
|
||||
integrity sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==
|
||||
Reference in new issue
Block a user