i wrote puuid in typescript

This commit is contained in:
Soph :3 2026-01-04 14:12:17 +02:00
parent 8a2c3d05c9
commit 91284c242a
4 changed files with 100 additions and 45 deletions

View file

@ -1,22 +1,40 @@
import { definePrefix, type Puuid } from "./puuid"
export const UserID = definePrefix("user");
export const GroupID = definePrefix("group");
export const ServerID = definePrefix("srv");
export type UserId = Puuid<"user">;
export type GroupId = Puuid<"group">;
export type ServerId = Puuid<"srv">;
export const Status: Record<string, 1|2|3> = {
OFFLINE: 1,
DND: 2,
ONLINE: 3
}
interface InnerData {
id: string
}
export interface Friend extends InnerData {
export interface User {
id: UserId
name: string,
status: 1|2|3,
image: string
}
export interface Group extends InnerData {
export interface Group {
id: GroupId
name: string
members: number
}
export interface Server extends InnerData {
export interface Server {
id: ServerId
name: string
image: string
}
export interface Data {
friends: User[],
groups: Group[],
servers: Server[],
};

42
src/lib/puuid.ts Normal file
View file

@ -0,0 +1,42 @@
import { v4 as uuidv4 } from "uuid";
import { v7 as uuidv7 } from "uuid";
type Brand<K, T> = K & { __brand: T };
export type Puuid<Prefix extends string> = Brand<
string,
{ prefix: Prefix }
>;
export function definePrefix<const P extends string>(prefix: P) {
const withPrefix = (uuid: string) =>
`${prefix}_${uuid}` as Puuid<P>;
return {
prefix,
is(value: string): value is Puuid<P> {
return value.startsWith(prefix + "_");
},
newV7(): Puuid<P> {
return withPrefix(uuidv7());
},
newV4(): Puuid<P> {
return withPrefix(uuidv4());
},
parse(value: string): Puuid<P> {
if (!value.startsWith(prefix + "_")) {
throw new Error(
`Invalid prefix, expected "${prefix}_"`
);
}
return value as Puuid<P>;
},
inner(id: Puuid<P>): string {
return id.slice(prefix.length + 1);
},
};
}

View file

@ -1,47 +1,40 @@
<script lang="ts">
import { Status, type Server, type Group, type Friend } from "$lib";
import { Status, type Server, type Group, type User, GroupID, UserID, ServerID, type GroupId, type ServerId, type UserId, type Data } from "$lib";
import AppSidebar from "$lib/components/app-sidebar.svelte";
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
let currentPageID: string|null = $state(null);
let currentPageType: string|null = $state(null);
let currentPage: Friend | Group | Server | null = $state(null);
let currentPageID: (UserId|GroupId|ServerId)|null = $state(null);
let currentPage: User | Group | Server | undefined = $state();
const overview_data = {
const overview_data: Data = {
friends: [
{ id: crypto.randomUUID(), name: "Alice", status: Status.OFFLINE, image: "https://placehold.co/40x40" },
{ id: crypto.randomUUID(), name: "Bob", status: Status.DND, image: "https://placehold.co/40x40" },
{ id: crypto.randomUUID(), name: "Charlie", status: Status.ONLINE, image: "https://placehold.co/40x40" },
{ id: UserID.newV7(), name: "Alice", status: Status.OFFLINE, image: "https://placehold.co/40x40" },
{ id: UserID.newV7(), name: "Bob", status: Status.DND, image: "https://placehold.co/40x40" },
{ id: UserID.newV7(), name: "Charlie", status: Status.ONLINE, image: "https://placehold.co/40x40" },
],
groups: [
{ id: crypto.randomUUID(), name: "Work Team", members: 5 },
{ id: crypto.randomUUID(), name: "Gaming Group", members: 8 },
{ id: GroupID.newV7(), name: "Work Team", members: 5 },
{ id: GroupID.newV7(), name: "Gaming Group", members: 8 },
],
servers: [
{ id: crypto.randomUUID(), name: "Main Server", image: "https://placehold.co/40x40" },
{ id: crypto.randomUUID(), name: "Backup Server", image: "https://placehold.co/40x40" },
{ id: ServerID.newV7(), name: "Main Server", image: "https://placehold.co/40x40" },
{ id: ServerID.newV7(), name: "Backup Server", image: "https://placehold.co/40x40" },
],
};
console.log(overview_data)
$effect(() => {
if (currentPageID) {
let f = overview_data.friends.find(friend => friend.id === currentPageID);
let g = overview_data.groups.find(group => group.id === currentPageID);
let s = overview_data.servers.find(server => server.id === currentPageID);
if(f) {
currentPageType = "friend";
currentPage = f;
} else if(g) {
currentPageType = "group";
currentPage = g;
} else if(s) {
currentPageType = "server";
currentPage = s;
if(UserID.is(currentPageID)) {
currentPage = overview_data.friends.find(friend => friend.id === currentPageID);
} else if(GroupID.is(currentPageID)) {
currentPage = overview_data.groups.find(group => group.id === currentPageID);
} else if(ServerID.is(currentPageID)) {
currentPage = overview_data.servers.find(server => server.id === currentPageID);
}
} else {
currentPage = null;
currentPageType = null;
currentPage = undefined;
}
});
</script>
@ -52,23 +45,25 @@
<Sidebar.Inset>
<header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
<Sidebar.Trigger class="-ms-1" />
{#if currentPageType == "server"}
{#if currentPageID && currentPage}
{#if ServerID.is(currentPageID)}
{@const server = (currentPage as Server)}
<img src={server!.image} alt={server!.name} class="size-6 rounded-full" />
<h1>{server!.name}</h1>
{:else if currentPageType == "friend"}
{@const friend = (currentPage as Friend)}
{:else if UserID.is(currentPageID)}
{@const friend = (currentPage as User)}
<img src={friend.image} alt={friend!.name} class="size-6 rounded-full" />
<h1>{friend!.name} [{friend.status == Status.ONLINE ? "Online!" : friend.status == Status.DND ? "DND" : friend.status == Status.OFFLINE ? "Offline" : "Unknown"}]</h1>
{:else if currentPageType == "group"}
{:else if GroupID.is(currentPageID)}
{@const group = (currentPage as Group)}
<h1>{group!.name} ({group.members} member{group.members > 1 ? "s" : ""})</h1>
{/if}
{/if}
</header>
<h1> this is like lowkirkounely the content, i should put messages and shi here</h1>
</Sidebar.Inset>

View file

@ -10,7 +10,7 @@
<div class="flex min-h-screen flex-col items-center justify-center gap-2">
<div class='w-1/2 p-2 bg-secondary rounded-md '>
<div class="text-center pb-2">
<Title size="2xl"></Title>
<Title class="text-2xl"></Title>
</div>
<form method="post" action="?/register">
<Input name="username" class="mb-2" type="text" placeholder="Username"></Input>