Schema Changes #
Data retrieval #
My Sveltekit app will be partly serverside, partly clientside.
- Initial Data Load holds User Data with all relevant players, team and club data.
- An event Watcher is initialized clientside only, subscribing to Changes in the pocketbase Backend.
Steps #
What do I have to change in my app?
- Initial Serverside load. server.layout.ts
- Calendar Data loading
Spatz-2 #
Spatz-2 uses Shadcn-svelte components, zod and superforms (but not everything from superforms) and gsap for animations.
Components #
A component like a back button is defined like this. I give it props like onclick, size, variant, extra classes and an Icon. The Icon is also a component which makes it easier to add SVG icons, without having my code become unreadable and get cluttered with SVG code.
<Button
onclick={() => window.history.back()}
size="sm"
variant="outline"
class="group/backButton backButton flex items-center gap-2">
<Icon
icon="mdi:arrow-left"
class="h-5 w-5 transition-all duration-300 md:group-hover/backButton:-translate-x-1"
/>
<span class="text-sm">back</span>
</Button>
Gsap #
Gsap is a complex, comprehensive library to create smooth and modern looking animations. Makes everything look all the more professional, without having to understand all the ins and outs of CSS and get lost in Frontend Development.
Gsap in animations.ts file.
import { gsap } from 'gsap';
export const animateMainStagger = () => {
gsap.from('.animate-item', {
opacity: 0,
y: 20,
duration: 1,
delay: 0.1,
stagger: 0.1,
ease: 'power4.out'
});
};
the onMount executes the exported animateMainStagger function. Gsap takes over.
onMount(() => {
animateMainStagger();
});
Typescript #
As an example for my problems with Typescript, I provide an example here.
import type {
EventsRecord,
UsersRecord,
TeamsRecord,
ClubsRecord
} from '$lib/types/pocketbase-types';
type ExpandedEvent = EventsRecord & {
expand: {
players: Array<UsersRecord>;
teams: Array<TeamsRecord>;
clubs: Array<ClubsRecord>;
};
};
interface Props {
data?: {
events?: Array<ExpandedEvent>;
};
}
let { data }: Props = $props();
// Ensure events is always an array
let events: ExpandedEvent[] = $derived(data?.events ?? []);
function getEventsByMonth(events: Array<ExpandedEvent>): Record<string, Array<ExpandedEvent>> {
const grouped: Record<string, Array<ExpandedEvent>> = {};
const sortedEvents = [...events].sort(
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
);
sortedEvents.forEach((event) => {
const date = new Date(event.date);
const monthYear = date.toLocaleString('default', { month: 'long', year: 'numeric' });
if (!grouped[monthYear]) {
grouped[monthYear] = [];
}
grouped[monthYear].push(event);
});
return grouped;
}
This Code imports the Pocketbase Types from my pocketbase-types.ts file. Basically a Schema of an Event it’s properties (aka variables). For example for Teams:
export type TeamsRecord = {
category?: string
created?: IsoDateString
id: string
players?: RecordIdString[]
team?: string
trainers?: RecordIdString[]
updated?: IsoDateString
}
The same code in Javascript would be:
let { data } = $props();
let events = $derived(data.events ?? []);
function getEventsByMonth(events) {
const grouped = {};
const sortedEvents = [...events].sort(
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
);
sortedEvents.forEach((event) => {
const date = new Date(event.date);
const monthYear = date.toLocaleString('default', { month: 'long', year: 'numeric' });
if (!grouped[monthYear]) {
grouped[monthYear] = [];
}
grouped[monthYear].push(event);
});
return grouped;
}
So there is a clear difference. For getting more IDE support and better maintainability, we have to sacrifice concise Syntax. The code with all it’s :: <> and {} becomes quite confusing at times.
Goals #
There is a lot to do. I want to especially focus on a deep understanding of the workings of Sveltekit, Javascript and Typescript. Especially the Types sometimes confuse me. The syntax makes the code harder to read, and my codebase is not yet that complicated, that it has really benefited me. Rather only confused me more. My general goals are:
- Improve my Typescript understanding
- Sveltekit understanding
- Write more code myself instead of Claude’s LLM
My next steps are:
- Implement a Current Player (in case of Users that have multiple Children or Trainers that should be able to change multiple players)
- Create the filters of the Calendar
- Signup button (is still only visually)
- More comprehensive Pocketbase API Authorization of individual Tables (Still open to anyone)