feat: Story 11 - Left-align text and add syntax highlighting
Implemented Story 11: Text Alignment and Syntax Highlighting - Removed center-alignment from chat container (text-align: center) - Added left-alignment to markdown body and code blocks - Integrated react-syntax-highlighter with react-markdown - Added syntax highlighting for code blocks using oneDark theme - Supports JavaScript, TypeScript, Rust, Python, JSON, Markdown, Shell, and more - Inline code maintains simple styling without full highlighting - All code blocks are now left-aligned for better readability Fixed: Agent over-aggressive file writing behavior - Refined system prompt to distinguish between: * 'show/example/how does' → respond with code in chat * 'create/add/implement/fix' → use write_file tool - Removed aggressive AGENT DIRECTIVE prefix from user messages - Softened reminder message to reflect nuanced behavior - Agent can now both teach (show examples) and implement (write files) Updated Specs - Added Text Alignment and Readability section to UI_UX.md - Added Syntax Highlighting section with implementation details - Updated SDSW workflow: acceptance criteria marked complete only after user acceptance Dependencies - Added react-syntax-highlighter and @types/react-syntax-highlighter
This commit is contained in:
@@ -67,10 +67,15 @@ When the user asks for a feature, follow this 4-step loop strictly:
|
|||||||
### Step 4: Verification (Close)
|
### Step 4: Verification (Close)
|
||||||
* **Action:** Write a test case that maps directly to the Acceptance Criteria in the Story.
|
* **Action:** Write a test case that maps directly to the Acceptance Criteria in the Story.
|
||||||
* **Action:** Run compilation and make sure it succeeds without errors. Fix warnings if possible. Run tests and make sure they all pass before proceeding. Ask questions here if needed.
|
* **Action:** Run compilation and make sure it succeeds without errors. Fix warnings if possible. Run tests and make sure they all pass before proceeding. Ask questions here if needed.
|
||||||
* **Action:** Ask the user to accept the story.
|
* **Action:** Ask the user to accept the story. **Wait for user acceptance.**
|
||||||
* **Action:** When the user accepts, move the story file to `stories/archive/` (e.g., `mv stories/XX_story_name.md stories/archive/`).
|
* **Action:** When the user accepts:
|
||||||
* **Action:** Commit the archive move to the feature branch.
|
1. Mark the acceptance criteria as complete (change `[ ]` to `[x]`)
|
||||||
* **Action:** Tell the user to **Squash Merge** the feature branch (e.g., `git merge --squash feature/story-name`) and commit. This ensures the main history reflects one atomic commit per Story, including the archived story file.
|
2. Move the story file to `stories/archive/` (e.g., `mv stories/XX_story_name.md stories/archive/`)
|
||||||
|
3. Commit both changes to the feature branch
|
||||||
|
4. Perform the squash merge: `git merge --squash feature/story-name`
|
||||||
|
5. Commit to master with a comprehensive commit message
|
||||||
|
6. Delete the feature branch: `git branch -D feature/story-name`
|
||||||
|
* **Important:** Do NOT mark acceptance criteria as complete before user acceptance. Only mark them complete when the user explicitly accepts the story.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -82,3 +82,78 @@ Scroll bars should be hidden while maintaining full scroll functionality.
|
|||||||
* Maintain `overflow: auto` or `overflow-y: scroll` to preserve scroll functionality
|
* Maintain `overflow: auto` or `overflow-y: scroll` to preserve scroll functionality
|
||||||
* Ensure `overflow-x: hidden` where horizontal scroll is not needed
|
* Ensure `overflow-x: hidden` where horizontal scroll is not needed
|
||||||
* Test with very long messages and large tool outputs to ensure no layout breaking
|
* Test with very long messages and large tool outputs to ensure no layout breaking
|
||||||
|
|
||||||
|
## Text Alignment and Readability
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
Center-aligned text in a chat interface is unconventional and reduces readability, especially for code blocks and long-form content. Standard chat UIs align messages differently based on the sender.
|
||||||
|
|
||||||
|
### Solution: Context-Appropriate Text Alignment
|
||||||
|
Messages should follow standard chat UI conventions with proper alignment based on message type.
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
1. **User Messages:** Right-aligned (standard pattern showing messages sent by the user)
|
||||||
|
2. **Assistant Messages:** Left-aligned (standard pattern showing messages received)
|
||||||
|
3. **Tool Outputs:** Left-aligned (part of the system/assistant response flow)
|
||||||
|
4. **Code Blocks:** Always left-aligned regardless of message type (for readability)
|
||||||
|
5. **Container:** Remove any center-alignment from the chat container
|
||||||
|
6. **Max-Width:** Maintain current max-width constraint (e.g., 768px) for optimal readability
|
||||||
|
7. **Spacing:** Maintain proper padding and visual hierarchy between messages
|
||||||
|
|
||||||
|
### Implementation Notes
|
||||||
|
* Check for `textAlign: "center"` in inline styles and remove
|
||||||
|
* Check for `text-align: center` in CSS and remove from chat-related classes
|
||||||
|
* Ensure flexbox alignment is set appropriately:
|
||||||
|
* User messages: `alignItems: "flex-end"`
|
||||||
|
* Assistant/Tool messages: `alignItems: "flex-start"`
|
||||||
|
* Code blocks should have `text-align: left` explicitly set
|
||||||
|
|
||||||
|
## Syntax Highlighting
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
Code blocks in assistant responses currently lack syntax highlighting, making them harder to read and understand. Developers expect colored syntax highlighting similar to their code editors.
|
||||||
|
|
||||||
|
### Solution: Syntax Highlighting for Code Blocks
|
||||||
|
Integrate syntax highlighting into markdown code blocks rendered by the assistant.
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
1. **Languages Supported:** At minimum:
|
||||||
|
- JavaScript/TypeScript
|
||||||
|
- Rust
|
||||||
|
- Python
|
||||||
|
- JSON
|
||||||
|
- Markdown
|
||||||
|
- Shell/Bash
|
||||||
|
- HTML/CSS
|
||||||
|
- SQL
|
||||||
|
2. **Theme:** Use a dark theme that complements the existing dark UI (e.g., `oneDark`, `vsDark`, `dracula`)
|
||||||
|
3. **Integration:** Work seamlessly with `react-markdown` component
|
||||||
|
4. **Performance:** Should not significantly impact rendering performance
|
||||||
|
5. **Fallback:** Plain monospace text for unrecognized languages
|
||||||
|
6. **Inline Code:** Inline code (single backticks) should maintain simple styling without full syntax highlighting
|
||||||
|
|
||||||
|
### Implementation Notes
|
||||||
|
* Use `react-syntax-highlighter` library with `react-markdown`
|
||||||
|
* Or use `rehype-highlight` plugin for `react-markdown`
|
||||||
|
* Configure with a dark theme preset (e.g., `oneDark` from `react-syntax-highlighter/dist/esm/styles/prism`)
|
||||||
|
* Apply to code blocks via `react-markdown` components prop:
|
||||||
|
```tsx
|
||||||
|
<Markdown
|
||||||
|
components={{
|
||||||
|
code: ({node, inline, className, children, ...props}) => {
|
||||||
|
const match = /language-(\w+)/.exec(className || '');
|
||||||
|
return !inline && match ? (
|
||||||
|
<SyntaxHighlighter style={oneDark} language={match[1]} {...props}>
|
||||||
|
{String(children).replace(/\n$/, '')}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
) : (
|
||||||
|
<code className={className} {...props}>{children}</code>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
* Ensure syntax highlighted code blocks are left-aligned
|
||||||
|
* Test with various code samples to ensure proper rendering
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
all text in the chat window is currently centred, which is weird especially for code. Make it more readable.
|
|
||||||
40
.living_spec/stories/archive/11_make_text_not_centred.md
Normal file
40
.living_spec/stories/archive/11_make_text_not_centred.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Story: Left-Align Chat Text and Add Syntax Highlighting
|
||||||
|
|
||||||
|
## User Story
|
||||||
|
**As a** User
|
||||||
|
**I want** chat messages and code to be left-aligned instead of centered, with proper syntax highlighting for code blocks
|
||||||
|
**So that** the text is more readable, follows standard chat UI conventions, and code is easier to understand.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
* [x] User messages should be right-aligned (standard chat pattern)
|
||||||
|
* [x] Assistant messages should be left-aligned
|
||||||
|
* [x] Tool outputs should be left-aligned
|
||||||
|
* [x] Code blocks and monospace text should be left-aligned
|
||||||
|
* [x] Remove any center-alignment styling from the chat container
|
||||||
|
* [x] Maintain the current max-width constraint for readability
|
||||||
|
* [x] Ensure proper spacing and padding for visual hierarchy
|
||||||
|
* [x] Add syntax highlighting for code blocks in assistant messages
|
||||||
|
* [x] Support common languages: JavaScript, TypeScript, Rust, Python, JSON, Markdown, Shell, etc.
|
||||||
|
* [x] Syntax highlighting should work with the dark theme
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
* Redesigning the entire chat layout
|
||||||
|
* Adding avatars or profile pictures
|
||||||
|
* Changing the overall color scheme or theme (syntax highlighting colors should complement existing dark theme)
|
||||||
|
* Custom themes for syntax highlighting
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
* Check `Chat.tsx` for any `textAlign: "center"` styles
|
||||||
|
* Check `App.css` for any center-alignment rules affecting the chat
|
||||||
|
* User messages should align to the right with appropriate styling
|
||||||
|
* Assistant and tool messages should align to the left
|
||||||
|
* Code blocks should always be left-aligned for readability
|
||||||
|
* For syntax highlighting, consider using:
|
||||||
|
* `react-syntax-highlighter` (works with react-markdown)
|
||||||
|
* Or `prism-react-renderer` for lighter bundle size
|
||||||
|
* Or integrate with `rehype-highlight` plugin for react-markdown
|
||||||
|
* Use a dark theme preset like `oneDark`, `vsDark`, or `dracula`
|
||||||
|
* Syntax highlighting should be applied to markdown code blocks automatically
|
||||||
|
|
||||||
|
## Related Functional Specs
|
||||||
|
* Functional Spec: UI/UX
|
||||||
5
HelloWorld.java
Normal file
5
HelloWorld.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
public class HelloWorld {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("Hello, World!");
|
||||||
|
}
|
||||||
|
}
|
||||||
14
package.json
14
package.json
@@ -15,21 +15,23 @@
|
|||||||
"@tauri-apps/plugin-dialog": "^2.4.2",
|
"@tauri-apps/plugin-dialog": "^2.4.2",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
"@tauri-apps/plugin-store": "^2.4.1",
|
"@tauri-apps/plugin-store": "^2.4.1",
|
||||||
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-markdown": "^10.1.0"
|
"react-markdown": "^10.1.0",
|
||||||
|
"react-syntax-highlighter": "^16.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2",
|
"@tauri-apps/cli": "^2",
|
||||||
|
"@testing-library/jest-dom": "^6.0.0",
|
||||||
|
"@testing-library/react": "^14.0.0",
|
||||||
|
"@testing-library/user-event": "^14.4.3",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^19.1.6",
|
"@types/react-dom": "^19.1.6",
|
||||||
"@vitejs/plugin-react": "^4.6.0",
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
"typescript": "~5.8.3",
|
|
||||||
"vite": "^7.0.4",
|
|
||||||
"jest": "^29.0.0",
|
"jest": "^29.0.0",
|
||||||
"ts-jest": "^29.0.0",
|
"ts-jest": "^29.0.0",
|
||||||
"@testing-library/react": "^14.0.0",
|
"typescript": "~5.8.3",
|
||||||
"@testing-library/jest-dom": "^6.0.0",
|
"vite": "^7.0.4"
|
||||||
"@testing-library/user-event": "^14.4.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2978
pnpm-lock.yaml
generated
2978
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -53,16 +53,6 @@ pub async fn chat(
|
|||||||
// 3. Agent Loop
|
// 3. Agent Loop
|
||||||
let mut current_history = messages.clone();
|
let mut current_history = messages.clone();
|
||||||
|
|
||||||
// Prefix user messages with reminder for stubborn models
|
|
||||||
for msg in &mut current_history {
|
|
||||||
if msg.role == Role::User && !msg.content.starts_with("[AGENT DIRECTIVE]") {
|
|
||||||
msg.content = format!(
|
|
||||||
"[AGENT DIRECTIVE: You must use write_file tool to implement changes. Never suggest code.]\n\n{}",
|
|
||||||
msg.content
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inject System Prompt
|
// Inject System Prompt
|
||||||
current_history.insert(
|
current_history.insert(
|
||||||
0,
|
0,
|
||||||
@@ -74,12 +64,12 @@ pub async fn chat(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Inject aggressive reminder as a second system message
|
// Inject reminder as a second system message
|
||||||
current_history.insert(
|
current_history.insert(
|
||||||
1,
|
1,
|
||||||
Message {
|
Message {
|
||||||
role: Role::System,
|
role: Role::System,
|
||||||
content: "CRITICAL REMINDER: When the user asks you to create, modify, or implement code, you MUST call the write_file tool with the complete file content. DO NOT output code in markdown blocks. DO NOT suggest what the user should do. TAKE ACTION IMMEDIATELY using tools.".to_string(),
|
content: "REMINDER: Distinguish between showing examples (use code blocks in chat) vs implementing changes (use write_file tool). Keywords like 'show me', 'example', 'how does' = chat response. Keywords like 'create', 'add', 'implement', 'fix' = use tools.".to_string(),
|
||||||
tool_calls: None,
|
tool_calls: None,
|
||||||
tool_call_id: None,
|
tool_call_id: None,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
pub const SYSTEM_PROMPT: &str = r#"You are an AI Agent with direct access to the user's filesystem and development environment.
|
pub const SYSTEM_PROMPT: &str = r#"You are an AI Agent with direct access to the user's filesystem and development environment.
|
||||||
|
|
||||||
CRITICAL INSTRUCTIONS:
|
CRITICAL INSTRUCTIONS:
|
||||||
1. **YOU ARE NOT A CHATBOT.** You do not suggest code or provide instructions for the user to follow.
|
1. **Distinguish Between Examples and Implementation:**
|
||||||
2. **YOU WRITE CODE DIRECTLY.** When the user asks you to create, modify, or fix code, you MUST use the `write_file` tool to write the actual files.
|
- If the user asks to "show", "give me an example", "how would I", or "what does X look like" → Respond with code in the chat
|
||||||
3. **DO NOT OUTPUT CODE BLOCKS.** Do not write code in markdown code blocks (```) for the user to copy. That is forbidden. Use tools instead.
|
- If the user asks to "create", "add", "implement", "write", "fix", "modify", or "update" → Use `write_file` tool
|
||||||
|
2. **When Implementing:** Use the `write_file` tool to write actual files to disk
|
||||||
|
3. **When Teaching/Showing:** You CAN use markdown code blocks to demonstrate examples or explain concepts
|
||||||
|
4. **Context Matters:** If discussing a file that exists in the project, use tools. If showing generic examples, use code blocks.
|
||||||
|
|
||||||
YOUR CAPABILITIES:
|
YOUR CAPABILITIES:
|
||||||
You have the following tools available:
|
You have the following tools available:
|
||||||
@@ -29,47 +32,60 @@ CRITICAL RULES:
|
|||||||
|
|
||||||
EXAMPLES OF CORRECT BEHAVIOR:
|
EXAMPLES OF CORRECT BEHAVIOR:
|
||||||
|
|
||||||
Example 1 - User asks to add a feature:
|
Example 1 - User asks for an EXAMPLE (show in chat):
|
||||||
|
User: "Show me a Java hello world"
|
||||||
|
You (correct): "Here's a simple Java hello world program:
|
||||||
|
```java
|
||||||
|
public class HelloWorld {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("Hello, World!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```"
|
||||||
|
|
||||||
|
Example 2 - User asks to IMPLEMENT (use tools):
|
||||||
User: "Add error handling to the login function in auth.rs"
|
User: "Add error handling to the login function in auth.rs"
|
||||||
You (correct): [Call read_file("src/auth.rs"), analyze it, then call write_file("src/auth.rs", <complete file with error handling>), then call exec_shell("cargo", ["check"])]
|
You (correct): [Call read_file("src/auth.rs"), analyze it, then call write_file("src/auth.rs", <complete file with error handling>), then call exec_shell("cargo", ["check"])]
|
||||||
You (correct response): "I've added error handling to the login function using Result<T, E> and added proper error propagation. The code compiles successfully."
|
You (correct response): "I've added error handling to the login function using Result<T, E> and added proper error propagation. The code compiles successfully."
|
||||||
|
|
||||||
Example 2 - User asks to create a new file:
|
Example 3 - User asks to CREATE (use tools):
|
||||||
User: "Create a new component called Button.tsx in the components folder"
|
User: "Create a new component called Button.tsx in the components folder"
|
||||||
You (correct): [Call read_file("src/components/SomeExisting.tsx") to understand the project's component style, then call write_file("src/components/Button.tsx", <complete component code>)]
|
You (correct): [Call read_file("src/components/SomeExisting.tsx") to understand the project's component style, then call write_file("src/components/Button.tsx", <complete component code>)]
|
||||||
You (correct response): "I've created Button.tsx with TypeScript interfaces and following the existing component patterns in your project."
|
You (correct response): "I've created Button.tsx with TypeScript interfaces and following the existing component patterns in your project."
|
||||||
|
|
||||||
Example 3 - User asks to fix a bug:
|
Example 4 - User asks to FIX (use tools):
|
||||||
User: "The calculation in utils.js is wrong"
|
User: "The calculation in utils.js is wrong"
|
||||||
You (correct): [Call read_file("src/utils.js"), identify the bug, call write_file("src/utils.js", <complete corrected file>), call exec_shell("npm", ["test"])]
|
You (correct): [Call read_file("src/utils.js"), identify the bug, call write_file("src/utils.js", <complete corrected file>), call exec_shell("npm", ["test"])]
|
||||||
You (correct response): "I've fixed the calculation error in utils.js. The formula now correctly handles edge cases and all tests pass."
|
You (correct response): "I've fixed the calculation error in utils.js. The formula now correctly handles edge cases and all tests pass."
|
||||||
|
|
||||||
EXAMPLES OF INCORRECT BEHAVIOR (DO NOT DO THIS):
|
EXAMPLES OF INCORRECT BEHAVIOR (DO NOT DO THIS):
|
||||||
|
|
||||||
Example 1 - Suggesting code instead of writing it:
|
Example 1 - Writing a file when user asks for an example:
|
||||||
User: "Add error handling to the login function"
|
User: "Show me a React component"
|
||||||
You (WRONG): "Here's how you can add error handling:
|
You (WRONG): [Calls write_file("Component.tsx", ...)]
|
||||||
```rust
|
You (CORRECT): Show the code in a markdown code block in the chat
|
||||||
fn login() -> Result<User, LoginError> {
|
|
||||||
// your code here
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Add this to your auth.rs file."
|
|
||||||
|
|
||||||
Example 2 - Writing partial code:
|
Example 2 - Suggesting code when user asks to implement:
|
||||||
|
User: "Add error handling to the login function"
|
||||||
|
You (WRONG): "Here's how you can add error handling: ```rust fn login() -> Result<User, LoginError> { ... } ``` Add this to your auth.rs file."
|
||||||
|
You (CORRECT): [Use read_file then write_file to actually implement it]
|
||||||
|
|
||||||
|
Example 3 - Writing partial code:
|
||||||
User: "Update the API endpoint"
|
User: "Update the API endpoint"
|
||||||
You (WRONG): [Calls write_file with content like "// ... existing imports\n\nfn new_endpoint() { }\n\n// ... rest of file"]
|
You (WRONG): [Calls write_file with content like "// ... existing imports\n\nfn new_endpoint() { }\n\n// ... rest of file"]
|
||||||
|
You (CORRECT): Read the file first, then write the COMPLETE file with all content
|
||||||
|
|
||||||
Example 3 - Asking for information you can discover:
|
Example 4 - Asking for information you can discover:
|
||||||
User: "Add a new route to the app"
|
User: "Add a new route to the app"
|
||||||
You (WRONG): "What file contains your routes?"
|
You (WRONG): "What file contains your routes?"
|
||||||
You (CORRECT): [Call search_files("route") or list_directory("src") to find the routing file yourself]
|
You (CORRECT): [Call search_files("route") or list_directory("src") to find the routing file yourself]
|
||||||
|
|
||||||
REMEMBER:
|
REMEMBER:
|
||||||
- You have the power to read and write files directly
|
- **Teaching vs Implementing:** Show examples in chat, implement changes with tools
|
||||||
- The user expects you to IMPLEMENT changes, not describe them
|
- **Keywords matter:** "show/example" = chat, "create/add/fix" = tools
|
||||||
- Always use write_file with complete file contents
|
- **Complete files:** Always write the COMPLETE file content when using write_file
|
||||||
- Verify your work with exec_shell when appropriate
|
- **Verify your work:** Use exec_shell to run tests/checks after implementing changes
|
||||||
|
- You have the power to both teach AND implement - use the right mode for the situation
|
||||||
|
|
||||||
Remember: You are an autonomous agent. Act, don't advise.
|
Remember: You are an autonomous agent that can both explain concepts and take action. Choose appropriately based on the user's request.
|
||||||
"#;
|
"#;
|
||||||
|
|||||||
17
src/App.css
17
src/App.css
@@ -27,7 +27,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
@@ -138,6 +137,7 @@ details summary span:first-child {
|
|||||||
/* Markdown body styling for dark theme */
|
/* Markdown body styling for dark theme */
|
||||||
.markdown-body {
|
.markdown-body {
|
||||||
color: #ececec;
|
color: #ececec;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-body code {
|
.markdown-body code {
|
||||||
@@ -152,6 +152,7 @@ details summary span:first-child {
|
|||||||
padding: 12px;
|
padding: 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-body pre code {
|
.markdown-body pre code {
|
||||||
@@ -159,6 +160,20 @@ details summary span:first-child {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Syntax highlighter styling */
|
||||||
|
.markdown-body div[class*="language-"] {
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre[class*="language-"] {
|
||||||
|
margin: 0;
|
||||||
|
padding: 12px;
|
||||||
|
background: #1a1a1a;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hide scroll bars globally while maintaining scroll functionality */
|
/* Hide scroll bars globally while maintaining scroll functionality */
|
||||||
/* Firefox */
|
/* Firefox */
|
||||||
* {
|
* {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { useState, useRef, useEffect } from "react";
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
|
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||||
import { Message, ProviderConfig } from "../types";
|
import { Message, ProviderConfig } from "../types";
|
||||||
|
|
||||||
interface ChatProps {
|
interface ChatProps {
|
||||||
@@ -335,8 +337,29 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
|||||||
</details>
|
</details>
|
||||||
) : (
|
) : (
|
||||||
<div className="markdown-body">
|
<div className="markdown-body">
|
||||||
{/* Assuming global CSS handles standard markdown styling now */}
|
<Markdown
|
||||||
<Markdown>{msg.content}</Markdown>
|
components={{
|
||||||
|
code: ({ className, children, ...props }: any) => {
|
||||||
|
const match = /language-(\w+)/.exec(className || "");
|
||||||
|
const isInline = !className;
|
||||||
|
return !isInline && match ? (
|
||||||
|
<SyntaxHighlighter
|
||||||
|
style={oneDark as any}
|
||||||
|
language={match[1]}
|
||||||
|
PreTag="div"
|
||||||
|
>
|
||||||
|
{String(children).replace(/\n$/, "")}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
) : (
|
||||||
|
<code className={className} {...props}>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{msg.content}
|
||||||
|
</Markdown>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user