Skip to content

Commit 73897af

Browse files
committed
Frontend fixes
1 parent 5ec4058 commit 73897af

File tree

13 files changed

+646
-172
lines changed

13 files changed

+646
-172
lines changed

frontend/package-lock.json

Lines changed: 25 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@blocknote/core": "^0.44.0",
1414
"@blocknote/mantine": "^0.44.0",
1515
"@blocknote/react": "^0.44.0",
16+
"nanoid": "^5.1.6",
1617
"phoenix": "^1.8.2",
1718
"react": "^19.2.0",
1819
"react-dom": "^19.2.0",

frontend/src/App.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
*/
66

77
import { Editor } from "./components/Editor";
8+
import { Landing } from "./components/Landing";
89

910
function App() {
1011
// Extract doc ID from URL path
11-
// Examples: /welcome → "welcome", /meeting-notes → "meeting-notes", / → "welcome"
12+
// Examples: /abc123 → "abc123", /meeting-notes → "meeting-notes"
1213
const path = window.location.pathname;
13-
const docId = path.slice(1) || "welcome";
14+
const docId = path.slice(1);
15+
16+
// Show landing page if no document ID
17+
if (!docId) {
18+
return <Landing />;
19+
}
1420

1521
return <Editor docId={docId} />;
1622
}
Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/**
22
* Cursors Component
33
*
4-
* Displays cursors for all connected users in real-time.
4+
* Displays cursors for all connected users in real-time (Google Docs style).
55
*/
66

7+
import { useState } from "react";
78
import type { CursorInfo } from "../hooks/useCursors";
89

910
interface CursorsProps {
@@ -13,61 +14,79 @@ interface CursorsProps {
1314
export function Cursors({ cursors }: CursorsProps) {
1415
return (
1516
<>
16-
{Object.entries(cursors).map(([userId, cursor]) => {
17-
return (
18-
<div
19-
key={userId}
20-
style={{
21-
position: "fixed",
22-
left: cursor.position.x,
23-
top: cursor.position.y,
24-
pointerEvents: "none",
25-
zIndex: 9999,
26-
transition: "left 0.15s ease-out, top 0.15s ease-out",
27-
willChange: "left, top",
28-
}}
29-
>
30-
{/* Cursor SVG */}
31-
<svg
32-
width="24"
33-
height="24"
34-
viewBox="0 0 24 24"
35-
fill="none"
36-
style={{
37-
filter: `drop-shadow(0 0 2px rgba(0,0,0,0.3))`,
38-
}}
39-
>
40-
<path
41-
d="M5.65376 12.3673L10.6477 17.3612L8.77546 19.2335L3.78149 14.2395L5.65376 12.3673Z"
42-
fill={cursor.user_color}
43-
/>
44-
<path
45-
d="M4.46164 14.2323L12.6866 6.00731L18.3264 11.647L10.1014 19.872L4.46164 14.2323Z"
46-
fill={cursor.user_color}
47-
/>
48-
</svg>
49-
50-
{/* User name label */}
51-
<div
52-
style={{
53-
position: "absolute",
54-
left: "20px",
55-
top: "0px",
56-
backgroundColor: cursor.user_color,
57-
color: "white",
58-
padding: "4px 8px",
59-
borderRadius: "4px",
60-
fontSize: "12px",
61-
fontWeight: 500,
62-
whiteSpace: "nowrap",
63-
boxShadow: "0 2px 8px rgba(0,0,0,0.2)",
64-
}}
65-
>
66-
{cursor.user_name}
67-
</div>
68-
</div>
69-
);
70-
})}
17+
{Object.entries(cursors).map(([userId, cursor]) => (
18+
<RemoteCursor key={userId} cursor={cursor} />
19+
))}
7120
</>
7221
);
7322
}
23+
24+
function RemoteCursor({ cursor }: { cursor: CursorInfo }) {
25+
const [isHovered, setIsHovered] = useState(false);
26+
27+
return (
28+
<div
29+
style={{
30+
position: "fixed",
31+
left: cursor.position.x,
32+
top: cursor.position.y,
33+
zIndex: 9999,
34+
transition: "left 0.15s ease-out, top 0.15s ease-out",
35+
willChange: "left, top",
36+
}}
37+
onMouseEnter={() => setIsHovered(true)}
38+
onMouseLeave={() => setIsHovered(false)}
39+
>
40+
{/* Vertical cursor line (caret) */}
41+
<div
42+
style={{
43+
position: "absolute",
44+
left: 0,
45+
top: 0,
46+
width: "2px",
47+
height: "20px",
48+
backgroundColor: cursor.user_color,
49+
pointerEvents: "auto",
50+
cursor: "default",
51+
}}
52+
/>
53+
54+
{/* Top flag/header */}
55+
<div
56+
style={{
57+
position: "absolute",
58+
left: "2px",
59+
top: "-2px",
60+
width: "8px",
61+
height: "8px",
62+
backgroundColor: cursor.user_color,
63+
borderRadius: "2px 2px 0 0",
64+
pointerEvents: "auto",
65+
cursor: "default",
66+
}}
67+
/>
68+
69+
{/* User name label (shown on hover) */}
70+
{isHovered && (
71+
<div
72+
style={{
73+
position: "absolute",
74+
left: "10px",
75+
top: "-6px",
76+
backgroundColor: cursor.user_color,
77+
color: "white",
78+
padding: "4px 8px",
79+
borderRadius: "4px",
80+
fontSize: "12px",
81+
fontWeight: 500,
82+
whiteSpace: "nowrap",
83+
boxShadow: "0 2px 8px rgba(0,0,0,0.2)",
84+
pointerEvents: "none",
85+
}}
86+
>
87+
{cursor.user_name}
88+
</div>
89+
)}
90+
</div>
91+
);
92+
}

0 commit comments

Comments
 (0)