Skip to content

Commit 7b7b4c6

Browse files
committed
feat: Add app details and basic documentation
1 parent 138f736 commit 7b7b4c6

File tree

6 files changed

+1365
-0
lines changed

6 files changed

+1365
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
5+
import { oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
6+
7+
type CodeBlockProps = {
8+
language: string;
9+
value: string;
10+
};
11+
12+
const CodeBlock = ({ language, value }: CodeBlockProps) => {
13+
return (
14+
<SyntaxHighlighter
15+
style={oneLight}
16+
language={language}
17+
PreTag="div"
18+
wrapLongLines
19+
>
20+
{value}
21+
</SyntaxHighlighter>
22+
);
23+
};
24+
25+
export default CodeBlock;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react';
2+
import ReactMarkdown from 'react-markdown';
3+
import remarkGfm from 'remark-gfm';
4+
import rehypeRaw from 'rehype-raw';
5+
import markdown from '@/content/detailsContent';
6+
import ClientTweet from '@/components/ClientTweet';
7+
// import dynamic from 'next/dynamic';
8+
import { type Components } from 'react-markdown';
9+
import CodeBlock from './CodeBlock';
10+
11+
// const CodeBlock = dynamic(() => import('./CodeBlock'), { ssr: false }); // 💡 Important: no SSR
12+
13+
export default function DetailsPage() {
14+
return (
15+
<div className="px-4 py-10 md:px-8 max-w-4xl mx-auto prose prose-lg">
16+
<ReactMarkdown
17+
remarkPlugins={[remarkGfm]}
18+
rehypePlugins={[rehypeRaw]}
19+
components={{
20+
code({ node, inline, className, children, ...props }) {
21+
const match = /language-(\w+)/.exec(className || '');
22+
return !inline && match ? (
23+
<CodeBlock language={match[1]} value={String(children).replace(/\n$/, '')} />
24+
) : (
25+
<code className="bg-gray-100 px-1 py-0.5 rounded" {...props}>{children}</code>
26+
);
27+
},
28+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
29+
iframe({ node, ...props }) {
30+
return (
31+
<div className="aspect-video w-full my-6">
32+
<iframe {...props} className="w-full h-full rounded-md" />
33+
</div>
34+
);
35+
},
36+
}}
37+
>
38+
{markdown}
39+
</ReactMarkdown>
40+
41+
<ClientTweet />
42+
</div>
43+
);
44+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import TweetEmbed from 'react-tweet-embed';
5+
6+
export default function ClientTweet() {
7+
return (
8+
<div className="my-6">
9+
<TweetEmbed tweetId="1711737824058880576" options={{ width: '100%' }} />
10+
</div>
11+
);
12+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
const detailsContent = String.raw`
2+
---
3+
4+
**CollabyDraw** is a web-based collaborative whiteboard where multiple users can draw, edit, and brainstorm together in real time. Whether solo or in a group session, the app offers a smooth, intuitive canvas experience with real-time sync, shape tools, editable text, and privacy-focused end-to-end encryption — all without needing an account.
5+
6+
---
7+
8+
### ✅ Core Features
9+
10+
- **Canvas Drawing**: Freehand, shapes, and editable text
11+
- **Rough.js Support**: Optional sketch-style drawing
12+
- **Perfect-freehand Support**: Hand drawn feel
13+
- **Eraser Tool**: Remove individual shapes
14+
- **Editable Text**: Double-click to edit on canvas
15+
16+
---
17+
18+
### 🔗 Collaboration
19+
20+
- **Real-time Sync**: WebSocket-powered live drawing
21+
- **Multi-Tab Awareness**: No duplicate join/leave events
22+
- **Optimistic Updates**: Instant feedback before server response
23+
24+
---
25+
26+
### 🔐 Privacy & End-to-End Encryption (E2EE) in CollabyDraw
27+
28+
CollabyDraw is built with **privacy by design** to ensure that no sensitive drawing data can be accessed by anyone other than the intended participants.
29+
30+
#### 🔑 How It Works
31+
32+
When a user creates or joins a room, the app generates a link like:
33+
34+
\`\`\`
35+
https://collabydraw.app/#room=abc123,xyz456
36+
\`\`\`
37+
38+
- \`abc123\`: Unique room ID (used by the server)
39+
- \`xyz456\`: Encryption key (used **only** on the client)
40+
41+
---
42+
43+
#### 🧠 Key Never Touches the Server
44+
45+
- The **encryption key** after the comma (\`xyz456\`) is part of the URL fragment (\`#...\`)
46+
- This fragment is **never sent** in HTTP requests, meaning:
47+
48+
> The server cannot see or store the encryption key.
49+
50+
---
51+
52+
#### 🔒 Client-Side Only Decryption
53+
54+
- All encrypted drawing data is transmitted over WebSocket
55+
- The **decryption and rendering** happen completely on the client-side using the \`key\` from the URL
56+
- Even if someone intercepts the WebSocket traffic, they cannot decrypt the data without the key
57+
58+
---
59+
60+
#### 🛡️ Benefits
61+
62+
- No one — not even the server — can read what’s drawn in a room without the key
63+
- Ensures **confidentiality** for private brainstorming, teaching, or design sessions
64+
- Works like **Excalidraw's E2EE rooms**, but tailored for your collaborative drawing logic
65+
66+
---
67+
68+
### 🧠 Reliability
69+
70+
- **Message Queue**: Stores unsent messages in memory/localStorage
71+
- **Auto Retry**: Flushes queued messages on reconnect
72+
73+
---
74+
75+
### 🧭 Modes
76+
77+
- **Standalone Mode**: Offline/local drawing
78+
- **Room Mode**: Collaborative sessions
79+
80+
---
81+
82+
### ⚙️ Tech Stack
83+
84+
- **Frontend**: React (Vite), TypeScript, Tailwind CSS
85+
- **Canvas**: HTML Canvas API + Custom Engine
86+
- **Realtime**: Native WebSocket (\`useWebSocket\` hook)
87+
- **Security**: Hash-based E2EE
88+
89+
---
90+
91+
### 📂 Github Repo
92+
93+
[github.com/coderomm/CollabyDraw](https://github.com/coderomm/CollabyDraw)
94+
95+
---
96+
97+
### 📽️ YouTube Demo
98+
99+
<iframe width="100%" height="400" src="https://www.youtube.com/embed/NNVdRCoFnK0" frameborder="0" allowfullscreen></iframe>
100+
101+
---
102+
103+
### 🐦 Tweet Embed
104+
105+
<Tweet id="1711737824058880576" />
106+
107+
`;
108+
109+
export default detailsContent;

apps/collabydraw/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
"react": "^18.3.1",
4343
"react-dom": "^18.3.1",
4444
"react-hook-form": "^7.54.2",
45+
"react-markdown": "^10.1.0",
46+
"react-syntax-highlighter": "^15.6.1",
47+
"react-tweet-embed": "^2.0.0",
48+
"rehype-raw": "^7.0.0",
49+
"remark-gfm": "^4.0.1",
4550
"roughjs": "^4.6.6",
4651
"sonner": "^1.7.4",
4752
"tailwind-merge": "^3.0.1",
@@ -57,6 +62,7 @@
5762
"@types/node": "^20",
5863
"@types/react": "^18.3.1",
5964
"@types/react-dom": "^18.3.1",
65+
"@types/react-syntax-highlighter": "^15.5.13",
6066
"eslint": "^9",
6167
"eslint-config-next": "15.1.7",
6268
"postcss": "^8",

0 commit comments

Comments
 (0)