This commit is contained in:
2026-08-19 03:01:56 +02:00
parent ad1cd151dc
commit 0da38dee53
5 changed files with 90 additions and 36 deletions
+2
View File
@@ -73,6 +73,8 @@ export default class Enclave {
getHTTPUrl(hostname, isSecure, "/meta"), getHTTPUrl(hostname, isSecure, "/meta"),
); );
this.server.meta = metaResponse.data as any;
this.serverList[hostname] = { this.serverList[hostname] = {
meta: metaResponse.data as any, meta: metaResponse.data as any,
isSecure, isSecure,
+6
View File
@@ -3,6 +3,7 @@ export interface ClientMeta {}
export interface ServerMeta { export interface ServerMeta {
name: string; name: string;
description: string; description: string;
channels: Channel[];
} }
export type ClientMethod = export type ClientMethod =
@@ -33,3 +34,8 @@ export type ServerMethod =
method: "Error"; method: "Error";
error: string; error: string;
}; };
export type Channel = { id: string; name: string } & ChannelKind;
export type ChannelKind =
{ kind: "text" } | { kind: "category"; channels: Channel[] };
+2
View File
@@ -3,6 +3,7 @@ import * as ed from "@noble/ed25519";
import EnclaveWebSocket from "./ws"; import EnclaveWebSocket from "./ws";
import { sha512 } from "@noble/hashes/sha2.js"; import { sha512 } from "@noble/hashes/sha2.js";
import { getWSUrl } from "@/lib/serverList"; import { getWSUrl } from "@/lib/serverList";
import { ServerMeta } from "./protocol";
ed.hashes.sha512 = sha512; ed.hashes.sha512 = sha512;
@@ -27,6 +28,7 @@ export default class EnclaveServer {
public hostname: string; public hostname: string;
public isSecure: boolean; public isSecure: boolean;
public websocket?: EnclaveWebSocket; public websocket?: EnclaveWebSocket;
public meta?: ServerMeta;
public constructor(hostname: string, isSecure: boolean) { public constructor(hostname: string, isSecure: boolean) {
this.hostname = hostname; this.hostname = hostname;
+44 -1
View File
@@ -1,9 +1,52 @@
import Enclave from "@/app/app"; import Enclave from "@/app/app";
import { Channel, ChannelKind } from "@/app/protocol";
import { HashIcon } from "lucide-react";
export function ChannelIcon({ kind }: { kind: ChannelKind["kind"] }) {
switch (kind) {
case "text":
return <HashIcon className="p-0.5" />;
default:
return null;
}
}
export function RenderChannels({ channels }: { channels: Channel[] }) {
return channels.map((channel) =>
channel.kind === "category" ? (
<div>
<div className="w-full px-0.5 py-1 rounded-md select-none cursor-default text-sm text-foreground/70">
{channel.name}
</div>
<div className="pl-2 pr-1.5 pt-0.5 w-full flex flex-col gap-1">
<RenderChannels channels={channel.channels} />
</div>
</div>
) : (
<div className="w-full hover:bg-accent px-2.5 py-1.5 rounded-md flex gap-2.5 items-center select-none cursor-default text-sm text-foreground/70">
<ChannelIcon kind={channel.kind} />
{channel.name}
</div>
),
);
}
export default function Sidebar({ export default function Sidebar({
appRef, appRef,
}: { }: {
appRef: React.RefObject<Enclave | null>; appRef: React.RefObject<Enclave | null>;
}) { }) {
return <div className="h-screen"></div>; return (
appRef.current?.server?.meta && (
<div className="h-screen">
<header className="px-3 pt-2.5 pb-2.5 text-lg font-semibold border-b border-b-border">
<h1>{appRef.current.server.meta.name}</h1>
</header>
<section className="px-1.5 pt-3.5 w-full flex flex-col gap-1">
<RenderChannels channels={appRef.current.server.meta.channels} />
</section>
</div>
)
);
} }
+36 -35
View File
@@ -49,41 +49,6 @@
} }
:root { :root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0); --background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0); --foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0); --card: oklch(0.205 0 0);
@@ -115,6 +80,42 @@
--sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%); --sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0); --sidebar-ring: oklch(0.556 0 0);
--radius: 0.625rem;
}
.dark {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
} }
@layer base { @layer base {