fix: improve styling of messsges

This commit is contained in:
Dan Ditomaso
2025-01-29 16:08:55 -05:00
parent c7e2baea1b
commit d9ad044ecd
5 changed files with 100 additions and 94 deletions

View File

@@ -8,6 +8,7 @@ import { MessageInput } from "@components/PageComponents/Messages/MessageInput.t
import { TraceRoute } from "@components/PageComponents/Messages/TraceRoute.tsx";
import type { Protobuf, Types } from "@meshtastic/js";
import { InboxIcon } from "lucide-react";
import type { JSX } from "react";
export interface ChannelChatProps {
messages?: MessageWithState[];
@@ -16,6 +17,13 @@ export interface ChannelChatProps {
traceroutes?: Types.PacketMetadata<Protobuf.Mesh.RouteDiscovery>[];
}
const EmptyState = () => (
<div className="flex flex-col place-content-center place-items-center p-8 text-white">
<InboxIcon className="h-8 w-8 mb-2" />
<span className="text-sm">No Messages</span>
</div>
);
export const ChannelChat = ({
messages,
channel,
@@ -24,53 +32,53 @@ export const ChannelChat = ({
}: ChannelChatProps): JSX.Element => {
const { nodes } = useDevice();
if (!messages?.length) {
return (
<>
<div className="flex place-content-center place-items-center h-full">
<EmptyState />
</div>
<div className="mt-auto pb-4 w-full">
<MessageInput to={to} channel={channel} />
</div>
</>
);
}
return (
<div className="flex flex-grow flex-col">
<div className="flex flex-grow">
<div className="flex flex-grow flex-col">
{messages ? (
messages.map((message, index) => (
<Message
key={message.id}
message={message}
lastMsgSameUser={
index === 0
? false
: messages[index - 1].from === message.from
}
sender={nodes.get(message.from)}
/>
))
) : (
<div className="m-auto">
<InboxIcon className="m-auto" />
<Subtle>No Messages</Subtle>
</div>
)}
<>
<div className="flex flex-col h-full">
<div className="w-full">
{messages.map((message, index) => (
<Message
key={message.id}
message={message}
lastMsgSameUser={
index > 0 && messages[index - 1].from === message.from
}
sender={nodes.get(message.from)}
/>
))}
</div>
<div
className={`flex flex-grow flex-col border-slate-400 border-l ${traceroutes === undefined ? "hidden" : ""}`}
>
{to === "broadcast" ? null : traceroutes ? (
traceroutes.map((traceroute, index) => (
<TraceRoute
key={traceroute.id}
from={nodes.get(traceroute.from)}
to={nodes.get(traceroute.to)}
route={traceroute.data.route}
/>
))
) : (
<div className="m-auto">
<InboxIcon className="m-auto" />
<Subtle>No Traceroutes</Subtle>
</div>
)}
<div className="mt-auto pb-4 w-full">
<MessageInput to={to} channel={channel} />
</div>
</div>
<div className="pl-3 pr-3 pt-3 pb-1">
<MessageInput to={to} channel={channel} />
</div>
</div>
{/* {to === "broadcast" ? null : traceroutes ? (
traceroutes.map((traceroute, index) => (
<TraceRoute
key={traceroute.id}
from={nodes.get(traceroute.from)}
to={nodes.get(traceroute.to)}
route={traceroute.data.route}
/>
))
) : (
<div className="m-auto">
<InboxIcon className="m-auto" />
<Subtle>No Traceroutes</Subtle>
</div>
)} */}
</>
);
};

View File

@@ -1,11 +1,7 @@
import type { MessageWithState } from "@app/core/stores/deviceStore.ts";
import { Avatar } from "@components/UI/Avatar";
import type { Protobuf } from "@meshtastic/js";
import {
AlertCircleIcon,
CheckCircle2Icon,
CircleEllipsisIcon,
} from "lucide-react";
import { AlertCircle, CheckCircle2, CircleEllipsis } from "lucide-react";
export interface MessageProps {
lastMsgSameUser: boolean;
@@ -13,61 +9,62 @@ export interface MessageProps {
sender?: Protobuf.Mesh.NodeInfo;
}
const StatusIcon = ({ state }: { state: MessageWithState["state"] }) => {
const iconClass = "text-gray-500 dark:text-gray-400 w-4 h-4";
switch (state) {
case "ack":
return <CheckCircle2 className={iconClass} />;
case "waiting":
return <CircleEllipsis className={iconClass} />;
default:
return <AlertCircle className={iconClass} />;
}
};
export const Message = ({ lastMsgSameUser, message, sender }: MessageProps) => {
return lastMsgSameUser ? (
<div className="ml-5 flex">
{message.state === "ack" ? (
<CheckCircle2Icon size={16} className="my-auto text-textSecondary" />
) : message.state === "waiting" ? (
<CircleEllipsisIcon size={16} className="my-auto text-textSecondary" />
) : (
<AlertCircleIcon size={16} className="my-auto text-textSecondary" />
)}
<span
className={`ml-4 border-l-2 border-l-backgroundPrimary pl-2 ${
message.state === "ack" ? "text-textPrimary" : "text-textSecondary"
}`}
>
{message.data}
</span>
</div>
) : (
<div className="mx-4 mt-2 gap-2">
<div className="flex gap-2">
<div className="w-6 cursor-pointer">
<Avatar text={sender?.user?.shortName ?? "UNK"} />
const messageTextClass =
message.state === "ack"
? "text-gray-900 dark:text-white"
: "text-gray-500 dark:text-gray-400";
if (lastMsgSameUser) {
return (
<div className="mx-4 mt-2">
<div className="ml-12 flex items-start gap-2">
<div
className={`${messageTextClass} border-l-2 border-gray-200 dark:border-gray-700 pl-4 flex-grow`}
>
{message.data}
</div>
<StatusIcon state={message.state} />
</div>
<span className="cursor-pointer font-medium text-textPrimary">
</div>
);
}
return (
<div className="mx-4 mt-2 space-y-2">
<div className="flex items-center gap-2">
<Avatar text={sender?.user?.shortName ?? "UNK"} />
<span className="font-medium text-gray-900 dark:text-white">
{sender?.user?.longName ?? "UNK"}
</span>
<span className="mt-1 font-mono text-xs text-textSecondary">
<span className="text-xs text-gray-500 dark:text-gray-400 font-mono">
{message.rxTime.toLocaleDateString()}
</span>
<span className="mt-1 font-mono text-xs text-textSecondary">
<span className="text-xs text-gray-500 dark:text-gray-400 font-mono">
{message.rxTime.toLocaleTimeString(undefined, {
hour: "2-digit",
minute: "2-digit",
})}
</span>
</div>
<div className="ml-1 flex">
{message.state === "ack" ? (
<CheckCircle2Icon size={16} className="my-auto text-textSecondary" />
) : message.state === "waiting" ? (
<CircleEllipsisIcon
size={16}
className="my-auto text-textSecondary"
/>
) : (
<AlertCircleIcon size={16} className="my-auto text-textSecondary" />
)}
<span
className={`ml-4 border-l-2 border-l-backgroundPrimary pl-2 ${
message.state === "ack" ? "text-textPrimary" : "text-textSecondary"
}`}
<div className="ml-12 flex items-start gap-2">
<div
className={`${messageTextClass} border-l-2 border-gray-200 dark:border-gray-700 pl-4 flex-grow`}
>
{message.data}
</span>
</div>
<StatusIcon state={message.state} />
</div>
</div>
);

View File

@@ -4,7 +4,7 @@ import { Input } from "@components/UI/Input.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import type { Types } from "@meshtastic/js";
import { SendIcon } from "lucide-react";
import { useCallback, useMemo, useState } from "react";
import { type JSX, useCallback, useMemo, useState } from "react";
export interface MessageInputProps {
to: Types.Destination;

View File

@@ -6,7 +6,7 @@ const Footer = React.forwardRef<HTMLElement, FooterProps>(
({ className, ...props }, ref) => {
return (
<footer
className={`flex flex- justify-center p-2 ${className}`}
className={`flex mt-auto justify-center p-2 ${className}`}
style={{
backgroundColor: "var(--backgroundPrimary)",
color: "var(--textPrimary)",

View File

@@ -1,5 +1,6 @@
import { Button } from "@components/UI/Button.tsx";
import type { LucideIcon } from "lucide-react";
import type { JSX } from "react";
export interface SidebarButtonProps {
label: string;
@@ -20,10 +21,10 @@ export const SidebarButton = ({
onClick={onClick}
variant={active ? "subtle" : "ghost"}
size="sm"
className="w-full justify-start gap-2"
className="flex gap-2"
>
{Icon && <Icon size={16} />}
{element && element}
{label}
<span className="flex flex-1 justify-start flex-shrink-0">{label}</span>
</Button>
);