Skip to content

Commit

Permalink
feat(components/layout): tokenize fluid grid styles
Browse files Browse the repository at this point in the history
  • Loading branch information
Blackbaud-TrevorBurch committed Jan 31, 2025
1 parent cb59851 commit 39f18b6
Show file tree
Hide file tree
Showing 11 changed files with 416 additions and 202 deletions.
2 changes: 1 addition & 1 deletion apps/code-examples/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
standalone: false,
})
export class AppComponent {
public height = 60;
public height = 80;

constructor(
renderer: Renderer2,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SkyThemeMode } from '@skyux/theme';

export type ThemeSelectorModeValue = keyof typeof SkyThemeMode.presets;
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export type ThemeSelectorValue = 'default' | 'modern-light' | 'modern-dark';
import { SkyTheme } from '@skyux/theme';

export type ThemeSelectorValue = keyof typeof SkyTheme.presets;
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,51 @@
<label class="sky-control-label" [for]="inputBoxSelect.id">Theme</label>
<select
#inputBoxSelect="skyId"
class="sky-theme-selector sky-form-control"
skyId
class="sky-theme-selector sky-form-control"
[(ngModel)]="themeName"
>
<option value="default">Default</option>
<option value="modern-light">Modern - Light</option>
<option value="modern-dark">Modern - Dark</option>
<option value="modern">Modern</option>
</select>
</sky-input-box>
<sky-input-box class="sky-margin-inline-lg theme-selector-input">
<label class="sky-control-label" [for]="inputBoxSelectMode.id">Mode</label>
<select
#inputBoxSelectMode="skyId"
class="sky-theme-selector sky-form-control"
skyId
[disabled]="modeValues().length === 1"
[(ngModel)]="themeMode"
>
@for (modeValue of modeValues(); track modeValue) {
<option [value]="modeValue">
{{ modeValue.charAt(0).toUpperCase() + modeValue.substring(1) }}
</option>
}
</select>
</sky-input-box>
<sky-input-box class="theme-selector-input">

<sky-input-box class="sky-margin-inline-lg theme-selector-input">
<label class="sky-control-label" [for]="inputBoxSelectSpacing.id"
>Spacing</label
>
<select
#inputBoxSelectSpacing="skyId"
class="sky-theme-selector sky-form-control"
skyId
class="sky-theme-selector sky-form-control"
[disabled]="spacingValues().length === 1"
[(ngModel)]="themeSpacing"
>
@for (spacingValue of spacingValues; track spacingValue) {
@for (spacingValue of spacingValues(); track spacingValue) {
<option [value]="spacingValue">
{{ spacingValue.charAt(0).toUpperCase() + spacingValue.substring(1) }}
</option>
}
</select>
</sky-input-box>
<sky-checkbox
labelText="Enable modern v2"
[disabled]="themeName() === 'default'"
[(ngModel)]="modernV2Enabled"
/>
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { Component, OnInit, inject } from '@angular/core';
import {
Component,
OnInit,
Renderer2,
computed,
effect,
inject,
signal,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { SkyIdModule } from '@skyux/core';
import { SkyInputBoxModule } from '@skyux/forms';
import { SkyCheckboxModule, SkyInputBoxModule } from '@skyux/forms';
import {
SkyTheme,
SkyThemeMode,
Expand All @@ -10,130 +18,117 @@ import {
SkyThemeSpacing,
} from '@skyux/theme';

import { ThemeSelectorModeValue } from './theme-selector-mode-value';
import { ThemeSelectorSpacingValue } from './theme-selector-spacing-value';
import { ThemeSelectorValue } from './theme-selector-value';

interface LocalStorageSettings {
themeName: ThemeSelectorValue;
themeMode: ThemeSelectorModeValue;
themeSpacing: ThemeSelectorSpacingValue;
modernV2Enabled: boolean | undefined;
}

const PREVIOUS_SETTINGS_KEY = 'skyux-playground-theme-selector-settings';
const PREVIOUS_SETTINGS_KEY =
'skyux-playground-theme-mode-spacing-selector-settings';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'sky-theme-selector',
imports: [FormsModule, SkyIdModule, SkyInputBoxModule],
imports: [FormsModule, SkyCheckboxModule, SkyIdModule, SkyInputBoxModule],
templateUrl: './theme-selector.component.html',
})
export class SkyThemeSelectorComponent implements OnInit {
public set themeName(value: ThemeSelectorValue) {
const previousThemeName = this.#_themeName;
this.#_themeName = value;

if (value !== previousThemeName) {
this.#updateThemeSettings();
}
}

public get themeName(): ThemeSelectorValue {
return this.#_themeName;
}

public set themeSpacing(value: ThemeSelectorSpacingValue) {
const previous = this.#_themeSpacing;
this.#_themeSpacing = value;
#renderer = inject(Renderer2);
#themeSvc = inject(SkyThemeService);

if (value !== previous) {
this.#updateThemeSettings();
}
}
#currentTheme = computed(
() => SkyTheme.presets[this.themeName() as ThemeSelectorValue],
);

protected readonly themeName = signal<ThemeSelectorValue>('default');
protected readonly themeMode = signal<ThemeSelectorModeValue>('light');
protected readonly themeSpacing =
signal<ThemeSelectorSpacingValue>('standard');
protected readonly modernV2Enabled = signal(false);

protected readonly spacingValues = computed(() =>
this.#currentTheme().supportedSpacing.map((spacing) => spacing.name),
);

protected readonly modeValues = computed(() =>
this.#currentTheme().supportedModes.map((mode) => mode.name),
);

constructor() {
effect(() => {
this.#updateThemeSettings(
this.themeName(),
this.themeMode(),
this.themeSpacing(),
this.modernV2Enabled(),
);
});

public get themeSpacing(): ThemeSelectorSpacingValue {
return this.#_themeSpacing;
effect(() => {
this.#toggleModernV2Class(this.modernV2Enabled());
});
}

protected spacingValues: ThemeSelectorSpacingValue[] = [];

#_themeName: ThemeSelectorValue = 'default';
#_themeSpacing: ThemeSelectorSpacingValue = 'standard';

#themeSvc = inject(SkyThemeService);
#currentThemeSettings: SkyThemeSettings | undefined;

public ngOnInit(): void {
const previousSettings = this.#getLastSettings();

if (previousSettings) {
try {
this.themeName = previousSettings.themeName;
this.themeSpacing = previousSettings.themeSpacing;
this.themeName.set(previousSettings.themeName);
this.themeMode.set(previousSettings.themeMode);
this.themeSpacing.set(previousSettings.themeSpacing);
this.modernV2Enabled.set(!!previousSettings.modernV2Enabled);
} catch {
// Bad settings.
}
}

this.#themeSvc.settingsChange.subscribe((settingsChange) => {
const settings = settingsChange.currentSettings;

if (settings.theme === SkyTheme.presets.modern) {
this.themeName =
settings.mode === SkyThemeMode.presets.dark
? 'modern-dark'
: 'modern-light';

this.themeSpacing = settings.spacing.name as ThemeSelectorSpacingValue;
} else {
this.themeName = 'default';
this.themeSpacing = 'standard';
}

this.#currentThemeSettings = settings;
this.#updateSpacingOptions();
});
}

