GtHn
zK_`)aZ}Ba&QgNJ#{KGykKH&BAI-Lc-@+Eg1Pd-27Y$|-B)a%^sw(nE!XsbK6Qzbiw
z1zb}=UGgL5htIqxw+>ZD}|526dBjMDNS4MZ-=<>R{$4?(|2m8Ig
z#O2oKl-JYh4!yEsJaNo@E1vxM&y=^bEqUgc;}t%7-^AEn??k`X)0ql*W%R}I#O}$1
zhg18dV)Co*H>Tph-Ja}YnW?zriMO0pMO(@z-ah5_A7@WGq4qX+@ICj{7gO7p)!lu2
z-MuHBc+tjO_rO`N?}dpSyWAshI{C$O_}}Q8+<#UozNPq;ikn}J7k_s$elmG_OeK$;
zWjhmNhrE{u)MWga+t#VPy}ew{wc-Uns=^6~rvAa*K|hwuR-2pE^A(>hcHev4=ll77-kIBA4S#i93%I^Z)9C-dgBivYG3>!rIDnb>J?7$%&KWFV{0HV?IuB{y
zi+)^yWmtu)F^cnziJLBd+{2Ci$j2O=n=q%agz;%4rWwa3dJJGa@-aL3Qk<8ug#FDvH*o@$`Dt8)=h2H-u@G2HJ>ZpIl6?iw7{_CvDNn43jpcX!i_hA@yc8#caVHc_+J-8l+
zP@PDi68#&sK_S_7&!cM8x^rZ$PJN0>^foH-I|cM#KXUkzLFYwxa@_
zaP#lF@df8aRH74Z`~%W`a|2i6ERw77$4Og(mZDnqfE!1!m~j-f@w2D}F;t)~cmEC4
z`aU;5h)WoM;Kq}v^*68_e@At!lr|}TJj4$Lcogr&S|mBs>fG(-Uq>xCjCy;AQ7_k7
zH~)q6Dzb-}LT#Kv9n~E-U(HR$*@$!^ZtC2PS5Xxn!__#1O6VFY#dxvaoV7c8LxM1so)%I9${9n##>@)xX
diff --git a/translations/zh/LC_MESSAGES/messages.po b/translations/zh/LC_MESSAGES/messages.po
index 054fc63..b50556b 100644
--- a/translations/zh/LC_MESSAGES/messages.po
+++ b/translations/zh/LC_MESSAGES/messages.po
@@ -336,6 +336,14 @@ msgstr "还没有回忆,下面添加一个吧!"
msgid "Date"
msgstr "日期"
+#: templates/memories.html:16
+msgid "Memory List"
+msgstr "回忆列表"
+
+#: templates/memories.html:42
+msgid "Add New Memory"
+msgstr "添加新回忆"
+
#: templates/memories.html:51
msgid "Memory"
msgstr "回忆"
From cb3376e12e20af850cc16583271ab06b4b1fb590 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 12:51:16 +0000
Subject: [PATCH 3/5] Fix canvas display mode and add comprehensive Chinese
translations
- Changed .clipboard-drawing-wrap display from 'block' to 'flex' to work with flexbox parent
- Wrapped all error messages in app.py with _() for translation support
- Added Chinese translations for all error messages (Invalid credentials, Connection not found, Access denied, etc.)
- Compiled updated translations
Co-authored-by: w1010tdev <246258262+w1010tdev@users.noreply.github.com>
---
app.py | 46 +++++++++----------
static/css/style.css | 2 +-
translations/zh/LC_MESSAGES/messages.mo | Bin 6994 -> 7733 bytes
translations/zh/LC_MESSAGES/messages.po | 57 ++++++++++++++++++++++++
4 files changed, 81 insertions(+), 24 deletions(-)
diff --git a/app.py b/app.py
index c811926..e6e758a 100644
--- a/app.py
+++ b/app.py
@@ -203,7 +203,7 @@ def login():
login_user(user)
return redirect(url_for('dashboard'))
- return render_template('login.html', error='Invalid credentials')
+ return render_template('login.html', error=_('Invalid credentials'))
return render_template('login.html')
@@ -239,17 +239,17 @@ def refresh_token():
def add_memory(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
- return jsonify({'success': False, 'error': 'Connection not found'}), 404
+ return jsonify({'success': False, 'error': _('Connection not found')}), 404
data = request.get_json(silent=True) or {}
memory_text = (data.get('memory_text') or '').strip()
memory_date = (data.get('memory_date') or '').strip()
if not memory_text or len(memory_text) > 200:
- return jsonify({'success': False, 'error': 'Invalid memory text'}), 400
+ return jsonify({'success': False, 'error': _('Invalid memory text')}), 400
if not validate_memory_date(memory_date):
- return jsonify({'success': False, 'error': 'Invalid memory date'}), 400
+ return jsonify({'success': False, 'error': _('Invalid memory date')}), 400
memory_id = ConnectionMemory.create(connection_id, current_user.id, memory_text, memory_date)
return jsonify({'success': True, 'memory_id': memory_id})
@@ -260,10 +260,10 @@ def add_memory(connection_id):
def approve_memory(connection_id, memory_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
- return jsonify({'success': False, 'error': 'Connection not found'}), 404
+ return jsonify({'success': False, 'error': _('Connection not found')}), 404
if not ConnectionMemory.approve(connection_id, memory_id, current_user.id):
- return jsonify({'success': False, 'error': 'Unable to approve memory'}), 400
+ return jsonify({'success': False, 'error': _('Unable to approve memory')}), 400
return jsonify({'success': True})
@@ -293,7 +293,7 @@ def connection_page(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
- return render_template('error.html', message='Connection not found')
+ return render_template('error.html', message=_('Connection not found'))
other_user = connection.get_other_user(current_user.id)
return render_template('connection.html', connection=connection, other_user=other_user)
@@ -304,7 +304,7 @@ def clipboard(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
- return render_template('error.html', message='Connection not found')
+ return render_template('error.html', message=_('Connection not found'))
clipboard_data = SharedClipboard.get_by_connection(connection_id)
other_user = connection.get_other_user(current_user.id)
@@ -319,7 +319,7 @@ def clipboard(connection_id):
def memories(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
- return render_template('error.html', message='Connection not found')
+ return render_template('error.html', message=_('Connection not found'))
other_user = connection.get_other_user(current_user.id)
memories = ConnectionMemory.get_for_connection(connection_id)
@@ -334,7 +334,7 @@ def drawing_game(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
- return render_template('error.html', message='Connection not found')
+ return render_template('error.html', message=_('Connection not found'))
game = DrawingGame.get_by_connection(connection_id)
other_user = connection.get_other_user(current_user.id)
@@ -350,7 +350,7 @@ def chat(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
- return render_template('error.html', message='Connection not found')
+ return render_template('error.html', message=_('Connection not found'))
other_user = connection.get_other_user(current_user.id)
messages = ChatMessage.get_messages(connection_id)
@@ -376,7 +376,7 @@ def admin_login():
if secrets.compare_digest(password, admin_password):
session['is_admin'] = True
return redirect(url_for('admin_panel'))
- return render_template('admin_login.html', error='Invalid password')
+ return render_template('admin_login.html', error=_('Invalid password'))
return render_template('admin_login.html')
@@ -615,23 +615,23 @@ def handle_drawing_start(data):
# Validate access
if not validate_connection_access(connection_id, drawer_id):
- return {'success': False, 'error': 'Access denied'}
+ return {'success': False, 'error': _('Access denied')}
# Validate answer (limit to 50 characters)
answer = answer.strip()[:50]
if not answer:
- return {'success': False, 'error': 'Answer required'}
+ return {'success': False, 'error': _('Answer required')}
# Get or create session
session = DrawingSession.get_active_session(connection_id)
if not session:
- return {'success': False, 'error': 'No active session'}
+ return {'success': False, 'error': _('No active session')}
if session.waiting_for_partner:
- return {'success': False, 'error': 'Waiting for partner to join'}
+ return {'success': False, 'error': _('Waiting for partner to join')}
if session.is_session_complete():
- return {'success': False, 'error': 'Session complete'}
+ return {'success': False, 'error': _('Session complete')}
# Start the round
session.start_next_round(drawer_id, answer)
@@ -721,15 +721,15 @@ def handle_end_game_early(data):
session_id = data.get('session_id')
if not validate_connection_access(connection_id, current_user.id):
- return {'success': False, 'error': 'Access denied'}
+ return {'success': False, 'error': _('Access denied')}
session = DrawingSession.get_by_id(session_id)
if not session or session.connection_id != connection_id:
- return {'success': False, 'error': 'Invalid session'}
+ return {'success': False, 'error': _('Invalid session')}
# Ensure the session is still active
if not session.is_active:
- return {'success': False, 'error': 'Session is not active'}
+ return {'success': False, 'error': _('Session is not active')}
# End the session
session.end_session()
@@ -749,7 +749,7 @@ def handle_create_new_game_session(data):
connection_id = data.get('connection_id')
if not validate_connection_access(connection_id, current_user.id):
- return {'success': False, 'error': 'Access denied'}
+ return {'success': False, 'error': _('Access denied')}
# Create new session (this will deactivate old ones)
session_id = DrawingSession.create(connection_id, current_user.id, DEFAULT_ROUNDS_PER_SESSION)
@@ -773,11 +773,11 @@ def handle_send_message(data):
# Validate access
if not validate_connection_access(connection_id, current_user.id):
- return {'success': False, 'error': 'Access denied'}
+ return {'success': False, 'error': _('Access denied')}
# Validate message length (max 1000 chars)
if not message or len(message) > 1000:
- return {'success': False, 'error': 'Invalid message'}
+ return {'success': False, 'error': _('Invalid message')}
# Save message
message_id = ChatMessage.create(connection_id, current_user.id, message)
diff --git a/static/css/style.css b/static/css/style.css
index 0d8a7d2..ef8aada 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -471,7 +471,7 @@ body {
}
.clipboard-display.drawing-active .clipboard-drawing-wrap {
- display: block;
+ display: flex;
}
.clipboard-display.drawing-active {
diff --git a/translations/zh/LC_MESSAGES/messages.mo b/translations/zh/LC_MESSAGES/messages.mo
index e04dc5d2aa71207491c56ef8489bcd9797acbf46..2b7624113aeb0b3aac849f410f7a6e5b4d0f71fe 100644
GIT binary patch
delta 2759
zcmZA14@}f$9LMqJ6jMY&PX$E73;dT^LQX1W)8S^*bh`d-%}mCf?o{rOJO5XwrU+>M
zJIz8(%rNHyoS0@BPA#*!N^7x3&DG*}fYzqVmbtRtpYAD~4DR(j&+mD@&-eL0zvHXC
z_wyr{-3i+bKV|$4$EXc2qe|a`x~i+F1aH{!
z6tYnwsi-(vsEUs6N&Qvg84M^9AL``uPrxjb1=iW)617<){<9g8gt4>dIJzWUVPjmGTW#0(d(SiG@*>sYG4XKGcREq2iuF#fw~^kxkVO}{`w?@RhEDzkDuK(kf6LmP>$nb8!7Xxb>hEmKaJxkU?%FF
z7>*+_A9b?1sExy@4OXD8YP}ubkAyO{sD#gA5B4`rG!*zJRDfUXgd4Wsl`OPDGJ0@;
z?dPKcO~%1E6Llr4P#aaD;vKRcLshsDm0&YQ)VN|N+(IpM5k(8rteMs!sDB(IZGRMM
zeI9DvB?O#Wo{3hz8U3epDnsn4lmy23o
zfd5v)IurGh22od3kDAwvs`QVjgs=9e{+i%oR}G9r{XZx`E%2fen2%#{DQcrSR3fKQ
z-~VRRyiU|t>rzntRNK!+RceHFEb7XpL}=vE2-*kxQD4WSsDzqPfv%wf|7A_!|EI>2
zP=V7?&xcz_p%Tlp{aL8e`%vG8HK=uw!!(A_ID^`-4RylXw%_~Sc*%xYb5R?OLw-#G
zADTbgj)zc{S#FIYIh*$|2hZF7AIJfcOh3|6fUL}DRo7`rMZQqTw)Az
zXo;`XQ|eo|$Y1L7HdJ;S=t>L(!=5?8MFDR^RpLQcWO86};R3(cQ^W*cAnY$(5HkOb
z75j>VrOQ0t!m#h|v9NDx_>QqqsBmt_oRY#&Xi2ct`~QRxdHI6@Gu0oM?c2si{i|Y|Hn%kHY^~iE+gl!8*yqp0*sg=IibkjWP{W+Qhh34_j_TO<^46*~&br#R
z`cEbmyGNa}wNBmfj?viB^4O~Sj=oc0)>?f>td^5iZS}iNd$cjO
zvBo)e*m>tQr~D{6IMD}E-*v|h?~U!Mh#fiMR33;=ZMc+r(lsdF*8I8+vGUC(-q!(6
ntz>q?hV)Ne(Fqwd+^w}0PUBjq{&?*5<4$F@v$iI>DdX%v9&ORp
delta 2059
zcmYMze`r-@9LMqJ%(>rgcXQtT>dtb@pQv+V^Pg>Z)yj}%7(_^Dm^P82(iZAexS}ZP
zSR0*6Vk=6xD)^7{6x^I53AxHjU8R3G3>g#W4_tqU4j20Vj4yaO_q?88=leX*_dMr^
z+QFLGjlAS99KY@SU*JD9MYZR@-c;wNQ~esNun$vk1T*j+X5%9aV@jHHnHVwWq57*a
z3mdI{CFVO9bE_#7($R{27lP~%dlXd#(66=$LP
z=W?5Yl~{{!Vg~cOeUk;}x=|VEK?O>n7Iqek@G5G7W60$mbJMsa(x3@bQT?T;ozBKm
ztilk!gE_bk=U^KaFu&`epcDtF6%U{S|AECgho#m#9E}}B|
zH|iYUMy2{5Hefy{Q5$&|XJKw$*b{UqhkQmzwqF
z>!=JgS$zX)Bb!kR--%lArx?>=IYvPfC2YVs)S((gr8tlGp#D14D`-S5cm=9|z16!=
zpJyC3egHM`pID98Q47drb}gX1ko@cWtfQuZAE6#>wR*eN_oGtXi8Xi%mC8}nS2B)T
zP=rrJajH;p8q8(Zz5?~!`_|r4ME)lyq(KX5w~p^nDL#%my#uHRAL7e6mHcYL1?DTL
z%)Do=Ma6Bw2)0_i8(FJ6Y@VD)L5Jg4tiTbghiTMKDp4tmmiRl;-tzxRiwB3&i@o5-
zjBmW;rj46h{F|Y$emw&^PBws{8Rq!8BcZ;PCN2C>u3pa1{>
diff --git a/translations/zh/LC_MESSAGES/messages.po b/translations/zh/LC_MESSAGES/messages.po
index b50556b..7bb2dc8 100644
--- a/translations/zh/LC_MESSAGES/messages.po
+++ b/translations/zh/LC_MESSAGES/messages.po
@@ -375,6 +375,63 @@ msgstr "无法确认回忆。"
#: templates/memories.html:117
msgid "Memory approved!"
msgstr "回忆已确认!"
+
+#: app.py:206
+msgid "Invalid credentials"
+msgstr "无效的凭证"
+
+#: app.py:249
+msgid "Invalid memory text"
+msgstr "无效的回忆内容"
+
+#: app.py:252
+msgid "Invalid memory date"
+msgstr "无效的回忆日期"
+
+#: app.py:242 app.py:263 app.py:296 app.py:307 app.py:322 app.py:337 app.py:353
+msgid "Connection not found"
+msgstr "未找到连接"
+
+#: app.py:266
+msgid "Unable to approve memory"
+msgstr "无法确认回忆"
+
+#: app.py:379
+msgid "Invalid password"
+msgstr "无效的密码"
+
+#: app.py:618 app.py:724 app.py:752 app.py:776
+msgid "Access denied"
+msgstr "拒绝访问"
+
+#: app.py:623
+msgid "Answer required"
+msgstr "需要提供答案"
+
+#: app.py:628
+msgid "No active session"
+msgstr "没有活动会话"
+
+#: app.py:631
+msgid "Waiting for partner to join"
+msgstr "等待对方加入"
+
+#: app.py:634
+msgid "Session complete"
+msgstr "会话已完成"
+
+#: app.py:728
+msgid "Invalid session"
+msgstr "无效的会话"
+
+#: app.py:732
+msgid "Session is not active"
+msgstr "会话未激活"
+
+#: app.py:780
+msgid "Invalid message"
+msgstr "无效的消息"
+
#: templates/dashboard.html:58
msgid "No connections yet. Share your invite token to connect with others!"
msgstr "还没有连接。分享您的邀请令牌以与他人连接!"
From 672941a524886c49ff7b08b4017646f37d77d0cd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 13:29:54 +0000
Subject: [PATCH 4/5] Fix canvas size to match textarea and fix drawing
trajectory playback
- Changed canvas min-height from 300px to 400px to match textarea (400px)
- Added mobile-specific canvas sizing (150px to match mobile textarea)
- Fixed renderDrawing() to maintain path continuity - removed ctx.beginPath() and ctx.moveTo() after each draw point
- Now receiver sees complete writing trajectory instead of moving dots
Co-authored-by: w1010tdev <246258262+w1010tdev@users.noreply.github.com>
---
static/css/style.css | 24 ++++++++++++++++++++----
templates/clipboard.html | 12 ++++++------
2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/static/css/style.css b/static/css/style.css
index ef8aada..aa6b431 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -450,7 +450,7 @@ body {
background: #ffffff;
padding: 0.5rem;
flex: 1;
- min-height: 300px;
+ min-height: 400px;
}
.clipboard-drawing-wrap canvas {
@@ -475,11 +475,11 @@ body {
}
.clipboard-display.drawing-active {
- min-height: 360px;
+ min-height: 400px;
}
.clipboard-pane.other-pane .clipboard-display.drawing-active {
- min-height: 320px;
+ min-height: 400px;
}
.clipboard-container.handwriting-mode {
@@ -495,7 +495,7 @@ body {
}
.clipboard-container.handwriting-mode .clipboard-pane.other-pane .clipboard-display.drawing-active {
- min-height: 180px;
+ min-height: 300px;
}
.clipboard-textarea {
@@ -1088,6 +1088,22 @@ body {
font-size: 0.9rem;
}
+ .clipboard-drawing-wrap {
+ min-height: 150px;
+ }
+
+ .clipboard-display.drawing-active {
+ min-height: 150px;
+ }
+
+ .clipboard-pane.other-pane .clipboard-display.drawing-active {
+ min-height: 150px;
+ }
+
+ .clipboard-container.handwriting-mode .clipboard-pane.other-pane .clipboard-display.drawing-active {
+ min-height: 120px;
+ }
+
.clipboard-toolbar {
flex-direction: column;
align-items: flex-start;
diff --git a/templates/clipboard.html b/templates/clipboard.html
index 40656e2..11e995e 100644
--- a/templates/clipboard.html
+++ b/templates/clipboard.html
@@ -586,19 +586,19 @@ {{ _('Your Area (%(username)s)', username=curren
}
return;
}
- if (drawing.type === 'stroke_end' || drawing.type === 'stroke_start') {
+ if (drawing.type === 'stroke_start') {
ctx.beginPath();
- if (drawing.type === 'stroke_start') {
- ctx.moveTo(drawing.x, drawing.y);
- }
+ ctx.moveTo(drawing.x, drawing.y);
+ return;
+ }
+ if (drawing.type === 'stroke_end') {
return;
}
+ // For 'draw' type - continue the current path
ctx.lineWidth = 4;
ctx.strokeStyle = '#1f2937';
ctx.lineTo(drawing.x, drawing.y);
ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(drawing.x, drawing.y);
if (ctx === otherDrawingCtx) {
otherDrawingHasContent = true;
}
From 5b4117f198f68648904e024d5529ffda77598207 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 5 Feb 2026 13:50:44 +0000
Subject: [PATCH 5/5] Refactor drawing rendering to match drawing game logic
- Removed stroke_start emission - drawer now only emits 'draw' and 'stroke_end' events
- Updated drawStroke() to match drawing game pattern: beginPath() and moveTo() after each point
- Updated renderDrawing() to match drawing game receiver pattern exactly
- Both drawer and receiver now use consistent ctx.beginPath()/moveTo() pattern
- Added lineCap and lineJoin for smoother strokes
- This ensures continuous stroke rendering on receiver side
Co-authored-by: w1010tdev <246258262+w1010tdev@users.noreply.github.com>
---
templates/clipboard.html | 39 ++++++++++++++++++---------------------
1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/templates/clipboard.html b/templates/clipboard.html
index 11e995e..f82e055 100644
--- a/templates/clipboard.html
+++ b/templates/clipboard.html
@@ -417,19 +417,18 @@ {{ _('Your Area (%(username)s)', username=curren
lastY = e.clientY - rect.top;
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(lastX, lastY);
- emitDrawing({ type: 'stroke_start', x: lastX, y: lastY });
}
function drawStroke(x, y) {
myDrawingCtx.lineWidth = 4;
+ myDrawingCtx.lineCap = 'round';
+ myDrawingCtx.lineJoin = 'round';
myDrawingCtx.strokeStyle = '#1f2937';
myDrawingCtx.lineTo(x, y);
myDrawingCtx.stroke();
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(x, y);
localDrawingHasContent = true;
- lastX = x;
- lastY = y;
emitDrawing({ type: 'draw', x, y });
}
@@ -438,8 +437,6 @@ {{ _('Your Area (%(username)s)', username=curren
const rect = myDrawingCanvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
- myDrawingCtx.beginPath();
- myDrawingCtx.moveTo(lastX, lastY);
drawStroke(x, y);
lastX = x;
lastY = y;
@@ -487,7 +484,6 @@ {{ _('Your Area (%(username)s)', username=curren
lastY = touch.clientY - rect.top;
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(lastX, lastY);
- emitDrawing({ type: 'stroke_start', x: lastX, y: lastY });
}, { passive: false });
myDrawingCanvas.addEventListener('touchmove', (event) => {
@@ -497,9 +493,9 @@ {{ _('Your Area (%(username)s)', username=curren
const rect = myDrawingCanvas.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
- myDrawingCtx.beginPath();
- myDrawingCtx.moveTo(lastX, lastY);
drawStroke(x, y);
+ lastX = x;
+ lastY = y;
}, { passive: false });
myDrawingCanvas.addEventListener('touchend', (event) => {
@@ -521,7 +517,7 @@ {{ _('Your Area (%(username)s)', username=curren
drawingPoints.push(drawing);
}
otherLastStroke = Date.now();
- if (drawing.type === 'stroke_start' || drawing.type === 'draw') {
+ if (drawing.type === 'draw') {
setRemoteDrawingActive(true);
}
lastRemoteTimestamp = drawing.ts || lastRemoteTimestamp;
@@ -586,21 +582,22 @@ {{ _('Your Area (%(username)s)', username=curren
}
return;
}
- if (drawing.type === 'stroke_start') {
- ctx.beginPath();
- ctx.moveTo(drawing.x, drawing.y);
- return;
- }
if (drawing.type === 'stroke_end') {
+ ctx.beginPath();
return;
}
- // For 'draw' type - continue the current path
- ctx.lineWidth = 4;
- ctx.strokeStyle = '#1f2937';
- ctx.lineTo(drawing.x, drawing.y);
- ctx.stroke();
- if (ctx === otherDrawingCtx) {
- otherDrawingHasContent = true;
+ if (drawing.type === 'draw') {
+ ctx.lineWidth = 4;
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+ ctx.strokeStyle = '#1f2937';
+ ctx.lineTo(drawing.x, drawing.y);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(drawing.x, drawing.y);
+ if (ctx === otherDrawingCtx) {
+ otherDrawingHasContent = true;
+ }
}
}