Skip to content

Commit bb3c424

Browse files
author
shmuel hizmi
committed
master
1 parent 35654c6 commit bb3c424

File tree

13 files changed

+265
-37
lines changed

13 files changed

+265
-37
lines changed

bun.lock

Lines changed: 29 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/** @jsxImportSource @opentui/react */
2+
import type { ReactNode } from "react";
3+
import { SyntaxStyle } from "@opentui/core";
4+
import { usePrefixContext } from "./FocusContext";
5+
6+
const syntaxStyle = SyntaxStyle.create();
7+
8+
interface WmuxMarkdownProps {
9+
readonly id: string;
10+
readonly name: string;
11+
readonly content: string;
12+
readonly children?: ReactNode;
13+
}
14+
15+
export const WmuxMarkdown = ({ id, content }: WmuxMarkdownProps): ReactNode => {
16+
const { activeTabId } = usePrefixContext();
17+
if (activeTabId !== id) return null;
18+
19+
return (
20+
<scrollbox flexGrow={1}>
21+
<markdown content={content} syntaxStyle={syntaxStyle} conceal />
22+
</scrollbox>
23+
);
24+
};

packages/wmux-client-terminal/src/tui.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import { WmuxApp } from "./components/WmuxApp";
99
import { WmuxTerminal } from "./components/WmuxTerminal";
1010
import { WmuxFileContent } from "./components/WmuxFileContent";
1111
import { WmuxIframe } from "./components/WmuxIframe";
12+
import { WmuxMarkdown } from "./components/WmuxMarkdown";
1213

1314
const tuiViewComponents = {
1415
WmuxApp,
1516
WmuxTerminal,
1617
WmuxFileContent,
1718
WmuxIframe,
19+
WmuxMarkdown,
1820
};
1921

2022
export interface WmuxTUIOptions {

packages/wmux-client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@xterm/xterm": "^5.5.0",
2020
"cmdk": "^1.1.1",
2121
"lucide-react": "^0.577.0",
22+
"marked": "^15.0.0",
2223
"react": "^19.0.0",
2324
"react-dom": "^19.0.0",
2425
"zod": "^4.3.6"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { useMemo, type ReactElement, type ReactNode } from "react";
2+
import { marked } from "marked";
3+
4+
interface WmuxMarkdownProps {
5+
readonly id: string;
6+
readonly name: string;
7+
readonly content: string;
8+
readonly children?: ReactNode;
9+
}
10+
11+
export function WmuxMarkdown({ content }: WmuxMarkdownProps): ReactElement {
12+
const html = useMemo(() => marked.parse(content, { async: false }) as string, [content]);
13+
14+
return (
15+
<div className="w-full h-full overflow-auto">
16+
<div
17+
className="wmux-markdown max-w-3xl mx-auto px-8 py-6"
18+
dangerouslySetInnerHTML={{ __html: html }}
19+
/>
20+
</div>
21+
);
22+
}

packages/wmux-client/src/index.css

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,100 @@ body {
130130
from { backdrop-filter: blur(0px); opacity: 0; }
131131
to { backdrop-filter: blur(12px); opacity: 1; }
132132
}
133+
134+
/* ── Markdown content styles ────────────────────────────── */
135+
136+
.wmux-markdown {
137+
color: #e5e5ea;
138+
font-size: 14px;
139+
line-height: 1.7;
140+
}
141+
142+
.wmux-markdown h1, .wmux-markdown h2, .wmux-markdown h3,
143+
.wmux-markdown h4, .wmux-markdown h5, .wmux-markdown h6 {
144+
color: #f5f5f7;
145+
font-weight: 600;
146+
margin-top: 1.5em;
147+
margin-bottom: 0.5em;
148+
line-height: 1.3;
149+
}
150+
151+
.wmux-markdown h1 { font-size: 1.75em; border-bottom: 1px solid #38383a; padding-bottom: 0.3em; }
152+
.wmux-markdown h2 { font-size: 1.4em; border-bottom: 1px solid #38383a; padding-bottom: 0.25em; }
153+
.wmux-markdown h3 { font-size: 1.15em; }
154+
155+
.wmux-markdown p { margin: 0.75em 0; }
156+
157+
.wmux-markdown a { color: #0a84ff; text-decoration: none; }
158+
.wmux-markdown a:hover { text-decoration: underline; }
159+
160+
.wmux-markdown strong { color: #f5f5f7; font-weight: 600; }
161+
.wmux-markdown em { font-style: italic; }
162+
163+
.wmux-markdown code {
164+
background: #2c2c2e;
165+
border: 1px solid #38383a;
166+
border-radius: 4px;
167+
padding: 0.15em 0.4em;
168+
font-size: 0.9em;
169+
font-family: var(--font-mono);
170+
color: #ff8170;
171+
}
172+
173+
.wmux-markdown pre {
174+
background: #1a1a1c;
175+
border: 1px solid #38383a;
176+
border-radius: 8px;
177+
padding: 1em;
178+
overflow-x: auto;
179+
margin: 1em 0;
180+
}
181+
182+
.wmux-markdown pre code {
183+
background: none;
184+
border: none;
185+
padding: 0;
186+
color: #e5e5ea;
187+
font-size: 13px;
188+
}
189+
190+
.wmux-markdown blockquote {
191+
border-left: 3px solid #48484a;
192+
margin: 1em 0;
193+
padding: 0.25em 1em;
194+
color: #98989d;
195+
}
196+
197+
.wmux-markdown ul, .wmux-markdown ol {
198+
margin: 0.75em 0;
199+
padding-left: 1.5em;
200+
}
201+
202+
.wmux-markdown li { margin: 0.25em 0; }
203+
.wmux-markdown li::marker { color: #636366; }
204+
205+
.wmux-markdown hr {
206+
border: none;
207+
border-top: 1px solid #38383a;
208+
margin: 1.5em 0;
209+
}
210+
211+
.wmux-markdown table {
212+
border-collapse: collapse;
213+
width: 100%;
214+
margin: 1em 0;
215+
}
216+
217+
.wmux-markdown th, .wmux-markdown td {
218+
border: 1px solid #38383a;
219+
padding: 0.5em 0.75em;
220+
text-align: left;
221+
}
222+
223+
.wmux-markdown th {
224+
background: #2c2c2e;
225+
color: #f5f5f7;
226+
font-weight: 600;
227+
}
228+
229+
.wmux-markdown img { max-width: 100%; border-radius: 8px; }

packages/wmux-client/src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import { WmuxApp } from "./components/WmuxApp";
88
import { WmuxTerminal } from "./components/WmuxTerminal";
99
import { WmuxFileContent } from "./components/WmuxFileContent";
1010
import { WmuxIframe } from "./components/WmuxIframe";
11+
import { WmuxMarkdown } from "./components/WmuxMarkdown";
1112

1213
const viewComponents = {
1314
WmuxApp,
1415
WmuxTerminal,
1516
WmuxFileContent,
1617
WmuxIframe,
18+
WmuxMarkdown,
1719
};
1820

1921
function TerminalLine({ text, delay, dimmed }: { readonly text: string; readonly delay: number; readonly dimmed?: boolean }): React.ReactElement {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { ReactElement } from "react";
2+
import { WmuxMarkdown } from "../views";
3+
4+
export function MarkdownSession({ id, name, content }: {
5+
readonly id: string;
6+
readonly name: string;
7+
readonly content: string;
8+
}): ReactElement {
9+
return <WmuxMarkdown id={id} name={name} content={content} />;
10+
}

0 commit comments

Comments
 (0)