Skip to content

Commit 478bfb2

Browse files
feat: enhance README and chat components with new features and UI improvements
- Updated README with new screenshots and highlights of features including document and image uploads, keyboard shortcuts, and error handling. - Improved UI consistency in chat components with adjusted padding and margins for better layout. - Enhanced file upload component styling for a more polished appearance. - Added tips section in README for user guidance on document and image attachments.
1 parent f32f32e commit 478bfb2

File tree

6 files changed

+45
-17
lines changed

6 files changed

+45
-17
lines changed

README.md

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,39 @@ Chatbot Ollama is an open source chat UI for Ollama.
66

77
This project is based on [chatbot-ui](https://github.com/mckaywrigley/chatbot-ui) by [Mckay Wrigley](https://github.com/mckaywrigley).
88

9-
![Chatbot Ollama](./public/screenshots/screenshot-2023-10-02.png)
9+
![Chatbot Ollama – Dark](./public/screenshots/screenshot-2025-09-dark.png)
10+
11+
![Chatbot Ollama – Light](./public/screenshots/screenshot-2025-09-light.png)
12+
13+
> If the image does not render, place the new screenshot at `public/screenshots/screenshot-2025-09-dark.png` (light version optional at `public/screenshots/screenshot-2025-09-light.png`).
14+
15+
## Highlights (new)
16+
17+
- Blue theme polished for light and dark modes with consistent sidebars, headers, and overlays.
18+
- Document upload (PDF, TXT, MD):
19+
- PDFs parsed server‑side for reliability; text/markdown read client‑side.
20+
- The full (truncated) content is attached invisibly to the model prompt — the UI stays clean.
21+
- 50 MB size cap, 100 page cap (PDF), 50k characters per attachment.
22+
- Image upload: attach images and send them to vision‑capable models (base64). Non‑vision models simply ignore images.
23+
- Code blocks: copy button, language label, optional line numbers, line‑wrap toggle, and “download as file”.
24+
- Streaming & control: Stop Generation button, auto‑scroll toggle (pause/resume when you scroll up).
25+
- Keyboard shortcuts:
26+
- Enter to send, Shift+Enter for newline
27+
- Esc to blur input
28+
- Ctrl/Cmd+L clears the composer
29+
- Arrow Up recalls the last user message
30+
- Error handling: a consistent toast shows details, Copy details, and Retry.
31+
- Conversation tools: Copy messages button copies the whole visible conversation (with role labels and any attached content).
32+
- Sidebar UX: search inputs are theme‑aware, prompts list matches chat list styling, improved hover/selection.
1033

1134
## Updates
1235

1336
Chatbot Ollama will be updated over time.
1437

1538
### Next up
1639

17-
- [ ] pull a model
18-
- [ ] delete a model
19-
- [ ] show model information
40+
- [ ] Model management (pull/delete)
41+
- [ ] Model info/details dialog
2042

2143
## Docker
2244

@@ -73,6 +95,12 @@ npm run dev
7395

7496
You should be able to start chatting.
7597

98+
### Tips
99+
100+
- Attach documents via the paper icon in the composer — the content is included for the model invisibly so the chat stays uncluttered.
101+
- Attach an image with the camera icon — vision models will “see” it; others will ignore it.
102+
- Use the clipboard icon in the sticky header to copy the current conversation.
103+
76104
## Configuration
77105

78106
When deploying the application, the following environment variables can be set:

components/Chat/Chat.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ export const Chat = memo(({ stopConversationRef }: Props) => {
523523
</>
524524
) : (
525525
<>
526-
<div className="sticky top-0 z-10 flex justify-center items-center gap-3 bg-white/80 dark:bg-[#0e1728]/80 backdrop-blur-lg border-b border-gray-200 dark:border-[#1b2a4a] py-3 px-4 text-sm text-gray-600 dark:text-gray-300 shadow-sm">
526+
<div className="sticky top-0 z-10 flex justify-center items-center gap-3 bg-white/80 dark:bg-[#0e1728]/80 backdrop-blur-lg border-b border-gray-200 dark:border-[#1b2a4a] py-2 px-3 text-sm text-gray-600 dark:text-gray-300 shadow-sm">
527527
<div className="flex items-center gap-2">
528528
<span className="font-medium">{t('Model')}:</span>
529529
<span className="text-primary-600 dark:text-primary-400 font-semibold">{selectedConversation?.model.name}</span>
@@ -577,7 +577,7 @@ export const Chat = memo(({ stopConversationRef }: Props) => {
577577
</div>
578578
)}
579579

580-
<div className="space-y-4 py-4">
580+
<div className="space-y-3 py-2">
581581
{selectedConversation?.messages.map((message, index) => (
582582
<MemoizedChatMessage
583583
key={index}

components/Chat/ChatInput.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ export const ChatInput = ({
361361
}, []);
362362

363363
return (
364-
<div className="absolute bottom-0 left-0 w-full border-transparent bg-gradient-to-b from-transparent via-white/90 to-white/90 pt-6 dark:border-white/20 dark:via-[#0e1728]/90 dark:to-[#0e1728]/90 md:pt-2 backdrop-blur-sm">
364+
<div className="absolute bottom-0 left-0 w-full border-transparent bg-gradient-to-b from-transparent via-white/90 to-white/90 pt-3 dark:border-white/20 dark:via-[#0e1728]/90 dark:to-[#0e1728]/90 md:pt-2 backdrop-blur-sm">
365365
<div className="stretch mx-2 mt-4 flex flex-row gap-3 last:mb-2 md:mx-4 md:mt-[52px] md:last:mb-6 lg:mx-auto lg:max-w-3xl">
366366
{messageIsStreaming && (
367367
<button
@@ -470,7 +470,7 @@ export const ChatInput = ({
470470
)}
471471

472472
{showFileUpload && (
473-
<div className="absolute bottom-12 w-full px-1">
473+
<div className="absolute bottom-12 left-1/2 -translate-x-1/2 w-[min(92vw,720px)] px-3 z-40">
474474
<FileUpload
475475
onFileSelect={handleFileSelect}
476476
onFileRemove={() => setSelectedFile(null)}
@@ -488,7 +488,7 @@ export const ChatInput = ({
488488
)}
489489

490490
{showImageUpload && (
491-
<div className="absolute bottom-24 w-full px-1">
491+
<div className="absolute bottom-12 left-1/2 -translate-x-1/2 w-[min(92vw,720px)] px-3 z-40">
492492
<FileUpload
493493
onFileSelect={async (file) => {
494494
// basic image validation

components/Chat/ChatLoader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const ChatLoader: FC<Props> = () => {
99
className="group border-b border-gray-200 bg-gray-50/90 text-gray-800 dark:border-[#1b2a4a] dark:bg-[#0f1d35]/95 dark:text-gray-100"
1010
style={{ overflowWrap: 'anywhere' }}
1111
>
12-
<div className="m-auto flex gap-4 p-4 text-base md:max-w-2xl md:gap-6 md:py-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl">
12+
<div className="m-auto flex gap-3 p-3 text-base md:max-w-2xl md:gap-4 md:py-4 lg:max-w-2xl lg:px-0 xl:max-w-3xl">
1313
<div className="min-w-[40px] items-end">
1414
<div className="flex h-8 w-8 items-center justify-center rounded-md bg-gradient-to-r from-purple-500/70 to-blue-500/70 text-white">
1515
<IconRobot size={20} stroke={2.5} />

components/Chat/ChatMessage.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,14 @@ export const ChatMessage: FC<Props> = memo(({ message, messageIndex, onEdit }) =
138138
}`}
139139
style={{ overflowWrap: 'anywhere' }}
140140
>
141-
<div className="relative m-auto flex p-4 text-base md:max-w-2xl md:gap-6 md:py-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl">
141+
<div className="relative m-auto flex p-3 text-base md:max-w-2xl md:gap-4 md:py-4 lg:max-w-2xl lg:px-0 xl:max-w-3xl">
142142
<div className="min-w-[40px] text-right">
143143
{message.role === 'assistant' ? (
144-
<div className="flex h-10 w-10 items-center justify-center rounded-2xl bg-gradient-to-br from-primary-500 to-accent-purple text-white shadow-card hover:shadow-hover transition-all duration-200 group-hover:scale-105">
144+
<div className="flex h-9 w-9 items-center justify-center rounded-2xl bg-gradient-to-br from-primary-500 to-accent-purple text-white shadow-card hover:shadow-hover transition-all duration-200 group-hover:scale-105">
145145
<IconRobot size={20} stroke={2} />
146146
</div>
147147
) : (
148-
<div className="flex h-10 w-10 items-center justify-center rounded-2xl bg-gradient-to-br from-accent-green to-accent-blue text-white shadow-card hover:shadow-hover transition-all duration-200 group-hover:scale-105">
148+
<div className="flex h-9 w-9 items-center justify-center rounded-2xl bg-gradient-to-br from-accent-green to-accent-blue text-white shadow-card hover:shadow-hover transition-all duration-200 group-hover:scale-105">
149149
<IconUser size={20} stroke={2} />
150150
</div>
151151
)}
@@ -158,7 +158,7 @@ export const ChatMessage: FC<Props> = memo(({ message, messageIndex, onEdit }) =
158158
<div className="flex w-full flex-col">
159159
<textarea
160160
ref={textareaRef}
161-
className="w-full resize-none whitespace-pre-wrap border-2 border-gray-200 dark:border-gray-600 rounded-xl bg-white dark:bg-gray-800 focus:ring-2 focus:ring-primary-500 focus:border-primary-500 p-4 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 transition-all duration-200"
161+
className="w-full resize-none whitespace-pre-wrap border-2 border-gray-200 dark:border-gray-600 rounded-xl bg-white dark:bg-gray-800 focus:ring-2 focus:ring-primary-500 focus:border-primary-500 p-3 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 transition-all duration-200"
162162
value={messageContent}
163163
onChange={handleInputChange}
164164
onKeyDown={handlePressEnter}
@@ -173,7 +173,7 @@ export const ChatMessage: FC<Props> = memo(({ message, messageIndex, onEdit }) =
173173
}}
174174
/>
175175

176-
<div className="mt-6 flex justify-center space-x-3">
176+
<div className="mt-4 flex justify-center space-x-3">
177177
<button
178178
className="px-6 py-2 rounded-xl bg-primary-600 hover:bg-primary-700 text-white font-medium transition-all duration-200 shadow-card hover:shadow-hover disabled:opacity-50 disabled:cursor-not-allowed"
179179
onClick={handleEditMessage}

components/FileUpload/FileUpload.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ export const FileUpload: FC<Props> = ({
9898
<div className="relative">
9999
{!selectedFile ? (
100100
<div
101-
className={`border-2 border-dashed rounded-lg p-6 text-center transition-colors ${
101+
className={`border-2 border-dashed rounded-xl p-6 text-center transition-colors shadow-card ${
102102
isDragging
103103
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
104-
: 'border-neutral-300 dark:border-neutral-600 hover:border-neutral-400 dark:hover:border-neutral-500'
104+
: 'border-blue-200 bg-white dark:border-[#1b2a4a] dark:bg-[#0f1d35]'
105105
}`}
106106
onDrop={handleDrop}
107107
onDragOver={handleDragOver}

0 commit comments

Comments
 (0)