Skip to content

Commit fa8944f

Browse files
CopilotPavelLaptev
andauthored
Add color blind-friendly diff preview with blue/orange palette and contrast level support (#10146)
* Initial plan * Implement color blind-friendly diff feature with blue/orange palette Co-authored-by: PavelLaptev <[email protected]> * Add color blind-friendly contrast levels support Co-authored-by: PavelLaptev <[email protected]> * Move color blind-friendly contrast handling to HunkDiff.svelte component Co-authored-by: PavelLaptev <[email protected]> * Refactor color blind-friendly handling to pure CSS approach Co-authored-by: PavelLaptev <[email protected]> * Fix Prettier formatting issues in HunkDiff.svelte Co-authored-by: PavelLaptev <[email protected]> * Fix dark theme colors * feat(ui): adjust spacing and sidebar sizing for better layout consistency --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: PavelLaptev <[email protected]> Co-authored-by: Pavel Laptev <[email protected]>
1 parent c124d19 commit fa8944f

File tree

7 files changed

+185
-34
lines changed

7 files changed

+185
-34
lines changed

apps/desktop/src/components/SettingsModalLayout.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
<div class="modal-settings-wrapper">
3838
<div class="settings-sidebar" use:focusable>
39-
<h3 class="settings-sidebar__title text-15 text-bold">{title}</h3>
39+
<h3 class="settings-sidebar__title text-16 text-bold">{title}</h3>
4040
<div class="settings-sidebar__links">
4141
{#each pages.filter((p) => !p.adminOnly || isAdmin) as page}
4242
{@const selected = page.id === currentSelectedId}
@@ -75,8 +75,8 @@
7575
display: flex;
7676
position: relative;
7777
width: 100%;
78-
height: 75vh;
79-
max-height: 720px;
78+
height: 76vh;
79+
max-height: 1000px;
8080
}
8181
8282
.settings-sidebar {

apps/desktop/src/components/ThemeSelector.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,11 @@
9797
}
9898
9999
.theme-card__icon {
100+
display: flex;
100101
z-index: 1;
101102
position: absolute;
102-
right: 6px;
103-
bottom: 6px;
103+
right: 8px;
104+
bottom: 8px;
104105
opacity: 0;
105106
}
106107

apps/desktop/src/components/projectSettings/AppearanceSettings.svelte

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
diffFont={$userSettings.diffFont}
7070
diffLigatures={$userSettings.diffLigatures}
7171
diffContrast={$userSettings.diffContrast}
72+
colorBlindFriendly={$userSettings.colorBlindFriendly}
7273
inlineUnifiedDiffs={$userSettings.inlineUnifiedDiffs}
7374
hunkStr={diff}
7475
/>
@@ -124,7 +125,7 @@
124125
Tab size
125126
{/snippet}
126127
{#snippet caption()}
127-
The number of spaces a tab is equal to when previewing code changes.
128+
Number of spaces per tab in the diff view.
128129
{/snippet}
129130

130131
{#snippet actions()}
@@ -174,7 +175,7 @@
174175
Lines contrast
175176
{/snippet}
176177
{#snippet caption()}
177-
The contrast level of the diff lines — added, deleted, and counter lines.
178+
The contrast for added, deleted, and context lines in diffs.
178179
{/snippet}
179180
{#snippet actions()}
180181
<Select
@@ -201,6 +202,34 @@
201202
{/snippet}
202203
</SectionCard>
203204

205+
<SectionCard
206+
labelFor="colorBlindFriendly"
207+
orientation="row"
208+
roundedTop={false}
209+
roundedBottom={false}
210+
>
211+
{#snippet title()}
212+
Color blind-friendly colors
213+
{/snippet}
214+
{#snippet caption()}
215+
Use blue and orange colors instead of green and red for better
216+
<br />
217+
accessibility with color vision deficiency.
218+
{/snippet}
219+
{#snippet actions()}
220+
<Toggle
221+
id="colorBlindFriendly"
222+
checked={$userSettings.colorBlindFriendly}
223+
onclick={() => {
224+
userSettings.update((s) => ({
225+
...s,
226+
colorBlindFriendly: !s.colorBlindFriendly
227+
}));
228+
}}
229+
/>
230+
{/snippet}
231+
</SectionCard>
232+
204233
<SectionCard labelFor="inlineUnifiedDiffs" orientation="row" roundedTop={false}>
205234
{#snippet title()}
206235
Display word diffs inline
@@ -325,8 +354,9 @@
325354
{/snippet}
326355
{#snippet caption()}
327356
Stage the selected assigned files to the stack on commit. If no files are selected, stage all
328-
files. If there are no assigned files, stage all selected unassigned files. And if no files
329-
are selected, stage all unassigned files.
357+
files. If there are no assigned files, stage all selected unassigned files.
358+
<br />
359+
And if no files are selected, stage all unassigned files.
330360
{/snippet}
331361
{#snippet actions()}
332362
<RadioButton

apps/desktop/src/lib/settings/userSettings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface Settings {
2929
diffLigatures: boolean;
3030
inlineUnifiedDiffs: boolean;
3131
diffContrast: 'light' | 'medium' | 'strong';
32+
colorBlindFriendly: boolean;
3233
defaultCodeEditor: CodeEditorSettings;
3334
}
3435

@@ -50,6 +51,7 @@ const defaults: Settings = {
5051
diffLigatures: false,
5152
inlineUnifiedDiffs: false,
5253
diffContrast: 'light',
54+
colorBlindFriendly: false,
5355
defaultCodeEditor: { schemeIdentifer: 'vscode', displayName: 'VSCode' }
5456
};
5557

packages/ui/src/lib/components/hunkDiff/HunkDiff.svelte

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
diffLigatures?: boolean;
3030
inlineUnifiedDiffs?: boolean;
3131
diffContrast?: 'light' | 'medium' | 'strong';
32+
colorBlindFriendly?: boolean;
3233
staged?: boolean;
3334
stagedLines?: LineId[];
3435
hideCheckboxes?: boolean;
@@ -53,6 +54,7 @@
5354
diffFont = 'var(--fontfamily-mono)',
5455
diffLigatures = true,
5556
diffContrast = 'medium',
57+
colorBlindFriendly = false,
5658
inlineUnifiedDiffs = false,
5759
staged,
5860
stagedLines,
@@ -113,6 +115,7 @@
113115
}}
114116
bind:this={tableWrapperElem}
115117
class="table__wrapper contrast-{diffContrast}"
118+
class:colorblind-friendly={colorBlindFriendly}
116119
style="--tab-size: {tabSize}; --diff-font: {diffFont};"
117120
style:font-variant-ligatures={diffLigatures ? 'common-ligatures' : 'none'}
118121
>
@@ -122,7 +125,6 @@
122125
</div>
123126
{/if}
124127
<ScrollableContainer horz whenToShow="always" padding={{ left: numberHeaderWidth }}>
125-
<!-- <div style="overflow: auto; max-height: 600px;"> -->
126128
<table class="table__section">
127129
<thead class="table__title" class:draggable={!draggingDisabled}>
128130
<tr>
@@ -190,7 +192,6 @@
190192
/>
191193
{/if}
192194
</table>
193-
<!-- </div> -->
194195
</ScrollableContainer>
195196
</div>
196197

@@ -370,6 +371,42 @@
370371
--clr-diff-locked-count-border: var('--', var(--clr-diff-locked-count-border));
371372
}
372373
374+
/* Color blind-friendly overrides for light contrast */
375+
.contrast-light.colorblind-friendly {
376+
/* deletion (orange) */
377+
--clr-diff-deletion-line-bg: color(srgb 1 0.94 0.87);
378+
--clr-diff-deletion-line-highlight: color(srgb 1 0.85 0.67);
379+
--clr-diff-deletion-count-bg: color(srgb 1 0.9 0.77);
380+
--clr-diff-deletion-count-text: color(srgb 0.8 0.4 0.1);
381+
--clr-diff-deletion-count-border: color(srgb 1 0.8 0.6);
382+
--clr-diff-deletion-count-checkmark: color(srgb 0.8 0.4 0.1);
383+
/* addition (blue) */
384+
--clr-diff-addition-line-bg: color(srgb 0.87 0.94 1);
385+
--clr-diff-addition-line-highlight: color(srgb 0.67 0.85 1);
386+
--clr-diff-addition-count-bg: color(srgb 0.77 0.9 1);
387+
--clr-diff-addition-count-text: color(srgb 0.1 0.4 0.8);
388+
--clr-diff-addition-count-border: color(srgb 0.6 0.8 1);
389+
--clr-diff-addition-count-checkmark: color(srgb 0.1 0.4 0.8);
390+
}
391+
392+
/* Dark theme color-blind friendly overrides for light contrast */
393+
:global(.dark) .contrast-light.colorblind-friendly {
394+
/* deletion (orange) - darker variants for dark theme */
395+
--clr-diff-deletion-line-bg: color(srgb 0.25 0.15 0.05);
396+
--clr-diff-deletion-line-highlight: color(srgb 0.4 0.2 0.05);
397+
--clr-diff-deletion-count-bg: color(srgb 0.35 0.2 0.08);
398+
--clr-diff-deletion-count-text: color(srgb 1 0.7 0.3);
399+
--clr-diff-deletion-count-border: color(srgb 0.6 0.4 0.15);
400+
--clr-diff-deletion-count-checkmark: color(srgb 1 0.7 0.3);
401+
/* addition (blue) - darker variants for dark theme */
402+
--clr-diff-addition-line-bg: color(srgb 0.05 0.15 0.25);
403+
--clr-diff-addition-line-highlight: color(srgb 0.05 0.25 0.4);
404+
--clr-diff-addition-count-bg: color(srgb 0.08 0.2 0.35);
405+
--clr-diff-addition-count-text: color(srgb 0.5 0.8 1);
406+
--clr-diff-addition-count-border: color(srgb 0.2 0.5 0.8);
407+
--clr-diff-addition-count-checkmark: color(srgb 0.5 0.8 1);
408+
}
409+
373410
.contrast-medium {
374411
--clr-diff-count-text: var(--clr-diff-count-text-contrast-2);
375412
/* deletion */
@@ -390,6 +427,42 @@
390427
--clr-diff-locked-count-border: var(--clr-diff-locked-contrast-2-count-border);
391428
}
392429
430+
/* Color blind-friendly overrides for medium contrast */
431+
.contrast-medium.colorblind-friendly {
432+
/* deletion (orange) */
433+
--clr-diff-deletion-line-bg: color(srgb 0.98 0.91 0.8);
434+
--clr-diff-deletion-line-highlight: color(srgb 0.96 0.82 0.6);
435+
--clr-diff-deletion-count-bg: color(srgb 0.96 0.87 0.7);
436+
--clr-diff-deletion-count-text: color(srgb 0.75 0.35 0.05);
437+
--clr-diff-deletion-count-border: color(srgb 0.95 0.75 0.5);
438+
--clr-diff-deletion-count-checkmark: color(srgb 0.75 0.35 0.05);
439+
/* addition (blue) */
440+
--clr-diff-addition-line-bg: color(srgb 0.8 0.91 0.98);
441+
--clr-diff-addition-line-highlight: color(srgb 0.6 0.82 0.96);
442+
--clr-diff-addition-count-bg: color(srgb 0.7 0.87 0.96);
443+
--clr-diff-addition-count-text: color(srgb 0.05 0.35 0.75);
444+
--clr-diff-addition-count-border: color(srgb 0.5 0.75 0.95);
445+
--clr-diff-addition-count-checkmark: color(srgb 0.05 0.35 0.75);
446+
}
447+
448+
/* Dark theme color-blind friendly overrides for medium contrast */
449+
:global(.dark) .contrast-medium.colorblind-friendly {
450+
/* deletion (orange) - darker variants for dark theme */
451+
--clr-diff-deletion-line-bg: color(srgb 0.3 0.18 0.08);
452+
--clr-diff-deletion-line-highlight: color(srgb 0.45 0.25 0.1);
453+
--clr-diff-deletion-count-bg: color(srgb 0.4 0.25 0.12);
454+
--clr-diff-deletion-count-text: color(srgb 1 0.75 0.4);
455+
--clr-diff-deletion-count-border: color(srgb 0.65 0.45 0.2);
456+
--clr-diff-deletion-count-checkmark: color(srgb 1 0.75 0.4);
457+
/* addition (blue) - darker variants for dark theme */
458+
--clr-diff-addition-line-bg: color(srgb 0.08 0.18 0.3);
459+
--clr-diff-addition-line-highlight: color(srgb 0.1 0.3 0.45);
460+
--clr-diff-addition-count-bg: color(srgb 0.12 0.25 0.4);
461+
--clr-diff-addition-count-text: color(srgb 0.6 0.85 1);
462+
--clr-diff-addition-count-border: color(srgb 0.25 0.55 0.85);
463+
--clr-diff-addition-count-checkmark: color(srgb 0.6 0.85 1);
464+
}
465+
393466
.contrast-strong {
394467
--clr-diff-count-text: var(--clr-diff-count-text-contrast-3);
395468
/* deletion */
@@ -409,4 +482,40 @@
409482
--clr-diff-locked-count-text: var(--clr-diff-locked-contrast-3-count-text);
410483
--clr-diff-locked-count-border: var(--clr-diff-locked-contrast-3-count-border);
411484
}
485+
486+
/* Color blind-friendly overrides for strong contrast */
487+
.contrast-strong.colorblind-friendly {
488+
/* deletion (orange) */
489+
--clr-diff-deletion-line-bg: color(srgb 0.96 0.88 0.75);
490+
--clr-diff-deletion-line-highlight: color(srgb 0.93 0.78 0.55);
491+
--clr-diff-deletion-count-bg: color(srgb 0.93 0.84 0.65);
492+
--clr-diff-deletion-count-text: color(srgb 0.7 0.3 0.02);
493+
--clr-diff-deletion-count-border: color(srgb 0.9 0.7 0.45);
494+
--clr-diff-deletion-count-checkmark: color(srgb 0.7 0.3 0.02);
495+
/* addition (blue) */
496+
--clr-diff-addition-line-bg: color(srgb 0.75 0.88 0.96);
497+
--clr-diff-addition-line-highlight: color(srgb 0.55 0.78 0.93);
498+
--clr-diff-addition-count-bg: color(srgb 0.65 0.84 0.93);
499+
--clr-diff-addition-count-text: color(srgb 0.02 0.3 0.7);
500+
--clr-diff-addition-count-border: color(srgb 0.45 0.7 0.9);
501+
--clr-diff-addition-count-checkmark: color(srgb 0.02 0.3 0.7);
502+
}
503+
504+
/* Dark theme color-blind friendly overrides for strong contrast */
505+
:global(.dark) .contrast-strong.colorblind-friendly {
506+
/* deletion (orange) - darker variants for dark theme */
507+
--clr-diff-deletion-line-bg: color(srgb 0.35 0.22 0.12);
508+
--clr-diff-deletion-line-highlight: color(srgb 0.5 0.3 0.15);
509+
--clr-diff-deletion-count-bg: color(srgb 0.45 0.3 0.18);
510+
--clr-diff-deletion-count-text: color(srgb 1 0.8 0.5);
511+
--clr-diff-deletion-count-border: color(srgb 0.7 0.5 0.25);
512+
--clr-diff-deletion-count-checkmark: color(srgb 1 0.8 0.5);
513+
/* addition (blue) - darker variants for dark theme */
514+
--clr-diff-addition-line-bg: color(srgb 0.12 0.22 0.35);
515+
--clr-diff-addition-line-highlight: color(srgb 0.15 0.35 0.5);
516+
--clr-diff-addition-count-bg: color(srgb 0.18 0.3 0.45);
517+
--clr-diff-addition-count-text: color(srgb 0.7 0.9 1);
518+
--clr-diff-addition-count-border: color(srgb 0.3 0.6 0.9);
519+
--clr-diff-addition-count-checkmark: color(srgb 0.7 0.9 1);
520+
}
412521
</style>

0 commit comments

Comments
 (0)