feat: styling changes for viewing sessions (#1974)

This commit is contained in:
Salman Mohammed
2025-04-01 12:51:34 -04:00
committed by GitHub
parent 2e5d879cb9
commit 759d6368e5
5 changed files with 135 additions and 85 deletions

View File

@@ -1,9 +1,19 @@
import React, { useState, useEffect } from 'react';
import { Clock, MessageSquare, Folder, Share, Copy, Check, LoaderCircle } from 'lucide-react';
import {
Calendar,
MessageSquareText,
Folder,
Share2,
Sparkles,
Copy,
Check,
Target,
LoaderCircle,
} from 'lucide-react';
import { type SessionDetails } from '../../sessions';
import { SessionHeaderCard, SessionMessages } from './SessionViewComponents';
import { SessionHeaderCard, SessionMessages, formatDate } from './SessionViewComponents';
import { createSharedSession } from '../../sharedSessions';
import { Modal, ModalContent, ModalHeader, ModalTitle, ModalFooter } from '../ui/modal';
import { Modal, ModalContent } from '../ui/modal';
import { Button } from '../ui/button';
import { toast } from 'react-toastify';
@@ -107,27 +117,30 @@ const SessionHistoryView: React.FC<SessionHistoryViewProps> = ({
<SessionHeaderCard onBack={onBack}>
{/* Session info row */}
<div className="ml-8">
<h1 className="text-lg font-bold text-textStandard">
<h1 className="text-lg text-textStandardInverse">
{session.metadata.description || session.session_id}
</h1>
<div className="flex items-center text-sm text-textSubtle mt-2 space-x-4">
<div className="flex items-center text-sm text-textSubtle mt-1 space-x-5">
<span className="flex items-center">
<Clock className="w-4 h-4 mr-1" />
{new Date(session.messages[0]?.created * 1000).toLocaleString()}
<Calendar className="w-4 h-4 mr-1" />
{formatDate(session.messages[0]?.created)}
</span>
<span className="flex items-center">
<MessageSquareText className="w-4 h-4 mr-1" />
{session.metadata.message_count}
</span>
{session.metadata.total_tokens !== null && (
<span className="flex items-center">
<Target className="w-4 h-4 mr-1" />
{session.metadata.total_tokens.toLocaleString()}
</span>
)}
</div>
<div className="flex items-center text-sm text-textSubtle space-x-5">
<span className="flex items-center">
<Folder className="w-4 h-4 mr-1" />
{session.metadata.working_dir}
</span>
<span className="flex items-center">
<MessageSquare className="w-4 h-4 mr-1" />
{session.metadata.message_count} messages
</span>
{session.metadata.total_tokens !== null && (
<span className="flex items-center">
{session.metadata.total_tokens.toLocaleString()} tokens
</span>
)}
</div>
</div>
@@ -135,30 +148,30 @@ const SessionHistoryView: React.FC<SessionHistoryViewProps> = ({
<button
onClick={handleShare}
disabled={!canShare || isSharing}
className={`flex items-center text-textStandard px-3 py-1 border rounded-md ${
className={`flex items-center text-textStandardInverse px-2 py-1 ${
canShare
? 'border-primary hover:text-primary hover:font-bold hover:scale-105 transition-all duration-150'
: 'border-gray-300 cursor-not-allowed opacity-50'
? 'hover:font-bold hover:scale-110 transition-all duration-150'
: 'cursor-not-allowed opacity-50'
}`}
>
{isSharing ? (
<>
<LoaderCircle className="w-5 h-5 animate-spin mr-2" />
<LoaderCircle className="w-7 h-7 animate-spin mr-2" />
<span>Sharing...</span>
</>
) : (
<>
<Share className="w-5 h-5" />
<Share2 className="w-7 h-7" />
</>
)}
</button>
<span
<button
onClick={onResume}
className="text-md cursor-pointer text-textStandard hover:font-bold hover:scale-105 transition-all duration-150"
className="flex items-center text-textStandardInverse px-2 py-1 hover:font-bold hover:scale-110 transition-all duration-150"
>
Resume Session
</span>
<Sparkles className="w-7 h-7" />
</button>
</div>
</SessionHeaderCard>
@@ -171,18 +184,31 @@ const SessionHistoryView: React.FC<SessionHistoryViewProps> = ({
{/* Share Link Modal */}
<Modal open={isShareModalOpen} onOpenChange={setIsShareModalOpen}>
<ModalContent className="sm:max-w-md dark:bg-black">
<ModalHeader>
<ModalTitle className="text-textStandard">Share Session</ModalTitle>
</ModalHeader>
<div className="flex flex-col gap-2 mt-2">
<div className="flex items-center gap-2">
<div className="flex-1 p-2 rounded-md overflow-x-auto">
<code className="text-sm text-textStandard">{shareLink}</code>
<ModalContent className="sm:max-w-md p-0 bg-bgApp dark:bg-bgApp dark:border-borderSubtle">
{/* Share Icon */}
<div className="flex justify-center mt-4">
<Share2 className="w-6 h-6 text-textStandard" />
</div>
{/* Centered Title */}
<div className="mt-2 px-6 text-center">
<h2 className="text-lg font-semibold text-textStandard">Share Session (beta)</h2>
</div>
{/* Description & Link */}
<div className="px-6 flex flex-col gap-4 mt-2">
<p className="text-sm text-center text-textSubtle">
Share this session link to give others a read only view of your goose chat.
</p>
<div className="relative rounded-lg border border-borderSubtle px-3 py-2 flex items-center bg-gray-100 dark:bg-gray-600">
<code className="text-sm text-textStandard dark:text-textStandardInverse overflow-x-hidden break-all pr-8 w-full">
{shareLink}
</code>
<Button
size="sm"
className="flex-shrink-0"
size="icon"
variant="ghost"
className="absolute right-2 top-1/2 -translate-y-1/2"
onClick={handleCopyLink}
disabled={isCopied}
>
@@ -190,22 +216,19 @@ const SessionHistoryView: React.FC<SessionHistoryViewProps> = ({
<span className="sr-only">Copy</span>
</Button>
</div>
<p className="text-sm text-textSubtle">
Share this link with others to give them access to this session.
<br />
They will need to have Goose installed and session sharing configured.
</p>
</div>
<ModalFooter className="sm:justify-start">
{/* Footer */}
<div>
<Button
type="button"
variant="ghost"
onClick={() => setIsShareModalOpen(false)}
className="hover:text-textStandard border border-borderSubtle text-textStandard hover:bg-bgSubtle"
className="w-full h-[60px] border-t rounded-b-lg dark:border-gray-600 text-lg text-textStandard hover:bg-gray-100 hover:dark:bg-gray-600"
>
Close
Cancel
</Button>
</ModalFooter>
</div>
</ModalContent>
</Modal>
</div>

View File

@@ -1,7 +1,8 @@
import React, { useEffect, useState } from 'react';
import { ViewConfig } from '../../App';
import {
MessageSquare,
MessageSquareText,
Target,
LoaderCircle,
AlertCircle,
Calendar,
@@ -46,7 +47,7 @@ const SessionListView: React.FC<SessionListViewProps> = ({ setView, onSelectSess
// Format date to be more readable
// eg. "10:39 PM, Feb 28, 2025"
const formatDate = (dateString: string) => {
const formatDateString = (dateString: string) => {
try {
const date = new Date(dateString);
const time = new Intl.DateTimeFormat('en-US', {
@@ -114,7 +115,7 @@ const SessionListView: React.FC<SessionListViewProps> = ({ setView, onSelectSess
<div className="flex gap-3">
<div className="flex items-center text-textSubtle text-sm">
<Calendar className="w-3 h-3 mr-1 flex-shrink-0" />
<span className="truncate">{formatDate(session.modified)}</span>
<span className="truncate">{formatDateString(session.modified)}</span>
</div>
<div className="flex items-center text-textSubtle text-sm">
<Folder className="w-3 h-3 mr-1 flex-shrink-0" />
@@ -130,12 +131,13 @@ const SessionListView: React.FC<SessionListViewProps> = ({ setView, onSelectSess
</div>
<div className="flex items-center mt-1 space-x-3 text-sm text-textSubtle">
<div className="flex items-center">
<MessageSquare className="w-3 h-3 mr-1" />
<MessageSquareText className="w-3 h-3 mr-1" />
<span>{session.metadata.message_count}</span>
</div>
{session.metadata.total_tokens !== null && (
<div className="flex items-center">
<span>{session.metadata.total_tokens.toLocaleString()} tokens</span>
<Target className="w-3 h-3 mr-1" />
<span>{session.metadata.total_tokens.toLocaleString()}</span>
</div>
)}
</div>
@@ -148,7 +150,7 @@ const SessionListView: React.FC<SessionListViewProps> = ({ setView, onSelectSess
</div>
) : (
<div className="flex flex-col items-center justify-center h-full text-textSubtle">
<MessageSquare className="h-12 w-12 mb-4" />
<MessageSquareText className="h-12 w-12 mb-4" />
<p className="text-lg mb-2">No chat sessions found</p>
<p className="text-sm">Your chat history will appear here</p>
</div>

View File

@@ -9,6 +9,31 @@ import ToolCallWithResponse from '../ToolCallWithResponse';
import { ToolRequestMessageContent, ToolResponseMessageContent } from '../../types/message';
import { type Message } from '../../types/message';
/**
* Format a timestamp into a human-readable date string
*/
export const formatDate = (timestamp: number) => {
const date = new Date(timestamp * 1000);
const getOrdinal = (n: number) => {
const s = ['th', 'st', 'nd', 'rd'];
const v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
};
const hours = date.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true,
});
const month = date.toLocaleString('en-US', { month: 'short' });
const day = getOrdinal(date.getDate());
const year = date.getFullYear();
return `${hours}, ${month} ${day}, ${year}`;
};
/**
* Get tool responses map from messages
*/
@@ -50,8 +75,13 @@ export interface SessionHeaderCardProps {
*/
export const SessionHeaderCard: React.FC<SessionHeaderCardProps> = ({ onBack, children }) => {
return (
<Card className="px-8 pt-6 pb-4 bg-bgSecondary flex items-center">
<BackButton showText={false} onClick={onBack} className="text-textStandard" />
<Card className="rounded-none px-8 pt-6 pb-4 bg-bgAppInverse text-textProminentInverse flex items-center">
<BackButton
showText={false}
onClick={onBack}
iconSize="w-7 h-7"
className="text-textProminentInverse hover:text-textProminentInverse"
/>
{children}
</Card>
);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Clock, Globe, MessageSquare, Folder } from 'lucide-react';
import { Calendar, MessageSquareText, Folder, Target } from 'lucide-react';
import { type SharedSessionDetails } from '../../sharedSessions';
import { SessionHeaderCard, SessionMessages } from './SessionViewComponents';
import { SessionHeaderCard, SessionMessages, formatDate } from './SessionViewComponents';
interface SharedSessionViewProps {
session: SharedSessionDetails | null;
@@ -20,44 +20,37 @@ const SharedSessionView: React.FC<SharedSessionViewProps> = ({
}) => {
return (
<div className="h-screen w-full">
<div className="relative flex items-center h-[36px] w-full bg-bgSubtle"></div>
<div className="relative flex items-center h-[36px] w-full"></div>
{/* Top Row - back, info (fixed) */}
<SessionHeaderCard onBack={onBack}>
{/* Session info row */}
<div className="ml-8">
<h1 className="text-lg font-bold text-textStandard">
<h1 className="text-lg text-textStandardInverse">
{session ? session.description : 'Shared Session'}
</h1>
{session && (
<div className="flex items-center text-sm text-textSubtle mt-2 space-x-4">
<div className="flex items-center text-sm text-textSubtle mt-1 space-x-5">
<span className="flex items-center">
<Clock className="w-4 h-4 mr-1" />
{new Date(session.messages[0]?.created * 1000).toLocaleString()}
<Calendar className="w-4 h-4 mr-1" />
{formatDate(session.messages[0]?.created)}
</span>
{/* <span className="flex items-center">
<Globe className="w-4 h-4 mr-1" />
{session.base_url}
</span> */}
<span className="flex items-center">
<MessageSquare className="w-4 h-4 mr-1" />
{session.message_count} messages
<MessageSquareText className="w-4 h-4 mr-1" />
{session.message_count}
</span>
{session.total_tokens !== null && (
<span className="flex items-center">
{session.total_tokens.toLocaleString()} tokens
<Target className="w-4 h-4 mr-1" />
{session.total_tokens.toLocaleString()}
</span>
)}
</div>
)}
{session && (
<div className="flex items-center text-sm text-textSubtle mt-1">
<div className="flex items-center text-sm text-textSubtle space-x-5">
<span className="flex items-center">
<Folder className="w-4 h-4 mr-1" />
{session.working_dir}
</span>
</div>
)}
</div>
</SessionHeaderCard>

View File

@@ -5,6 +5,7 @@ interface BackButtonProps {
onClick?: () => void; // Mark onClick as optional
className?: string;
textSize?: 'sm' | 'base' | 'md' | 'lg';
iconSize?: 'w-3 h-3' | 'w-4 h-4' | 'w-5 h-5' | 'w-6 h-6' | 'w-7 h-7';
showText?: boolean; // Add new prop
}
@@ -12,6 +13,7 @@ const BackButton: React.FC<BackButtonProps> = ({
onClick,
className = '',
textSize = 'sm',
iconSize = 'w-3 h-3',
showText = true,
}) => {
const handleExit = () => {
@@ -29,7 +31,7 @@ const BackButton: React.FC<BackButtonProps> = ({
onClick={handleExit}
className={`flex items-center text-${textSize} text-textSubtle group hover:text-textStandard ${className}`}
>
<Back className="w-3 h-3 group-hover:-translate-x-1 transition-all mr-1" />
<Back className={`${iconSize} group-hover:-translate-x-1 transition-all mr-1`} />
{showText && <span>Exit</span>}
</button>
);