Files
apes/ui/colony/src/components/ChannelSidebar.tsx
limiteinductive f8420496b2 S3+S4: user param auth, static file serving, Docker deploy config
- replace hardcoded benji with ?user= query param
- add GET /api/users and GET /api/me?user= endpoints
- serve frontend static files via tower-http ServeDir
- add multi-stage Dockerfile (Rust + Vite → single image)
- add docker-compose.yml + Caddyfile for apes.unslope.com
- frontend: getCurrentUsername() from URL param → localStorage
- sidebar shows current user

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 19:18:06 +02:00

85 lines
2.8 KiB
TypeScript

import { useState } from "react";
import type { Channel } from "@/types/Channel";
import { createChannel, getCurrentUsername } from "@/api";
interface Props {
channels: Channel[];
activeId: string | null;
onSelect: (id: string) => void;
onChannelCreated: () => void;
}
export function ChannelSidebar({
channels,
activeId,
onSelect,
onChannelCreated,
}: Props) {
const [newName, setNewName] = useState("");
const [creating, setCreating] = useState(false);
async function handleCreate() {
if (!newName.trim()) return;
setCreating(true);
await createChannel({ name: newName.trim(), description: "" });
setNewName("");
setCreating(false);
onChannelCreated();
}
return (
<div className="flex flex-col h-full w-52 border-r border-sidebar-border bg-sidebar text-sidebar-foreground">
{/* Header */}
<div className="px-3 py-3 border-b border-sidebar-border">
<div className="text-[15px] font-bold tracking-tight text-foreground">
COLONY
</div>
<div className="text-[10px] text-muted-foreground mt-0.5">
apes.unslope.com
</div>
</div>
{/* Channel list */}
<div className="flex-1 overflow-y-auto py-2">
<div className="px-2 mb-1 text-[10px] font-bold text-muted-foreground tracking-widest">
CHANNELS
</div>
{channels.map((ch) => (
<button
type="button"
key={ch.id}
onClick={() => onSelect(ch.id)}
className={`w-full text-left px-3 py-1 text-[12px] transition-colors ${
ch.id === activeId
? "bg-sidebar-accent text-sidebar-accent-foreground font-medium"
: "text-sidebar-foreground hover:bg-sidebar-accent/50"
}`}
>
<span className="text-muted-foreground mr-1">#</span>
{ch.name}
</button>
))}
</div>
{/* Current user */}
<div className="px-3 py-2 border-t border-sidebar-border text-[11px]">
<span className="text-muted-foreground">logged in as </span>
<span className="font-bold text-foreground">{getCurrentUsername()}</span>
</div>
{/* New channel input */}
<div className="p-2 border-t border-sidebar-border">
<input
type="text"
placeholder="+ new channel"
value={newName}
onChange={(e) => setNewName(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && handleCreate()}
disabled={creating}
className="w-full bg-sidebar-accent text-[11px] text-sidebar-foreground placeholder:text-muted-foreground px-2 py-1 rounded-sm border border-sidebar-border focus:outline-none focus:border-[var(--color-agent-glow)]"
/>
</div>
</div>
);
}