Skip to content

Commit e142255

Browse files
committed
enhanced cursor styling
1 parent 2270f91 commit e142255

4 files changed

Lines changed: 160 additions & 132 deletions

File tree

src/components/TextEditor.tsx

Lines changed: 113 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Highlight from "@tiptap/extension-highlight";
1313
import TextAlign from "@tiptap/extension-text-align";
1414
import {
1515
FaBold,
16-
FaItalic,
16+
FaItalic,
1717
FaStrikethrough,
1818
FaHeading,
1919
FaListOl,
@@ -32,9 +32,10 @@ import {
3232
FaCode,
3333
FaCodeBranch,
3434
} from "react-icons/fa";
35+
import { once } from "events";
36+
import useAuth from "../hooks/useAuth";
3537

36-
37-
export const document = new collabDocument();
38+
export const collaborationDocument = new collabDocument();
3839

3940
const MenuBar = ({ editor }) => {
4041
if (!editor) {
@@ -46,229 +47,226 @@ const MenuBar = ({ editor }) => {
4647
<div>
4748
<button
4849
onClick={() => editor.chain().focus().toggleBold().run()}
49-
disabled={
50-
!editor.can()
51-
.chain()
52-
.focus()
53-
.toggleBold()
54-
.run()
55-
}
50+
disabled={!editor.can().chain().focus().toggleBold().run()}
5651
className={editor.isActive("bold") ? "is-active" : ""}
5752
>
58-
<FaBold/>
53+
<FaBold />
5954
</button>
6055
<button
6156
onClick={() => editor.chain().focus().toggleItalic().run()}
62-
disabled={
63-
!editor.can()
64-
.chain()
65-
.focus()
66-
.toggleItalic()
67-
.run()
68-
}
57+
disabled={!editor.can().chain().focus().toggleItalic().run()}
6958
className={editor.isActive("italic") ? "is-active" : ""}
7059
>
71-
<FaItalic/>
60+
<FaItalic />
7261
</button>
73-
<button
62+
<button
7463
onClick={() => editor.chain().focus().toggleUnderline().run()}
75-
disabled={
76-
!editor.can()
77-
.chain()
78-
.focus()
79-
.toggleItalic()
80-
.run()
81-
}
64+
disabled={!editor.can().chain().focus().toggleItalic().run()}
8265
className={editor.isActive("underline") ? "is-active" : ""}
8366
>
84-
<FaUnderline/>
67+
<FaUnderline />
8568
</button>
8669
<button
87-
onClick={() => editor.chain().focus().toggleHighlight({color:"#FFFF00"}).run()}
70+
onClick={() =>
71+
editor.chain().focus().toggleHighlight({ color: "#FFFF00" }).run()
72+
}
8873
className={editor.isActive("highlight") ? "is-active" : ""}
8974
>
90-
<FaHighlighter/>
91-
</button>
75+
<FaHighlighter />
76+
</button>
9277
{/*<ColorPicker editor={editor}/>*/}
9378
<button
9479
onClick={() => editor.chain().focus().setTextAlign("left").run()}
95-
className={editor.isActive({textAlign:"left"}) ? "is-active" : ""}
80+
className={editor.isActive({ textAlign: "left" }) ? "is-active" : ""}
9681
>
97-
<FaAlignLeft/>
98-
</button>
82+
<FaAlignLeft />
83+
</button>
9984
<button
10085
onClick={() => editor.chain().focus().setTextAlign("center").run()}
101-
className={editor.isActive({textAlign:"center"}) ? "is-active" : ""}
86+
className={
87+
editor.isActive({ textAlign: "center" }) ? "is-active" : ""
88+
}
10289
>
103-
<FaAlignCenter/>
104-
</button>
90+
<FaAlignCenter />
91+
</button>
10592
<button
10693
onClick={() => editor.chain().focus().setTextAlign("right").run()}
107-
className={editor.isActive({textAlign:"right"}) ? "is-active" : ""}
94+
className={editor.isActive({ textAlign: "right" }) ? "is-active" : ""}
10895
>
109-
<FaAlignRight/>
110-
</button>
96+
<FaAlignRight />
97+
</button>
11198
<button
11299
onClick={() => editor.chain().focus().setTextAlign("justify").run()}
113-
className={editor.isActive({textAlign:"justify"}) ? "is-active" : ""}
100+
className={
101+
editor.isActive({ textAlign: "justify" }) ? "is-active" : ""
102+
}
114103
>
115-
<FaAlignJustify/>
116-
</button>
104+
<FaAlignJustify />
105+
</button>
117106
<button
118107
onClick={() => editor.chain().focus().toggleStrike().run()}
119-
disabled={
120-
!editor.can()
121-
.chain()
122-
.focus()
123-
.toggleStrike()
124-
.run()
125-
}
108+
disabled={!editor.can().chain().focus().toggleStrike().run()}
126109
className={editor.isActive("strike") ? "is-active" : ""}
127110
>
128-
<FaStrikethrough/>
129-
</button>
111+
<FaStrikethrough />
112+
</button>
130113
<button
131-
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
132-
className={editor.isActive("heading", { level: 1 }) ? "is-active" : ""}
114+
onClick={() =>
115+
editor.chain().focus().toggleHeading({ level: 1 }).run()
116+
}
117+
className={
118+
editor.isActive("heading", { level: 1 }) ? "is-active" : ""
119+
}
133120
>
134-
<FaHeading/>
135-
</button>
121+
<FaHeading />
122+
</button>
136123
<button
137124
onClick={() => editor.chain().focus().setParagraph().run()}
138125
className={editor.isActive("paragraph") ? "is-active" : ""}
139126
>
140-
<FaParagraph/>
141-
</button>
127+
<FaParagraph />
128+
</button>
142129
<button
143130
onClick={() => editor.chain().focus().toggleBulletList().run()}
144131
className={editor.isActive("bulletList") ? "is-active" : ""}
145132
>
146-
<FaListUl/>
133+
<FaListUl />
147134
</button>
148135
<button
149136
onClick={() => editor.chain().focus().toggleOrderedList().run()}
150137
className={editor.isActive("orderedList") ? "is-active" : ""}
151138
>
152-
<FaListOl/>
153-
</button>
139+
<FaListOl />
140+
</button>
154141
<button
155142
onClick={() => editor.chain().focus().toggleBlockquote().run()}
156143
className={editor.isActive("blockquote") ? "is-active" : ""}
157144
>
158-
<FaQuoteLeft/>
145+
<FaQuoteLeft />
159146
</button>
160147
<button
161148
onClick={() => editor.chain().focus().toggleCode().run()}
162-
disabled={
163-
!editor.can()
164-
.chain()
165-
.focus()
166-
.toggleCode()
167-
.run()
168-
}
149+
disabled={!editor.can().chain().focus().toggleCode().run()}
169150
className={editor.isActive("code") ? "is-active" : ""}
170151
>
171-
<FaCode/>
152+
<FaCode />
172153
</button>
173154
<button
174155
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
175156
className={editor.isActive("codeBlock") ? "is-active" : ""}
176157
>
177-
<FaCodeBranch/>
158+
<FaCodeBranch />
159+
</button>
160+
<button
161+
onClick={() => editor.chain().focus().setHorizontalRule().run()}
162+
>
163+
<FaRulerHorizontal />
178164
</button>
179-
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
180-
<FaRulerHorizontal/>
181-
</button>
182165
</div>
183-
<div>
184-
<button
166+
<div>
167+
<button
185168
onClick={() => editor.chain().focus().undo().run()}
186-
disabled={
187-
!editor.can()
188-
.chain()
189-
.focus()
190-
.undo()
191-
.run()
192-
}
169+
disabled={!editor.can().chain().focus().undo().run()}
193170
>
194-
<FaUndo/>
171+
<FaUndo />
195172
</button>
196173
<button
197174
onClick={() => editor.chain().focus().redo().run()}
198-
disabled={
199-
!editor.can()
200-
.chain()
201-
.focus()
202-
.redo()
203-
.run()
204-
}
175+
disabled={!editor.can().chain().focus().redo().run()}
205176
>
206-
<FaRedo/>
207-
</button>
177+
<FaRedo />
178+
</button>
208179
</div>
209180
</div>
210181
);
211182
};
212183
//console.log(TextStyle);
213-
const Tiptap = (props: { documentID: string; }) => {
184+
const Tiptap = (props: { documentID: string }) => {
214185
const documentID = props.documentID;
186+
const user = useAuth();
215187
useEffect(() => {
216188
socket.documentID = documentID;
217-
socket.connectHandler(document.ydoc);
218-
document.ydoc.on("update", socket.distributeDocumentUpdate);
219-
189+
socket.connectHandler(collaborationDocument.ydoc);
190+
collaborationDocument.ydoc.on("update", socket.distributeDocumentUpdate);
191+
220192
return () => {
221193
socket.disconnectHandler();
222-
document.ydoc.off("update", socket.distributeDocumentUpdate);
194+
collaborationDocument.ydoc.off("update", socket.distributeDocumentUpdate);
223195
};
224196
}, []);
197+
//generate random red color in hex
198+
const red = Math.floor(Math.random() * 255);
199+
const green = Math.floor(Math.random() * 255);
200+
const blue = Math.floor(Math.random() * 255);
201+
//generate hex code from red, green , blue
202+
225203
const editor = useEditor({
226204
extensions: [
227205
Underline,
228206
Highlight.configure({
229-
multicolor:true,
207+
multicolor: true,
230208
}),
231209
TextAlign.configure({
232-
types:["heading","paragraph"],
210+
types: ["heading", "paragraph"],
233211
alignments: ["left", "center", "right", "justify"],
234212
defaultAlignment: "left",
235213
}),
236214
TextStyle,
237-
//Color.configure({ types: [TextStyle.name, ListItem.name] }),
238-
Color.configure({
215+
//Color.configure({ types: [TextStyle.name, ListItem.name] }),
216+
Color.configure({
239217
types: ["TextStyle"],
240218
}),
241219
StarterKit.configure({
242220
// The Collaboration extension comes with its own history handling
243221
history: false,
244222
bulletList: {
245-
keepMarks: true,
246-
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
247-
},
248-
orderedList: {
249-
keepMarks: true,
250-
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
251-
},
223+
keepMarks: true,
224+
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
225+
},
226+
orderedList: {
227+
keepMarks: true,
228+
keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
229+
},
252230
}),
253231
// Register the document with Tiptap
254232
Collaboration.configure({
255-
document: document.ydoc,
256-
233+
document: collaborationDocument.ydoc,
257234
}),
258235
CollaborationCursor.configure({
259236
provider: socket,
260-
}),
237+
user: {
238+
name: user.userData?.userName ?? "Anonymous",
239+
color: "#" + red.toString(16).padStart(2,"0") + green.toString(16).padStart(2,"0") + blue.toString(16).padStart(2,"0"),
240+
},
241+
render: (user) => {
242+
const cursor = document.createElement("span");
261243

244+
cursor.classList.add("collaboration-cursor__caret");
245+
cursor.setAttribute("style", `border-color: ${user.color}`);
246+
const generateContrastColor = (red: number, green: number, blue: number) => {
247+
const luminance = (0.299 * red + 0.587 * green + 0.114 * blue) / 255;
248+
return luminance > 0.5 ? "#000000" : "#ffffff";
249+
};
250+
cursor.style.color = generateContrastColor(red, green, blue);
251+
const label = document.createElement("div");
252+
253+
label.classList.add("collaboration-cursor__label");
254+
label.setAttribute("style", `background-color: ${user.color}`);
255+
label.insertBefore(document.createTextNode(user.name), null);
256+
cursor.insertBefore(label, null);
257+
258+
return cursor;
259+
},
260+
}),
262261
],
263262
content: "",
264-
onUpdate:({editor})=>{
263+
onUpdate: ({ editor }) => {
265264
//use this to extract document contents
266265
const html = editor.getHTML();
267266
//console.log(html);
268267
const json = editor.getJSON();
269-
}
268+
},
270269
});
271-
272270
return (
273271
<div className="text-editor-area">
274272
<MenuBar editor={editor} />

src/styles/document.module.css

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
width: 100vw;
55
place-items: center;
66
}*/
7-
.root {
8-
margin: 5 rem auto;
9-
height: 100vh;
10-
width: 100vw;
11-
place-items: center;
7+
.root {
8+
margin: 5 rem auto;
9+
height: 100vh;
10+
width: 100vw;
11+
place-items: center;
1212
}
13+

0 commit comments

Comments
 (0)