refactor(channels): cap name length at 32 chars and fix sidebar truncation layout
This commit is contained in:
parent
2325c5725e
commit
be4e10893e
6 changed files with 36 additions and 20 deletions
|
|
@ -32,13 +32,21 @@ export async function PATCH(
|
|||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
if (!name || !name.trim()) {
|
||||
if (!name) {
|
||||
return NextResponse.json(
|
||||
{ error: "Channel name cannot be empty" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
// Validate maximum length for channel name
|
||||
if (name.length > 32) {
|
||||
return NextResponse.json(
|
||||
{ error: "Channel name cannot exceed 32 characters" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const [existingChannel] = await db
|
||||
.select()
|
||||
.from(channels)
|
||||
|
|
|
|||
|
|
@ -27,13 +27,21 @@ export async function POST(req: Request) {
|
|||
|
||||
const { name, serverId } = await req.json();
|
||||
|
||||
if (!name?.trim() || !serverId) {
|
||||
if (!name || !serverId) {
|
||||
return NextResponse.json(
|
||||
{ error: "Name and server ID are required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
// Validate maximum length for channel name
|
||||
if (name.length > 32) {
|
||||
return NextResponse.json(
|
||||
{ error: "Channel name cannot exceed 32 characters" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the user is a member of the server
|
||||
const [member] = await db
|
||||
.select()
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ export function CreateChannelModal({
|
|||
type="text"
|
||||
required
|
||||
value={name}
|
||||
maxLength={32}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="new-channel"
|
||||
disabled={isLoading}
|
||||
|
|
|
|||
|
|
@ -82,16 +82,15 @@ export function EditChannelModal({
|
|||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Fehler beim Aktualisieren des Channels.");
|
||||
throw new Error("Error updating the channel.");
|
||||
}
|
||||
|
||||
const updated = await response.json();
|
||||
updateChannel(updated);
|
||||
router.refresh();
|
||||
onClose();
|
||||
} catch (err: unknown) {
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Etwas ist schiefgelaufen.",
|
||||
);
|
||||
setError(err instanceof Error ? err.message : "Something went wrong.");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -116,7 +115,7 @@ export function EditChannelModal({
|
|||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Fehler beim Löschen des Channels.");
|
||||
throw new Error("Error deleting the channel.");
|
||||
}
|
||||
|
||||
removeChannel(channel.id);
|
||||
|
|
@ -135,9 +134,7 @@ export function EditChannelModal({
|
|||
}
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Etwas ist schiefgelaufen.",
|
||||
);
|
||||
setError(err instanceof Error ? err.message : "Something went wrong.");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
|
|
@ -179,6 +176,7 @@ export function EditChannelModal({
|
|||
type="text"
|
||||
required
|
||||
value={name}
|
||||
maxLength={32}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="channel-name"
|
||||
disabled={isLoading || isDeleting}
|
||||
|
|
|
|||
|
|
@ -62,22 +62,22 @@ export function ChannelSidebar() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="flex-1 w-full md:w-72 bg-surface/50 border-r border-background flex flex-col h-full shrink-0">
|
||||
<div className="flex-1 w-full bg-surface/50 border-r border-background flex flex-col h-full min-w-0 overflow-hidden">
|
||||
{/* Server Header */}
|
||||
<div className="h-14 border-b border-background flex items-center justify-between px-4 font-bold text-white shadow-sm">
|
||||
<div className="h-14 border-b border-background flex items-center justify-between px-4 font-bold text-white shadow-sm shrink-0">
|
||||
<span className="truncate">{activeServer.name}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleNav}
|
||||
title="Collapse the sidebar"
|
||||
className="p-1.5 rounded-md text-muted hover:text-white hover:bg-surface transition-colors cursor-pointer"
|
||||
className="p-1.5 rounded-md text-muted hover:text-white hover:bg-surface transition-colors cursor-pointer shrink-0"
|
||||
>
|
||||
<PanelLeftClose className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Channel List */}
|
||||
<div className="flex-1 overflow-y-auto p-3 space-y-1">
|
||||
<div className="flex-1 overflow-y-auto p-3 space-y-1 min-w-0">
|
||||
<div className="flex items-center justify-between text-xs font-semibold text-muted px-2 py-1 uppercase tracking-wider">
|
||||
<span>Text Channels</span>
|
||||
<button
|
||||
|
|
@ -90,7 +90,7 @@ export function ChannelSidebar() {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-0.5">
|
||||
<div className="space-y-0.5 w-full">
|
||||
{activeServer.channels.map((channel) => {
|
||||
const isActive = currentChannelId === channel.id;
|
||||
|
||||
|
|
@ -100,14 +100,15 @@ export function ChannelSidebar() {
|
|||
href={`/servers/${activeServer.id}/channels/${channel.id}`}
|
||||
onClick={handleChannelClick}
|
||||
prefetch={false}
|
||||
className={`flex items-center justify-between px-2 py-1.5 rounded-md text-sm transition-all group ${
|
||||
className={`flex items-center justify-between w-full px-2 py-1.5 rounded-md text-sm transition-all group min-w-0 overflow-hidden ${
|
||||
isActive
|
||||
? "bg-accent/50 text-white font-medium"
|
||||
: "text-muted hover:bg-surface hover:text-white"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="text-muted group-hover:text-white text-base">
|
||||
{/* Text Area */}
|
||||
<div className="flex items-center gap-2 min-w-0 flex-1 overflow-hidden">
|
||||
<span className="text-muted group-hover:text-white text-base shrink-0">
|
||||
#
|
||||
</span>
|
||||
<span className="truncate">{channel.name}</span>
|
||||
|
|
@ -118,7 +119,7 @@ export function ChannelSidebar() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={(e) => handleOpenSettings(e, channel)}
|
||||
className="opacity-0 group-hover:opacity-100 p-1 text-muted hover:text-white focus:outline-none transition-all cursor-pointer"
|
||||
className="opacity-0 group-hover:opacity-100 p-1 text-muted hover:text-white focus:outline-none transition-all cursor-pointer shrink-0 ml-2"
|
||||
aria-label="Channel Settings"
|
||||
title="Channel Settings"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export const members = pgTable("members", {
|
|||
*/
|
||||
export const channels = pgTable("channels", {
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
name: text("name").notNull(),
|
||||
name: varchar("name", { length: 32 }).notNull(),
|
||||
serverId: uuid("server_id")
|
||||
.references(() => servers.id, { onDelete: "cascade" })
|
||||
.notNull(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue