Skip to content

Commit a0ad6b7

Browse files
authored
feat: add christmas 2025 theme (#806)
1 parent 2db88c5 commit a0ad6b7

File tree

18 files changed

+865
-198
lines changed

18 files changed

+865
-198
lines changed

apps/discord-bot/src/commands/blitzsg/blitzsg.profile.tsx

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,26 @@ const OverallBlitzSGTable = ({ blitzsg, t }: OverallBlitzSGTableProps) => (
3434
<Table.table>
3535
<Table.ts title="§6Overall">
3636
<Table.tr>
37-
<Table.td title={t("stats.wins")} value={t(blitzsg.overall.wins)} color="§e" />
38-
<Table.td title={t("stats.kills")} value={t(blitzsg.overall.kills)} color="§a" />
37+
<Table.td
38+
title={t("stats.wins")}
39+
value={t(blitzsg.overall.wins)}
40+
color="§e"
41+
/>
42+
<Table.td
43+
title={t("stats.kills")}
44+
value={t(blitzsg.overall.kills)}
45+
color="§a"
46+
/>
3947
<Table.td
4048
title={t("stats.deaths")}
4149
value={t(blitzsg.overall.deaths)}
4250
color="§c"
4351
/>
44-
<Table.td title={t("stats.kdr")} value={t(blitzsg.overall.kdr)} color="§6" />
52+
<Table.td
53+
title={t("stats.kdr")}
54+
value={t(blitzsg.overall.kdr)}
55+
color="§6"
56+
/>
4557
</Table.tr>
4658
</Table.ts>
4759
<Table.tr>
@@ -104,7 +116,11 @@ const KitBlitzSGTable = ({ stats, t }: KitBlitzSGTableProps) => (
104116
value={formatTime(stats.playtime)}
105117
color="§e"
106118
/>
107-
<Table.td title={t("stats.gamesPlayed")} value={t(stats.gamesPlayed)} color="§b" />
119+
<Table.td
120+
title={t("stats.gamesPlayed")}
121+
value={t(stats.gamesPlayed)}
122+
color="§b"
123+
/>
108124
</Table.tr>
109125
</Table.table>
110126
);
@@ -138,7 +154,18 @@ export const BlitzSGProfile = ({
138154
break;
139155

140156
default: {
141-
const colors = ["§a", "§a", "§2", "§2", "§e", "§e", "§6", "§6", "§c", "§4"];
157+
const colors = [
158+
"§a",
159+
"§a",
160+
"§2",
161+
"§2",
162+
"§e",
163+
"§e",
164+
"§6",
165+
"§6",
166+
"§c",
167+
"§4",
168+
];
142169
const stats = blitzsg[mode.api];
143170

144171
if (stats.level) {
@@ -173,13 +200,15 @@ export const BlitzSGProfile = ({
173200
title={`§l${FormattedGame.BLITZSG} §fStats §r(${mode.formatted})`}
174201
description={
175202
mode.api === "overall" ?
176-
`§7${t("stats.prefix")}: ${blitzsg.naturalPrefix}\n${formatProgression({
177-
t,
178-
label: t("stats.progression.kill"),
179-
progression: blitzsg.progression,
180-
currentLevel: blitzsg.currentPrefix,
181-
nextLevel: blitzsg.nextPrefix,
182-
})}` :
203+
`§7${t("stats.prefix")}: ${blitzsg.naturalPrefix}\n${formatProgression(
204+
{
205+
t,
206+
label: t("stats.progression.kill"),
207+
progression: blitzsg.progression,
208+
currentLevel: blitzsg.currentPrefix,
209+
nextLevel: blitzsg.nextPrefix,
210+
}
211+
)}` :
183212
""
184213
}
185214
time={time}
@@ -189,4 +218,3 @@ export const BlitzSGProfile = ({
189218
</Container>
190219
);
191220
};
192-

apps/discord-bot/src/commands/config/theme.command.tsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class ThemeCommand {
7171
choices: [
7272
["Default", UserFont.DEFAULT],
7373
["HD", UserFont.HD],
74+
["FPack", UserFont.FPACK],
7475
],
7576
}),
7677
],
@@ -107,7 +108,8 @@ export class ThemeCommand {
107108
const user = context.getUser();
108109
const t = context.t();
109110

110-
if (!user?.uuid) throw new ErrorMessage("verification.requiredVerification");
111+
if (!user?.uuid)
112+
throw new ErrorMessage("verification.requiredVerification");
111113

112114
const profile = await this.getProfile(t, "theme", user);
113115

@@ -125,10 +127,9 @@ export class ThemeCommand {
125127
group: "footer",
126128
})
127129
public message(context: CommandContext) {
128-
const message = convertColorCodes(context.option<string>("message")).replace(
129-
/§\^\d\^/g,
130-
""
131-
);
130+
const message = convertColorCodes(
131+
context.option<string>("message")
132+
).replace(/§\^\d\^/g, "");
132133

133134
const length = removeFormatting(message).length;
134135

@@ -165,7 +166,8 @@ export class ThemeCommand {
165166
})
166167
public icon(context: CommandContext) {
167168
const user = context.getUser();
168-
if (!user?.uuid) throw new ErrorMessage("verification.requiredVerification");
169+
if (!user?.uuid)
170+
throw new ErrorMessage("verification.requiredVerification");
169171

170172
const icon = context.option<UserLogo>("icon");
171173

@@ -175,12 +177,16 @@ export class ThemeCommand {
175177
return this.updateField(context, "footer", "icon", icon);
176178
}
177179

178-
@SubCommand({ description: (t) => t("commands.theme-footer-reset"), group: "footer" })
180+
@SubCommand({
181+
description: (t) => t("commands.theme-footer-reset"),
182+
group: "footer",
183+
})
179184
public async reset(context: CommandContext) {
180185
const user = context.getUser();
181186
const t = context.t();
182187

183-
if (!user?.uuid) throw new ErrorMessage("verification.requiredVerification");
188+
if (!user?.uuid)
189+
throw new ErrorMessage("verification.requiredVerification");
184190

185191
user.footer = {
186192
icon: User.tierToLogo(user.tier ?? UserTier.NONE),
@@ -201,24 +207,35 @@ export class ThemeCommand {
201207
M extends "theme" | "footer",
202208
K extends keyof T,
203209
T = M extends "theme" ? UserTheme : UserFooter
204-
>(context: CommandContext, mode: M, field: K, value: T[K]): Promise<IMessage> {
210+
>(
211+
context: CommandContext,
212+
mode: M,
213+
field: K,
214+
value: T[K]
215+
): Promise<IMessage> {
205216
const user = context.getUser();
206217
const t = context.t();
207218

208-
if (!user?.uuid) throw new ErrorMessage("verification.requiredVerification");
219+
if (!user?.uuid)
220+
throw new ErrorMessage("verification.requiredVerification");
209221

210222
user[mode] = { ...user[mode], [field]: value };
211223
await this.apiService.updateUser(user.id, { [mode]: user[mode] });
212224

213225
const profile = await this.getProfile(t, mode, user);
214226

215227
return {
216-
content: mode === "theme" ? t("config.theme.set") : t("config.footer.set"),
228+
content:
229+
mode === "theme" ? t("config.theme.set") : t("config.footer.set"),
217230
files: [{ name: `${mode}.png`, data: profile, type: "image/png" }],
218231
};
219232
}
220233

221-
private async getProfile(t: LocalizeFunction, mode: "theme" | "footer", user: User) {
234+
private async getProfile(
235+
t: LocalizeFunction,
236+
mode: "theme" | "footer",
237+
user: User
238+
) {
222239
if (!user?.uuid) throw new ErrorMessage("errors.unknown");
223240

224241
const [player, skin, badge, logo, background] = await Promise.all([
@@ -238,7 +255,9 @@ export class ThemeCommand {
238255
badge={badge}
239256
user={user}
240257
message={
241-
mode === "theme" ? t("config.theme.profile") : t("config.footer.profile")
258+
mode === "theme" ?
259+
t("config.theme.profile") :
260+
t("config.footer.profile")
242261
}
243262
/>,
244263
getTheme(user)

apps/discord-bot/src/commands/minecraft/text.command.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import {
1414
NumberArgument,
1515
TextArgument,
1616
} from "@statsify/discord";
17+
import { Container } from "typedi";
18+
import { FontRenderer, StyleLocation, render } from "@statsify/rendering";
1719
import { Multiline } from "#components";
18-
import { StyleLocation, render } from "@statsify/rendering";
1920
import { convertColorCodes } from "#lib/convert-color-codes";
2021
import { getTheme } from "#themes";
2122

@@ -40,6 +41,14 @@ export class TextCommand {
4041
const alignment = context.option<StyleLocation>("alignment", "left");
4142

4243
const text = convertColorCodes(content).replaceAll(String.raw`\n`, "\n");
44+
let theme = getTheme(user);
45+
46+
if (theme === undefined) {
47+
theme = {
48+
context: { renderer: Container.get(FontRenderer) },
49+
elements: {},
50+
};
51+
}
4352

4453
const canvas = render(
4554
<div direction="column" padding={2}>

apps/discord-bot/src/components/Table/TableSeparator.tsx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,21 @@ export const TableSeparator = ({ children, title }: TableSeparatorProps) => {
3131
const topDivider = (
3232
<box
3333
width="100%"
34-
border={{ topLeft: border, topRight: border, bottomLeft: 0, bottomRight: 0 }}
35-
padding={0}
34+
border={{
35+
topLeft: border,
36+
topRight: border,
37+
bottomLeft: 0,
38+
bottomRight: 0,
39+
}}
40+
padding={-2}
3641
>
3742
{title ?
3843
(
39-
<text margin={{ top: 1, left: 8, right: 8, bottom: 1 }}>
40-
§l{title}
41-
</text>
44+
<text margin={{ top: 1, left: 8, right: 8, bottom: 1 }}>§l{title}</text>
4245
) :
43-
<></>}
46+
(
47+
<></>
48+
)}
4449
</box>
4550
);
4651

@@ -51,8 +56,13 @@ export const TableSeparator = ({ children, title }: TableSeparatorProps) => {
5156
<box
5257
width="100%"
5358
height={title ? Math.round(topDividerHeight / 2) : topDividerHeight}
54-
border={{ topLeft: 0, topRight: 0, bottomRight: border, bottomLeft: border }}
55-
padding={0}
59+
border={{
60+
topLeft: 0,
61+
topRight: 0,
62+
bottomRight: border,
63+
bottomLeft: border,
64+
}}
65+
padding={-4}
5666
/>
5767
);
5868

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
1-
/**
2-
* Copyright (c) Statsify
3-
*
4-
* This source code is licensed under the GNU GPL v3 license found in the
5-
* LICENSE file in the root directory of this source tree.
6-
* https://github.com/Statsify/statsify/blob/main/LICENSE
7-
*/
8-
9-
import { Container, Service } from "typedi";
10-
import { FontRenderer } from "@statsify/rendering";
11-
import { getMinecraftTexturePath } from "@statsify/assets";
12-
13-
const renderer = new FontRenderer();
14-
const hdRenderer = new FontRenderer();
15-
16-
Container.set(FontRenderer, renderer);
17-
Container.set("HDFontRenderer", hdRenderer);
18-
19-
@Service()
20-
export class FontLoaderService {
21-
public async init() {
22-
await renderer.loadImages(getMinecraftTexturePath("textures/font"));
23-
await hdRenderer.loadImages(getMinecraftTexturePath("textures/font", "hd"));
24-
}
25-
}
1+
/**
2+
* Copyright (c) Statsify
3+
*
4+
* This source code is licensed under the GNU GPL v3 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
* https://github.com/Statsify/statsify/blob/main/LICENSE
7+
*/
8+
9+
import { Container, Service } from "typedi";
10+
import { FontRenderer } from "@statsify/rendering";
11+
import { getMinecraftTexturePath } from "@statsify/assets";
12+
13+
const renderer = new FontRenderer(false);
14+
const hdRenderer = new FontRenderer(false);
15+
const fpackRenderer = new FontRenderer(true);
16+
17+
Container.set(FontRenderer, renderer);
18+
Container.set("HDFontRenderer", hdRenderer);
19+
Container.set("FPackFontRenderer", fpackRenderer);
20+
21+
@Service()
22+
export class FontLoaderService {
23+
public async init() {
24+
await renderer.loadImages(getMinecraftTexturePath("textures/font"));
25+
await hdRenderer.loadImages(getMinecraftTexturePath("textures/font", "hd"));
26+
await fpackRenderer.loadImages(
27+
getMinecraftTexturePath("textures/font", "fpack")
28+
);
29+
}
30+
}

apps/discord-bot/src/themes/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@ export const getTheme = (user: User | null): Theme | undefined => {
2626

2727
const renderer = getFontRenderer(font);
2828
const box = getBoxRenderer(boxes);
29-
const colorPalette = User.isDiamond(user) ? getColorPalette(palette) : undefined;
29+
const colorPalette = User.isDiamond(user) ?
30+
getColorPalette(palette) :
31+
undefined;
3032

3133
return {
32-
context: { renderer },
34+
context: { renderer, boxColorId: undefined },
3335
elements: {
3436
box(ctx, props, location, theme) {
35-
if (colorPalette?.boxes?.color) props.color ??= colorPalette.boxes.color;
37+
if (colorPalette?.boxes?.color)
38+
props.color ??= colorPalette.boxes.color;
3639
if (colorPalette?.boxes?.shadowOpacity !== undefined) {
3740
props.shadowOpacity ??= colorPalette.boxes.shadowOpacity;
3841
}

apps/discord-bot/src/themes/renderer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export function getFontRenderer(font: UserFont): FontRenderer {
1515
case UserFont.HD:
1616
return Container.get("HDFontRenderer");
1717

18+
case UserFont.FPACK:
19+
return Container.get("FPackFontRenderer");
20+
1821
default:
1922
return Container.get(FontRenderer);
2023
}

0 commit comments

Comments
 (0)