@filipc77/cowrite 0.4.27 → 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,19 @@
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
+
84
+ <script type="module">
85
+ import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
86
+ mermaid.initialize({ startOnLoad: false, theme: 'dark' });
87
+ window.__mermaid = mermaid;
88
+ </script>
67
89
  <script src="client.js"></script>
68
90
  </body>
69
91
  </html>
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,9 +328,12 @@ main {
302
328
  }
303
329
 
304
330
  #fileContent {
305
- max-width: 760px;
331
+ position: relative;
332
+ max-width: 860px;
306
333
  margin: 0 auto;
307
- line-height: 1.8;
334
+ font-size: 16px;
335
+ line-height: 1.5;
336
+ word-wrap: break-word;
308
337
  animation: fade-in 0.3s ease;
309
338
  }
310
339
 
@@ -313,72 +342,71 @@ main {
313
342
  to { opacity: 1; transform: translateY(0); }
314
343
  }
315
344
 
316
- /* ---- Markdown styles ---- */
317
- .markdown-body h1, .markdown-body h2, .markdown-body h3,
318
- .markdown-body h4, .markdown-body h5, .markdown-body h6 {
319
- margin: 1.5em 0 0.6em;
320
- font-weight: 600;
321
- color: var(--text);
322
- line-height: 1.3;
323
- letter-spacing: -0.3px;
345
+ /* ---- Markdown body theme overrides (on top of github-markdown-css) ---- */
346
+ .markdown-body {
347
+ color-scheme: dark;
348
+ background: transparent !important;
349
+ }
350
+ [data-theme="light"] .markdown-body {
351
+ color-scheme: light;
324
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; }
356
+ .markdown-body > *:first-child { margin-top: 0; }
357
+ .markdown-body > *:last-child { margin-bottom: 0; }
325
358
 
326
- .markdown-body h1 {
327
- font-size: 1.75em;
328
- border-bottom: 1px solid var(--border);
329
- padding-bottom: 0.4em;
359
+ /* ---- Code block wrapper ---- */
360
+ .code-block-wrapper {
361
+ position: relative;
362
+ margin-top: 0;
363
+ margin-bottom: 16px;
364
+ border: 1px solid var(--border);
365
+ border-radius: 6px;
366
+ overflow: hidden;
330
367
  }
331
368
 
332
- .markdown-body h2 {
333
- font-size: 1.35em;
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);
334
375
  border-bottom: 1px solid var(--border);
335
- padding-bottom: 0.3em;
376
+ font-size: 12px;
336
377
  }
337
378
 
338
- .markdown-body h3 { font-size: 1.15em; }
339
-
340
- .markdown-body p { margin: 0.8em 0; }
341
- .markdown-body ul, .markdown-body ol { margin: 0.8em 0; padding-left: 2em; }
342
- .markdown-body li { margin: 0.3em 0; }
343
-
344
- .markdown-body code {
379
+ .code-block-lang {
345
380
  font-family: var(--font-mono);
346
- font-size: 0.85em;
347
- background: var(--surface-hover);
348
- padding: 2px 8px;
349
- border-radius: 5px;
350
- border: 1px solid var(--border);
381
+ font-size: 11px;
382
+ color: var(--text-dim);
383
+ text-transform: lowercase;
351
384
  }
352
385
 
353
- .markdown-body pre {
354
- background: var(--surface);
355
- padding: 20px;
356
- border-radius: var(--radius-md);
357
- overflow-x: auto;
358
- margin: 1.2em 0;
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;
359
392
  border: 1px solid var(--border);
393
+ background: var(--surface);
394
+ color: var(--text-dim);
395
+ cursor: pointer;
396
+ transition: all 0.15s ease;
360
397
  }
361
398
 
362
- .markdown-body pre code {
363
- background: none;
364
- padding: 0;
365
- border: none;
399
+ .code-copy-btn:hover {
400
+ color: var(--accent);
401
+ border-color: var(--accent);
366
402
  }
367
403
 
368
- .markdown-body blockquote {
369
- border-left: 3px solid var(--accent);
370
- padding-left: 16px;
371
- color: var(--text-dim);
372
- margin: 1em 0;
404
+ .code-block-wrapper pre {
405
+ margin: 0 !important;
406
+ border: none !important;
407
+ border-radius: 0 !important;
373
408
  }
374
409
 
375
- .markdown-body a { color: var(--accent); text-decoration: none; }
376
- .markdown-body a:hover { text-decoration: underline; }
377
-
378
- .markdown-body table { border-collapse: collapse; margin: 1em 0; width: 100%; }
379
- .markdown-body th, .markdown-body td { border: 1px solid var(--border); padding: 8px 12px; text-align: left; }
380
- .markdown-body th { background: var(--surface); }
381
-
382
410
  /* Plain text */
383
411
  .plain-text {
384
412
  font-family: var(--font-mono);
@@ -399,11 +427,6 @@ main {
399
427
  border-radius: 2px;
400
428
  }
401
429
 
402
- .comment-highlight.resolved {
403
- background: transparent;
404
- border-bottom-color: transparent;
405
- }
406
-
407
430
  .comment-highlight:hover {
408
431
  background: rgba(212, 165, 84, 0.18);
409
432
  }
@@ -462,6 +485,7 @@ main {
462
485
 
463
486
  /* ---- Comment card ---- */
464
487
  .comment-card {
488
+ position: relative;
465
489
  background: var(--bg-subtle);
466
490
  border: 1px solid var(--border);
467
491
  border-radius: var(--radius-md);
@@ -472,6 +496,30 @@ main {
472
496
  animation: card-enter 0.25s ease both;
473
497
  }
474
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
+
475
523
  .comment-card:hover {
476
524
  border-color: var(--border-hover);
477
525
  box-shadow: var(--shadow-sm);
@@ -671,31 +719,40 @@ main {
671
719
  transform: scale(0.97);
672
720
  }
673
721
 
674
- /* ---- Comment trigger button ---- */
675
- .comment-trigger {
722
+ /* ---- Selection toolbar ---- */
723
+ .selection-toolbar {
676
724
  position: fixed;
677
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 {
678
739
  font-family: var(--font-sans);
679
740
  font-size: 12px;
680
741
  font-weight: 600;
681
742
  padding: 6px 14px;
682
- border-radius: var(--radius-sm);
683
- border: 1px solid var(--border);
743
+ border: none;
684
744
  background: var(--surface);
685
745
  color: var(--accent);
686
746
  cursor: pointer;
687
- box-shadow: var(--shadow-md);
688
- transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
689
- animation: popup-enter 0.15s ease;
747
+ transition: background 0.15s ease, color 0.15s ease;
690
748
  }
691
749
 
692
- .comment-trigger:hover {
750
+ .selection-toolbar button:hover {
693
751
  background: var(--accent);
694
752
  color: var(--bg);
695
- border-color: var(--accent);
696
753
  }
697
754
 
698
- .comment-trigger:active {
755
+ .selection-toolbar button:active {
699
756
  transform: scale(0.96);
700
757
  }
701
758
 
@@ -731,6 +788,12 @@ main {
731
788
  letter-spacing: 0.8px;
732
789
  color: var(--text-faint);
733
790
  margin-bottom: 6px;
791
+ cursor: grab;
792
+ user-select: none;
793
+ }
794
+
795
+ .popup-header:active {
796
+ cursor: grabbing;
734
797
  }
735
798
 
736
799
  .popup-selection {
@@ -838,3 +901,270 @@ main {
838
901
  [data-theme="light"] ::selection {
839
902
  background: rgba(176, 125, 46, 0.2);
840
903
  }
904
+
905
+ /* ---- Mermaid diagrams ---- */
906
+ .mermaid-container {
907
+ margin: 1.2em 0;
908
+ user-select: none;
909
+ -webkit-user-select: none;
910
+ }
911
+
912
+ .mermaid-container pre.mermaid {
913
+ background: var(--surface);
914
+ border: 1px solid var(--border);
915
+ border-radius: var(--radius-md);
916
+ padding: 20px;
917
+ display: flex;
918
+ justify-content: center;
919
+ }
920
+
921
+ .mermaid-container svg {
922
+ max-width: 100%;
923
+ height: auto;
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
+