feat: markdown rendering + font size slider
- Chat messages now render full markdown via Obsidian's MarkdownRenderer (headers, bold, italic, code blocks, lists, links) - Streaming shows plain text, swaps to rendered markdown on completion - User messages render instantly as markdown - New Chat font size slider in plugin settings (10-24px, default 14) - Live-applies via CSS custom property --hermes-chat-font-size - No restart needed
This commit is contained in:
parent
16fb2238dd
commit
695a8e0050
5 changed files with 45 additions and 14 deletions
16
main.js
16
main.js
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
|||
import { ItemView, WorkspaceLeaf, MarkdownView } from "obsidian";
|
||||
import { ItemView, WorkspaceLeaf, MarkdownView, MarkdownRenderer } from "obsidian";
|
||||
import type { Message, ChatState, ChatCompletionResponse, SlashCommand } from "./types";
|
||||
import { ContextBridge } from "./context-bridge";
|
||||
|
||||
|
|
@ -192,8 +192,13 @@ export class ChatView extends ItemView {
|
|||
this.slashCommands = commands;
|
||||
}
|
||||
|
||||
/** Set chat font size via CSS custom property on the container. */
|
||||
setChatFontSize(size: number): void {
|
||||
this.containerEl.style.setProperty("--hermes-chat-font-size", `${size}px`);
|
||||
}
|
||||
|
||||
/** Append a message bubble to the chat display and scroll to bottom. */
|
||||
appendMessage(role: "user" | "assistant" | "system", content: string): void {
|
||||
async appendMessage(role: "user" | "assistant" | "system", content: string): Promise<void> {
|
||||
if (!this.messagesContainer) return;
|
||||
|
||||
const wrapper = this.messagesContainer.createDiv("chat-message");
|
||||
|
|
@ -205,7 +210,7 @@ export class ChatView extends ItemView {
|
|||
);
|
||||
|
||||
const contentEl = wrapper.createDiv("chat-message-content");
|
||||
contentEl.setText(content);
|
||||
await MarkdownRenderer.render(this.app, content, contentEl, "", this);
|
||||
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
|
@ -399,11 +404,11 @@ export class ChatView extends ItemView {
|
|||
const userInput = this.resolveSlashCommand(rawInput);
|
||||
|
||||
// Display user message (show the resolved prompt, not the /trigger)
|
||||
this.appendMessage("user", userInput);
|
||||
await this.appendMessage("user", userInput);
|
||||
|
||||
// Check API client availability
|
||||
if (!this.apiClient) {
|
||||
this.appendMessage(
|
||||
await this.appendMessage(
|
||||
"assistant",
|
||||
"[API client not configured. Check plugin settings.]"
|
||||
);
|
||||
|
|
@ -461,6 +466,12 @@ export class ChatView extends ItemView {
|
|||
}
|
||||
);
|
||||
|
||||
// Replace streaming plain text with rendered markdown
|
||||
if (contentDiv) {
|
||||
contentDiv.empty();
|
||||
await MarkdownRenderer.render(this.app, fullContent, contentDiv, "", this);
|
||||
}
|
||||
|
||||
if (response.sessionId) {
|
||||
this.chatState.sessionId = response.sessionId;
|
||||
this.updateStatus(response.model, response.sessionId);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export default class HermesChatPlugin extends Plugin {
|
|||
const view = new ChatView(leaf, client, this.contextBridge!);
|
||||
view.setContextActive(this.settings.enableContextInjection);
|
||||
view.setSlashCommands(this.getAllCommands());
|
||||
view.setChatFontSize(this.settings.chatFontSize);
|
||||
return view;
|
||||
}
|
||||
);
|
||||
|
|
@ -147,6 +148,7 @@ export default class HermesChatPlugin extends Plugin {
|
|||
if (leaf.view instanceof ChatView) {
|
||||
leaf.view.setContextActive(this.settings.enableContextInjection);
|
||||
leaf.view.setSlashCommands(commands);
|
||||
leaf.view.setChatFontSize(this.settings.chatFontSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export interface HermesChatSettings {
|
|||
apiKey: string;
|
||||
showModelInfo: boolean;
|
||||
enableContextInjection: boolean;
|
||||
chatFontSize: number;
|
||||
customCommands: { trigger: string; description: string; prompt: string }[];
|
||||
}
|
||||
|
||||
|
|
@ -33,6 +34,7 @@ export const DEFAULT_SETTINGS: HermesChatSettings = {
|
|||
apiKey: "0f224b188b52e8728d135ec339f8db8dfbf82d89a60021dcfe20d91c6174cf9b",
|
||||
showModelInfo: true,
|
||||
enableContextInjection: true,
|
||||
chatFontSize: 14,
|
||||
customCommands: [],
|
||||
};
|
||||
|
||||
|
|
@ -101,6 +103,20 @@ export class HermesChatSettingTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Chat font size")
|
||||
.setDesc("Font size for chat messages and input (10—24 px)")
|
||||
.addSlider((slider) =>
|
||||
slider
|
||||
.setLimits(10, 24, 1)
|
||||
.setValue(this.plugin.settings.chatFontSize)
|
||||
.setDynamicTooltip()
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.chatFontSize = value;
|
||||
await this.plugin.saveData(this.plugin.settings);
|
||||
})
|
||||
);
|
||||
|
||||
// --- Slash commands ---
|
||||
containerEl.createEl("h3", { text: "Slash Commands" });
|
||||
containerEl.createEl("p", {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
--hermes-chat-font-size: 14px;
|
||||
}
|
||||
|
||||
/* --- Message list --- */
|
||||
|
|
@ -45,6 +46,7 @@
|
|||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
color: var(--text-normal);
|
||||
font-size: var(--hermes-chat-font-size);
|
||||
}
|
||||
|
||||
/* --- Loading indicator --- */
|
||||
|
|
@ -74,7 +76,7 @@
|
|||
max-height: 120px;
|
||||
padding: 0.5rem;
|
||||
font-family: inherit;
|
||||
font-size: 0.9rem;
|
||||
font-size: var(--hermes-chat-font-size);
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue