Skip to content

Commit

Permalink
styles: mega visual polish-apalooza (#731)
Browse files Browse the repository at this point in the history
Co-authored-by: Mic Neale <[email protected]>
  • Loading branch information
nahiyankhan and michaelneale authored Jan 24, 2025
1 parent 8855920 commit 23cf9f4
Show file tree
Hide file tree
Showing 39 changed files with 1,181 additions and 851 deletions.
20 changes: 7 additions & 13 deletions ui/desktop/index.html
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Goose</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
rel="stylesheet"
/>
<link href="/src/styles/main.css" rel="stylesheet" />
</head>
<script>
// On page load or when changing themes, best to add inline in `head` to avoid FOUC
const useSystemTheme = localStorage.getItem("use_system_theme") === "true";
const savedTheme = localStorage.getItem("theme");
const useSystemTheme = localStorage.getItem('use_system_theme') === 'true';
const savedTheme = localStorage.getItem('theme');

document.documentElement.classList.toggle(
"dark",
'dark',
useSystemTheme
? window.matchMedia("(prefers-color-scheme: dark)").matches
: savedTheme === "dark"
? window.matchMedia('(prefers-color-scheme: dark)').matches
: savedTheme === 'dark'
);
</script>
<body>
<div id="root" class="inter-app-type"></div>
<div id="root"></div>
<script type="module" src="/src/renderer.tsx"></script>
</body>
</html>
116 changes: 58 additions & 58 deletions ui/desktop/src/ChatWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,75 +233,75 @@ export function ChatContent({
};

return (
<div className="chat-content flex flex-col w-full h-screen items-center justify-center">
<div className="relative flex items-center h-[36px] w-full">
<div className="flex flex-col w-full h-screen items-center justify-center">
<div className="relative flex items-center h-[36px] w-full bg-bgSubtle border-b border-borderSubtle">
<MoreMenu />
</div>
<Card className="flex flex-col flex-1 rounded-none h-[calc(100vh-95px)] w-full bg-card-gradient dark:bg-dark-card-gradient mt-0 border-none relative">
<Card className="flex flex-col flex-1 rounded-none h-[calc(100vh-95px)] w-full bg-bgApp mt-0 border-none relative">
{messages.length === 0 ? (
<Splash append={append} />
) : (
<ScrollArea className="flex-1 px-[10px]" id="chat-scroll-area">
<div className="pt-4">
{messages.map((message) => (
<div key={message.id}>
{message.role === 'user' ? (
<UserMessage message={message} />
) : (
<GooseMessage
message={message}
messages={messages}
metadata={messageMetadata[message.id]}
append={append}
/>
)}
<ScrollArea className="flex-1 px-4" id="chat-scroll-area">
{messages.map((message) => (
<div key={message.id} className="mt-[16px]">
{message.role === 'user' ? (
<UserMessage message={message} />
) : (
<GooseMessage
message={message}
messages={messages}
metadata={messageMetadata[message.id]}
append={append}
/>
)}
</div>
))}
{/* {isLoading && (
<div className="flex items-center justify-center p-4">
<div onClick={() => setShowGame(true)} style={{ cursor: 'pointer' }}>
</div>
))}
{isLoading && (
<div className="flex items-center justify-center p-4">
<div onClick={() => setShowGame(true)} style={{ cursor: 'pointer' }}>
<LoadingGoose />
</div>
</div>
)} */}
{error && (
<div className="flex flex-col items-center justify-center p-4">
<div className="text-red-700 dark:text-red-300 bg-red-400/50 p-3 rounded-lg mb-2">
{error.message || 'Honk! Goose experienced an error while responding'}
{error.status && <span className="ml-2">(Status: {error.status})</span>}
</div>
)}
{error && (
<div className="flex flex-col items-center justify-center p-4">
<div className="text-red-700 dark:text-red-300 bg-red-400/50 p-3 rounded-lg mb-2">
{error.message || 'Honk! Goose experienced an error while responding'}
{error.status && <span className="ml-2">(Status: {error.status})</span>}
</div>
<div
className="p-4 text-center text-splash-pills-text whitespace-nowrap cursor-pointer bg-prev-goose-gradient dark:bg-dark-prev-goose-gradient text-prev-goose-text dark:text-prev-goose-text-dark rounded-[14px] inline-block hover:scale-[1.02] transition-all duration-150"
onClick={async () => {
const lastUserMessage = messages.reduceRight(
(found, m) => found || (m.role === 'user' ? m : null),
null
);
if (lastUserMessage) {
append({
role: 'user',
content: lastUserMessage.content,
});
}
}}
>
Retry Last Message
</div>
<div
className="px-3 py-2 mt-2 text-center whitespace-nowrap cursor-pointer text-textStandard border border-borderSubtle hover:bg-bgSubtle rounded-full inline-block transition-all duration-150"
onClick={async () => {
const lastUserMessage = messages.reduceRight(
(found, m) => found || (m.role === 'user' ? m : null),
null
);
if (lastUserMessage) {
append({
role: 'user',
content: lastUserMessage.content,
});
}
}}
>
Retry Last Message
</div>
)}
<div ref={messagesEndRef} style={{ height: '1px' }} />
</div>
<div className="block h-10" />
</div>
)}
<div className="block h-16" />
<div ref={messagesEndRef} style={{ height: '1px' }} />
</ScrollArea>
)}

<Input
handleSubmit={handleSubmit}
disabled={isLoading}
isLoading={isLoading}
onStop={onStopGoose}
/>
<BottomMenu hasMessages={hasMessages} />
<div className="relative">
{isLoading && <LoadingGoose />}
<Input
handleSubmit={handleSubmit}
disabled={isLoading}
isLoading={isLoading}
onStop={onStopGoose}
/>
<BottomMenu hasMessages={hasMessages} />
</div>
</Card>

{showGame && <FlappyGoose onClose={() => setShowGame(false)} />}
Expand Down
30 changes: 16 additions & 14 deletions ui/desktop/src/components/BottomMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { useState, useEffect, useRef } from 'react';
import { useModel } from './settings/models/ModelContext';
import { useRecentModels } from './settings/models/RecentModels'; // Hook for recent models
import { ChevronUp, ChevronDown, Sliders } from 'lucide-react';
import { Sliders } from 'lucide-react';
import { ModelRadioList } from './settings/models/ModelRadioList';
import { useNavigate } from 'react-router-dom';
import { Document, ChevronUp, ChevronDown } from './icons';

export default function BottomMenu({ hasMessages }) {
const [isModelMenuOpen, setIsModelMenuOpen] = useState(false);
Expand Down Expand Up @@ -47,10 +48,10 @@ export default function BottomMenu({ hasMessages }) {
}, [isModelMenuOpen]);

return (
<div className="flex justify-between relative border-t dark:border-gray-700 text-bottom-menu dark:text-bottom-menu-dark pl-[15px] text-[10px] h-[30px] leading-[30px] align-middle bg-bottom-menu-background dark:bg-bottom-menu-background-dark rounded-b-2xl">
<div className="flex justify-between items-center text-textSubtle relative bg-bgSubtle border-t border-borderSubtle text-xs pl-4 h-[40px] pb-1 align-middle">
{/* Directory Chooser - Always visible */}
<span
className="cursor-pointer"
className="cursor-pointer flex items-center [&>svg]:size-4"
onClick={async () => {
console.log('Opening directory chooser');
if (hasMessages) {
Expand All @@ -60,7 +61,9 @@ export default function BottomMenu({ hasMessages }) {
}
}}
>
<Document className="mr-1" />
Working in {window.appConfig.get('GOOSE_WORKING_DIR')}
<ChevronUp className="ml-1" />
</span>

{/* Model Selector Dropdown - Only in development */}
Expand All @@ -71,28 +74,27 @@ export default function BottomMenu({ hasMessages }) {
>
<span>{currentModel?.name || 'Select Model'}</span>
{isModelMenuOpen ? (
<ChevronUp className="w-4 h-4 ml-1" />
) : (
<ChevronDown className="w-4 h-4 ml-1" />
) : (
<ChevronUp className="w-4 h-4 ml-1" />
)}
</div>

{/* Dropdown Menu */}
{isModelMenuOpen && (
<div className="absolute bottom-[30px] right-0 w-[300px] bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-lg shadow-lg">
<div className="p-2">
<div className="absolute bottom-[24px] right-0 w-[300px] bg-bgApp rounded-lg border border-borderSubtle">
<div className="">
<ModelRadioList
className="divide-y divide-gray-100 dark:divide-gray-700"
className="divide-y divide-borderSubtle"
renderItem={({ model, isSelected, onSelect }) => (
<label key={model.name} className="block cursor-pointer">
<div
className="flex items-center justify-between p-3 transition-colors
hover:text-gray-900 dark:hover:text-white"
className="flex items-center justify-between p-2 text-textStandard hover:bg-bgSubtle transition-colors"
onClick={onSelect}
>
<div>
<p className="text-sm font-semibold">{model.name}</p>
<p className="text-xs text-muted-foreground">{model.provider}</p>
<p className="text-sm ">{model.name}</p>
<p className="text-xs text-textSubtle">{model.provider}</p>
</div>
<div className="relative">
<input
Expand All @@ -115,8 +117,8 @@ export default function BottomMenu({ hasMessages }) {
)}
/>
<div
className="flex items-center justify-between p-3 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700
border-t-2 border-gray-200 dark:border-gray-600"
className="flex items-center justify-between text-textStandard p-2 cursor-pointer hover:bg-bgStandard
border-t border-borderSubtle mt-2"
onClick={() => {
setIsModelMenuOpen(false);
navigate('/settings');
Expand Down
27 changes: 27 additions & 0 deletions ui/desktop/src/components/GooseLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { Goose, Rain } from './icons/Goose';

export default function GooseLogo({ className = '', size = 'default', hover = true }) {
const sizes = {
default: {
frame: 'w-16 h-16',
rain: 'w-[275px] h-[275px]',
goose: 'w-16 h-16',
},
small: {
frame: 'w-8 h-8',
rain: 'w-[150px] h-[150px]',
goose: 'w-8 h-8',
},
};
return (
<div
className={`${className} ${sizes[size].frame} ${hover ? 'group/with-hover' : ''} relative overflow-hidden`}
>
<Rain
className={`${sizes[size].rain} absolute left-0 bottom-0 ${hover ? 'opacity-0 opacity-0 group-hover/with-hover:opacity-100' : ''} transition-all duration-300 z-1`}
/>
<Goose className={`${sizes[size].goose} absolute left-0 bottom-0 z-2`} />
</div>
);
}
47 changes: 26 additions & 21 deletions ui/desktop/src/components/GooseMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,38 @@ export default function GooseMessage({ message, metadata, messages, append }: Go
const urls = !message.toolInvocations ? extractUrls(message.content, previousUrls) : [];

return (
<div className="flex justify-start mb-[16px]">
<div className="flex-col w-[90%]">
<div className="flex flex-col bg-goose-bubble dark:bg-goose-bubble-dark rounded-2xl p-4">
{message.content && <MarkdownContent content={message.content} />}
{message.toolInvocations && (
<div className="mt-1">
<ToolInvocations toolInvocations={message.toolInvocations} />
</div>
)}
</div>

{urls.length > 0 && (
<div className="flex flex-wrap mt-[16px]">
{urls.map((url, index) => (
<LinkPreview key={index} url={url} />
))}
<div className="goose-message flex w-[90%] justify-start opacity-0 animate-[appear_150ms_ease-in_forwards]">
<div className="flex flex-col w-full">
{message.content && (
<div
className={`goose-message-content bg-bgSubtle rounded-2xl px-4 py-2 ${message.toolInvocations ? 'rounded-b-none' : ''}`}
>
<MarkdownContent content={message.content} />
</div>
)}

{/* enable or disable prompts here */}
{/* NOTE from alexhancock on 1/14/2025 - disabling again temporarily due to non-determinism in when the forms show up */}
{false && metadata && (
<div className="flex mt-[16px]">
<GooseResponseForm message={message.content} metadata={metadata} append={append} />
{message.toolInvocations && (
<div className="goose-message-tool bg-bgApp border border-borderSubtle rounded-b-2xl px-4 pt-4 pb-2 mt-1">
<ToolInvocations toolInvocations={message.toolInvocations} />
</div>
)}
</div>

{urls.length > 0 && (
<div className="flex flex-wrap mt-[16px]">
{urls.map((url, index) => (
<LinkPreview key={index} url={url} />
))}
</div>
)}

{/* enable or disable prompts here */}
{/* NOTE from alexhancock on 1/14/2025 - disabling again temporarily due to non-determinism in when the forms show up */}
{false && metadata && (
<div className="flex mt-[16px]">
<GooseResponseForm message={message.content} metadata={metadata} append={append} />
</div>
)}
</div>
);
}
Loading

0 comments on commit 23cf9f4

Please sign in to comment.