Skip to content

Commit 3f338e2

Browse files
authored
Refactor draw page layout and improve functionality
Enhanced the layout and functionality of the draw page by updating styles, improving the tool palette, and refining the canvas behavior.
1 parent 08e3341 commit 3f338e2

1 file changed

Lines changed: 188 additions & 97 deletions

File tree

draw/index.html

Lines changed: 188 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -2,148 +2,239 @@
22
<html lang="en">
33
<head>
44
<script>fetch('https://api.countapi.xyz/hit/rmkr-dev.github.io/draw');</script>
5-
65
<meta charset="UTF-8">
76
<meta name="viewport" content="width=device-width, initial-scale=1.0">
87
<title>Architect Draw | RMKR Dev</title>
98

10-
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23FFC300' d='M448 96c0-35.3-28.7-64-64-64H128C92.7 32 64 60.7 64 96v320c0 35.3 28.7 64 64 64h256c35.3 0 64-28.7 64-64V96zM128 80h256c8.8 0 16 7.2 16 16v24H112V96c0-8.8 7.2-16 16-16zm256 352H128c-8.8 0-16-7.2-16-16v-24h288v24c0 8.8-7.2 16-16 16z'/%3E%3C/svg%3E">
9+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
10+
1111
<script src="https://cdn.tailwindcss.com"></script>
12-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Fira+Code:wght@300..700&display=swap" rel="stylesheet">
12+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet">
1313
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" />
1414

15-
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
16-
1715
<style>
1816
:root {
1917
--color-bg: #0C1524; --color-card: #18233C;
2018
--color-accent: #FFC300; --color-text: #F0F4F8;
2119
--color-muted: #A0AEC0; --color-line: #2D3748;
2220
}
23-
body { font-family: 'Inter', sans-serif; background-color: var(--color-bg); color: var(--color-text); }
24-
.wrap { max-width: 1200px; margin: 0 auto; padding: 2rem; }
21+
body { font-family: 'Inter', sans-serif; background-color: var(--color-bg); color: var(--color-text); overflow: hidden; }
22+
.wrap { max-width: 1400px; margin: 0 auto; padding: 2rem; height: 100vh; display: flex; flex-direction: column; }
2523

26-
textarea {
27-
font-family: 'Fira Code', monospace;
28-
background: #080E1A !important;
29-
color: #4ade80 !important; /* Code Green */
30-
resize: none;
31-
outline: none;
32-
border: 1px solid var(--color-line);
24+
/* Whiteboard Canvas */
25+
#whiteboard {
26+
background-color: #F0F4F8; /* White/Light Gray background for drawing */
27+
border-radius: 12px;
28+
cursor: crosshair;
29+
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
30+
flex-grow: 1;
31+
width: 100%;
3332
}
34-
35-
#diagram-output {
36-
background: rgba(255,255,255,0.02);
37-
border: 1px dashed var(--color-line);
33+
34+
/* Tool Palette */
35+
.tool-palette {
36+
background: var(--color-card);
37+
border: 1px solid var(--color-line);
3838
border-radius: 12px;
39-
min-height: 500px;
39+
padding: 10px;
4040
display: flex;
41-
justify-content: center;
41+
gap: 10px;
42+
margin-bottom: 20px;
4243
align-items: center;
43-
overflow: auto;
4444
}
4545

