@filipc77/cowrite 0.4.28 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ui/index.html CHANGED
@@ -8,6 +8,10 @@
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
10
10
  <link rel="stylesheet" href="styles.css">
11
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown-dark.css" id="gmc-dark" />
12
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown-light.css" id="gmc-light" disabled />
13
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11/styles/github-dark.min.css" id="hljs-dark" />
14
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11/styles/github.min.css" id="hljs-light" disabled />
11
15
  </head>
12
16
  <body>
13
17
  <header>
@@ -22,6 +26,9 @@
22
26
  <span class="file-path" id="filePath"></span>
23
27
  </div>
24
28
  <div class="header-right">
29
+ <button class="undo-btn" id="undoBtn" disabled title="Undo (Cmd+Z)">
30
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>
31
+ </button>
25
32
  <span class="status" id="status">
26
33
  <span class="status-dot"></span>
27
34
  Connecting...
@@ -50,8 +57,10 @@
50
57
  </div>
51
58
  </main>
52
59
 
53
- <!-- Floating comment button (appears on text selection) -->
54
- <button class="comment-trigger" id="commentTrigger" hidden>Comment</button>
60
+ <!-- Floating selection toolbar (appears on text selection) -->
61
+ <div class="selection-toolbar" id="selectionToolbar" hidden>
62
+ <button id="commentTrigger">Comment</button>
63
+ </div>
55
64
 
56
65
  <!-- Comment form (appears when comment button is clicked) -->
57
66
  <div class="comment-popup" id="commentPopup" hidden>
@@ -64,6 +73,14 @@
64
73
  </div>
65
74
  </div>
66
75
 
76
+ <!-- Highlight popover (appears when clicking a comment highlight) -->
77
+ <div class="highlight-popover" id="highlightPopover" hidden>
78
+ <div class="highlight-popover-text" id="highlightPopoverText"></div>
79
+ <div class="highlight-popover-actions">
80
+ <button id="highlightEditBtn">Edit</button>
81
+ </div>
82
+ </div>
83
+
67
84
  <script type="module">
68
85
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
69
86
  mermaid.initialize({ startOnLoad: false, theme: 'dark' });
package/ui/styles.css CHANGED
@@ -185,6 +185,32 @@ header h1 {
185
185
  letter-spacing: 0.2px;
186
186
  }
187
187
 
188
+ /* ---- Undo button ---- */
189
+ .undo-btn {
190
+ display: flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ width: 32px;
194
+ height: 32px;
195
+ border-radius: var(--radius-sm);
196
+ border: 1px solid var(--border);
197
+ background: var(--surface);
198
+ color: var(--text-dim);
199
+ cursor: pointer;
200
+ transition: all 0.15s ease;
201
+ flex-shrink: 0;
202
+ }
203
+
204
+ .undo-btn:hover:not(:disabled) {
205
+ color: var(--accent);
206
+ border-color: var(--accent);
207
+ }
208
+
209
+ .undo-btn:disabled {
210
+ opacity: 0.3;
211
+ cursor: default;
212
+ }
213
+
188
214
  /* Status badge */
