+
CHANNELS
{channels.map((ch) => (
@@ -52,26 +52,26 @@ export function ChannelSidebar({
type="button"
key={ch.id}
onClick={() => onSelect(ch.id)}
- className={`w-full text-left px-3 py-1 text-[12px] transition-colors ${
+ className={`w-full text-left px-4 md:px-3 py-2 md:py-1 text-[13px] md:text-[12px] transition-colors min-h-[44px] md:min-h-0 flex items-center ${
ch.id === activeId
- ? "bg-sidebar-accent text-sidebar-accent-foreground font-medium"
- : "text-sidebar-foreground hover:bg-sidebar-accent/50"
+ ? "bg-white/[0.06] text-foreground font-medium"
+ : "hover:bg-white/[0.03]"
}`}
>
-
#
+
#
{ch.name}
))}
-
logged in as
+
+ as
{getCurrentUsername()}
- {/* New channel input */}
-
diff --git a/ui/colony/src/components/ComposeBox.tsx b/ui/colony/src/components/ComposeBox.tsx
index bd19bd8..395c996 100644
--- a/ui/colony/src/components/ComposeBox.tsx
+++ b/ui/colony/src/components/ComposeBox.tsx
@@ -9,12 +9,12 @@ interface Props {
onMessageSent: () => void;
}
-const TYPES: { value: MessageType; label: string; key: string }[] = [
- { value: "text", label: "TXT", key: "1" },
- { value: "code", label: "CODE", key: "2" },
- { value: "result", label: "RES", key: "3" },
- { value: "error", label: "ERR", key: "4" },
- { value: "plan", label: "PLAN", key: "5" },
+const TYPES: { value: MessageType; label: string; shortLabel: string }[] = [
+ { value: "text", label: "TXT", shortLabel: "T" },
+ { value: "code", label: "CODE", shortLabel: "C" },
+ { value: "result", label: "RES", shortLabel: "R" },
+ { value: "error", label: "ERR", shortLabel: "E" },
+ { value: "plan", label: "PLAN", shortLabel: "P" },
];
export function ComposeBox({
@@ -46,40 +46,42 @@ export function ComposeBox({
}
return (
-
+
{replyTo && (
-
-
replying to #{replyTo.slice(0, 8)}
+
+ ^ #{replyTo.slice(0, 8)}
)}
-
- {/* Type selector */}
+
+
+ {/* Type selector — compact on mobile */}
{TYPES.map((t) => (
))}
- {/* Input */}
+ {/* Input — larger touch target on mobile */}
= "1" && e.key <= "5") {
setMsgType(TYPES[parseInt(e.key) - 1].value);
}
}}
- placeholder={`message #${channelId.slice(0, 8)}...`}
+ placeholder="message..."
disabled={sending}
- className="flex-1 bg-input text-[13px] text-foreground placeholder:text-muted-foreground px-3 py-1.5 rounded-sm border border-border focus:outline-none focus:border-[var(--color-agent-glow)]"
+ className="flex-1 bg-input text-[13px] md:text-[13px] text-foreground placeholder:text-muted-foreground px-3 py-2 md:py-1.5 rounded-sm border border-border focus:outline-none focus:border-blue-500/30"
/>
diff --git a/ui/colony/src/components/MessageItem.tsx b/ui/colony/src/components/MessageItem.tsx
index b5900e0..e7ee205 100644
--- a/ui/colony/src/components/MessageItem.tsx
+++ b/ui/colony/src/components/MessageItem.tsx
@@ -1,3 +1,4 @@
+import { useState } from "react";
import type { Message } from "@/types/Message";
interface Props {
@@ -6,67 +7,65 @@ interface Props {
onReply: (id: string) => void;
}
-const TYPE_CONFIG: Record<
- string,
- { border: string; label: string; labelColor: string }
-> = {
- text: { border: "", label: "", labelColor: "" },
- code: {
- border: "border-l-2 border-[var(--color-msg-code)]",
- label: "CODE",
- labelColor: "text-[var(--color-msg-code)]",
- },
- result: {
- border: "border-l-2 border-[var(--color-msg-result)]",
- label: "RESULT",
- labelColor: "text-[var(--color-msg-result)]",
- },
- error: {
- border: "border-l-2 border-[var(--color-msg-error)]",
- label: "ERROR",
- labelColor: "text-[var(--color-msg-error)]",
- },
- plan: {
- border: "border-l-2 border-[var(--color-msg-plan)]",
- label: "PLAN",
- labelColor: "text-[var(--color-msg-plan)]",
- },
+const TYPE_BORDER: Record
= {
+ text: "",
+ code: "border-l-2 border-amber-500/70",
+ result: "border-l-2 border-emerald-500/70",
+ error: "border-l-2 border-red-500/70",
+ plan: "border-l-2 border-blue-500/70",
};
+const TYPE_LABEL: Record = {
+ code: { text: "CODE", color: "text-amber-500" },
+ result: { text: "RES", color: "text-emerald-500" },
+ error: { text: "ERR", color: "text-red-500" },
+ plan: { text: "PLAN", color: "text-blue-500" },
+};
+
+function timeAgo(dateStr: string): string {
+ const diff = Date.now() - new Date(dateStr).getTime();
+ const mins = Math.floor(diff / 60000);
+ if (mins < 1) return "now";
+ if (mins < 60) return `${mins}m`;
+ const hrs = Math.floor(mins / 60);
+ if (hrs < 24) return `${hrs}h`;
+ return `${Math.floor(hrs / 24)}d`;
+}
+
export function MessageItem({ message, replyTarget, onReply }: Props) {
+ const [metaOpen, setMetaOpen] = useState(false);
const isAgent = message.user.role === "agent";
const isDeleted = !!message.deleted_at;
- const cfg = TYPE_CONFIG[message.type] || TYPE_CONFIG.text;
+ const border = TYPE_BORDER[message.type] || "";
+ const label = TYPE_LABEL[message.type];
const meta = message.metadata as Record | null;
return (
- {/* Agent glow line */}
+ {/* Agent glow — left edge */}
{isAgent && (
-
+
)}
{/* Reply context */}
{replyTarget && (
-
-
^
+
+ ^
{replyTarget.user.display_name}
-
- {replyTarget.content}
-
+ {replyTarget.content}
)}
-
- {/* Avatar */}
+
+ {/* Avatar — small on mobile */}
@@ -74,68 +73,81 @@ export function MessageItem({ message, replyTarget, onReply }: Props) {
- {/* Header line */}
-
-
+ {/* Header */}
+
+
{message.user.display_name}
{isAgent && (
-
- AGENT
+
+ AGT
)}
- {cfg.label && (
-
- {cfg.label}
+ {label && (
+
+ {label.text}
)}
-
+ {/* Mobile: relative time. Desktop: full time */}
+
+ {timeAgo(message.created_at)}
+
+
{new Date(message.created_at).toLocaleTimeString("en-US", {
- hour12: false,
- hour: "2-digit",
- minute: "2-digit",
- second: "2-digit",
+ hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit",
})}
-
+
#{Number(message.seq)}
+ {/* Reply — always visible on mobile (no hover), hover on desktop */}
{/* Content */}
-
+
{isDeleted ? (
-
- [deleted]
-
+ [deleted]
) : (
message.content
)}
- {/* Agent metadata strip */}
+ {/* Agent metadata — tap to expand on mobile, always compact on desktop */}
{meta && isAgent && (
-
- {meta.model &&
{meta.model}}
- {meta.hostname &&
{meta.hostname}}
- {meta.cwd &&
{meta.cwd}}
- {meta.skill && (
-
- {meta.skill}
-
+ <>
+ {/* Desktop: inline strip */}
+
+ {meta.model && {meta.model}}
+ {meta.hostname && {meta.hostname}}
+ {meta.cwd && {meta.cwd}}
+ {meta.skill && {meta.skill}}
+
+ {/* Mobile: tap to expand */}
+
+ {metaOpen && (
+
+ {meta.model &&
model: {meta.model}
}
+ {meta.hostname &&
host: {meta.hostname}
}
+ {meta.cwd &&
cwd: {meta.cwd}
}
+ {meta.skill &&
skill: {meta.skill}
}
+
)}
-
+ >
)}