Skip to content

Commit 155ac30

Browse files
committed
UI fixes and dark mode
1 parent 312303d commit 155ac30

File tree

11 files changed

+387
-69
lines changed

11 files changed

+387
-69
lines changed

frontend/src/components/Editor.tsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ import type { BlockNoteEditor } from "@blocknote/core";
1515
import * as Y from "yjs";
1616
import { nanoid } from "nanoid";
1717
import { schema } from "../lib/editorSchema";
18+
import { setThemeMode } from "../lib/syntaxHighlighting";
1819
import { PhoenixProvider } from "../lib/PhoenixProvider";
1920
import type { UserInfo } from "../lib/PhoenixProvider";
2021
import { UserPresence } from "./UserPresence";
2122
import { ConnectionStatus } from "./ConnectionStatus";
2223
import { NamePrompt } from "./NamePrompt";
2324
import { Cursors } from "./Cursors";
2425
import { ExportMenu } from "./ExportMenu";
26+
import { ThemeToggle } from "./ThemeToggle";
27+
import { useTheme } from "../contexts/ThemeContext";
2528
import { useCursors } from "../hooks/useCursors";
2629
import { usePresence } from "../hooks/usePresence";
2730
import { generateDocId } from "../lib/generateDocId";
@@ -95,6 +98,12 @@ export function Editor({ docId }: EditorProps) {
9598
const [provider, setProvider] = useState<PhoenixProvider | null>(null);
9699
const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
97100
const [showNamePrompt, setShowNamePrompt] = useState(false);
101+
const { mode } = useTheme();
102+
103+
// Update syntax highlighting theme when mode changes
104+
useEffect(() => {
105+
setThemeMode(mode);
106+
}, [mode]);
98107

99108
// Create Y.js document (persists across re-renders)
100109
const doc = useMemo(() => new Y.Doc(), []);
@@ -302,15 +311,15 @@ export function Editor({ docId }: EditorProps) {
302311
style={{
303312
width: "100%",
304313
minHeight: "100vh",
305-
backgroundColor: "#fafafa",
306314
}}
307315
>
308316
{/* Header */}
309317
<div
310318
style={{
311-
backgroundColor: "white",
312-
borderBottom: "1px solid #e0e0e0",
319+
backgroundColor: "var(--header-bg)",
320+
borderBottom: "1px solid var(--header-border)",
313321
padding: "16px 24px",
322+
transition: "background-color 0.2s ease, border-color 0.2s ease",
314323
}}
315324
>
316325
<div
@@ -330,23 +339,28 @@ export function Editor({ docId }: EditorProps) {
330339
margin: 0,
331340
fontSize: "20px",
332341
fontWeight: 600,
333-
color: "#1a1a1a",
342+
color: "var(--page-text)",
334343
}}
335344
>
336345
<span style={{ fontWeight: 800, fontSize:"28px", color: "#646cff"}}>[</span>
337346
<span>MarkDoc </span>
338347
<span style={{ fontWeight: 800, fontSize:"28px", color: "#646cff"}}>]</span>
339348
</h1>
340349
<p
341-
style={{ margin: "4px 0 0 0", color: "#666", fontSize: "13px" }}
350+
style={{
351+
margin: "4px 0 0 0",
352+
color: mode === "dark" ? "#8b949e" : "#666",
353+
fontSize: "13px"
354+
}}
342355
>
343356
Document:{" "}
344357
<code
345358
style={{
346-
background: "#f5f5f5",
359+
background: mode === "dark" ? "#21262d" : "#f5f5f5",
347360
padding: "2px 6px",
348361
borderRadius: "3px",
349362
fontSize: "12px",
363+
color: mode === "dark" ? "#e6edf3" : "#24292f",
350364
}}
351365
>
352366
{docId}
@@ -371,6 +385,9 @@ export function Editor({ docId }: EditorProps) {
371385
{/* User Presence Avatars */}
372386
<UserPresence channel={provider?.channel || null} />
373387

388+
{/* Theme Toggle */}
389+
<ThemeToggle />
390+
374391
{/* Combined Menu (New Document + Export) */}
375392
{editor && (
376393
<ExportMenu
@@ -393,16 +410,17 @@ export function Editor({ docId }: EditorProps) {
393410
>
394411
<div
395412
style={{
396-
backgroundColor: "white",
397-
border: "1px solid #e0e0e0",
413+
backgroundColor: "var(--editor-bg)",
414+
border: "1px solid var(--editor-border)",
398415
borderRadius: "8px",
399416
overflow: "hidden",
400417
minHeight: "calc(100vh - 200px)",
418+
transition: "background-color 0.2s ease, border-color 0.2s ease",
401419
}}
402420
>
403421
{editorContextValue ? (
404422
<EditorContext.Provider value={editorContextValue}>
405-
<BlockNoteView editor={editor} theme="light" slashMenu={false}>
423+
<BlockNoteView editor={editor} theme={mode} slashMenu={false}>
406424
<SuggestionMenuController
407425
triggerCharacter={"/"}
408426
getItems={async (query) =>
@@ -415,7 +433,7 @@ export function Editor({ docId }: EditorProps) {
415433
</BlockNoteView>
416434
</EditorContext.Provider>
417435
) : (
418-
<BlockNoteView editor={editor} theme="light" slashMenu={false}>
436+
<BlockNoteView editor={editor} theme={mode} slashMenu={false}>
419437
<SuggestionMenuController
420438
triggerCharacter={"/"}
421439
getItems={async (query) =>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Theme Toggle Component
3+
*
4+
* Button to switch between light and dark mode for code blocks.
5+
*/
6+
7+
import { useTheme } from "../contexts/ThemeContext";
8+
9+
export function ThemeToggle() {
10+
const { mode, toggleTheme } = useTheme();
11+
12+
return (
13+
<button
14+
onClick={toggleTheme}
15+
style={{
16+
display: "flex",
17+
alignItems: "center",
18+
gap: "6px",
19+
padding: "8px 12px",
20+
backgroundColor: mode === "dark" ? "#2d333b" : "#f6f8fa",
21+
color: mode === "dark" ? "#e6edf3" : "#24292f",
22+
border: "1px solid",
23+
borderColor: mode === "dark" ? "#444c56" : "#d0d7de",
24+
borderRadius: "6px",
25+
cursor: "pointer",
26+
fontSize: "14px",
27+
fontWeight: 500,
28+
transition: "all 0.2s ease",
29+
}}
30+
onMouseEnter={(e) => {
31+
e.currentTarget.style.backgroundColor =
32+
mode === "dark" ? "#373e47" : "#f3f4f6";
33+
}}
34+
onMouseLeave={(e) => {
35+
e.currentTarget.style.backgroundColor =
36+
mode === "dark" ? "#2d333b" : "#f6f8fa";
37+
}}
38+
title={`Switch to ${mode === "light" ? "dark" : "light"} mode`}
39+
>
40+
{mode === "light" ? (
41+
<>
42+
<svg
43+
width="16"
44+
height="16"
45+
viewBox="0 0 16 16"
46+
fill="currentColor"
47+
>
48+
<path d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0V.75A.75.75 0 0 1 8 0zm0 13a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 8 13zM2.343 2.343a.75.75 0 0 1 1.061 0l1.06 1.061a.75.75 0 0 1-1.06 1.06l-1.06-1.06a.75.75 0 0 1 0-1.06zm9.193 9.193a.75.75 0 0 1 1.06 0l1.061 1.06a.75.75 0 0 1-1.06 1.061l-1.061-1.06a.75.75 0 0 1 0-1.061zM16 8a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1 0-1.5h1.5A.75.75 0 0 1 16 8zM3 8a.75.75 0 0 1-.75.75H.75a.75.75 0 0 1 0-1.5h1.5A.75.75 0 0 1 3 8zm10.657-5.657a.75.75 0 0 1 0 1.061l-1.061 1.06a.75.75 0 1 1-1.06-1.06l1.06-1.06a.75.75 0 0 1 1.061 0zm-9.193 9.193a.75.75 0 0 1 0 1.06l-1.06 1.061a.75.75 0 0 1-1.061-1.06l1.06-1.061a.75.75 0 0 1 1.061 0z" />
49+
</svg>
50+
</>
51+
) : (
52+
<>
53+
<svg
54+
width="16"
55+
height="16"
56+
viewBox="0 0 16 16"
57+
fill="currentColor"
58+
>
59+
<path d="M9.598 1.591a.75.75 0 0 1 .785-.175 7 7 0 1 1-8.967 8.967.75.75 0 0 1 .961-.96 5.5 5.5 0 0 0 7.046-7.046.75.75 0 0 1 .175-.786zm1.616 1.945a7 7 0 0 1-7.678 7.678 5.5 5.5 0 1 0 7.678-7.678z" />
60+
</svg>
61+
</>
62+
)}
63+
</button>
64+
);
65+
}

frontend/src/components/chat/ChatBlock.tsx

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useChatReadReceipts } from "../../hooks/useChatReadReceipts";
1515
import { ChatMessages } from "./ChatMessages";
1616
import { ChatInput } from "./ChatInput";
1717
import { useBlockNoteEditor } from "@blocknote/react";
18+
import { useTheme } from "../../contexts/ThemeContext";
1819
import {
1920
loadFloatingState,
2021
saveFloatingState,
@@ -76,10 +77,10 @@ export function ChatBlock({ block }: ChatBlockProps) {
7677
<div
7778
style={{
7879
padding: "16px",
79-
border: "1px solid #e0e0e0",
80+
border: "1px solid var(--chat-border)",
8081
borderRadius: "8px",
81-
backgroundColor: "#fff9e6",
82-
color: "#666",
82+
backgroundColor: "var(--chat-header-bg)",
83+
color: "var(--chat-text-secondary)",
8384
}}
8485
>
8586
Chat block error: Editor context not available
@@ -354,10 +355,10 @@ export function ChatBlock({ block }: ChatBlockProps) {
354355
<div
355356
style={{
356357
padding: "16px",
357-
border: "1px solid #e0e0e0",
358+
border: "1px solid var(--chat-border)",
358359
borderRadius: "8px",
359-
backgroundColor: "#fff9e6",
360-
color: "#666",
360+
backgroundColor: "var(--chat-header-bg)",
361+
color: "var(--chat-text-secondary)",
361362
}}
362363
>
363364
Initializing chat...
@@ -372,22 +373,24 @@ export function ChatBlock({ block }: ChatBlockProps) {
372373
left: `${floatingPosition.x}px`,
373374
top: `${floatingPosition.y}px`,
374375
zIndex: floatingZIndex,
375-
border: "1px solid #e0e0e0",
376+
border: "1px solid var(--chat-border)",
376377
borderRadius: "8px",
377-
backgroundColor: "white",
378+
backgroundColor: "var(--chat-bg)",
378379
overflow: "hidden",
379380
width: `${width}px`,
380381
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)",
382+
transition: "background-color 0.2s ease, border-color 0.2s ease",
381383
}
382384
: {
383-
border: "1px solid #e0e0e0",
385+
border: "1px solid var(--chat-border)",
384386
borderRadius: "8px",
385-
backgroundColor: "white",
387+
backgroundColor: "var(--chat-bg)",
386388
marginTop: "8px",
387389
marginBottom: "8px",
388390
overflow: "hidden",
389391
width: `${width}px`,
390392
position: "relative",
393+
transition: "background-color 0.2s ease, border-color 0.2s ease",
391394
};
392395

393396
return (
@@ -404,9 +407,10 @@ export function ChatBlock({ block }: ChatBlockProps) {
404407
justifyContent: "space-between",
405408
alignItems: "center",
406409
padding: "12px 16px",
407-
borderBottom: "1px solid #e0e0e0",
408-
backgroundColor: "#fafafa",
410+
borderBottom: "1px solid var(--chat-border)",
411+
backgroundColor: "var(--chat-header-bg)",
409412
cursor: isFloating && !isEditingTitle ? "move" : "default",
413+
transition: "background-color 0.2s ease, border-color 0.2s ease",
410414
}}
411415
onMouseDown={isFloating && !isEditingTitle ? handleDragStart : undefined}
412416
>
@@ -429,7 +433,8 @@ export function ChatBlock({ block }: ChatBlockProps) {
429433
style={{
430434
fontWeight: 600,
431435
fontSize: "14px",
432-
color: "#1a1a1a",
436+
color: "var(--chat-text)",
437+
backgroundColor: "var(--chat-btn-bg)",
433438
border: "1px solid #646cff",
434439
borderRadius: "4px",
435440
padding: "2px 6px",
@@ -443,14 +448,14 @@ export function ChatBlock({ block }: ChatBlockProps) {
443448
style={{
444449
fontWeight: 600,
445450
fontSize: "14px",
446-
color: "#1a1a1a",
451+
color: "var(--chat-text)",
447452
cursor: "pointer",
448453
padding: "2px 6px",
449454
borderRadius: "4px",
450455
transition: "background-color 0.2s",
451456
}}
452457
onMouseEnter={(e) => {
453-
e.currentTarget.style.backgroundColor = "#f5f5f5";
458+
e.currentTarget.style.backgroundColor = "var(--chat-btn-hover)";
454459
}}
455460
onMouseLeave={(e) => {
456461
e.currentTarget.style.backgroundColor = "transparent";
@@ -463,7 +468,7 @@ export function ChatBlock({ block }: ChatBlockProps) {
463468
<span
464469
style={{
465470
fontSize: "12px",
466-
color: "#999",
471+
color: "var(--chat-text-tertiary)",
467472
}}
468473
>
469474
{messages.length} {messages.length === 1 ? "message" : "messages"}
@@ -515,21 +520,22 @@ export function ChatBlock({ block }: ChatBlockProps) {
515520
style={{
516521
width: "24px",
517522
height: "24px",
518-
border: "1px solid #e0e0e0",
523+
border: "1px solid var(--chat-border)",
519524
borderRadius: "4px",
520-
backgroundColor: "white",
525+
backgroundColor: "var(--chat-btn-bg)",
521526
cursor: "pointer",
522527
display: "flex",
523528
alignItems: "center",
524529
justifyContent: "center",
525530
fontSize: "14px",
526-
color: "#666",
531+
color: "var(--chat-text-secondary)",
532+
transition: "background-color 0.2s ease",
527533
}}
528534
onMouseEnter={(e) => {
529-
e.currentTarget.style.backgroundColor = "#f5f5f5";
535+
e.currentTarget.style.backgroundColor = "var(--chat-btn-hover)";
530536
}}
531537
onMouseLeave={(e) => {
532-
e.currentTarget.style.backgroundColor = "white";
538+
e.currentTarget.style.backgroundColor = "var(--chat-btn-bg)";
533539
}}
534540
title={isMinimized ? "Expand" : "Minimize"}
535541
>
@@ -545,22 +551,23 @@ export function ChatBlock({ block }: ChatBlockProps) {
545551
style={{
546552
width: "24px",
547553
height: "24px",
548-
border: "1px solid #e0e0e0",
554+
border: "1px solid var(--chat-border)",
549555
borderRadius: "4px",
550-
backgroundColor: "white",
556+
backgroundColor: "var(--chat-btn-bg)",
551557
cursor: "pointer",
552558
display: "flex",
553559
alignItems: "center",
554560
justifyContent: "center",
555561
fontSize: "14px",
556562
color: "#646cff",
557-
fontWeight: 800
563+
fontWeight: 800,
564+
transition: "background-color 0.2s ease",
558565
}}
559566
onMouseEnter={(e) => {
560-
e.currentTarget.style.backgroundColor = "#f5f5f5";
567+
e.currentTarget.style.backgroundColor = "var(--chat-btn-hover)";
561568
}}
562569
onMouseLeave={(e) => {
563-
e.currentTarget.style.backgroundColor = "white";
570+
e.currentTarget.style.backgroundColor = "var(--chat-btn-bg)";
564571
}}
565572
title={isFloating ? "Dock to document" : "Open in floating window"}
566573
>
@@ -645,7 +652,7 @@ export function ChatBlock({ block }: ChatBlockProps) {
645652
<div
646653
style={{
647654
padding: "12px 16px",
648-
color: "#999",
655+
color: "var(--chat-text-tertiary)",
649656
fontSize: "13px",
650657
fontStyle: "italic",
651658
display: "flex",
@@ -678,16 +685,17 @@ export function ChatBlock({ block }: ChatBlockProps) {
678685
{isFloating && (
679686
<div
680687
style={{
681-
border: "1px dashed #e0e0e0",
688+
border: "1px dashed var(--chat-border)",
682689
borderRadius: "8px",
683-
backgroundColor: "#fafafa",
690+
backgroundColor: "var(--chat-header-bg)",
684691
marginTop: "8px",
685692
marginBottom: "8px",
686693
padding: "16px",
687-
color: "#999",
694+
color: "var(--chat-text-tertiary)",
688695
fontSize: "13px",
689696
fontStyle: "italic",
690697
textAlign: "center",
698+
transition: "background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease",
691699
}}
692700
contentEditable={false}
693701
>

0 commit comments

Comments
 (0)