almost finish status support everywhere else, group setting start impl

This commit is contained in:
Soph :3 2026-01-08 14:47:07 +02:00
parent 6b47888514
commit 92a95cb365
14 changed files with 770 additions and 116 deletions

View file

@ -168,45 +168,10 @@
</Dialog.Header>
{#each data.friends as friend (friend.id)}
<Sidebar.MenuSubItem class="flex items-center gap-2">
<Sidebar.MenuSubButton>
<User
onclick={(e) => {
e.preventDefault();
currentPage = friend.id;
}}
user={friend}
></User>
</Sidebar.MenuSubButton>
<Dialog.Root>
<Dialog.Trigger>
<Button variant="destructive" size="icon">
<MinusIcon />
</Button>
</Dialog.Trigger>
<Dialog.Content class="sm:max-w-106.25">
<Dialog.Header>
<Dialog.Title>Remove Friend</Dialog.Title>
<Dialog.Description>
Are you sure you want to remove {friend.username} from your friends?
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer class="flex gap-2">
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>
Cancel
</Dialog.Close>
<form method="POST" action="?/removeFriend">
<input type="hidden" name="userId" value={friend.id} />
<Button type="submit" variant="destructive">Remove</Button>
</form>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
</Sidebar.MenuSubItem>
<label class="flex items-center gap-2">
<input type="checkbox" name="member" value={friend.id} />
<User crown={false} user={friend} />
</label>
{/each}
<Dialog.Footer>

View file

@ -1,34 +1,53 @@
<script lang="ts">
import { Status, type UserWithStatus } from '$lib';
import Crown from '@lucide/svelte/icons/crown';
const { onclick, user }: { onclick?: (e: MouseEvent) => void; user: UserWithStatus } = $props();
const {
onclick,
user,
crown
}: { crown: boolean; onclick?: (e: MouseEvent) => void; user: UserWithStatus } = $props();
</script>
<a
{onclick}
oncontextmenu={async (e) => {
e.preventDefault();
await navigator.clipboard.writeText(user.id);
}}
href="##"
class="flex items-center gap-2"
>
<div class="relative">
<div class="flex flex-row gap-2">
<div>
<img
src={'https://api.dicebear.com/7.x/pixel-art/svg?seed=' + user.username}
alt={user.username}
class="size-6 rounded-full"
/>
{#if user.status === Status.OFFLINE}
<span class="absolute end-0 bottom-0 block size-2 rounded-full bg-gray-500 ring-1 ring-white"
></span>
{:else if user.status === Status.DND}
<span class="absolute end-0 bottom-0 block size-2 rounded-full bg-red-500 ring-1 ring-white"
></span>
{:else if user.status === Status.ONLINE}
<span class="absolute end-0 bottom-0 block size-2 rounded-full bg-green-500 ring-1 ring-white"
></span>
{/if}
<div class="relative">
{#if user.status === Status.OFFLINE}
<span
class="absolute end-0 bottom-0 block size-2 rounded-full bg-gray-500 ring-1 ring-white"
></span>
{:else if user.status === Status.DND}
<span class="absolute end-0 bottom-0 block size-2 rounded-full bg-red-500 ring-1 ring-white"
></span>
{:else if user.status === Status.ONLINE}
<span
class="absolute end-0 bottom-0 block size-2 rounded-full bg-green-500 ring-1 ring-white"
></span>
{/if}
</div>
</div>
{user.username}
</a>
<div>
<a
{onclick}
oncontextmenu={async (e) => {
e.preventDefault();
await navigator.clipboard.writeText(user.id);
}}
href="##"
class="flex items-center gap-2"
>
{user.username}
{#if crown}
<Crown></Crown>
{/if}
</a>
<div class="pl-2 text-xs text-gray-400 italic">
{user.statusMessage}
</div>
</div>
</div>

View file

@ -1,36 +1,128 @@
<script lang="ts">
import UserRoundPlus from '@lucide/svelte/icons/user-round-plus';
import UserRoundMinus from '@lucide/svelte/icons/user-round-minus';
import * as Dialog from '$lib/components/ui/dialog/index.js';
import * as Tabs from '$lib/components/ui/tabs/index.js';
import Cog from '@lucide/svelte/icons/cog';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import { useSidebar } from '$lib/components/ui/sidebar/context.svelte.js';
import { onMount } from 'svelte';
import User from './extra/User.svelte';
import type { SessionValidationResult } from '$lib/server/auth';
import { ServerID, type UserWithStatus } from '$lib';
import {
GroupID,
ServerID,
type OverviewGroup,
type OverviewServer,
type UserWithStatus
} from '$lib';
import Button from './ui/button/button.svelte';
// Props for the member sidebar.
let {
open = $bindable(true),
members = $bindable<UserWithStatus[]>([]),
user,
currentEntity,
currentEntityId = $bindable<string | null>(null)
}: {
open: boolean;
members: UserWithStatus[];
user: SessionValidationResult['user'];
currentEntity: OverviewGroup | OverviewServer;
currentEntityId: string | null;
} = $props();
let sidebar_probably = useSidebar();
let this_sidebar = useSidebar();
$effect(() => {
if (sidebar_probably.open != open) {
sidebar_probably.setOpen(open);
if (this_sidebar.open != open) {
this_sidebar.setOpen(open);
}
});
</script>
<Sidebar.Root side="right">
<Sidebar.Header>
<div class="align-center flex w-full justify-center">
{#if user && currentEntityId}
<Dialog.Root>
<Dialog.Trigger><Button variant="outline"><Cog></Cog></Button></Dialog.Trigger>
<Dialog.Content class="sm:max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Group Settings</Dialog.Title>
<Dialog.Description>Configure your group settings here.</Dialog.Description>
</Dialog.Header>
<Tabs.Root value="users" class="w-[400px]">
<Tabs.List class="grid w-full grid-cols-2">
<Tabs.Trigger value="users">User Permissions</Tabs.Trigger>
{#if user.id == currentEntity.ownerId}
<Tabs.Trigger value="admins">Admin Settings</Tabs.Trigger>
{/if}
</Tabs.List>
{#if ServerID.is(currentEntityId)}
<h1>not done yet for later</h1>
{:else if GroupID.is(currentEntityId)}
{#if user.id == currentEntity.ownerId}
<Tabs.Content value="admins">
<form method="POST" action="?/configureGroup" class="space-y-4 p-2">
<input type="hidden" name="groupId" value={currentEntityId} />
<div class="flex items-center justify-between">
<label for="addUsers">Allow everyone to add users</label>
<input
type="checkbox"
id="addMembers"
name="addMembers"
checked={(currentEntity as OverviewGroup).permissions.addMembers}
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
/>
</div>
<div class="flex items-center justify-between">
<label for="removeUsers">Allow everyone to remove users</label>
<input
type="checkbox"
id="removeUsers"
name="removeUsers"
checked={(currentEntity as OverviewGroup).permissions.removeMembers}
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
/>
</div>
<div class="flex items-center justify-between">
<label for="changeTitle">Allow everyone to change title</label>
<input
type="checkbox"
id="changeTitle"
name="changeTitle"
checked={(currentEntity as OverviewGroup).permissions.changeTitle}
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
/>
</div>
<Button type="submit" class="w-full">Save Changes</Button>
</form>
</Tabs.Content>
{/if}
<Tabs.Content value="users">
<div class="space-y-4 p-2">
{#if (currentEntity as OverviewGroup).permissions.addMembers || user.id == currentEntity.ownerId}
<h1>you have permission to add members</h1>
{/if}
{#if (currentEntity as OverviewGroup).permissions.changeTitle || user.id == currentEntity.ownerId}
<h1>you have permission to change title</h1>
{/if}
{#if (currentEntity as OverviewGroup).permissions.removeMembers || user.id == currentEntity.ownerId}
<h1>you have permission to remove members</h1>
{/if}
</div>
</Tabs.Content>
{/if}
</Tabs.Root>
</Dialog.Content>
</Dialog.Root>
{/if}
</div>
</Sidebar.Header>
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.GroupLabel>Members</Sidebar.GroupLabel>
@ -41,7 +133,7 @@
<Sidebar.MenuItem>
<Sidebar.MenuButton>
{#snippet child({ props })}
<User user={member} />
<User user={member} crown={member.id == currentEntity.ownerId} />
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
@ -49,45 +141,5 @@
</Sidebar.Menu>
</Sidebar.GroupContent>
</Sidebar.Group>
{#if currentEntityId && ServerID.is(currentEntityId) && user}
<Sidebar.Group>
<Sidebar.GroupLabel>Server Actions</Sidebar.GroupLabel>
<Sidebar.GroupContent>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.MenuButton>
{#snippet child({ props })}
<form method="POST" action="?/inviteUser" class="w-full">
<input type="hidden" name="serverId" value={currentEntityId} />
<button type="submit" class="flex w-full items-center gap-2" {...props}>
<UserRoundPlus class="size-4" />
<span>Invite User</span>
</button>
</form>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
{#if user.id === members.find((m) => m.id === currentEntityId)?.ownerId}
<Sidebar.MenuItem>
<Sidebar.MenuButton>
{#snippet child({ props })}
<form method="POST" action="?/leaveServer" class="w-full">
<input type="hidden" name="serverId" value={currentEntityId} />
<button type="submit" class="flex w-full items-center gap-2" {...props}>
<UserRoundMinus class="size-4" />
<span>Leave Server</span>
</button>
</form>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
{/if}
</Sidebar.Menu>
</Sidebar.GroupContent>
</Sidebar.Group>
{/if}
</Sidebar.Content>
</Sidebar.Root>