Implement most of status system (still kinda bootycheeks at checking if
you're connected), fionally fix prettierrc
This commit is contained in:
parent
126acf52f3
commit
e64910d895
29 changed files with 2001 additions and 879 deletions
|
|
@ -1,22 +1,27 @@
|
|||
<script lang="ts">
|
||||
import { type Data, type OverviewUser } from "$lib";
|
||||
import * as Collapsible from "$lib/components/ui/collapsible/index.js";
|
||||
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
||||
import * as Dialog from "$lib/components/ui/dialog/index.js";
|
||||
import * as Tabs from "$lib/components/ui/tabs/index.js";
|
||||
import * as Card from "$lib/components/ui/card/index.js";
|
||||
import MessagesSquare from "@lucide/svelte/icons/messages-square";
|
||||
import MinusIcon from "@lucide/svelte/icons/minus";
|
||||
import PlusIcon from "@lucide/svelte/icons/plus";
|
||||
import { type Data, type OverviewUser } from '$lib';
|
||||
import * as Collapsible from '$lib/components/ui/collapsible/index.js';
|
||||
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
|
||||
import * as Dialog from '$lib/components/ui/dialog/index.js';
|
||||
import * as Tabs from '$lib/components/ui/tabs/index.js';
|
||||
import * as Card from '$lib/components/ui/card/index.js';
|
||||
import MessagesSquare from '@lucide/svelte/icons/messages-square';
|
||||
import MinusIcon from '@lucide/svelte/icons/minus';
|
||||
import PlusIcon from '@lucide/svelte/icons/plus';
|
||||
import UserRoundPlus from '@lucide/svelte/icons/user-round-plus';
|
||||
import UsersRound from '@lucide/svelte/icons/users-round';
|
||||
import CirclePlus from '@lucide/svelte/icons/circle-plus';
|
||||
import Input from "./ui/input/input.svelte";
|
||||
import Button, { buttonVariants } from "./ui/button/button.svelte";
|
||||
import User from "./extra/User.svelte";
|
||||
import type { SessionValidationResult } from "$lib/server/auth";
|
||||
import Input from './ui/input/input.svelte';
|
||||
import Button, { buttonVariants } from './ui/button/button.svelte';
|
||||
import User from './extra/User.svelte';
|
||||
import type { SessionValidationResult } from '$lib/server/auth';
|
||||
|
||||
let { currentPage = $bindable<string|null>(), data, user, ...restProps }: {currentPage: string|null, data: Data, user: SessionValidationResult['user'] }= $props();
|
||||
let {
|
||||
currentPage = $bindable<string | null>(),
|
||||
data,
|
||||
user,
|
||||
...restProps
|
||||
}: { currentPage: string | null; data: Data; user: SessionValidationResult['user'] } = $props();
|
||||
</script>
|
||||
|
||||
<Sidebar.Root {...restProps}>
|
||||
|
|
@ -25,7 +30,7 @@
|
|||
<Sidebar.MenuItem>
|
||||
<Sidebar.MenuButton size="lg">
|
||||
<div
|
||||
class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg"
|
||||
class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"
|
||||
>
|
||||
<MessagesSquare class="size-4" />
|
||||
</div>
|
||||
|
|
@ -33,193 +38,170 @@
|
|||
<span class="font-medium">chat.sad.ovh</span>
|
||||
</div>
|
||||
</Sidebar.MenuButton>
|
||||
<div class="w-full flex gap-2 justify-center">
|
||||
<div class="flex w-full justify-center gap-2">
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button
|
||||
variant={user!.friendRequests.length > 0 ? 'destructive' : 'outline'}
|
||||
size="icon"
|
||||
>
|
||||
<UserRoundPlus />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button variant={user!.friendRequests.length > 0 ? "destructive" : "outline"} size="icon">
|
||||
<UserRoundPlus />
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Add a friend</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Add a friend using their username or manage pending requests.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
<!-- input to add a new friend -->
|
||||
<form method="POST" action="?/addFriend" class="mb-4">
|
||||
<Input name="username" placeholder="username" required class="mb-2" />
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Cancel</Dialog.Close>
|
||||
<Button type="submit">Send request</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
|
||||
<!-- Tabs for Friend Requests -->
|
||||
<Tabs.Root value="outgoing">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="outgoing">Outgoing</Tabs.Trigger>
|
||||
<Tabs.Trigger value="incoming">Incoming</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Add a friend</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Add a friend using their username or manage pending requests.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
<!-- Outgoing Requests -->
|
||||
<Tabs.Content value="outgoing">
|
||||
{#if user.friendRequests.filter((r) => r.fromUser === user.id).length === 0}
|
||||
<p class="text-sm text-muted-foreground">No outgoing requests</p>
|
||||
{:else}
|
||||
{#each user.friendRequests.filter((r) => r.fromUser === user.id) as request (request.id)}
|
||||
<Card.Root class="mb-2">
|
||||
<Card.Header>
|
||||
<Card.Title>{request.username}</Card.Title>
|
||||
<Card.Description>Request sent</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Footer>
|
||||
<form method="POST" action="?/cancelFriendRequest">
|
||||
<input type="hidden" name="requestId" value={request.id} />
|
||||
<Button type="submit" variant="outline" size="sm">Cancel</Button>
|
||||
</form>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
{/if}
|
||||
</Tabs.Content>
|
||||
|
||||
<!-- input to add a new friend -->
|
||||
<form method="POST" action="?/addFriend" class="mb-4">
|
||||
<Input name="username" placeholder="username" required class="mb-2" />
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: "outline" })}>
|
||||
Cancel
|
||||
</Dialog.Close>
|
||||
<Button type="submit">Send request</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
<!-- Incoming Requests -->
|
||||
<Tabs.Content value="incoming">
|
||||
{#if user.friendRequests.filter((r) => r.toUser === user.id).length === 0}
|
||||
<p class="text-sm text-muted-foreground">No incoming requests</p>
|
||||
{:else}
|
||||
{#each user.friendRequests.filter((r) => r.toUser === user.id) as request (request.id)}
|
||||
<Card.Root class="mb-2">
|
||||
<Card.Header>
|
||||
<Card.Title>{request.username}</Card.Title>
|
||||
<Card.Description>Sent you a friend request</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Footer class="flex gap-2">
|
||||
<!-- accept friend -->
|
||||
<form method="POST" action="?/addFriend">
|
||||
<input type="hidden" name="userId" value={request.fromUser} />
|
||||
<Button type="submit" size="sm">Accept</Button>
|
||||
</form>
|
||||
<!-- decline friend -->
|
||||
<form method="POST" action="?/cancelFriendRequest">
|
||||
<input type="hidden" name="requestId" value={request.id} />
|
||||
<Button type="submit" variant="outline" size="sm">Decline</Button>
|
||||
</form>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
{/if}
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<!-- Tabs for Friend Requests -->
|
||||
<Tabs.Root value="outgoing">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="outgoing">Outgoing</Tabs.Trigger>
|
||||
<Tabs.Trigger value="incoming">Incoming</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<UsersRound />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
|
||||
<!-- Outgoing Requests -->
|
||||
<Tabs.Content value="outgoing">
|
||||
{#if user.friendRequests.filter(r => r.fromUser === user.id).length === 0}
|
||||
<p class="text-sm text-muted-foreground">No outgoing requests</p>
|
||||
{:else}
|
||||
{#each user.friendRequests.filter(r => r.fromUser === user.id) as request (request.id)}
|
||||
<Card.Root class="mb-2">
|
||||
<Card.Header>
|
||||
<Card.Title>{request.username}</Card.Title>
|
||||
<Card.Description>Request sent</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Footer>
|
||||
<form method="POST" action="?/cancelFriendRequest">
|
||||
<input type="hidden" name="requestId" value={request.id} />
|
||||
<Button type="submit" variant="outline" size="sm">
|
||||
Cancel
|
||||
</Button>
|
||||
</form>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
{/if}
|
||||
</Tabs.Content>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<form method="POST" action="?/createGroup">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Create a group</Dialog.Title>
|
||||
<Dialog.Description>Add friends into your group!</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<!-- Incoming Requests -->
|
||||
<Tabs.Content value="incoming">
|
||||
{#if user.friendRequests.filter(r => r.toUser === user.id).length === 0}
|
||||
<p class="text-sm text-muted-foreground">No incoming requests</p>
|
||||
{:else}
|
||||
{#each user.friendRequests.filter(r => r.toUser === user.id) as request (request.id)}
|
||||
<Card.Root class="mb-2">
|
||||
<Card.Header>
|
||||
<Card.Title>{request.username}</Card.Title>
|
||||
<Card.Description>Sent you a friend request</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Footer class="flex gap-2">
|
||||
<!-- accept friend -->
|
||||
<form method="POST" action="?/addFriend">
|
||||
<input type="hidden" name="userId" value={request.fromUser} />
|
||||
<Button type="submit" size="sm">Accept</Button>
|
||||
</form>
|
||||
<!-- decline friend -->
|
||||
<form method="POST" action="?/cancelFriendRequest">
|
||||
<input type="hidden" name="requestId" value={request.id} />
|
||||
<Button type="submit" variant="outline" size="sm">Decline</Button>
|
||||
</form>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
{/each}
|
||||
{/if}
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
</Dialog.Content>
|
||||
{#each data.friends as friend (friend.id)}
|
||||
<label class="flex items-center gap-2">
|
||||
<input type="checkbox" name="member" value={friend.id} />
|
||||
<User user={friend} />
|
||||
</label>
|
||||
{/each}
|
||||
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Cancel</Dialog.Close>
|
||||
<Button type="submit">Create group</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
</Dialog.Root>
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<CirclePlus />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<UsersRound />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<form method="POST" action="?/joinServer">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Join a server</Dialog.Title>
|
||||
<Dialog.Description>Enter an invite link.</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<form method="POST" action="?/createGroup">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Create a group</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Add friends into your group!
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
<Input name="invite" placeholder="invite link" required />
|
||||
|
||||
{#each data.friends as friend (friend.id)}
|
||||
<label class="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="member"
|
||||
value={friend.id}
|
||||
/>
|
||||
<User user={friend} />
|
||||
</label>
|
||||
{/each}
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Cancel</Dialog.Close>
|
||||
<Button type="submit">Join</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: "outline" })}>
|
||||
Cancel
|
||||
</Dialog.Close>
|
||||
<Button type="submit">Create group</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<PlusIcon />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<CirclePlus />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<form method="POST" action="?/createServer">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Create a server</Dialog.Title>
|
||||
<Dialog.Description>Name your new server.</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<form method="POST" action="?/joinServer">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Join a server</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Enter an invite link.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<Input name="invite" placeholder="invite link" required />
|
||||
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: "outline" })}>
|
||||
Cancel
|
||||
</Dialog.Close>
|
||||
<Button type="submit">Join</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<PlusIcon />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Content class="sm:max-w-[425px]">
|
||||
<form method="POST" action="?/createServer">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Create a server</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Name your new server.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<Input name="name" placeholder="Server name" required />
|
||||
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: "outline" })}>
|
||||
Cancel
|
||||
</Dialog.Close>
|
||||
<Button type="submit">Create</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
<Input name="name" placeholder="Server name" required />
|
||||
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Cancel</Dialog.Close>
|
||||
<Button type="submit">Create</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
</div>
|
||||
</Sidebar.MenuItem>
|
||||
</Sidebar.Menu>
|
||||
|
|
@ -230,26 +212,24 @@
|
|||
<Collapsible.Root open={true} class="group/collapsible">
|
||||
<Sidebar.MenuItem>
|
||||
<Collapsible.Trigger>
|
||||
<Sidebar.MenuButton>
|
||||
Friends
|
||||
<PlusIcon
|
||||
class="ms-auto group-data-[state=open]/collapsible:hidden"
|
||||
/>
|
||||
<MinusIcon
|
||||
class="ms-auto group-data-[state=closed]/collapsible:hidden"
|
||||
/>
|
||||
</Sidebar.MenuButton>
|
||||
<Sidebar.MenuButton>
|
||||
Friends
|
||||
<PlusIcon class="ms-auto group-data-[state=open]/collapsible:hidden" />
|
||||
<MinusIcon class="ms-auto group-data-[state=closed]/collapsible:hidden" />
|
||||
</Sidebar.MenuButton>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
<Sidebar.MenuSub>
|
||||
{#each data.friends as friend (friend.id)}
|
||||
<Sidebar.MenuSubItem>
|
||||
<Sidebar.MenuSubButton>
|
||||
|
||||
<User onclick={(e) => {
|
||||
e.preventDefault();
|
||||
currentPage = friend.id;
|
||||
}} user={friend}></User>
|
||||
<User
|
||||
onclick={(e) => {
|
||||
e.preventDefault();
|
||||
currentPage = friend.id;
|
||||
}}
|
||||
user={friend}
|
||||
></User>
|
||||
</Sidebar.MenuSubButton>
|
||||
</Sidebar.MenuSubItem>
|
||||
{/each}
|
||||
|
|
@ -263,12 +243,8 @@
|
|||
<Collapsible.Trigger>
|
||||
<Sidebar.MenuButton>
|
||||
Groups
|
||||
<PlusIcon
|
||||
class="ms-auto group-data-[state=open]/collapsible:hidden"
|
||||
/>
|
||||
<MinusIcon
|
||||
class="ms-auto group-data-[state=closed]/collapsible:hidden"
|
||||
/>
|
||||
<PlusIcon class="ms-auto group-data-[state=open]/collapsible:hidden" />
|
||||
<MinusIcon class="ms-auto group-data-[state=closed]/collapsible:hidden" />
|
||||
</Sidebar.MenuButton>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
|
|
@ -276,10 +252,13 @@
|
|||
{#each data.groups as group (group.id)}
|
||||
<Sidebar.MenuSubItem>
|
||||
<Sidebar.MenuSubButton>
|
||||
<a onclick={(e) => {
|
||||
e.preventDefault();
|
||||
currentPage = group.id;
|
||||
}} href="##">
|
||||
<a
|
||||
onclick={(e) => {
|
||||
e.preventDefault();
|
||||
currentPage = group.id;
|
||||
}}
|
||||
href="##"
|
||||
>
|
||||
{group.name} ({group.members} members)
|
||||
</a>
|
||||
</Sidebar.MenuSubButton>
|
||||
|
|
@ -295,12 +274,8 @@
|
|||
<Collapsible.Trigger>
|
||||
<Sidebar.MenuButton>
|
||||
Servers
|
||||
<PlusIcon
|
||||
class="ms-auto group-data-[state=open]/collapsible:hidden"
|
||||
/>
|
||||
<MinusIcon
|
||||
class="ms-auto group-data-[state=closed]/collapsible:hidden"
|
||||
/>
|
||||
<PlusIcon class="ms-auto group-data-[state=open]/collapsible:hidden" />
|
||||
<MinusIcon class="ms-auto group-data-[state=closed]/collapsible:hidden" />
|
||||
</Sidebar.MenuButton>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
|
|
@ -308,11 +283,19 @@
|
|||
{#each data.servers as server (server.id)}
|
||||
<Sidebar.MenuSubItem>
|
||||
<Sidebar.MenuSubButton>
|
||||
<a onclick={(e) => {
|
||||
e.preventDefault();
|
||||
currentPage = server.id;
|
||||
}} href="##" class="flex items-center gap-2">
|
||||
<img src={"https://api.dicebear.com/7.x/pixel-art/svg?seed=" + server.name} alt={server.name} class="size-6 rounded-full" />
|
||||
<a
|
||||
onclick={(e) => {
|
||||
e.preventDefault();
|
||||
currentPage = server.id;
|
||||
}}
|
||||
href="##"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<img
|
||||
src={'https://api.dicebear.com/7.x/pixel-art/svg?seed=' + server.name}
|
||||
alt={server.name}
|
||||
class="size-6 rounded-full"
|
||||
/>
|
||||
{server.name}
|
||||
</a>
|
||||
</Sidebar.MenuSubButton>
|
||||
|
|
|
|||
9
src/lib/components/hooks/is-mobile.svelte.ts
Normal file
9
src/lib/components/hooks/is-mobile.svelte.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { MediaQuery } from "svelte/reactivity";
|
||||
|
||||
const DEFAULT_MOBILE_BREAKPOINT = 768;
|
||||
|
||||
export class IsMobile extends MediaQuery {
|
||||
constructor(breakpoint: number = DEFAULT_MOBILE_BREAKPOINT) {
|
||||
super(`max-width: ${breakpoint - 1}px`);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue