feat: add Ollama icon and modern chat UI styling
- src/chat-view.ts: Add getIcon() returning 'bot' for the view tab icon.
Improve render() with role-specific CSS classes (user vs assistant) and
message header structure for better styling hooks.
- src/main.ts: Add ribbon icon ('bot') in the left sidebar that opens the
chat view with a single click.
- styles.css (new): Modern chat UI with message bubbles, distinct user and
assistant themes using Obsidian CSS variables, sticky input bar, styled
send button with accent color, and emoji role indicators.
- install.sh: Copy styles.css into the plugin directory and verify its
presence during installation.
- README.md: Include styles.css in manual install instructions.
- __mocks__/obsidian.ts: Add addRibbonIcon() mock for test compatibility.
- tests/chat-view.test.ts: Add getIcon() assertion.
This commit is contained in:
+26
-13
@@ -76,6 +76,10 @@ export class ChatView extends ItemView {
|
||||
return 'Ollama Chat';
|
||||
}
|
||||
|
||||
getIcon(): string {
|
||||
return 'bot';
|
||||
}
|
||||
|
||||
async onOpen(): Promise<void> {
|
||||
try {
|
||||
await this.ollamaClient.initializeCache();
|
||||
@@ -145,9 +149,14 @@ export class ChatView extends ItemView {
|
||||
contentEl.textContent = msg.content;
|
||||
}
|
||||
} else {
|
||||
const messageEl = container.createEl('div', { cls: 'ollama-message' });
|
||||
const messageEl = container.createEl('div', {
|
||||
cls: `ollama-message ollama-message-${msg.role}`,
|
||||
});
|
||||
messageEl.setAttribute('data-msg-id', msg.id);
|
||||
messageEl.createEl('div', { cls: 'ollama-message-role', text: msg.role });
|
||||
|
||||
const headerEl = messageEl.createEl('div', { cls: 'ollama-message-header' });
|
||||
headerEl.createEl('span', { cls: 'ollama-message-role', text: msg.role });
|
||||
|
||||
const contentEl = messageEl.createEl('div', { cls: 'ollama-message-content' });
|
||||
contentEl.textContent = msg.content;
|
||||
}
|
||||
@@ -366,15 +375,15 @@ export class ChatView extends ItemView {
|
||||
): Promise<void> {
|
||||
const toolResults = (
|
||||
await Promise.all(
|
||||
toolCalls.slice(0, MAX_TOOL_CALLS).map(async (toolCall) => {
|
||||
try {
|
||||
const toolResult = await this.toolExecutor.handleToolCall(toolCall);
|
||||
return { ...toolResult, id: toolCall.id };
|
||||
} catch (error) {
|
||||
ErrorHandler.handleError(error, 'ChatView.handleUserInput');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
toolCalls.slice(0, MAX_TOOL_CALLS).map(async (toolCall) => {
|
||||
try {
|
||||
const toolResult = await this.toolExecutor.handleToolCall(toolCall);
|
||||
return { ...toolResult, id: toolCall.id };
|
||||
} catch (error) {
|
||||
ErrorHandler.handleError(error, 'ChatView.handleUserInput');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
)
|
||||
).filter((result): result is NonNullable<typeof result> => result !== null);
|
||||
|
||||
@@ -449,7 +458,10 @@ export class ChatView extends ItemView {
|
||||
}
|
||||
|
||||
try {
|
||||
const entries = await this.vaultIndexer.searchVault(userMessage, this.settings.vaultSearchLimit);
|
||||
const entries = await this.vaultIndexer.searchVault(
|
||||
userMessage,
|
||||
this.settings.vaultSearchLimit
|
||||
);
|
||||
const context = entries
|
||||
.map((entry) => `${entry.title}\n${entry.content}`)
|
||||
.join('\n\n')
|
||||
@@ -459,7 +471,8 @@ export class ChatView extends ItemView {
|
||||
: userMessage;
|
||||
|
||||
// Get the complete messages array for the LLM with all context layers
|
||||
const completeMessages = this.conversationStateManager.getCompleteMessages(userMessageWithContext);
|
||||
const completeMessages =
|
||||
this.conversationStateManager.getCompleteMessages(userMessageWithContext);
|
||||
|
||||
const stream = this.ollamaClient.streamChat(completeMessages, tools);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user