Skip to content

Commit

Permalink
feat: add Dark Mode grid option (#1163)
Browse files Browse the repository at this point in the history
* feat: add Dark Mode grid option
  • Loading branch information
ghiscoding committed Mar 5, 2024
1 parent c5c927a commit 2dc9e1d
Show file tree
Hide file tree
Showing 16 changed files with 483 additions and 168 deletions.
1 change: 1 addition & 0 deletions docs/TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

## Styling

* [Dark Mode](styling/dark-mode.md)
* [Styling CSS/SASS/Themes](styling/styling.md)
* [SVG Icons](styling/svg-icons.md)

Expand Down
65 changes: 65 additions & 0 deletions docs/styling/dark-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## Dark Mode

When enabled (defaults to false), it will show the grid in Dark Mode by adding `slick-dark-mode` CSS class to the grid. Note that it is defined as a grid option because the grid uses a few elements that could be appended to the DOM `body` (e.g. ColumnPicker, GridMenu, LongTextEditor, CompositeEditorModal, ...) and when Dark Mode is enabled, it needs to advise all of these features that we are using Dark Mode (or Light Mode by default). So whenever any of these features are in play, and before it is appended to the `body`, it will add a `slick-dark-mode` (or `ms-dark-mode` for ms-select) CSS class to that element to let it know that we are in Dark Mode.


### Toggle Light/Dark Mode

You can easily toggle light/dark mode by using `grid.setOptions()`

```ts
export class MyDemo {
isDarkModeEnabled = false;
gridOptions: GridOption;

prepareGrid() {
this.gridOptions = {
// ...
darkMode: this.isDarkModeEnabled;
}
}

toggleDarkMode() {
this.isDarkModeEnabled = !this.isDarkModeEnabled;
this.sgb.slickGrid?.setOptions({ darkMode: this.isDarkModeEnabled });

// optionally update your local grid options as well
this.gridOptions = { ...this.gridOptions, darkMode: this.isDarkModeEnabled };
}
}
```

### How to Auto-Detect Dark Mode?

By default the grid will **not** automatically enable Dark Mode, neither read the browser's color scheme (the reason are mentioned in the description above). However, you could implement your own code to detect the color scheme (for modern browser only) when loading your browser and set it in your grid options. You can see a demo of that in the first grid of [Example 1](https://ghiscoding.github.io/slickgrid-universal/#/example01)

```ts
export class MyDemo {
gridOptions: GridOption;

// auto-detect browser's color scheme function
isBrowserDarkModeEnabled() {
return window.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
}

prepareGrid() {
this.gridOptions = {
// ...
darkMode: this.isBrowserDarkModeEnabled();
}
}
}
```

### Composite Editor Modal (for Bootstrap users)

For `Bootstrap` users, it will also require the developer to add a `data-bs-theme="dark"` attribute which is also another reason why we added `darkMode` as a grid option. So for Bootstrap users, you will have to add this required attribute by yourself for the Dark Mode to display properly. If you forget to add this attribute, you might see some of the filter inputs and other sections displayed with a white background instead of an expected dark gray backgroud.

> **Note** the `onRendered` is a new lifecycle callback of Composite Editor Modal that was added specifically for this Bootstrap use case
```ts
this.compositeEditorInstance?.openDetails({
// ...
onRendered: (modalElm) => modalElm.dataset.bsTheme = 'dark',
});
```
14 changes: 7 additions & 7 deletions packages/aurelia-slickgrid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@
"@aurelia/i18n": "latest",
"@aurelia/runtime": "latest",
"@aurelia/runtime-html": "latest",
"@slickgrid-universal/common": "~4.4.1",
"@slickgrid-universal/custom-footer-component": "~4.4.1",
"@slickgrid-universal/empty-warning-component": "~4.4.1",
"@slickgrid-universal/event-pub-sub": "~4.4.1",
"@slickgrid-universal/pagination-component": "~4.4.1",
"@slickgrid-universal/row-detail-view-plugin": "~4.4.1",
"@slickgrid-universal/utils": "~4.4.1",
"@slickgrid-universal/common": "~4.5.0",
"@slickgrid-universal/custom-footer-component": "~4.5.0",
"@slickgrid-universal/empty-warning-component": "~4.5.0",
"@slickgrid-universal/event-pub-sub": "~4.5.0",
"@slickgrid-universal/pagination-component": "~4.5.0",
"@slickgrid-universal/row-detail-view-plugin": "~4.5.0",
"@slickgrid-universal/utils": "~4.5.0",
"dequal": "^2.0.3",
"dompurify": "^3.0.9",
"moment-mini": "^2.29.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import { SlickRowDetailView } from '../extensions/slickRowDetailView';
export class AureliaSlickgridCustomElement {
protected _columnDefinitions: Column[] = [];
protected _currentDatasetLength = 0;
protected _darkMode = false;
protected _dataset: any[] | null = null;
protected _eventHandler!: SlickEventHandler;
protected _eventPubSubService!: EventPubSubService;
Expand Down Expand Up @@ -265,6 +266,11 @@ export class AureliaSlickgridCustomElement {
this.displayEmptyDataWarning(finalTotalCount < 1);
}
}

// add dark mode CSS class when enabled
if (this.gridOptions.darkMode) {
this.setDarkMode(true);
}
}

