Skip to content

Commit a57ddfb

Browse files
authored
Merge pull request #217 from SkyCryptWebsite/dev
2 parents a8be847 + 23b7038 commit a57ddfb

31 files changed

+1092
-800
lines changed

package.json

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,22 @@
3232
"@commitlint/config-conventional": "^20.0.0",
3333
"@commitlint/types": "^20.0.0",
3434
"@date-fns/tz": "^1.4.1",
35-
"@eslint/compat": "^1.4.1",
35+
"@eslint/compat": "^2.0.0",
3636
"@eslint/js": "^9.39.1",
37-
"@lucide/svelte": "^0.553.0",
37+
"@lucide/svelte": "^0.554.0",
3838
"@oslojs/crypto": "^1.0.1",
3939
"@oslojs/encoding": "^1.1.0",
4040
"@sveltejs/adapter-node": "^5.4.0",
41-
"@sveltejs/kit": "^2.48.4",
41+
"@sveltejs/kit": "^2.48.5",
4242
"@sveltejs/vite-plugin-svelte": "^6.2.1",
4343
"@tailwindcss/vite": "^4.1.17",
4444
"@types/eslint": "^9.6.1",
45-
"@types/node": "^24.10.0",
45+
"@types/node": "^24.10.1",
4646
"@types/relaxed-json": "^1.0.4",
4747
"@types/upng-js": "^2.1.5",
48-
"@vitest/browser-webdriverio": "^4.0.8",
49-
"@vitest/ui": "^4.0.8",
50-
"bits-ui": "^2.14.2",
48+
"@vitest/browser-webdriverio": "^4.0.10",
49+
"@vitest/ui": "^4.0.10",
50+
"bits-ui": "^2.14.3",
5151
"changelogen": "^0.6.2",
5252
"clsx": "^2.1.1",
5353
"date-fns": "^4.1.0",
@@ -68,8 +68,8 @@
6868
"pretty-ms": "^9.3.0",
6969
"runed": "^0.36.0",
7070
"skinview3d": "^3.4.1",
71-
"svelte": "^5.43.5",
72-
"svelte-check": "^4.3.3",
71+
"svelte": "^5.43.11",
72+
"svelte-check": "^4.3.4",
7373
"svelte-dnd-action": "^0.9.67",
7474
"svelte-interactions": "^0.2.0",
7575
"svelte-persisted-store": "^0.12.0",
@@ -82,17 +82,17 @@
8282
"tailwindcss": "^4.1.17",
8383
"tslib": "^2.8.1",
8484
"typescript": "^5.9.3",
85-
"typescript-eslint": "^8.46.3",
85+
"typescript-eslint": "^8.47.0",
8686
"vaul-svelte": "1.0.0-next.7",
87-
"vite": "^7.2.2",
87+
"vite": "npm:rolldown-vite@latest",
8888
"vite-plugin-devtools-json": "^1.0.0",
89-
"vitest": "^4.0.8",
89+
"vitest": "^4.0.10",
9090
"vitest-browser-svelte": "^2.0.1",
91-
"webdriverio": "^9.20.0",
91+
"webdriverio": "^9.20.1",
9292
"zod": "^4.1.12"
9393
},
9494
"dependencies": {
95-
"@sentry/sveltekit": "^10.24.0",
95+
"@sentry/sveltekit": "^10.25.0",
9696
"simple-git-hooks": "^2.13.1"
9797
},
9898
"engines": {
@@ -112,7 +112,10 @@
112112
"geckodriver",
113113
"simple-git-hooks",
114114
"svelte-preprocess"
115-
]
115+
],
116+
"overrides": {
117+
"vite": "npm:rolldown-vite@latest"
118+
}
116119
},
117120
"simple-git-hooks": {
118121
"commit-msg": "pnpm exec commitlint --edit $1"

pnpm-lock.yaml

Lines changed: 767 additions & 528 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/context/createContext.svelte.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ import type { IsMobile } from "$lib/hooks/is-mobile.svelte";
33
import type { ModelsMiscOutput, ModelsResourcePackConfig, ModelsSkillsOutput, ModelsStatsOutput } from "$lib/shared/api/orval-generated";
44
import { createContext } from "svelte";
55

6+
export class ProfileContext {
7+
#current: ModelsStatsOutput | null = $state(null);
8+
9+
get current() {
10+
return this.#current;
11+
}
12+
13+
set current(value: ModelsStatsOutput | null) {
14+
this.#current = value;
15+
}
16+
}
17+
618
export class PacksContext {
719
#packs: ModelsResourcePackConfig[] = $state([]);
820

@@ -39,7 +51,7 @@ export class SkillsContext {
3951
}
4052
}
4153

42-
export const [getProfileContext, setProfileContext] = createContext<ModelsStatsOutput>();
54+
export const [getProfileContext, setProfileContext] = createContext<ProfileContext>();
4355
export const [getSkillsContext, setSkillsContext] = createContext<SkillsContext>();
4456
export const [getMiscContext, setMiscContext] = createContext<MiscContext>();
4557
export const [getMobileContext, setMobileContext] = createContext<IsMobile>();

src/hooks.client.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { dev } from "$app/environment";
22
import { env } from "$env/dynamic/public";
33
import * as Sentry from "@sentry/sveltekit";
4-
import { browserTracingIntegration, consoleLoggingIntegration, contextLinesIntegration, extraErrorDataIntegration, httpClientIntegration } from "@sentry/sveltekit";
4+
import { browserTracingIntegration, consoleLoggingIntegration, contextLinesIntegration, extraErrorDataIntegration, handleErrorWithSentry, httpClientIntegration } from "@sentry/sveltekit";
55

66
const { PUBLIC_SENTRY_DSN } = env;
77

@@ -14,19 +14,12 @@ Sentry.init({
1414

1515
// Enable debug
1616
debug: true,
17-
18-
// Set tracesSampleRate to 1.0 to capture 100%
19-
// of transactions for tracing.
20-
// We recommend adjusting this value in production
21-
// Learn more at
22-
// https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
23-
tracesSampleRate: 0.5,
17+
tracesSampleRate: 1.0,
2418

2519
integrations: [browserTracingIntegration(), httpClientIntegration(), contextLinesIntegration(), extraErrorDataIntegration(), consoleLoggingIntegration()],
26-
2720
enabled: !dev,
2821
environment: dev ? "development" : "production"
2922
});
3023

3124
// If you have a custom error handler, pass it to `handleErrorWithSentry`
32-
export const handleError = Sentry.handleErrorWithSentry();
25+
export const handleError = handleErrorWithSentry();

src/hooks.server.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as Sentry from "@sentry/sveltekit";
1+
import { handleErrorWithSentry, sentryHandle } from "@sentry/sveltekit";
22
import type { Handle } from "@sveltejs/kit";
33
import { sequence } from "@sveltejs/kit/hooks";
44

@@ -22,5 +22,8 @@ const headersHandler = (async ({ event, resolve }) => {
2222
return response;
2323
}) satisfies Handle;
2424

25-
export const handleError = Sentry.handleErrorWithSentry();
26-
export const handle = sequence(Sentry.sentryHandle(), headersHandler) satisfies Handle;
25+
// If you have a custom error handler, pass it to `handleErrorWithSentry`
26+
export const handleError = handleErrorWithSentry();
27+
28+
// If you have custom handlers, make sure to place them after `sentryHandle()` in the `sequence` function.
29+
export const handle = sequence(sentryHandle(), headersHandler) satisfies Handle;

src/instrumentation.server.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,7 @@ Sentry.init({
1111
// Enable logs to be sent to Sentry
1212
enableLogs: true,
1313

14-
// Set tracesSampleRate to 1.0 to capture 100%
15-
// of transactions for tracing.
16-
// We recommend adjusting this value in production
17-
// Learn more at
18-
// https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
19-
tracesSampleRate: 0.5,
20-
14+
tracesSampleRate: 1.0,
2115
integrations: [contextLinesIntegration(), extraErrorDataIntegration(), consoleLoggingIntegration()],
2216

2317
// Disable Sentry during development

src/lib/components/APINotice.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import { fade } from "svelte/transition";
88
import { Drawer } from "vaul-svelte";
99
10-
const profile = $derived(getProfileContext());
10+
const profile = $derived(getProfileContext().current);
1111
12-
const apiSettings = $derived(Object.entries(profile.apiSettings ?? {}).filter(([_, value]) => !value));
12+
const apiSettings = $derived(Object.entries(profile?.apiSettings ?? {}).filter(([_, value]) => !value));
1313
1414
const isHover = getHoverContext();
1515
</script>
@@ -24,7 +24,7 @@
2424
{/if}
2525
<span class="inline-block whitespace-nowrap capitalize">{key.replaceAll("_", " ")}</span>{#if index < apiSettings.length - 1},{/if}
2626
{/each}
27-
{apiSettings.length === 1 ? "is" : "are"} not available for {profile.username} due to limited API access.
27+
{apiSettings.length === 1 ? "is" : "are"} not available for {profile?.username} due to limited API access.
2828
</p>
2929
<p>
3030
{#if isHover.current}

src/lib/components/Navbar.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
import { onDestroy, onMount, tick, type Snippet } from "svelte";
1212
const { children }: { children?: Snippet } = $props();
1313
14-
const profile = $derived(getProfileContext());
14+
const profile = $derived(getProfileContext().current);
1515
16-
const apiSettings = $derived(Object.entries(profile.apiSettings ?? {}).filter(([_, value]) => !value));
16+
const apiSettings = $derived(Object.entries(profile?.apiSettings ?? {}).filter(([_, value]) => !value));
1717
const disabledApiSettings: string[] = $derived(apiSettings.map(([key]) => key));
1818
1919
const filteredSectionOrderPreferences = $derived(
@@ -125,7 +125,7 @@
125125
<ScrollArea.Root type="always" class="navbar group sticky! top-[calc(3rem+env(safe-area-inset-top,0))] z-20 overflow-clip" data-pinned={pinned} bind:ref={navbarElement}>
126126
<ScrollArea.Viewport>
127127
<div class="flex! flex-nowrap items-center gap-2 pb-2 font-semibold whitespace-nowrap text-text/80">
128-
<div class="absolute bottom-1.75 z-1 h-[2px] w-[calc(100%+0.5rem)] bg-icon"></div>
128+
<div class="absolute bottom-1.75 z-1 h-0.5 w-[calc(100%+0.5rem)] bg-icon"></div>
129129
<div class="absolute inset-0 bottom-2 group-data-[pinned=true]:group-data-[mode=dark]/html:bg-[oklch(19.13%_0_0)]/90 group-data-[pinned=true]:group-data-[mode=light]/html:bg-[oklch(95.51%_0_0)]/92"></div>
130130
{#each filteredSectionOrderPreferences as section, index (index)}
131131
<Button.Root class="relative px-2 py-3 after:absolute after:top-full after:left-0 after:h-0 after:w-full after:origin-top after:rounded-full after:bg-icon after:transition-all after:duration-100 after:ease-out hover:after:top-[calc(100%-4px)] hover:after:h-2 data-[active=true]:text-text data-[active=true]:after:top-[calc(100%-4px)] data-[active=true]:after:h-2" data-id={section.name} data-active={$tabValue === section.name} onclick={() => handleSectionClick(section.name)}>

src/lib/components/Skin3D.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import * as skinview3d from "skinview3d";
66
import { onDestroy } from "svelte";
77
8-
const ctx = getProfileContext();
9-
const uuid = $derived(ctx.uuid);
8+
const ctx = $derived(getProfileContext().current);
9+
const uuid = $derived(ctx?.uuid);
1010
1111
let { class: className }: { class: string | undefined } = $props();
1212
let viewer = $state<skinview3d.SkinViewer>();

src/lib/layouts/stats/AdditionalStats.svelte

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
import { format as dateFormat, formatDistanceToNowStrict } from "date-fns";
1515
import { format as numberFormat } from "numerable";
1616
17-
const profile = $derived(getProfileContext());
18-
const profileUUID = $derived(profile.uuid);
19-
const profileId = $derived(profile.profile_id);
17+
const profile = $derived(getProfileContext().current);
18+
const profileUUID = $derived(profile?.uuid);
19+
const profileId = $derived(profile?.profile_id);
2020
2121
const defaultPatternDecimal: string = "0,0.##";
2222
const defaultPattern: string = "0,0";
@@ -27,75 +27,76 @@
2727
</script>
2828

2929
<div class="additional-stats flex flex-col gap-2 @md:flex-row @md:flex-wrap">
30-
{#if profile.joined != null}
31-
<AdditionStat text="Joined" data={formatDistanceToNowStrict(profile.joined, { addSuffix: true, in: tz(Intl.DateTimeFormat().resolvedOptions().timeZone) })} asterisk={true}>
32-
Joined on {dateFormat(profile.joined, "dd MMMM yyyy 'at' HH:mm", { in: tz(Intl.DateTimeFormat().resolvedOptions().timeZone) })}
33-
</AdditionStat>
34-
{/if}
35-
{#if profile.purse != null}
36-
<AdditionStat text="Purse" data={`${formatNumber(profile.purse)} Coins`} />
37-
{/if}
38-
{#if profile.bank != null && profile.personalBank != null}
39-
<AdditionStat text="Bank Account" data={`${formatNumber(profile.bank + profile.personalBank)} Coins`} asterisk={profile.bank && profile.personalBank ? true : false}>
40-
<div>
41-
<h3 class="font-bold text-text/85">
42-
Bank:
43-
<span class="text-text">
44-
{formatNumber(profile.bank)}
45-
</span>
46-
</h3>
47-
{#if profile.personalBank}
48-
<h3 class="font-bold text-text/85">
49-
Personal Bank:
50-
<span class="text-text">
51-
{formatNumber(profile.personalBank)}
52-
</span>
53-
</h3>
54-
{/if}
55-
</div>
56-
</AdditionStat>
57-
{/if}
58-
{#if profile.skills?.averageSkillLevel}
59-
<AdditionStat text="Average Skill Level" data={profile.skills.averageSkillLevel.toFixed(2)} asterisk={true}>
60-
<div class="max-w-xs space-y-2">
30+
{#if profile != null}
31+
{#if profile.joined != null}
32+
<AdditionStat text="Joined" data={formatDistanceToNowStrict(profile.joined, { addSuffix: true, in: tz(Intl.DateTimeFormat().resolvedOptions().timeZone) })} asterisk={true}>
33+
Joined on {dateFormat(profile.joined, "dd MMMM yyyy 'at' HH:mm", { in: tz(Intl.DateTimeFormat().resolvedOptions().timeZone) })}
34+
</AdditionStat>
35+
{/if}
36+
{#if profile.purse != null}
37+
<AdditionStat text="Purse" data={`${formatNumber(profile.purse)} Coins`} />
38+
{/if}
39+
{#if profile.bank != null && profile.personalBank != null}
40+
<AdditionStat text="Bank Account" data={`${formatNumber(profile.bank + profile.personalBank)} Coins`} asterisk={profile.bank && profile.personalBank ? true : false}>
6141
<div>
6242
<h3 class="font-bold text-text/85">
63-
Total Skill XP:
43+
Bank:
6444
<span class="text-text">
65-
{numberFormat(profile.skills.totalSkillXp, defaultPattern)}
45+
{formatNumber(profile.bank)}
6646
</span>
6747
</h3>
68-
<p class="font-medium text-text/80">Total XP gained in all skills except Social and Runecrafting.</p>
48+
{#if profile.personalBank}
49+
<h3 class="font-bold text-text/85">
50+
Personal Bank:
51+
<span class="text-text">
52+
{formatNumber(profile.personalBank)}
53+
</span>
54+
</h3>
55+
{/if}
6956
</div>
70-
{#if profile.skills.averageSkillLevelWithProgress != null}
57+
</AdditionStat>
58+
{/if}
59+
{#if profile.skills?.averageSkillLevel}
60+
<AdditionStat text="Average Skill Level" data={profile.skills.averageSkillLevel.toFixed(2)} asterisk={true}>
61+
<div class="max-w-xs space-y-2">
7162
<div>
7263
<h3 class="font-bold text-text/85">
73-
Average Level:
64+
Total Skill XP:
7465
<span class="text-text">
75-
{profile.skills.averageSkillLevelWithProgress.toFixed(2)}
66+
{numberFormat(profile.skills.totalSkillXp, defaultPattern)}
7667
</span>
7768
</h3>
78-
<p class="font-medium text-text/80">Average skill level over all skills except Social and Runecrafting, includes progress to next level.</p>
69+
<p class="font-medium text-text/80">Total XP gained in all skills except Social and Runecrafting.</p>
70+
</div>
71+
{#if profile.skills.averageSkillLevelWithProgress != null}
72+
<div>
73+
<h3 class="font-bold text-text/85">
74+
Average Level:
75+
<span class="text-text">
76+
{profile.skills.averageSkillLevelWithProgress.toFixed(2)}
77+
</span>
78+
</h3>
79+
<p class="font-medium text-text/80">Average skill level over all skills except Social and Runecrafting, includes progress to next level.</p>
80+
</div>
81+
{/if}
82+
<div>
83+
<h3 class="font-bold text-text/85">
84+
Average Level without progress:
85+
<span class="text-text">
86+
{numberFormat(profile.skills.averageSkillLevel, defaultPatternDecimal)}
87+
</span>
88+
</h3>
89+
<p class="font-medium text-text/80">Average skill level without including partial level progress.</p>
7990
</div>
80-
{/if}
81-
<div>
82-
<h3 class="font-bold text-text/85">
83-
Average Level without progress:
84-
<span class="text-text">
85-
{numberFormat(profile.skills.averageSkillLevel, defaultPatternDecimal)}
86-
</span>
87-
</h3>
88-
<p class="font-medium text-text/80">Average skill level without including partial level progress.</p>
8991
</div>
90-
</div>
91-
</AdditionStat>
92-
{/if}
93-
{#if profile.fairySouls}
94-
<AdditionStat text="Fairy Souls" data={`${profile.fairySouls.found} / ${profile.fairySouls.total}`} maxed={(profile.fairySouls.found ?? 0) >= (profile.fairySouls.total ?? 0)} asterisk={true}>
95-
{calculatePercentage(profile.fairySouls.found ?? 0, profile.fairySouls.total ?? 0)}% of fairy souls found.
96-
</AdditionStat>
92+
</AdditionStat>
93+
{/if}
94+
{#if profile.fairySouls}
95+
<AdditionStat text="Fairy Souls" data={`${profile.fairySouls.found} / ${profile.fairySouls.total}`} maxed={(profile.fairySouls.found ?? 0) >= (profile.fairySouls.total ?? 0)} asterisk={true}>
96+
{calculatePercentage(profile.fairySouls.found ?? 0, profile.fairySouls.total ?? 0)}% of fairy souls found.
97+
</AdditionStat>
98+
{/if}
9799
{/if}
98-
99100
<svelte:boundary>
100101
{#snippet pending()}
101102
<div class="my-0 flex items-center gap-1 font-bold text-text/60">
@@ -132,13 +133,15 @@
132133
<Button.Root onclick={retry} class="text-icon hover:text-icon/80">Retry</Button.Root>
133134
</div>
134135
{/snippet}
135-
{@const networthData = await getNetworth({ uuid: profileUUID!, profileId: profileId! })}
136+
{#if profileUUID != null && profileId != null}
137+
{@const networthData = await getNetworth({ uuid: profileUUID, profileId: profileId })}
136138

137-
{#if networthData.normal}
138-
{@render NetworthSnippet(networthData.normal, "Networth")}
139-
{/if}
140-
{#if networthData.nonCosmetic}
141-
{@render NetworthSnippet(networthData.nonCosmetic, "Non-Cosmetic Networth")}
139+
{#if networthData.normal}
140+
{@render NetworthSnippet(networthData.normal, "Networth")}
141+
{/if}
142+
{#if networthData.nonCosmetic}
143+
{@render NetworthSnippet(networthData.nonCosmetic, "Non-Cosmetic Networth")}
144+
{/if}
142145
{/if}
143146
</svelte:boundary>
144147
</div>

0 commit comments

Comments
 (0)