46-
/* Customizing Mermaid SVG Colors */
47-
.mermaid svg { max-width: 100% !important; height: auto !important; }
46+
.tool-btn {
47+
width: 40px; height: 40px;
48+
display: flex; align-items: center; justify-content: center;
49+
border-radius: 8px; border: 1px solid transparent;
50+
color: var(--color-muted);
51+
transition: all 0.2s;
52+
}
53+
.tool-btn:hover { background: rgba(255,195,0,0.1); color: var(--color-accent); }
54+
.tool-btn.active { background: var(--color-accent); color: var(--color-bg); font-weight: bold; border-color: var(--color-accent); }
55+
56+
.color-dot {
57+
width: 20px; height: 20px; border-radius: 50%;
58+
cursor: pointer; border: 2px solid transparent;
59+
transition: all 0.2s;
60+
}
61+
.color-dot:hover { transform: scale(1.1); }
62+
.color-dot.active { border-color: #fff; box-shadow: 0 0 5px rgba(255,255,255,0.5); }
63+
64+
.btn-gold { background: var(--color-accent); color: var(--color-bg); padding: 8px 16px; border-radius: 8px; font-weight: bold; font-size: 0.8rem; }
4865
</style>
4966
</head>
5067
<body>
5168

5269
<div class="wrap">
53-
<header class="flex justify-between items-center mb-8 border-b border-[--color-line] pb-4">
70+
<header class="flex justify-between items-center mb-6 border-b border-[--color-line] pb-4">
5471
<div>
55-
<h1 class="text-2xl font-bold italic tracking-tighter">ARCHITECT<span class="text-[--color-accent] not-italic">DRAW</span></h1>
56-
<p class="text-xs text-[--color-muted] font-bold uppercase tracking-widest mt-1">Diagrams as Code</p>
57-
</div>
58-
<div class="flex gap-4">
59-
<button onclick="downloadSVG()" class="text-xs font-bold text-[--color-accent] hover:underline uppercase">Export SVG</button>
60-
<a href="../" class="text-sm font-bold text-[--color-accent] hover:underline"><i class="fa-solid fa-house mr-1"></i> HUB</a>
72+
<h1 class="text-2xl font-bold tracking-tighteritalic">ARCHITECT<span class="text-[--color-accent] not-italic">DRAW</span></h1>
73+
<p class="text-xs text-[--color-muted] font-bold uppercase tracking-widest mt-1">Client-side Whiteboard</p>
6174
</div>
75+
<a href="../" class="bg-[--color-card] p-3 rounded-xl border border-[--color-line] hover:border-[--color-accent] transition">
76+
<i class="fa-solid fa-house-user"></i>
77+
</a>
6278
</header>
6379

64-
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6 h-[75vh]">
65-
<div class="lg:col-span-4 flex flex-col gap-4">
66-
<div class="bg-[--color-card] p-4 rounded-xl border border-[--color-line] flex-grow flex flex-col">
67-
<label class="text-[10px] font-black text-[--color-muted] uppercase mb-2">Mermaid Script</label>
68-
<textarea id="editor" class="w-full flex-grow p-4 rounded-lg text-xs leading-relaxed" spellcheck="false">graph TD
69-
A[Client] -->|Request| B(API Gateway)
70-
B --> C{Authorizer}
71-
C -->|Allow| D[Service A]
72-
C -->|Deny| E[403 Forbidden]
73-
D --> F[(Database)]</textarea>
74-
<p class="text-[9px] text-gray-500 mt-3 uppercase font-mono italic">Live rendering enabled</p>
75-
</div>
80+
<div class="tool-palette flex flex-wrap">
81+
<div class="flex gap-1 border-r border-[--color-line] pr-4">
82+
<button onclick="setTool('pencil')" id="btn-pencil" class="tool-btn active"><i class="fa-solid fa-pencil"></i></button>
83+
<button onclick="setTool('rect')" id="btn-rect" class="tool-btn"><i class="fa-regular fa-square"></i></button>
84+
<button onclick="setTool('circle')" id="btn-circle" class="tool-btn"><i class="fa-regular fa-circle"></i></button>
85+
<button onclick="setTool('line')" id="btn-line" class="tool-btn"><i class="fa-solid fa-grip-lines"></i></button>
86+
</div>
87+
88+
<div class="flex gap-2 border-r border-[--color-line] pr-4 ml-2">
89+
<div onclick="setColor('#0C1524')" style="background:#0C1524" class="color-dot active"></div>
90+
<div onclick="setColor('#ef4444')" style="background:#ef4444" class="color-dot"></div>
91+
<div onclick="setColor('#22c55e')" style="background:#22c55e" class="color-dot"></div>
92+
<div onclick="setColor('#3b82f6')" style="background:#3b82f6" class="color-dot"></div>
93+
<div onclick="setColor('#FFC300')" style="background:#FFC300" class="color-dot"></div>
7694
</div>
7795

78-
<div class="lg:col-span-8 bg-[--color-card] rounded-xl border border-[--color-line] p-6 flex flex-col overflow-hidden">
79-
<div class="flex justify-between items-center mb-4">
80-
<span class="text-[10px] font-black text-[--color-muted] uppercase">Live Preview</span>
81-
<div class="flex gap-2">
82-
<button onclick="updateDiagram('graph TD\n A-->B')" class="text-[9px] bg-[--color-line] px-2 py-1 rounded text-white">Flow</button>
83-
<button onclick="updateDiagram('sequenceDiagram\n Alice->>Bob: Hello')" class="text-[9px] bg-[--color-line] px-2 py-1 rounded text-white">Sequence</button>
84-
</div>
85-
</div>
86-
<div id="diagram-output" class="mermaid">
87-
</div>
96+
<button onclick="clearCanvas()" class="text-xs font-bold text-red-400/50 hover:text-red-400 ml-2 uppercase">Clear</button>
97+
98+
<div class="ml-auto flex gap-3">
99+
<button onclick="exportJPG()" class="btn-gold uppercase">Export JPG</button>
100+
<button onclick="exportPDF()" class="btn-gold uppercase">Export PDF</button>
88101
</div>
89102
</div>
103+
104+
<canvas id="whiteboard"></canvas>
90105
</div>
91106

92107
<script>
93-
// Initialize Mermaid with Dark Theme
94-
mermaid.initialize({
95-
startOnLoad: false,
96-
theme: 'dark',
97-
themeVariables: {
98-
primaryColor: '#FFC300',
99-
primaryTextColor: '#0C1524',
100-
primaryBorderColor: '#FFC300',
101-
lineColor: '#A0AEC0',
102-
secondaryColor: '#18233C',
103-
tertiaryColor: '#0C1524'
108+
const canvas = document.getElementById('whiteboard');
109+
const ctx = canvas.getContext('2d');
110+
111+
// Set canvas dimensions based on container
112+
function resizeCanvas() {
113+
// Create an offline buffer to save the state
114+
const buffer = document.createElement('canvas');
115+
buffer.width = canvas.width;
116+
buffer.height = canvas.height;
117+
buffer.getContext('2d').drawImage(canvas, 0, 0);
118+
119+
canvas.width = canvas.parentElement.offsetWidth - 32; // Include padding
120+
canvas.height = canvas.parentElement.offsetHeight - 200; // Offset for headers
121+
122+
// Restore state
123+
ctx.drawImage(buffer, 0, 0);
124+
}
125+
126+
// Whiteboard State
127+
let drawing = false;
128+
let currentTool = 'pencil';
129+
let currentColor = '#0C1524';
130+
let startX, startY;
131+
let savedCanvasImage;
132+
133+
function setTool(tool) {
134+
currentTool = tool;
135+
document.querySelectorAll('.tool-btn').forEach(b => b.classList.remove('active'));
136+
document.getElementById('btn-'+tool).classList.add('active');
137+
}
138+
139+
function setColor(color) {
140+
currentColor = color;
141+
document.querySelectorAll('.color-dot').forEach(b => b.classList.remove('active'));
142+
// Find the color dot by its style background and add active class
143+
event.target.classList.add('active');
144+
}
145+
146+
function clearCanvas() {
147+
ctx.clearRect(0, 0, canvas.width, canvas.height);
148+
}
149+
150+
// Core Drawing Logic
151+
function startDrawing(e) {
152+
drawing = true;
153+
startX = e.offsetX;
154+
startY = e.offsetY;
155+
156+
if (currentTool === 'pencil') {
157+
ctx.beginPath();
158+
ctx.moveTo(startX, startY);
159+
} else {
160+
// Save the state for shape preview
161+
savedCanvasImage = ctx.getImageData(0, 0, canvas.width, canvas.height);
104162
}
105-
});
106-
107-
const editor = document.getElementById('editor');
108-
const output = document.getElementById('diagram-output');
109-
110-
async function render() {
111-
const code = editor.value;
112-
try {
113-
output.innerHTML = ''; // Clear old
114-
const { svg } = await mermaid.render('mermaid-svg', code);
115-
output.innerHTML = svg;
116-
} catch (err) {
117-
// Silently wait for user to finish typing valid Mermaid syntax
163+
}
164+
165+
function stopDrawing() {
166+
drawing = false;
167+
ctx.beginPath(); // Reset path for pencil
168+
}
169+
170+
function draw(e) {
171+
if (!drawing) return;
172+
const x = e.offsetX;
173+
const y = e.offsetY;
174+
175+
ctx.lineWidth = currentTool === 'pencil' ? 3 : 2;
176+
ctx.lineCap = 'round';
177+
ctx.strokeStyle = currentColor;
178+
179+
if (currentTool === 'pencil') {
180+
ctx.lineTo(x, y);
181+
ctx.stroke();
182+
} else {
183+
// Shape Preview Logic
184+
ctx.putImageData(savedCanvasImage, 0, 0); // Restore original state
185+
ctx.beginPath();
186+
187+
if (currentTool === 'rect') {
188+
ctx.rect(startX, startY, x - startX, y - startY);
189+
} else if (currentTool === 'circle') {
190+
const radius = Math.sqrt(Math.pow(x - startX, 2) + Math.pow(y - startY, 2));
191+
ctx.arc(startX, startY, radius, 0, 2 * Math.PI);
192+
} else if (currentTool === 'line') {
193+
ctx.moveTo(startX, startY);
194+
ctx.lineTo(x, y);
195+
}
196+
ctx.stroke();
118197
}
119198
}
120199

121-
function updateDiagram(template) {
122-
editor.value = template;
123-
render();
200+
// Export Logic
201+
function exportJPG() {
202+
// Create a temporary canvas to add the solid background
203+
const exportCanvas = document.createElement('canvas');
204+
exportCanvas.width = canvas.width;
205+
exportCanvas.height = canvas.height;
206+
const eCtx = exportCanvas.getContext('2d');
207+
208+
// Add solid background (JPG doesn't support transparency)
209+
eCtx.fillStyle = "#F0F4F8";
210+
eCtx.fillRect(0, 0, canvas.width, canvas.height);
211+
eCtx.drawImage(canvas, 0, 0);
212+
213+
const link = document.createElement('a');
214+
link.download = 'whiteboard-sketch.jpg';
215+
link.href = exportCanvas.toDataURL('image/jpeg', 0.9);
216+
link.click();
124217
}
125218

126-
function downloadSVG() {
127-
const svgData = document.getElementById('mermaid-svg').outerHTML;
128-
const svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
129-
const svgUrl = URL.createObjectURL(svgBlob);
130-
const downloadLink = document.createElement("a");
131-
downloadLink.href = svgUrl;
132-
downloadLink.download = "architecture-diagram.svg";
133-
document.body.appendChild(downloadLink);
134-
downloadLink.click();
135-
document.body.removeChild(downloadLink);
219+
function exportPDF() {
220+
const { jsPDF } = window.jspdf;
221+
const doc = new jsPDF('l', 'px', [canvas.width, canvas.height]);
222+
223+
// Jspdf works best with base64 images
224+
const imgData = canvas.toDataURL('image/png');
225+
doc.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height);
226+
doc.save('whiteboard-sketch.pdf');
136227
}
137228

138-
// Debounced listener
139-
let timeout = null;
140-
editor.addEventListener('input', () => {
141-
clearTimeout(timeout);
142-
timeout = setTimeout(render, 500);
143-
});
229+
// Event Listeners
230+
canvas.addEventListener('mousedown', startDrawing);
231+
canvas.addEventListener('mousemove', draw);
232+
canvas.addEventListener('mouseup', stopDrawing);
233+
canvas.addEventListener('mouseout', stopDrawing);
234+
235+
window.addEventListener('load', resizeCanvas);
236+
window.addEventListener('resize', resizeCanvas);
144237

145-
// Initial load
146-
window.onload = render;
147238
</script>
148239
</body>
149240
</html>

0 commit comments

Comments
 (0)