mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-07-05 01:11:32 +02:00
Add better preview pane and tweak some themes for contrast
This commit is contained in:
@@ -94,15 +94,23 @@ export function ChatHeader({
|
||||
onSetChannelFloodScopeOverride(conversation.id, nextValue);
|
||||
};
|
||||
|
||||
const handleOpenConversationInfo = () => {
|
||||
if (conversation.type === 'contact' && onOpenContactInfo) {
|
||||
onOpenContactInfo(conversation.id);
|
||||
return;
|
||||
}
|
||||
if (conversation.type === 'channel' && onOpenChannelInfo) {
|
||||
onOpenChannelInfo(conversation.id);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="conversation-header flex justify-between items-start px-4 py-2.5 border-b border-border gap-2">
|
||||
<span className="flex min-w-0 flex-1 items-start gap-2">
|
||||
{conversation.type === 'contact' && onOpenContactInfo && (
|
||||
<span
|
||||
className="flex-shrink-0 cursor-pointer"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onKeyDown={handleKeyboardActivate}
|
||||
<button
|
||||
type="button"
|
||||
className="avatar-action-button flex-shrink-0 cursor-pointer rounded-full border-none bg-transparent p-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
onClick={() => onOpenContactInfo(conversation.id)}
|
||||
title="View contact info"
|
||||
aria-label={`View info for ${conversation.name}`}
|
||||
@@ -114,42 +122,41 @@ export function ChatHeader({
|
||||
contactType={contacts.find((c) => c.public_key === conversation.id)?.type}
|
||||
clickable
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
<span className="flex min-w-0 flex-1 flex-col">
|
||||
<span className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5">
|
||||
<span className="flex min-w-0 flex-1 items-baseline gap-2">
|
||||
<h2
|
||||
className={`flex shrink min-w-0 items-center gap-1.5 font-semibold text-base ${titleClickable ? 'cursor-pointer hover:text-primary transition-colors' : ''}`}
|
||||
role={titleClickable ? 'button' : undefined}
|
||||
tabIndex={titleClickable ? 0 : undefined}
|
||||
aria-label={titleClickable ? `View info for ${conversation.name}` : undefined}
|
||||
onKeyDown={titleClickable ? handleKeyboardActivate : undefined}
|
||||
onClick={
|
||||
titleClickable
|
||||
? () => {
|
||||
if (conversation.type === 'contact' && onOpenContactInfo) {
|
||||
onOpenContactInfo(conversation.id);
|
||||
} else if (conversation.type === 'channel' && onOpenChannelInfo) {
|
||||
onOpenChannelInfo(conversation.id);
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<span className="truncate">
|
||||
{conversation.type === 'channel' &&
|
||||
!conversation.name.startsWith('#') &&
|
||||
activeChannel?.is_hashtag
|
||||
? '#'
|
||||
: ''}
|
||||
{conversation.name}
|
||||
</span>
|
||||
{titleClickable && (
|
||||
<Info
|
||||
className="h-3.5 w-3.5 flex-shrink-0 text-muted-foreground/80"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<h2 className="min-w-0 flex-1 font-semibold text-base">
|
||||
{titleClickable ? (
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-w-0 shrink items-center gap-1.5 text-left hover:text-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm"
|
||||
aria-label={`View info for ${conversation.name}`}
|
||||
onClick={handleOpenConversationInfo}
|
||||
>
|
||||
<span className="truncate">
|
||||
{conversation.type === 'channel' &&
|
||||
!conversation.name.startsWith('#') &&
|
||||
activeChannel?.is_hashtag
|
||||
? '#'
|
||||
: ''}
|
||||
{conversation.name}
|
||||
</span>
|
||||
<Info
|
||||
className="h-3.5 w-3.5 flex-shrink-0 text-muted-foreground/80"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
) : (
|
||||
<span className="truncate">
|
||||
{conversation.type === 'channel' &&
|
||||
!conversation.name.startsWith('#') &&
|
||||
activeChannel?.is_hashtag
|
||||
? '#'
|
||||
: ''}
|
||||
{conversation.name}
|
||||
</span>
|
||||
)}
|
||||
</h2>
|
||||
{isPrivateChannel && !showKey ? (
|
||||
|
||||
@@ -606,6 +606,10 @@ export function MessageList({
|
||||
(avatarName ? `name:${avatarName}` : `message:${msg.id}`);
|
||||
}
|
||||
}
|
||||
const avatarActionLabel =
|
||||
avatarName && avatarName !== 'Unknown'
|
||||
? `View info for ${avatarName}`
|
||||
: `View info for ${avatarKey.slice(0, 12)}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -619,26 +623,33 @@ export function MessageList({
|
||||
>
|
||||
{!msg.outgoing && (
|
||||
<div className="w-10 flex-shrink-0 flex items-start pt-0.5">
|
||||
{showAvatar && avatarKey && (
|
||||
<span
|
||||
role={onOpenContactInfo ? 'button' : undefined}
|
||||
tabIndex={onOpenContactInfo ? 0 : undefined}
|
||||
onKeyDown={onOpenContactInfo ? handleKeyboardActivate : undefined}
|
||||
onClick={
|
||||
onOpenContactInfo
|
||||
? () => onOpenContactInfo(avatarKey, msg.type === 'CHAN')
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<ContactAvatar
|
||||
name={avatarName}
|
||||
publicKey={avatarKey}
|
||||
size={32}
|
||||
clickable={!!onOpenContactInfo}
|
||||
variant={avatarVariant}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{showAvatar &&
|
||||
avatarKey &&
|
||||
(onOpenContactInfo ? (
|
||||
<button
|
||||
type="button"
|
||||
className="avatar-action-button rounded-full border-none bg-transparent p-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
aria-label={avatarActionLabel}
|
||||
onClick={() => onOpenContactInfo(avatarKey, msg.type === 'CHAN')}
|
||||
>
|
||||
<ContactAvatar
|
||||
name={avatarName}
|
||||
publicKey={avatarKey}
|
||||
size={32}
|
||||
clickable
|
||||
variant={avatarVariant}
|
||||
/>
|
||||
</button>
|
||||
) : (
|
||||
<span>
|
||||
<ContactAvatar
|
||||
name={avatarName}
|
||||
publicKey={avatarKey}
|
||||
size={32}
|
||||
variant={avatarVariant}
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
LockOpen,
|
||||
Logs,
|
||||
Map,
|
||||
Search as SearchIcon,
|
||||
Sparkles,
|
||||
SquarePen,
|
||||
Waypoints,
|
||||
X,
|
||||
@@ -533,7 +533,7 @@ export function Sidebar({
|
||||
renderSidebarActionRow({
|
||||
key: 'tool-raw',
|
||||
active: isActive('raw', 'raw'),
|
||||
icon: <Waypoints className="h-4 w-4" />,
|
||||
icon: <Logs className="h-4 w-4" />,
|
||||
label: 'Packet Feed',
|
||||
onClick: () =>
|
||||
handleSelectConversation({
|
||||
@@ -557,7 +557,7 @@ export function Sidebar({
|
||||
renderSidebarActionRow({
|
||||
key: 'tool-visualizer',
|
||||
active: isActive('visualizer', 'visualizer'),
|
||||
icon: <Sparkles className="h-4 w-4" />,
|
||||
icon: <Waypoints className="h-4 w-4" />,
|
||||
label: 'Mesh Visualizer',
|
||||
onClick: () =>
|
||||
handleSelectConversation({
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { Logs, MessageSquare } from 'lucide-react';
|
||||
import { Input } from '../ui/input';
|
||||
import { Label } from '../ui/label';
|
||||
import { Separator } from '../ui/separator';
|
||||
import { ContactAvatar } from '../ContactAvatar';
|
||||
import {
|
||||
captureLastViewedConversationFromHash,
|
||||
getReopenLastConversationEnabled,
|
||||
@@ -97,7 +99,7 @@ function ThemePreview({ className }: { className?: string }) {
|
||||
return (
|
||||
<div className={`rounded-lg border border-border bg-card p-3 ${className ?? ''}`}>
|
||||
<p className="text-xs text-muted-foreground mb-3">
|
||||
Preview alert and message contrast for the selected theme.
|
||||
Preview alert, message, sidebar, and badge contrast for the selected theme.
|
||||
</p>
|
||||
|
||||
<div className="space-y-2">
|
||||
@@ -125,6 +127,42 @@ function ThemePreview({ className }: { className?: string }) {
|
||||
text="Hi there! I'm using RemoteTerm."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 rounded-md border border-border bg-background p-2">
|
||||
<p className="mb-2 text-[11px] font-medium text-muted-foreground">Sidebar preview</p>
|
||||
<div className="space-y-1">
|
||||
<PreviewSidebarRow
|
||||
active
|
||||
leading={
|
||||
<span
|
||||
className="flex h-6 w-6 items-center justify-center rounded-md bg-primary/10 text-primary"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Logs className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
}
|
||||
label="Packet Feed"
|
||||
/>
|
||||
<PreviewSidebarRow
|
||||
leading={<ContactAvatar name="Alice" publicKey={'ab'.repeat(32)} size={24} />}
|
||||
label="Alice"
|
||||
badge={
|
||||
<span className="rounded-full bg-badge-unread/90 px-1.5 py-0.5 text-[10px] font-semibold text-badge-unread-foreground">
|
||||
3
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<PreviewSidebarRow
|
||||
leading={<ContactAvatar name="Mesh Ops" publicKey={'cd'.repeat(32)} size={24} />}
|
||||
label="Mesh Ops"
|
||||
badge={
|
||||
<span className="rounded-full bg-badge-mention px-1.5 py-0.5 text-[10px] font-semibold text-badge-mention-foreground">
|
||||
@2
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -153,3 +191,34 @@ function PreviewMessage({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PreviewSidebarRow({
|
||||
leading,
|
||||
label,
|
||||
badge,
|
||||
active = false,
|
||||
}: {
|
||||
leading: React.ReactNode;
|
||||
label: string;
|
||||
badge?: React.ReactNode;
|
||||
active?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center gap-2 rounded-md border-l-2 px-3 py-2 text-[13px] ${
|
||||
active ? 'border-l-primary bg-accent text-foreground' : 'border-l-transparent'
|
||||
}`}
|
||||
>
|
||||
{leading}
|
||||
<span className={`min-w-0 flex-1 truncate ${active ? 'font-medium' : 'text-foreground'}`}>
|
||||
{label}
|
||||
</span>
|
||||
{badge}
|
||||
{!badge && (
|
||||
<span className="text-muted-foreground" aria-hidden="true">
|
||||
<MessageSquare className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user