Skip to content

Commit 1b1c17a

Browse files
authored
Merge pull request #8679 from Turbo87/fix-dark-chart
Fix low contrast on downloads graph labels and borders
2 parents 5aed44f + bc801d3 commit 1b1c17a

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

app/components/download-graph.hbs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<canvas
1212
{{did-insert this.createChart}}
1313
{{did-update this.updateChart @data}}
14+
{{did-update this.updateColorScheme this.colorScheme.resolvedScheme}}
1415
{{did-update this.updateStacked @stacked}}
1516
{{will-destroy this.destroyChart}}
1617
/>

app/components/download-graph.js

+34-2
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,32 @@ const ONE_DAY = 24 * 60 * 60 * 1000;
1515

1616
export default class DownloadGraph extends Component {
1717
@service chartjs;
18+
@service colorScheme;
1819

1920
@action loadChartJs() {
2021
waitForPromise(this.chartjs.loadTask.perform()).catch(() => {
2122
// Ignore Promise rejections. We'll handle them through the derived state properties.
2223
});
2324
}
2425

26+
get fontColor() {
27+
return this.colorScheme.isDark ? '#ADBABD' : '#666';
28+
}
29+
30+
get borderColor() {
31+
return this.colorScheme.isDark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
32+
}
33+
2534
@action createChart(element) {
2635
let Chart = this.chartjs.loadTask.lastSuccessful.value;
2736

37+
let { fontColor: color, borderColor } = this;
38+
2839
this.chart = new Chart(element, {
2940
type: 'line',
3041
data: this.data,
3142
options: {
43+
color,
3244
maintainAspectRatio: false,
3345
layout: {
3446
padding: 10,
@@ -37,9 +49,15 @@ export default class DownloadGraph extends Component {
3749
x: {
3850
type: 'time',
3951
time: { tooltipFormat: 'MMM d', unit: 'day' },
40-
ticks: { maxTicksLimit: 13 },
52+
ticks: { maxTicksLimit: 13, color },
53+
grid: { color: borderColor },
54+
},
55+
y: {
56+
beginAtZero: true,
57+
stacked: true,
58+
ticks: { precision: 0, color },
59+
grid: { color: borderColor },
4160
},
42-
y: { beginAtZero: true, stacked: true, ticks: { precision: 0 } },
4361
},
4462
interaction: {
4563
mode: 'index',
@@ -50,6 +68,20 @@ export default class DownloadGraph extends Component {
5068
});
5169
}
5270

71+
@action updateColorScheme() {
72+
let { chart } = this;
73+
74+
if (chart) {
75+
let { fontColor, borderColor } = this;
76+
chart.options.color = fontColor;
77+
chart.options.scales.x.ticks.color = fontColor;
78+
chart.options.scales.x.grid.color = borderColor;
79+
chart.options.scales.y.ticks.color = fontColor;
80+
chart.options.scales.y.grid.color = borderColor;
81+
chart.update();
82+
}
83+
}
84+
5385
@action updateChart() {
5486
let { chart } = this;
5587

app/services/color-scheme.js

+39
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { action } from '@ember/object';
22
import Service from '@ember/service';
33
import { tracked } from '@glimmer/tracking';
44

5+
import { restartableTask, waitForEvent } from 'ember-concurrency';
6+
57
import * as localStorage from '../utils/local-storage';
68

79
const DEFAULT_SCHEME = 'light';
@@ -10,6 +12,16 @@ const LS_KEY = 'color-scheme';
1012

1113
export default class DesignService extends Service {
1214
@tracked _scheme = localStorage.getItem(LS_KEY);
15+
@tracked resolvedScheme;
16+
17+
constructor() {
18+
super(...arguments);
19+
this.restartWatcherTask();
20+
}
21+
22+
get isDark() {
23+
return this.resolvedScheme === 'dark';
24+
}
1325

1426
get scheme() {
1527
return VALID_SCHEMES.has(this._scheme) ? this._scheme : DEFAULT_SCHEME;
@@ -18,5 +30,32 @@ export default class DesignService extends Service {
1830
@action set(scheme) {
1931
this._scheme = scheme;
2032
localStorage.setItem(LS_KEY, scheme);
33+
this.restartWatcherTask();
2134
}
35+
36+
restartWatcherTask() {
37+
this.watcherTask.perform().catch(() => {
38+
// Ignore Promise rejections. This shouldn't be able to fail, and task cancellations are expected.
39+
});
40+
}
41+
42+
/**
43+
* This task watches for changes in the system color scheme and updates the `resolvedScheme` property accordingly.
44+
*/
45+
watcherTask = restartableTask(async () => {
46+
let mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');
47+
// eslint-disable-next-line no-constant-condition
48+
while (true) {
49+
let scheme = this.scheme;
50+
if (scheme === 'system') {
51+
scheme = mediaQueryList.matches ? 'dark' : 'light';
52+
}
53+
54+
if (this.resolvedScheme !== scheme) {
55+
this.resolvedScheme = scheme;
56+
}
57+
58+
await waitForEvent(mediaQueryList, 'change');
59+
}
60+
});
2261
}

0 commit comments

Comments
 (0)