189
215
  .status {
190
216
  display: flex;
@@ -302,6 +328,7 @@ main {
302
328
  }
303
329
 
304
330
  #fileContent {
331
+ position: relative;
305
332
  max-width: 860px;
306
333
  margin: 0 auto;
307
334
  font-size: 16px;
@@ -315,159 +342,69 @@ main {
315
342
  to { opacity: 1; transform: translateY(0); }
316
343
  }
317
344
 
318
- /* ---- Markdown styles (GitHub-like) ---- */
345
+ /* ---- Markdown body theme overrides (on top of github-markdown-css) ---- */
319
346
  .markdown-body {
320
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
321
- font-size: 16px;
322
- line-height: 1.5;
323
- word-wrap: break-word;
347
+ color-scheme: dark;
348
+ background: transparent !important;
324
349
  }
325
-
350
+ [data-theme="light"] .markdown-body {
351
+ color-scheme: light;
352
+ }
353
+ .markdown-body a { color: var(--accent); text-decoration: none; }
354
+ .markdown-body a:hover { text-decoration: underline; }
355
+ .markdown-body pre code.hljs { background: none; padding: 0; }
326
356
  .markdown-body > *:first-child { margin-top: 0; }
327
357
  .markdown-body > *:last-child { margin-bottom: 0; }
328
358
 
329
- .markdown-body h1, .markdown-body h2, .markdown-body h3,
330
- .markdown-body h4, .markdown-body h5, .markdown-body h6 {
331
- margin-top: 24px;
332
- margin-bottom: 16px;
333
- font-weight: 600;
334
- color: var(--text);
335
- line-height: 1.25;
336
- }
337
-
338
- .markdown-body h1 {
339
- font-size: 2em;
340
- border-bottom: 1px solid var(--border);
341
- padding-bottom: 0.3em;
342
- }
343
-
344
- .markdown-body h2 {
345
- font-size: 1.5em;
346
- border-bottom: 1px solid var(--border);
347
- padding-bottom: 0.3em;
348
- }
349
-
350
- .markdown-body h3 { font-size: 1.25em; }
351
- .markdown-body h4 { font-size: 1em; }
352
- .markdown-body h5 { font-size: 0.875em; }
353
- .markdown-body h6 { font-size: 0.85em; color: var(--text-dim); }
354
-
355
- .markdown-body p {
356
- margin-top: 0;
357
- margin-bottom: 16px;
358
- }
359
-
360
- .markdown-body ul, .markdown-body ol {
361
- margin-top: 0;
362
- margin-bottom: 16px;
363
- padding-left: 2em;
364
- }
365
-
366
- .markdown-body li {
367
- margin-top: 0.25em;
368
- }
369
-
370
- .markdown-body li + li {
371
- margin-top: 0.25em;
372
- }
373
-
374
- .markdown-body code {
375
- font-family: var(--font-mono);
376
- font-size: 85%;
377
- background: var(--surface-hover);
378
- padding: 0.2em 0.4em;
379
- border-radius: 6px;
380
- }
381
-
382
- .markdown-body pre {
383
- background: var(--surface);
384
- padding: 16px;
385
- border-radius: 6px;
386
- overflow-x: auto;
359
+ /* ---- Code block wrapper ---- */
360
+ .code-block-wrapper {
361
+ position: relative;
387
362
  margin-top: 0;
388
363
  margin-bottom: 16px;
389
- font-size: 85%;
390
- line-height: 1.45;
391
364
  border: 1px solid var(--border);
392
- }
393
-
394
- .markdown-body pre code {
395
- background: none;
396
- padding: 0;
397
- border-radius: 0;
398
- font-size: 100%;
399
- word-break: normal;
400
- white-space: pre;
401
- }
402
-
403
- .markdown-body blockquote {
404
- border-left: 0.25em solid var(--border);
405
- padding: 0 1em;
406
- color: var(--text-dim);
407
- margin-top: 0;
408
- margin-bottom: 16px;
409
- }
410
-
411
- .markdown-body blockquote > :first-child { margin-top: 0; }
412
- .markdown-body blockquote > :last-child { margin-bottom: 0; }
413
-
414
- .markdown-body a { color: var(--accent); text-decoration: none; }
415
- .markdown-body a:hover { text-decoration: underline; }
416
-
417
- .markdown-body img {
418
- max-width: 100%;
419
365
  border-radius: 6px;
366
+ overflow: hidden;
420
367
  }
421
368
 
422
- .markdown-body hr {
423
- height: 0.25em;
424
- padding: 0;
425
- margin: 24px 0;
426
- background: var(--border);
427
- border: 0;
428
- border-radius: 2px;
369
+ .code-block-header {
370
+ display: flex;
371
+ align-items: center;
372
+ justify-content: space-between;
373
+ padding: 6px 12px;
374
+ background: var(--surface-hover);
375
+ border-bottom: 1px solid var(--border);
376
+ font-size: 12px;
429
377
  }
430
378
 
431
- .markdown-body table {
432
- border-collapse: collapse;
433
- border-spacing: 0;
434
- margin-top: 0;
435
- margin-bottom: 16px;
436
- width: auto;
437
- display: block;
438
- overflow-x: auto;
379
+ .code-block-lang {
380
+ font-family: var(--font-mono);
381
+ font-size: 11px;
382
+ color: var(--text-dim);
383
+ text-transform: lowercase;
439
384
  }
440
385
 
441
- .markdown-body th, .markdown-body td {
386
+ .code-copy-btn {
387
+ font-family: var(--font-sans);
388
+ font-size: 11px;
389
+ font-weight: 500;
390
+ padding: 2px 10px;
391
+ border-radius: 4px;
442
392
  border: 1px solid var(--border);
443
- padding: 6px 13px;
444
- text-align: left;
445
- }
446
-
447
- .markdown-body th {
448
- font-weight: 600;
449
393
  background: var(--surface);
394
+ color: var(--text-dim);
395
+ cursor: pointer;
396
+ transition: all 0.15s ease;
450
397
  }
451
398
 
452
- .markdown-body tr:nth-child(2n) {
453
- background: var(--bg-subtle);
454
- }
455
-
456
- .markdown-body dl {
457
- padding: 0;
458
- margin-bottom: 16px;
459
- }
460
-
461
- .markdown-body dl dt {
462
- font-weight: 600;
463
- margin-top: 16px;
464
- padding: 0;
465
- font-size: 1em;
399
+ .code-copy-btn:hover {
400
+ color: var(--accent);
401
+ border-color: var(--accent);
466
402
  }
467
403
 
468
- .markdown-body dl dd {
469
- padding: 0 16px;
470
- margin-bottom: 16px;
404
+ .code-block-wrapper pre {
405
+ margin: 0 !important;
406
+ border: none !important;
407
+ border-radius: 0 !important;
471
408
  }
472
409
 
473
410
  /* Plain text */
@@ -490,11 +427,6 @@ main {
490
427
  border-radius: 2px;
491
428
  }
492
429
 
493
- .comment-highlight.resolved {
494
- background: transparent;
495
- border-bottom-color: transparent;
496
- }
497
-
498
430
  .comment-highlight:hover {
499
431
  background: rgba(212, 165, 84, 0.18);
500
432
  }
@@ -553,6 +485,7 @@ main {
553
485
 
554
486
  /* ---- Comment card ---- */
555
487
  .comment-card {
488
+ position: relative;
556
489
  background: var(--bg-subtle);
557
490
  border: 1px solid var(--border);
558
491
  border-radius: var(--radius-md);
@@ -563,6 +496,30 @@ main {
563
496
  animation: card-enter 0.25s ease both;
564
497
  }
565
498
 
499
+ .comment-delete-btn {
500
+ position: absolute;
501
+ top: 8px;
502
+ right: 8px;
503
+ background: none;
504
+ border: none;
505
+ color: var(--text-faint);
506
+ cursor: pointer;
507
+ padding: 4px;
508
+ border-radius: var(--radius-sm);
509
+ opacity: 0;
510
+ transition: opacity 0.15s, color 0.15s, background 0.15s;
511
+ line-height: 1;
512
+ }
513
+
514
+ .comment-card:hover .comment-delete-btn {
515
+ opacity: 1;
516
+ }
517
+
518
+ .comment-delete-btn:hover {
519
+ color: var(--red, #d4616e);
520
+ background: rgba(212, 97, 110, 0.1);
521
+ }
522
+
566
523
  .comment-card:hover {
567
524
  border-color: var(--border-hover);
568
525
  box-shadow: var(--shadow-sm);
@@ -762,31 +719,40 @@ main {
762
719
  transform: scale(0.97);
763
720
  }
764
721
 
765
- /* ---- Comment trigger button ---- */
766
- .comment-trigger {
722
+ /* ---- Selection toolbar ---- */
723
+ .selection-toolbar {
767
724
  position: fixed;
768
725
  z-index: 999;
726
+ display: flex;
727
+ gap: 1px;
728
+ background: var(--border);
729
+ border-radius: var(--radius-sm);
730
+ box-shadow: var(--shadow-md);
731
+ overflow: hidden;
732
+ animation: popup-enter 0.15s ease;
733
+ }
734
+
735
+ .selection-toolbar[hidden] { display: none; }
736
+ .comment-popup[hidden] { display: none; }
737
+
738
+ .selection-toolbar button {
769
739
  font-family: var(--font-sans);
770
740
  font-size: 12px;
771
741
  font-weight: 600;
772
742
  padding: 6px 14px;
773
- border-radius: var(--radius-sm);
774
- border: 1px solid var(--border);
743
+ border: none;
775
744
  background: var(--surface);
776
745
  color: var(--accent);
777
746
  cursor: pointer;
778
- box-shadow: var(--shadow-md);
779
- transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
780
- animation: popup-enter 0.15s ease;
747
+ transition: background 0.15s ease, color 0.15s ease;
781
748
  }
782
749
 
783
- .comment-trigger:hover {
750
+ .selection-toolbar button:hover {
784
751
  background: var(--accent);
785
752
  color: var(--bg);
786
- border-color: var(--accent);
787
753
  }
788
754
 
789
- .comment-trigger:active {
755
+ .selection-toolbar button:active {
790
756
  transform: scale(0.96);
791
757
  }
792
758
 
@@ -822,6 +788,12 @@ main {
822
788
  letter-spacing: 0.8px;
823
789
  color: var(--text-faint);
824
790
  margin-bottom: 6px;
791
+ cursor: grab;
792
+ user-select: none;
793
+ }
794
+
795
+ .popup-header:active {
796
+ cursor: grabbing;
825
797
  }
826
798
 
827
799
  .popup-selection {
@@ -950,3 +922,249 @@ main {
950
922
  max-width: 100%;
951
923
  height: auto;
952
924
  }
925
+
926
+ /* ---- Highlight popover ---- */
927
+ .highlight-popover {
928
+ position: fixed;
929
+ z-index: 1000;
930
+ width: 240px;
931
+ background: var(--surface);
932
+ border: 1px solid var(--border);
933
+ border-radius: var(--radius-md);
934
+ padding: 14px;
935
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
936
+ animation: popup-enter 0.15s ease;
937
+ }
938
+
939
+ .highlight-popover[hidden] { display: none; }
940
+
941
+ .highlight-popover-text {
942
+ font-size: 13px;
943
+ line-height: 1.5;
944
+ color: var(--text);
945
+ margin-bottom: 12px;
946
+ max-height: 120px;
947
+ overflow-y: auto;
948
+ }
949
+
950
+ .highlight-popover-actions {
951
+ display: flex;
952
+ gap: 6px;
953
+ }
954
+
955
+ .highlight-popover-actions button {
956
+ font-family: var(--font-sans);
957
+ font-size: 11px;
958
+ font-weight: 600;
959
+ padding: 6px 14px;
960
+ border-radius: var(--radius-sm);
961
+ border: 1px solid var(--border);
962
+ background: var(--surface);
963
+ color: var(--text-dim);
964
+ cursor: pointer;
965
+ transition: all 0.15s ease;
966
+ }
967
+
968
+ .highlight-popover-actions button:hover {
969
+ color: var(--accent);
970
+ border-color: var(--accent);
971
+ background: var(--accent-glow);
972
+ }
973
+
974
+ /* ---- Block gutter insert button ---- */
975
+ .block-insert-btn {
976
+ position: absolute;
977
+ left: -40px;
978
+ width: 28px;
979
+ height: 28px;
980
+ border-radius: 50%;
981
+ background: var(--surface);
982
+ border: 1px solid var(--border);
983
+ color: var(--text-faint);
984
+ font-size: 18px;
985
+ cursor: pointer;
986
+ opacity: 0;
987
+ transform: translateY(-50%);
988
+ transition: opacity 0.15s, color 0.15s, border-color 0.15s;
989
+ z-index: 10;
990
+ display: flex;
991
+ align-items: center;
992
+ justify-content: center;
993
+ line-height: 1;
994
+ }
995
+
996
+ .block-insert-btn.visible {
997
+ opacity: 1;
998
+ }
999
+
1000
+ .block-insert-btn:hover {
1001
+ color: var(--accent);
1002
+ border-color: var(--accent);
1003
+ }
1004
+
1005
+ /* ---- Block gap indicator line ---- */
1006
+ .block-insert-line {
1007
+ position: absolute;
1008
+ left: 0;
1009
+ right: 0;
1010
+ height: 2px;
1011
+ background: var(--accent);
1012
+ opacity: 0;
1013
+ transform: translateY(-50%);
1014
+ transition: opacity 0.15s;
1015
+ pointer-events: none;
1016
+ }
1017
+
1018
+ .block-insert-line.visible {
1019
+ opacity: 0.4;
1020
+ }
1021
+
1022
+ /* ---- Block type menu ---- */
1023
+ .block-type-menu {
1024
+ width: 260px;
1025
+ background: var(--surface);
1026
+ border: 1px solid var(--border);
1027
+ border-radius: var(--radius-md);
1028
+ box-shadow: var(--shadow-md);
1029
+ margin: 8px 0;
1030
+ overflow: hidden;
1031
+ animation: popup-enter 0.2s ease;
1032
+ }
1033
+
1034
+ .block-type-filter {
1035
+ width: 100%;
1036
+ font-family: var(--font-sans);
1037
+ font-size: 13px;
1038
+ color: var(--text);
1039
+ background: var(--bg);
1040
+ border: none;
1041
+ border-bottom: 1px solid var(--border);
1042
+ padding: 10px 14px;
1043
+ outline: none;
1044
+ transition: background 0.4s ease;
1045
+ }
1046
+
1047
+ .block-type-filter::placeholder {
1048
+ color: var(--text-faint);
1049
+ }
1050
+
1051
+ .block-type-list {
1052
+ max-height: 280px;
1053
+ overflow-y: auto;
1054
+ padding: 6px 0;
1055
+ }
1056
+
1057
+ .block-type-category {
1058
+ font-size: 10px;
1059
+ font-weight: 600;
1060
+ text-transform: uppercase;
1061
+ letter-spacing: 0.8px;
1062
+ color: var(--text-faint);
1063
+ padding: 8px 14px 4px;
1064
+ }
1065
+
1066
+ .block-type-item {
1067
+ display: flex;
1068
+ align-items: center;
1069
+ gap: 10px;
1070
+ padding: 7px 14px;
1071
+ cursor: pointer;
1072
+ font-size: 13px;
1073
+ color: var(--text);
1074
+ transition: background 0.1s ease;
1075
+ }
1076
+
1077
+ .block-type-item:hover,
1078
+ .block-type-item.highlighted {
1079
+ background: var(--surface-hover);
1080
+ }
1081
+
1082
+ .block-type-icon {
1083
+ width: 28px;
1084
+ height: 28px;
1085
+ display: flex;
1086
+ align-items: center;
1087
+ justify-content: center;
1088
+ border: 1px solid var(--border);
1089
+ border-radius: 6px;
1090
+ font-family: var(--font-mono);
1091
+ font-size: 12px;
1092
+ font-weight: 600;
1093
+ color: var(--text-dim);
1094
+ flex-shrink: 0;
1095
+ background: var(--bg);
1096
+ }
1097
+
1098
+ .block-type-empty {
1099
+ padding: 16px 14px;
1100
+ color: var(--text-faint);
1101
+ font-size: 13px;
1102
+ text-align: center;
1103
+ }
1104
+
1105
+ /* ---- Block hover affordance (click-to-edit) ---- */
1106
+ .markdown-body > *:not(.block-edit-wrapper):not(.block-type-menu):not(.block-insert-btn):not(.block-insert-line):not(.block-editing) {
1107
+ cursor: text;
1108
+ transition: outline-color 0.15s ease;
1109
+ outline: 1px solid transparent;
1110
+ outline-offset: 4px;
1111
+ border-radius: 2px;
1112
+ }
1113
+
1114
+ .markdown-body > *:not(.block-edit-wrapper):not(.block-type-menu):not(.block-insert-btn):not(.block-insert-line):not(.block-editing):hover {
1115
+ outline-color: var(--border-hover);
1116
+ }
1117
+
1118
+ .plain-text > *:not(.block-edit-wrapper):not(.block-type-menu):not(.block-insert-btn):not(.block-insert-line):not(.block-editing) {
1119
+ cursor: text;
1120
+ transition: outline-color 0.15s ease;
1121
+ outline: 1px solid transparent;
1122
+ outline-offset: 4px;
1123
+ border-radius: 2px;
1124
+ }
1125
+
1126
+ .plain-text > *:not(.block-edit-wrapper):not(.block-type-menu):not(.block-insert-btn):not(.block-insert-line):not(.block-editing):hover {
1127
+ outline-color: var(--border-hover);
1128
+ }
1129
+
1130
+ /* ---- Contenteditable inline editing ---- */
1131
+ .block-editing {
1132
+ outline: 2px solid var(--accent) !important;
1133
+ outline-offset: 4px;
1134
+ box-shadow: 0 0 0 6px var(--accent-glow);
1135
+ }
1136
+
1137
+ /* ---- Block edit wrapper (in-place editing) ---- */
1138
+ .block-edit-wrapper {
1139
+ margin: 4px 0;
1140
+ }
1141
+
1142
+ .block-edit-textarea {
1143
+ width: 100%;
1144
+ font-family: var(--font-mono);
1145
+ font-size: 13px;
1146
+ line-height: 1.5;
1147
+ color: var(--text);
1148
+ background: var(--bg);
1149
+ border: 2px solid var(--accent);
1150
+ border-radius: var(--radius-sm);
1151
+ padding: 10px 12px;
1152
+ white-space: pre;
1153
+ tab-size: 2;
1154
+ resize: none;
1155
+ outline: none;
1156
+ box-shadow: 0 0 0 4px var(--accent-glow);
1157
+ transition: border-color 0.2s, box-shadow 0.2s, background 0.4s ease;
1158
+ }
1159
+
1160
+ .block-edit-hint {
1161
+ text-align: right;
1162
+ font-size: 11px;
1163
+ color: var(--text-faint);
1164
+ margin-top: 4px;
1165
+ padding-right: 2px;
1166
+ }
1167
+
1168
+
1169
+
1170
+