forked from silvanocerza/github-gitless-sync
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstyles.css
More file actions
1175 lines (1109 loc) · 46.8 KB
/
Copy pathstyles.css
File metadata and controls
1175 lines (1109 loc) · 46.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
.hidden-navigation-header {
display: none;
}
.padless-conflicts-view-container {
padding: 0;
height: 100%;
width: 100%;
}
/* ── diff2 widget — Phase 1 / Phase 2 ───────────────────────────── */
.diff2-edit-view-root {
padding: 8px;
/* bug-23 — fill the tab as a flex column and clip at the root, so ONLY the
* inner body scrolls (the CM6 editor's own scroller). Without this the whole
* tab got a second scrollbar and the toolbar scrolled off-screen. */
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
box-sizing: border-box;
/* Diff-editor colours (TODO §6 — OVERRIDE these to taste). The defaults are
* GitHub-style red/green: a subtle line/gutter TINT (-bg) under a saturated
* number/glyph/↵ colour (-fg, so it stays readable — red-on-red was the bug),
* with a STRONGER tint for the <<<<< / ===== / >>>>> marker rows (-strong).
* Translucent rgba over the editor background, so it adapts to light/dark. */
--diff2-ours-fg: #f85149;
--diff2-ours-bg: rgba(248, 81, 73, 0.16);
--diff2-ours-strong: rgba(248, 81, 73, 0.30);
--diff2-theirs-fg: #2ea043;
--diff2-theirs-bg: rgba(63, 185, 80, 0.16);
--diff2-theirs-strong: rgba(63, 185, 80, 0.30);
}
/* Sub-tabs header (Conflicts | Deleted) */
.diff2-view-header {
display: flex;
gap: 12px;
border-bottom: 1px solid var(--background-modifier-border);
margin-bottom: 8px;
flex: 0 0 auto; /* bug-23 — fixed; the list body below scrolls */
}
/* bug-23 — the list body takes the remaining height and scrolls on its own. */
.diff2-view-body {
flex: 1 1 auto;
min-height: 0;
overflow: auto;
}
.diff2-tab {
padding: 6px 10px;
cursor: pointer;
border-bottom: 2px solid transparent;
color: var(--text-muted);
}
.diff2-tab-active {
color: var(--text-normal);
border-bottom-color: var(--interactive-accent);
}
/* Conflicts list */
.diff2-conflicts-empty {
color: var(--text-muted);
padding: 16px;
text-align: center;
}
.diff2-conflicts-group {
margin-bottom: 12px;
}
.diff2-conflicts-group-header {
font-weight: 600;
color: var(--text-normal);
padding: 4px 0;
}
.diff2-conflicts-version-count {
color: var(--text-muted);
font-weight: normal;
font-size: 0.9em;
}
.diff2-conflicts-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 10px;
margin: 2px 0;
border-radius: 4px;
background: var(--background-secondary);
}
.diff2-conflicts-row:hover {
background: var(--background-modifier-hover);
}
.diff2-conflicts-row-meta {
flex: 1;
color: var(--text-muted);
font-size: 0.9em;
}
.diff2-conflicts-device-label {
color: var(--text-normal);
margin-right: 4px;
}
.diff2-conflicts-badge {
padding: 2px 6px;
border-radius: 3px;
font-size: 0.75em;
font-weight: 600;
}
.diff2-conflicts-badge-tracked {
background: var(--background-modifier-border);
color: var(--text-normal);
}
.diff2-conflicts-badge-synthetic {
background: var(--color-orange);
color: var(--background-primary);
}
/* Detail toolbar */
.diff2-detail-toolbar {
display: flex;
align-items: center;
gap: 10px;
padding: 4px 0;
border-bottom: 1px solid var(--background-modifier-border);
margin-bottom: 6px;
flex: 0 0 auto; /* bug-23 — fixed toolbar, never scrolls off-screen */
}
/* §31 (TODO) — loading state while the editor body mounts asynchronously (big diff or
* crash-replay). controller.mount adds `.diff2-detail-loading` + a spinner overlay, then
* removes both (revealReady) once the CM6 owner is mounted — so a slow open shows
* "Loading…" instead of an inert default toolbar over a blank body. */
.diff2-edit-view-root {
position: relative; /* containing block for the absolute loading overlay */
}
.diff2-detail-loading .diff2-detail-toolbar {
display: none; /* keep the toolbar hidden until the editor is ready */
}
.diff2-detail-loading-overlay {
position: absolute;
inset: 0;
z-index: 500; /* above the CM6 body + its markers (max z-index 250) */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
background: var(--background-primary);
}
.diff2-detail-spinner {
width: 28px;
height: 28px;
border: 3px solid var(--background-modifier-border);
border-top-color: var(--interactive-accent);
border-radius: 50%;
animation: diff2-detail-spin 0.8s linear infinite;
}
@keyframes diff2-detail-spin {
to {
transform: rotate(360deg);
}
}
.diff2-detail-loading-text {
color: var(--text-muted);
font-size: 0.9em;
}
/* bug-23 — the detail body fills the remaining height; the CM6 editor inside it
* owns the ONLY scrollbar. No fixed calc() (toolbar height varies with wrap), no
* own overflow:auto (that was the second scrollbar). */
.diff2-detail-body {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
.diff2-detail-body .cm-editor {
height: 100%;
}
/* Android soft-keyboard fix (docs/tasks/imgs/screenshot-mobile-1..3): the keyboard shrank the view,
* the tall flex toolbar ate the height, the editor body collapsed to 0 → blank content (+ reversed
* IME typing). Mobile: the view-root scrolls the [toolbar + body] block; mobile-header-clamp.ts sizes
* the body (so the editor never collapses) and hard-clamps that scroll at the header bottom, leaving a
* grab-tail. Uniform across ALL mobile modes (keyboard or not). Desktop keeps the bug-23 layout. */
body.is-mobile .diff2-edit-view-root {
overflow-y: auto;
}
/* Mobile #4 — decouple the two nested scrolls. The text scroller must NEVER chain its leftover
* overscroll delta into the outer (view-root) scroll, or scrolling the text at its top/bottom edge
* would drag the toolbar. `contain` stops the chaining (keeps native rubber-band); the toolbar then
* moves ONLY by dragging the toolbar body or the tail (both are outside .cm-scroller). */
body.is-mobile .diff2-edit-view-root .cm-scroller {
overscroll-behavior: contain;
}
/* Mobile #2/#5 — the last lines sat under Obsidian's floating navbar (screenshot-mobile-4), and with
* the toolbar OPEN the scroller's bottom hangs below the fold so its inner scroll can't push them into
* view (screenshot-mobile-5). Pad the content bottom by: a fixed base (navbar + home-indicator safe
* area) PLUS --diff2-offfold, which mobile-header-clamp.ts sets to how far the scroller currently hangs
* below the fold (≈ toolbar height when open, 0 when collapsed → no excess overscroll gap). This grows
* the INNER scrollHeight only, never the outer content — so no feedback with the view-root scroll. */
body.is-mobile .diff2-edit-view-root .cm-content {
padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 4em + var(--diff2-offfold, 0px));
}
/* Keyboard open → the Obsidian navbar is gone (the keyboard is there instead), so drop the navbar
* clearance base and keep only the off-fold padding (still needed to reach the end with the toolbar
* open). mobile-header-clamp.ts toggles .diff2-kbd-open on view shrink. */
body.is-mobile .diff2-edit-view-root.diff2-kbd-open .cm-content {
padding-bottom: var(--diff2-offfold, 0px);
}
/* Mobile keyboard grab-strips — 16px bars that are the bottom continuation of the collapsible header,
* NOT floating stickies. mobile-header-clamp.ts hard-clamps the outer scroll at the header bottom, so
* the header scrolls fully off but the tail stays as a handle. Two of them (the header is split:
* toolbar is a view-root child, the CM6 search panel is inside the editor), toggled by search state
* (no keyboard gate — uniform across all mobile modes):
* mobile + no search → tail1 (under toolbar); search open → tail2 (bottom of .cm-search).
* Hidden by default; JS adds .is-visible. Colour/pattern is a placeholder (accent). */
.diff2-detail-kbd-strip,
.diff2-search-kbd-strip {
display: none;
flex: 0 0 auto;
height: 16px;
background: var(--interactive-accent);
}
.diff2-detail-kbd-strip.is-visible,
.diff2-search-kbd-strip.is-visible {
display: block;
}
.diff2-detail-error {
color: var(--text-error);
}
/* §2.2.15 — diff-editor-v2 toolbar. Two ROWS; each row is a LEFT group + a RIGHT group that
* wrap independently (the right group right-aligned). Row 2's left/right groups hold 2-LINE
* COLUMNS (.diff2-tb-col) that wrap as atomic units. */
.diff2-toolbar {
display: flex;
flex-direction: column;
/* the container also carries .diff2-detail-toolbar (align-items:center) — override so the
* rows STRETCH to full width; otherwise they shrink-to-content and bunch in the centre
* (bug-52). full-width rows let each row's justify-content:space-between push the left
* group left and the right group right. */
align-items: stretch;
gap: 6px;
padding: 6px 4px;
border-bottom: 1px solid var(--background-modifier-border);
flex: 0 0 auto;
}
.diff2-tb-row {
display: flex;
justify-content: space-between;
/* center the left vs right group vertically — bug-54: row 1's single-line Editor-mode
* was top-aligned against the taller buttons. (Columns within each group are already
* centered by .diff2-tb-left/right; row 2's groups are both ~2-line so this is a no-op.) */
align-items: center;
/* row-gap 6px = spacing when the right group WRAPS below the left. column-gap 1px = the
* left↔right MIN horizontal gap, which only bites when the row is cramped (margin-left:auto
* on .diff2-tb-right eats free space otherwise) — so the right group can slide right up to
* the left group before wrapping instead of stopping 16px short. */
gap: 6px 1px;
flex-wrap: wrap;
}
.diff2-tb-left,
.diff2-tb-right {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
/* finger-friendly spacing between the LEFT-group buttons/columns (row1 back/Keep/Apply/Join,
* row2 Conflicts/nav/undo-redo) so they're easy to tap on a phone. */
.diff2-tb-left {
gap: 14px;
}
.diff2-tb-right {
margin-left: auto; /* push right group to the far edge; wrapped items stay right-aligned */
justify-content: flex-end;
font-size: 0.9em;
color: var(--text-muted);
}
/* Row 1 flattens its buttons + the trailing Edit toggle into ONE wrap flow (no left/right
* sub-groups) so the Edit checkbox rides on the LAST button line, right-aligned, instead of
* wrapping to a separate line — saves a row of height. Buttons keep their 14px finger-spacing;
* the row-level 1px column-gap (base rule, for row 2) is overridden here. */
.diff2-tb-row1 {
justify-content: flex-start;
column-gap: 14px;
}
.diff2-tb-editmode {
margin-left: auto; /* right-align + wrap WITH the last button, not as its own group */
font-size: 0.9em;
color: var(--text-muted);
}
/* a 2-line column (Conflicts:/NNN, ↑/↓, Undo/Redo, Auto-focus/Diff-mode) — wraps as one unit */
.diff2-tb-col {
display: flex;
flex-direction: column;
gap: 2px;
}
/* bug-53 — in the RIGHT group the two stacked controls (Auto-focus / Diff-mode) right-align,
* so the narrower Auto-focus toggle's right edge lines up with the wider Diff-mode below it
* (and with Touch-mode in row 1). Left-group columns stay left-aligned. */
.diff2-tb-right .diff2-tb-col {
align-items: flex-end;
}
/* row 2 — ONLY the RIGHT block (Auto-focus / Diff-mode) stretches to the row height and
* pushes Auto-focus to the top, Diff-mode to the bottom. The LEFT block (Conflicts/NNN,
* ↑/↓, Undo/Redo) stays compact + vertically centered (its base .diff2-tb-left
* align-items:center). The row stretches so the right column has the full height to span. */
.diff2-tb-row-cols {
align-items: stretch;
}
.diff2-tb-row-cols .diff2-tb-right {
align-items: stretch;
}
.diff2-tb-row-cols .diff2-tb-right .diff2-tb-col {
justify-content: space-between;
}
.diff2-tb-icon {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 3px;
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
background: var(--background-secondary);
color: var(--text-normal);
cursor: pointer;
}
.diff2-tb-icon:hover {
background: var(--background-modifier-hover);
}
/* Visual-only "disabled" — the button stays CLICKABLE (its handler no-ops + refocuses the
* editor); the HTML `disabled` attribute is NOT used (a disabled <button> fires no events, so
* the browser shifts focus off it → caret vanishes, hotkeys die). */
.diff2-tb-icon.diff2-tb-off {
opacity: 0.4;
cursor: default;
}
.diff2-tb-icon.diff2-tb-off:hover {
background: var(--background-secondary); /* no hover affordance when "off" */
}
.diff2-tb-count {
font-weight: 600;
color: inherit; /* take the red/green from .diff2-tb-conflicts (below), not a fixed colour */
text-align: center; /* centre NNN horizontally under the "Conflicts:" label (was left-aligned) */
}
/* "Conflicts:" + NNN coloured by remaining count — red (ver1 gutter colour) while >0, green
* (ver2 gutter colour) at 0. Both GitHub hues, legible in light + dark. update() sets .is-zero. */
.diff2-tb-conflicts {
color: var(--diff2-ours-fg);
}
.diff2-tb-conflicts.is-zero {
color: var(--diff2-theirs-fg);
}
.diff2-tb-toggle,
.diff2-tb-mode {
display: inline-flex;
align-items: center;
gap: 4px;
white-space: nowrap;
}
.diff2-btn {
padding: 4px 10px;
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
background: var(--background-secondary);
color: var(--text-normal);
cursor: pointer;
font-size: 0.85em;
}
.diff2-btn:hover {
background: var(--background-modifier-hover);
}
/* TODO §6 — global toolbar buttons tinted to the side they keep (red = ver1,
* green = ver2), matching the ver-block backgrounds; the saturated -fg border +
* text make them readable in either theme. */
.diff2-btn-keep-local {
background: var(--diff2-ours-bg);
border-color: var(--diff2-ours-fg);
color: var(--diff2-ours-fg);
}
.diff2-btn-keep-local:hover {
background: var(--diff2-ours-strong);
}
.diff2-btn-apply-remote {
background: var(--diff2-theirs-bg);
border-color: var(--diff2-theirs-fg);
color: var(--diff2-theirs-fg);
}
.diff2-btn-apply-remote:hover {
background: var(--diff2-theirs-strong);
}
.diff2-btn-join-all {
border-color: var(--interactive-accent);
}
/* ── DiffPane (Phase 2) — line + word decorations + markers ────── */
/* Marker block-widgets (<<<<<, =====, >>>>>) */
.diff2-marker {
position: relative; /* §2.2.6 п.7 — stacking context for the selection ::before overlay */
padding: 2px 6px;
font-family: var(--font-monospace);
font-size: 0.85em;
user-select: none;
/* §2.2.4.9 — flex row so the clickable glyph can stretch to the FULL row height
* (align-self:stretch below). align-items:center keeps glyph/buttons/label centred,
* as the old inline `vertical-align:middle` did. */
display: flex;
align-items: center;
/* marker-panel rebuild (§2.2.15 flow model) — ONE flex-wrap flow of MONOLITHIC atoms
* (glyph · each button · label). Each atom is flex:0 0 auto + nowrap (below), so nothing
* splits mid-atom (the glyph never breaks into single `<`) and the LAST atom that doesn't
* fit wraps to the next line — the toolbar row-1 principle. On DESKTOP everything fits on
* one line, so the layout is unchanged; wrapping only kicks in when width is tight (mobile).
* col-gap 6px + the glyph's margin-right:8px / label's margin-left:8px below reproduce the
* old 14/6/14px spacing EXACTLY; row-gap 4px separates wrapped lines. */
flex-wrap: wrap;
gap: 4px 6px;
}
/* The marker rows share the SAME tint as the ver-block lines they border, so
* <<<<< flows into ver1 and >>>>> into ver2 as one continuous band (TODO §6).
* --text-normal, not --text-on-accent: the glyph (<<<<<) + device label must be
* theme-readable — black on the light theme, white on the dark.
*
* OPAQUE (bug-34/33): the marker is a block widget INSIDE .cm-content; the native
* drawSelection layer sits BEHIND .cm-content, so a translucent marker row let the
* trailing-`\n` selection rect of an adjacent normal-line selection bleed through.
* Compositing the side tint over an opaque --background-primary base (a solid-colour
* gradient layer over the colour) makes the row opaque → nothing behind shows. */
.diff2-marker-top {
background:
linear-gradient(var(--diff2-ours-bg) 0 100%),
var(--background-primary);
color: var(--text-normal);
/*border-top: 1px solid var(--background-modifier-border);*/
/* TODO §33 — ver1 (<<<<<) ONLY: when the device label wraps to its own line it must go
* ABOVE the glyph+buttons row, not below (below reads as ver1-block text, esp. for an
* empty ver1). `wrap-reverse` stacks the wrapped flex line on top of line 1 (label →
* top, `<<<<< [buttons]` → bottom). No effect on the single-line case (rungs 1-4).
* Uniform for every group (this class), matching the marker-panel one-mode-per-document
* rule. >>>>> (ver2/remote) is intentionally left wrapping downward (§33 = ver1 only). */
flex-wrap: wrap-reverse;
}
/* §6.6 — split the ===== separator background: top half = ours (red), bottom
* half = theirs (green), so it reads as the seam between the two sides instead
* of a distracting blank white strip. Theme-aware via the Obsidian vars. */
.diff2-marker-middle {
background:
linear-gradient(
to bottom,
var(--diff2-ours-bg) 0 50%,
var(--diff2-theirs-bg) 50% 100%
),
var(--background-primary);
color: var(--text-normal);
}
.diff2-marker-bottom {
background:
linear-gradient(var(--diff2-theirs-bg) 0 100%),
var(--background-primary);
color: var(--text-normal);
/*border-bottom: 10px solid var(--background-modifier-border);*/
}
/* §2.2.6 п.7 — when an ENTIRE ver-block (content + terminal \n) is selected, its
* marker rows show the selection too: open(<<<<<) + the ===== top-half for ver1,
* the ===== bottom-half + close(>>>>>) for ver2 (group-atomic lights all four).
* A translucent --text-selection overlay matching the content-line selection, drawn
* via ::before ABOVE the opaque tint but BELOW the glyph/buttons (which are lifted to
* z-index:1 below). full = whole row (open/close); top/bottom = half (the split ===). */
.diff2-marker-sel-full::before,
.diff2-marker-sel-top::before,
.diff2-marker-sel-bottom::before {
content: "";
position: absolute;
/* bug-41/44 — inset to match CM6's native .cm-selectionBackground, which is drawn
* inside the .cm-line padding (left 6px / right 2px). The marker is a block widget
* whose ::before is positioned in its padding box (= the row's full width), so
* left:0/right:0 stuck out 6px past the content-line selection. Matching the line
* padding lines the marker selection up edge-to-edge with the ver-content AND the
* normal-line selection — one uniform left edge for the whole group. */
left: 0;
right: 0;
background: var(--text-selection);
pointer-events: none;
z-index: 0;
}
.diff2-marker-sel-full::before {
top: 0;
bottom: 0;
}
.diff2-marker-sel-top::before {
top: 0;
height: 50%;
}
.diff2-marker-sel-bottom::before {
bottom: 0;
height: 50%;
}
/* lift the row's interactive content above the ::before selection overlay. Each atom
* (glyph / every button / label) is lifted directly now that the buttons live in the
* marker's own flow (no `.diff2-marker-buttons` sub-container). */
.diff2-marker-glyph,
.diff2-marker-btn,
.diff2-marker-label {
position: relative;
z-index: 1;
}
/* marker-panel rebuild — each button is a MONOLITHIC atom in the marker's flex-wrap flow:
* flex:0 0 auto so it never shrinks, nowrap so its label never splits. It wraps to the next
* line as a WHOLE unit (the toolbar §2.2.15 principle), the col-gap 6px from .diff2-marker
* replaces the old wrapper's internal gap. */
.diff2-marker-btn {
flex: 0 0 auto;
white-space: nowrap;
display: inline-flex;
align-items: center;
}
/* п.3 — HYBRID text↔icon. WIDE (default): show the FULL word+arrows text, hide the compact
* form → the button is byte-identical to the pre-rebuild one, so desktop is unchanged. The
* @container rule below flips this when the editor is too narrow for the text to fit. */
.diff2-marker-btn-compact {
display: none;
align-items: center;
gap: 3px; /* separates the lucide glyph from the direction arrows */
}
.diff2-marker-btn-full {
display: inline;
}
/* the lucide verb icon (check / trash-2), sized to the button text (~1em) and inheriting the
* button colour, so it reads as a monochrome glyph, not a chunky 24px icon. */
.diff2-marker-btn-icon {
display: inline-flex;
align-items: center;
}
.diff2-marker-btn-icon svg {
width: 1.1em;
height: 1.1em;
}
/* marker-panel rebuild — the mode is chosen in JS (markerLayoutController measures the constant
* widths once, then runs the priority ladder chooseMarkerMode on every real width change) and
* applied as two classes on the editor DOM. CSS just renders each mode:
*
* SLIDE — `.diff2-marker-slid` slides every marker row LEFT into the empty gutter zone opposite
* it (no line numbers beside a <<<<< / ===== / >>>>> row) by the measured gutter width
* (--diff2-gutter-w), reclaiming that space so the text/labels keep fitting to a narrower editor.
* z-index lifts the row above CM6's sticky gutter, which otherwise paints over it. */
.diff2-marker-slid .diff2-marker {
margin-inline-start: calc(-1 * var(--diff2-gutter-w, 0px));
z-index: 250; /* above .cm-gutters (sticky, ~z-index 200) */
}
/* ICONS — `.diff2-btns-icon` swaps every button from its full word+arrows text to its compact
* icon+arrows form. */
.diff2-btns-icon .diff2-marker-btn-full {
display: none;
}
.diff2-btns-icon .diff2-marker-btn-compact {
display: inline-flex;
}
/* §6.3 — marker action buttons hover the same as the toolbar [Keep all RED/
* GREEN] buttons: a STRONGER side tint as the background, text colour unchanged.
* Top = ver1 (red), bottom = ver2 (green); the middle (Apply Both / Join) uses
* the accent. */
.diff2-marker-top .diff2-marker-btn:hover {
background: var(--diff2-ours-strong);
}
.diff2-marker-bottom .diff2-marker-btn:hover {
background: var(--diff2-theirs-strong);
}
.diff2-marker-middle .diff2-marker-btn:hover {
background: var(--interactive-accent);
color: var(--text-on-accent);
}
.diff2-marker-glyph {
font-weight: bold;
margin-right: 8px;
/* marker-panel rebuild — the glyph is ONE atom: never split into single `<` chars,
* even when the row is squeezed (the editor has line-wrap on, which used to break it). */
white-space: nowrap;
}
/* §1.8.a: marker chars become a click hit-target when the adjacent
* ver-block is empty (data-action set to focus-ver1 / focus-ver2). */
.diff2-marker-glyph[data-action^="focus-"] {
cursor: pointer;
text-decoration: underline dotted;
}
/* §2.2.4.9 (V2): a hit wrapper around the open(<<<<<) / close(>>>>>) glyph that stretches
* to the marker's FULL HEIGHT (so it's an easy mouse/tap target — vs the short glyph
* line), but stops at the first action button (NOT the whole row): a click drops the
* caret at the block START (pos 0), so the target stays near the start to keep that
* intuitive. `.diff2-marker` is `display:flex` → align-self:stretch fills the row height;
* the inner glyph is centred. */
.diff2-marker-glyph-hit {
align-self: stretch;
/* align-self:stretch fills the marker's CONTENT box; -2px margin reclaims the
* marker's 2px vertical padding so the hit is the marker's FULL height. */
margin-block: -2px;
display: flex;
align-items: center;
/* marker-panel rebuild — the glyph zone never shrinks: it stays a whole atom on the
* first line so buttons/label wrap around it, rather than the glyph being squeezed. */
flex: 0 0 auto;
}
.diff2-marker-clickable {
/* text I-beam, not a pointer finger: the zone POSITIONS the text caret (into the
* ver-block), it doesn't trigger a button-like action. */
cursor: text;
}
/* §1.6.a.1: ghost ↵ marking each real newline (line-wrap is always on, so
* this disambiguates a hard break from a soft wrap). Faint, non-interactive.
* Rendered as a `::after` on the ver LINE decoration (.diff2-glyph-line), NOT a
* widget: a widget at line.to went STALE when a [Delete] made the line EOL-less
* without changing its text (CM6 reused the line DOM). A line-decoration class is
* part of CM6 per-line dirty tracking (like .diff2-collapsed), so it updates. */
.diff2-glyph-line::after {
content: "↵";
color: var(--text-faint);
opacity: 0.5;
margin-left: 2px;
pointer-events: none;
}
/* bug-25: on an EMPTY line CM6 inserts a `<br>` filler (needed for caret
* placement); a normal `::after` would wrap onto a 2nd visual row AFTER it. Don't
* hide the `<br>` (that breaks the caret) — instead take the ↵ out of flow and
* pin it to the line start so it sits ON the same (empty) row, with the caret
* still landing before it. A non-empty line has no `<br>`, so :has(br) leaves it
* inline. */
.diff2-glyph-line:has(br) {
position: relative;
}
.diff2-glyph-line:has(br)::after {
/* Out of flow so the `<br>` line break doesn't push the ↵ to a 2nd row;
* `top:0` pins it to the (single) row. NO `left` — keep the static horizontal
* position (the content start, i.e. just after the caret), so it reads "|↵"
* not "↵" under the caret. `margin-left:2px` (from the base rule) keeps the
* small gap after the caret. */
position: absolute;
top: 0;
}
.diff2-marker-label {
margin-left: 8px;
opacity: 0.85;
/* marker-panel rebuild — the device label is a semibold, tag-like atom (distinct from the
* editable text), and the LAST atom in the flow, so it is the first to wrap to its own line
* when width is tight. flex:0 0 auto + nowrap → it moves as a whole unit (no mid-word break).
* NOTE: how heavy `font-weight:600` actually RENDERS is font-dependent — a monospace font with
* no matching weight face (and a theme with `font-synthesis:none`) shows it lighter. That's an
* environment thing (differs per vault by the configured monospace font), not this rule. */
font-weight: 600;
flex: 0 0 auto;
white-space: nowrap;
}
/* Line decorations — subtle red tint for ours, green for theirs (TODO §6). */
.diff2-line-ours {
background: var(--diff2-ours-bg);
}
.diff2-line-theirs {
background: var(--diff2-theirs-bg);
}
/* V2 §2.2.8 — the bare terminal `\n` line of a ver-block (and an unfocused empty
* ver-block) collapses to zero height: it is an internal structural newline, not
* real content. CM6's heightmap honours this; native moveVertically skips it.
* (V2-specific — there was no §1 equivalent, so this rule is NEW, not ported.) */
.cm-line.diff2-collapsed {
height: 0;
min-height: 0;
padding: 0;
line-height: 0;
overflow: hidden;
}
/* §6.5/§6.7 — sibling-wins gutter (line-numbers.ts). Each cell carries a
* number plus a side glyph (− ours / + theirs), and the CELL is tinted to the
* line's side colour (matching the line background) so the whole gutter column
* — across every wrapped visual row — reads as ours/theirs. Theme handling is
* automatic: the Obsidian vars below are light-red/green in the light theme and
* dark-red/green in the dark theme, while the number/glyph colour (--text-error
* / --color-green) stays a saturated, readable shade on either. */
.diff2-gutter-cell {
display: flex;
align-items: center;
gap: 4px;
/* a digit-ish of left breathing room so the numbers don't jam against the left
* edge of the ver-row colour band (the band stays full-bleed; only the content
* is inset). */
padding-left: 0.6em;
font-size: 0.85em; /* a touch smaller than the text (markdown gutter style) */
}
/* normal-line numbers: faint + plain, like Obsidian's own gutter. The ours/theirs
* rules below override the colour for diff lines (they carry the side tint). */
.cm-gutterElement.diff2-gutter-normal {
color: var(--text-faint);
}
/* +/− glyph: a FIXED-width column (always present, empty for normal) so it never
* shifts the number. */
.diff2-gutter-glyph {
flex: 0 0 auto;
width: 0.7em;
text-align: center;
font-weight: bold;
}
/* the NUMBER takes the rest and right-aligns against the text — so numbers form one
* clean right column across normal AND diff rows (markdown-style), independent of
* the +/− glyph. */
.diff2-gutter-num {
flex: 1 1 auto;
text-align: right;
}
/* §6.7 — gutter cell tinted to the side colour (-bg), with a SATURATED number +
* glyph (-fg) so they stay readable on the tint (a same-colour fg/bg was the
* "no numbers/+−" bug). The widgetMarker (line-numbers.ts) carries the same tint
* onto the <<<<< / ===== / >>>>> rows' gutter cells. */
.cm-gutterElement.diff2-gutter-ours {
background: var(--diff2-ours-bg);
color: var(--diff2-ours-fg);
}
.cm-gutterElement.diff2-gutter-theirs {
background: var(--diff2-theirs-bg);
color: var(--diff2-theirs-fg);
}
/* The gutter COLUMN itself must be transparent so the translucent cell tints
* composite over the editor background (dark in the dark theme) — otherwise the
* default gutter background showed through as a white strip in dark mode. */
.diff2-edit-view-root .cm-gutters {
background-color: transparent;
border-right: none;
}
/* Editor font: a bare CM6 EditorView does NOT inherit Obsidian's editor theme, so
* font family/size/line-height must be set here (same reason as the caret below).
* MONOSPACE family (a diff with ASCII markers + a line-number gutter reads better
* fixed-width) at the Settings → Appearance "Text" SIZE + line height, so the
* editor tracks the user's Appearance settings. Applied to BOTH the content and the
* gutter so the line numbers stay aligned. Markers (.diff2-marker) set their own
* font and are unaffected. */
.diff2-edit-view-root .cm-content,
.diff2-edit-view-root .cm-gutters {
font-family: var(--font-monospace);
font-size: var(--font-text-size); /* tracks Settings → Appearance "Text" size */
/* A monospace face renders visually LARGER than the proportional text font at
* the same px (bigger x-height), so plain var(--font-text-size) looked bigger
* than a markdown source-mode editor. font-size-adjust normalizes the x-height
* to a TARGET ratio (~ the proportional text font's), so the editor visually
* matches markdown REGARDLESS of which monospace font is configured. Tune
* 0.45–0.55 to taste. (Chromium ≥ 127; older → ignored, falls back to full px.) */
font-size-adjust: 0.5;
/* bug-47 — NOT --line-height-normal (~1.5). Native drawSelection draws the
* selection rect at the TEXT/font height (~18px); the extra line-height leading
* (1.5 → 24px box) is never covered, so the selection sits ~3px short top & bottom
* and that shortfall SHOWS at the block-widget markers (the band can't merge across
* them) — the "stripe under <<<<</=====/>>>>>" artifact. A tighter line-height makes
* the line box ≈ the selection rect (measured: 1.2 → 1px residual, no shift), so the
* band covers the full line and meets the markers edge-to-edge. Trade-off: slightly
* denser lines than Obsidian's prose default — fine for a code/diff view. */
line-height: 1.2;
}
/* bug-49 — PIN the .cm-line horizontal padding EXPLICITLY. CM6's DEFAULT line padding
* (`0 2px 0 6px`) differs between CM6 versions, and Obsidian ships a different CM6 than
* the harness — so the NATIVE .cm-selectionBackground inset on the device ≠ the marker
* ::before overlay's hardcoded inset → the marker selection looked wider than the
* content selection (left+right edges uneven). Pinning the line padding here makes the
* native selection inset version-independent. ⚠️ THESE TWO VALUES MUST EQUAL the marker
* ::before's `left` / `right` (search "bug-41/44 — inset to match", ~line 320:
* `left: 6px; right: 2px`). TUNE-BY-EYE on device: keep padding-left == ::before left,
* padding-right == ::before right, and the two selections line up edge-to-edge. */
.diff2-edit-view-root .cm-line:not(.diff2-collapsed) {
padding-left: 0; /* ⟵ tune: must match the marker ::before `left` (~line 320) */
padding-right: 0; /* ⟵ tune: must match the marker ::before `right` (~line 320) */
}
/* The text caret — our bare CM6 EditorView doesn't inherit Obsidian's editor
* caret colour, so it defaulted to black and went invisible on the dark theme.
* --text-normal is theme-aware (black on light, white on dark). Covers both the
* native caret (caret-color) and a drawn one (.cm-cursor border). */
.diff2-edit-view-root .cm-content {
caret-color: var(--text-normal);
}
.diff2-edit-view-root .cm-cursor,
.diff2-edit-view-root .cm-cursor-primary {
border-left-color: var(--text-normal);
}
/* Selection: the bare CM6 view doesn't inherit Obsidian's editor theme, so
* drawSelection() used CM6's DEFAULT (light) selection background — in dark mode
* that's a light band under white text → unreadable (bug-27). Use Obsidian's
* theme-aware --text-selection (a translucent accent that works in BOTH themes,
* keeping the text readable — no need to flip the text colour). Both selectors
* out-specify CM6's `.cm-selectionBackground` / `.cm-focused .cm-selectionBackground`. */
.diff2-edit-view-root .cm-selectionBackground,
.diff2-edit-view-root .cm-focused .cm-selectionBackground {
/* !important — CM6 injects its drawSelection StyleModule into <head> AFTER this
* stylesheet with equal specificity, so it would otherwise win. */
background-color: var(--text-selection) !important;
}
/* Marker-row gutter cells (#3) — SAME tint as the lines, so the gutter is one
* continuous ours/theirs band across the whole group. */
.cm-gutterElement.diff2-gutter-ours-marker {
background: var(--diff2-ours-bg);
}
.cm-gutterElement.diff2-gutter-theirs-marker {
background: var(--diff2-theirs-bg);
}
.cm-gutterElement.diff2-gutter-split-marker {
background: linear-gradient(
to bottom,
var(--diff2-ours-bg) 0 50%,
var(--diff2-theirs-bg) 50% 100%
);
}
/* §6.7 — ↵ inside ver-blocks tinted to the side colour (matches the gutter). */
.diff2-line-ours.diff2-glyph-line::after {
color: var(--diff2-ours-fg);
opacity: 0.85;
}
.diff2-line-theirs.diff2-glyph-line::after {
color: var(--diff2-theirs-fg);
opacity: 0.85;
}
/* bug-50 §2.2.12(a) — a trailing-newline DIFF (the last EOL-less group: one side's `↵`
* exists, the other's doesn't). The `↵` is a CSS-only glyph, so it can't carry a content
* mark — its LINE gets `.diff2-glyph-diff` and we render the glyph like a changed word:
* the strong side tint behind a full-opacity bold `↵`, so the newline difference reads as
* a diff instead of a faint decoration. */
.diff2-glyph-line.diff2-glyph-diff::after {
opacity: 1;
font-weight: bold;
}
.diff2-line-ours.diff2-glyph-diff::after {
background: var(--diff2-ours-strong);
}
.diff2-line-theirs.diff2-glyph-diff::after {
background: var(--diff2-theirs-strong);
}
/* Word-level overlay (R7.4 / TODO §6.4) — the CHANGED fragments inside a ver
* line get the STRONGER side tint (red in ver1, green in ver2), so they stand
* out from the subtle line tint. (Replaces the disliked yellow.) */
.diff2-word-changed {
background: var(--background-modifier-border); /* fallback for non-ver lines */
}
.diff2-line-ours .diff2-word-changed {
background: var(--diff2-ours-strong);
}
.diff2-line-theirs .diff2-word-changed {
background: var(--diff2-theirs-strong);
}
/* 2.0.2-beta2 — ribbon "syncing" affordance. While a drain runs, the
* sync (and commit) ribbon icon spins and tints to the accent color
* so the user sees at a glance that a sync is in progress. Targets
* the inner lucide SVG; the pending-batches badge sits in the corner
* and is unaffected. Toggled by main.ts applyRibbonSyncingState.
*/
.github-easy-sync-ribbon-syncing svg {
color: var(--interactive-accent);
animation: github-easy-sync-ribbon-spin 1s linear infinite;
}
/* TODO §14 — "Spin the sync icon" OFF: keep the accent tint (the syncing cue) but
* suppress the rotation. main.ts applySyncIconSpin toggles the -no-spin marker. */
.github-easy-sync-ribbon-syncing.github-easy-sync-no-spin svg {
animation: none;
}
@keyframes github-easy-sync-ribbon-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* 2.0.2-beta2 — status-bar "Syncing…" affordance. While a drain runs,
* the GitHub status-bar item turns accent-green and its leading
* refresh icon spins (reusing the ribbon spin keyframe). Idle, it's a
* plain "GitHub". Toggled by main.ts updateStatusBarItem.
*/
.github-easy-sync-statusbar-syncing {
color: var(--text-success);
}
/* Preserve the " (" leading space so the suffix reads "GitHub (↑ N)" — the
* flex status-bar item otherwise collapses it to "GitHub(↑ N)". */
.github-easy-sync-statusbar {
white-space: pre;
}
/* TODO §10 — settings header (plugin name + version + repo link). */
.github-easy-sync-settings-title {
font-weight: 600;
font-size: 1.15em;
margin-bottom: 0.75em;
}
.github-easy-sync-settings-repo {
font-weight: normal;
font-size: 0.85em;
}
/* E2 (TODO §6) — status-bar suffix "(↑ N | M ⁇)". The push-queue "↑ N" is
* green, the conflict count "M ⁇" red. These sit on the span itself, so they
* override the parent's inherited syncing-green while a drain runs. */
.github-easy-sync-statusbar-up {
color: var(--text-success);
}
.github-easy-sync-statusbar-conflict {
color: var(--text-error);
}
/* §35 — token-expired: the "GitHub" word turns red (sits on the span itself so
* it overrides the parent's syncing-green). Toggled by updateStatusBarItem. */
.github-easy-sync-statusbar-token-expired {
color: var(--text-error);
font-weight: 600;
}
/* §35 — token-expired: the sync ribbon icon turns red. Toggled by
* refreshSyncRibbonTokenExpired. Uses !important so it wins over the
* syncing-green accent tint if a stale drain class lingers. */
.github-easy-sync-ribbon-token-expired svg {
color: var(--text-error) !important;
}
/* §35 — the recovery-modal button row wraps + centers so on a narrow (mobile)
* screen no button (esp. the first, "Open GitHub token page") is pushed off the
* edge. Column direction lets the control span full width; the buttons then wrap
* and center within it. Harmless on desktop (they fit on one centered row). */
.github-easy-sync-token-modal-buttons {
flex-direction: column;
}
.github-easy-sync-token-modal-buttons .setting-item-control {
flex-wrap: wrap;
justify-content: center;
gap: 0.5em;
}
/* §2.2.17 — tidy the CM6 search/replace panel (Mod+F) to match Obsidian's form controls. Scoped
* to the diff-editor. BLOCK layout (NOT flex) so the panel's native <br> reliably breaks the
* replace controls onto their own row at ANY width (a flex <br> only wraps when the row is full);
* the × close sits top-right. */
.diff2-edit-view-root .cm-panels.cm-panels-top {
background: var(--background-secondary);
border-bottom: 1px solid var(--background-modifier-border);
color: var(--text-normal);
}
.diff2-edit-view-root .cm-search {
position: relative;
padding: 8px 38px 8px 10px; /* right pad leaves room for the × */
font-size: var(--font-ui-small);
line-height: 2.4; /* vertical rhythm between the find + replace rows */
}
.diff2-edit-view-root .cm-search .cm-textfield {
background: var(--background-modifier-form-field);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-s);
color: var(--text-normal);
padding: 5px 8px;
margin: 0 6px 0 0;
font-size: var(--font-ui-small);
min-width: 12em;
vertical-align: middle;
}
.diff2-edit-view-root .cm-search .cm-textfield:focus {
border-color: var(--interactive-accent);
box-shadow: 0 0 0 2px var(--background-modifier-border-focus, var(--interactive-accent));
outline: none;
}
/* Buttons mirror the toolbar's `.diff2-btn` form, modelled on `[ > Join all ]` (accent border). */
.diff2-edit-view-root .cm-search .cm-button {
padding: 4px 10px;
border: 1px solid var(--interactive-accent);
border-radius: 4px;
background: var(--background-secondary);
background-image: none;
box-shadow: none;
color: var(--text-normal);
margin: 0 6px 0 0;
font-size: 0.85em;
cursor: pointer;
vertical-align: middle;
}