initialization(eventHandler: SlickEventHandler) {
Expand Down Expand Up @@ -744,6 +750,13 @@ export class AureliaSlickgridCustomElement {
this.sharedService.visibleColumns = args.impactedColumns;
});

this._eventHandler.subscribe(grid.onSetOptions, (_e, args) => {
// add/remove dark mode CSS class when enabled
if (args.optionsBefore.darkMode !== args.optionsAfter.darkMode && this.sharedService.gridContainerElement) {
this.setDarkMode(args.optionsAfter.darkMode);
}
});

// load any presets if any (after dataset is initialized)
this.loadColumnPresetsWhenDatasetInitialized();
this.loadFilterPresetsWhenDatasetInitialized();
Expand Down Expand Up @@ -1013,6 +1026,14 @@ export class AureliaSlickgridCustomElement {
return paginationOptions;
}

setDarkMode(dark = false) {
if (dark) {
this.sharedService.gridContainerElement?.classList.add('slick-dark-mode');
} else {
this.sharedService.gridContainerElement?.classList.remove('slick-dark-mode');
}
}

/**
* Dynamically change or update the column definitions list.
* We will re-render the grid so that the new header and data shows up correctly.
Expand Down
18 changes: 9 additions & 9 deletions packages/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@
"@faker-js/faker": "^8.4.1",
"@fnando/sparkline": "^0.3.10",
"@popperjs/core": "^2.11.8",
"@slickgrid-universal/common": "^4.4.1",
"@slickgrid-universal/composite-editor-component": "^4.4.1",
"@slickgrid-universal/custom-tooltip-plugin": "^4.4.1",
"@slickgrid-universal/excel-export": "^4.4.1",
"@slickgrid-universal/graphql": "^4.4.1",
"@slickgrid-universal/odata": "^4.4.1",
"@slickgrid-universal/row-detail-view-plugin": "^4.4.1",
"@slickgrid-universal/rxjs-observable": "^4.4.1",
"@slickgrid-universal/text-export": "^4.4.1",
"@slickgrid-universal/common": "^4.5.0",
"@slickgrid-universal/composite-editor-component": "^4.5.0",
"@slickgrid-universal/custom-tooltip-plugin": "^4.5.0",
"@slickgrid-universal/excel-export": "^4.5.0",
"@slickgrid-universal/graphql": "^4.5.0",
"@slickgrid-universal/odata": "^4.5.0",
"@slickgrid-universal/row-detail-view-plugin": "^4.5.0",
"@slickgrid-universal/rxjs-observable": "^4.5.0",
"@slickgrid-universal/text-export": "^4.5.0",
"aurelia": "latest",
"aurelia-slickgrid": "workspace:*",
"bootstrap": "^5.3.3",
Expand Down
23 changes: 18 additions & 5 deletions packages/demo/src/examples/slickgrid/example1.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,27 @@ <h2>
</h2>
<div class="subtitle" innerhtml.bind="subTitle"></div>

<h3>Grid 1</h3>
<aurelia-slickgrid grid-id="grid1-1" column-definitions.bind="columnDefinitions1" grid-options.bind="gridOptions1"
dataset.bind="dataset1">
</aurelia-slickgrid>
<h3>
<div class="column">
<span class="mr-3">Grid 1</span>
<button class="btn btn-outline-secondary btn-sm ms-2" click.trigger="toggleDarkModeGrid1()" data-test="toggle-dark-mode">
<span>Toggle Dark Mode</span>
</button>
</div>
</h3>

<div class="grid-container1">
<aurelia-slickgrid grid-id="grid1-1" column-definitions.bind="columnDefinitions1" grid-options.bind="gridOptions1"
dataset.bind="dataset1"
on-aurelia-grid-created.trigger="aureliaGridReady($event.detail)">
</aurelia-slickgrid>
</div>

<hr />

<h3>Grid 2 <small>(with local Pagination)</small></h3>
<aurelia-slickgrid grid-id="grid1-2" column-definitions.bind="columnDefinitions2" grid-options.bind="gridOptions2"
<aurelia-slickgrid grid-id="grid1-2"
column-definitions.bind="columnDefinitions2"
grid-options.bind="gridOptions2"
dataset.bind="dataset2">
</aurelia-slickgrid>
31 changes: 30 additions & 1 deletion packages/demo/src/examples/slickgrid/example1.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Column, GridOption, Formatters } from 'aurelia-slickgrid';
import { Column, GridOption, Formatters, AureliaGridInstance } from 'aurelia-slickgrid';

const NB_ITEMS = 995;

export class Example1 {
private _darkModeGrid1 = false;
title = 'Example 1: Basic Grids';
subTitle = `Simple Grids with Fixed Sizes (800 x 225)`;

aureliaGrid1!: AureliaGridInstance;
gridOptions1!: GridOption;
gridOptions2!: GridOption;
columnDefinitions1: Column[] = [];
Expand All @@ -24,6 +26,20 @@ export class Example1 {
this.dataset2 = this.mockData(NB_ITEMS);
}

aureliaGridReady(aureliaGrid: AureliaGridInstance) {
this.aureliaGrid1 = aureliaGrid;
}

isBrowserDarkModeEnabled() {
return window.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
}

detaching() {
// also unsubscribe all Angular Subscriptions
document.querySelector('.panel-wm-content')!.classList.remove('dark-mode');
document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme = 'light';
}

/* Define grid Options and Columns */
defineGrids() {
this.columnDefinitions1 = [
Expand All @@ -34,7 +50,9 @@ export class Example1 {
{ id: 'finish', name: 'Finish', field: 'finish', formatter: Formatters.dateIso },
{ id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', sortable: true, minWidth: 100 }
];
this._darkModeGrid1 = this.isBrowserDarkModeEnabled();
this.gridOptions1 = {
darkMode: this._darkModeGrid1,
gridHeight: 225,
gridWidth: 800,
enableAutoResize: false,
Expand All @@ -47,6 +65,7 @@ export class Example1 {
this.gridOptions2 = {
...this.gridOptions1,
...{
darkMode: false,
enablePagination: true,
pagination: {
pageSizes: [5, 10, 20, 25, 50],
Expand Down Expand Up @@ -78,4 +97,14 @@ export class Example1 {

return mockDataset;
}

toggleDarkModeGrid1() {
this._darkModeGrid1 = !this._darkModeGrid1;
if (this._darkModeGrid1) {
document.querySelector('.grid-container1')?.classList.add('dark-mode');
} else {
document.querySelector('.grid-container1')?.classList.remove('dark-mode');
}
this.aureliaGrid1.slickGrid?.setOptions({ darkMode: this._darkModeGrid1 });
}
}
3 changes: 3 additions & 0 deletions packages/demo/src/examples/slickgrid/example24.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<h2>
${title}
<button class="btn btn-outline-secondary btn-sm ms-2" click.trigger="toggleDarkMode()" data-test="toggle-dark-mode">
<span>Toggle Dark Mode</span>
</button>
<span class="float-end">
<a style="font-size: 18px"
target="_blank"
Expand Down
19 changes: 19 additions & 0 deletions packages/demo/src/examples/slickgrid/example24.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const taskTranslateFormatter: Formatter = (_row, _cell, value, _columnDef, _data
};

export class Example24 {
private _darkModeGrid = false;
title = 'Example 24: Cell Menu & Context Menu Plugins';
subTitle = `Add Cell Menu and Context Menu
<ul>
Expand Down Expand Up @@ -115,6 +116,11 @@ export class Example24 {
this.dataset = this.getData(1000);
}

detaching() {
document.querySelector('.panel-wm-content')!.classList.remove('dark-mode');
document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme = 'light';
}

/* Define grid Options and Columns */
defineGrid() {
this.columnDefinitions = [
Expand Down Expand Up @@ -275,6 +281,7 @@ export class Example24 {
container: '#demo-container',
rightPadding: 10
},
darkMode: this._darkModeGrid,
enableCellNavigation: true,
enableFiltering: true,
enableSorting: true,
Expand Down Expand Up @@ -528,4 +535,16 @@ export class Example24 {
await this.i18n.setLocale(nextLanguage);
this.selectedLanguage = nextLanguage;
}

toggleDarkMode() {
this._darkModeGrid = !this._darkModeGrid;
if (this._darkModeGrid) {
document.querySelector<HTMLDivElement>('.panel-wm-content')!.classList.add('dark-mode');
document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme = 'dark';
} else {
document.querySelector('.panel-wm-content')!.classList.remove('dark-mode');
document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme = 'light';
}
this.aureliaGrid.slickGrid?.setOptions({ darkMode: this._darkModeGrid });
}
}
3 changes: 3 additions & 0 deletions packages/demo/src/examples/slickgrid/example30.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<h2>
${title}
<button class="btn btn-outline-secondary btn-sm ms-2" click.trigger="toggleDarkMode()" data-test="toggle-dark-mode">
<span>Toggle Dark Mode</span>
</button>
<span class="float-end">
<a style="font-size: 18px"
target="_blank"
Expand Down
24 changes: 14 additions & 10 deletions packages/demo/src/examples/slickgrid/example30.scss
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
$slick-button-border-color: #ababab !default;

.editable-field {
// box-shadow: inset 0 0 0 1px lightblue !important;
background-color: rgba(227, 240, 251, 0.569) !important;
}
.slick-dark-mode .editable-field {
background-color: rgb(105 123 145 / 57%) !important
}
.unsaved-editable-field {
background-color: #fbfdd1 !important;
}
.button-style {
cursor: pointer;
background-color: white;
border: 1px solid #{$slick-button-border-color};
border-radius: 2px;
justify-content: center;
text-align: center;
&:hover {
border-color: darken($slick-button-border-color, 10%);
}
.slick-dark-mode .unsaved-editable-field {
background-color: rgba(255, 183, 50, 0.8) !important;
color: white;
}

.slick-dark-mode {
--bs-btn-color: #bebebe;
}
.panel-wm {
width: calc(100vw - 12px);
}

0 comments on commit 2dc9e1d

Please sign in to comment.