#updateSpacingOptions(): void {
if (this.#currentThemeSettings) {
this.spacingValues =
this.#currentThemeSettings.theme.supportedSpacing.map(
(spacing) => spacing.name as ThemeSelectorSpacingValue,
);
}
}

#updateThemeSettings(): void {
const themeSpacing = SkyThemeSpacing.presets[this.themeSpacing];
#updateThemeSettings(
themeName: ThemeSelectorValue,
themeModeName: ThemeSelectorModeValue,
themeSpacingName: ThemeSelectorSpacingValue,
modernV2Enabled: boolean,
): void {
const themeSpacing = SkyThemeSpacing.presets[themeSpacingName];
const themeMode = SkyThemeMode.presets[themeModeName];

let theme: SkyTheme;
let themeMode = SkyThemeMode.presets.light;

switch (this.themeName) {
case 'modern-light':
theme = SkyTheme.presets.modern;
break;
case 'modern-dark':
theme = SkyTheme.presets.modern;
themeMode = SkyThemeMode.presets.dark;
break;
default:
theme = SkyTheme.presets.default;
break;

if (themeName === 'modern') {
theme = SkyTheme.presets.modern;
} else {
theme = SkyTheme.presets.default;
}

this.#themeSvc.setTheme(
new SkyThemeSettings(theme, themeMode, themeSpacing),
);

this.#saveSettings({
themeName: this.themeName,
themeSpacing: this.themeSpacing,
themeName: themeName,
themeMode: themeModeName,
themeSpacing: themeSpacingName,
modernV2Enabled: modernV2Enabled,
});
}

#toggleModernV2Class(addClass: boolean): void {
this.#renderer[addClass ? 'addClass' : 'removeClass'](
document.body,
'sky-theme-brand-blackbaud',
);
}

#getLastSettings(): LocalStorageSettings | undefined {
try {
return JSON.parse(localStorage.getItem(PREVIOUS_SETTINGS_KEY)!);
return JSON.parse(localStorage.getItem(PREVIOUS_SETTINGS_KEY) ?? '');
} catch {
// Local storage is disabled or settings are invalid.
return undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ describe('layout-storybook - fluid-grid', () => {
});
});
});
});
}, true);
});
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class SkyThemeSelectorComponent implements OnInit {
this.themeName.set(previousSettings.themeName);
this.themeMode.set(previousSettings.themeMode);
this.themeSpacing.set(previousSettings.themeSpacing);
this.modernV2Enabled.set(previousSettings.modernV2Enabled);
this.modernV2Enabled.set(!!previousSettings.modernV2Enabled);
} catch {
// Bad settings.
}
Expand Down Expand Up @@ -128,7 +128,7 @@ export class SkyThemeSelectorComponent implements OnInit {

#getLastSettings(): LocalStorageSettings | undefined {
try {
return JSON.parse(localStorage.getItem(PREVIOUS_SETTINGS_KEY));
return JSON.parse(localStorage.getItem(PREVIOUS_SETTINGS_KEY) ?? '');
} catch {
// Local storage is disabled or settings are invalid.
return undefined;
Expand Down
Loading

0 comments on commit 39f18b6

Please sign in to comment.