Skip to content

Commit 92910be

Browse files
committed
PORTING OF SHOWCASE THEMING SQUASHED
1 parent 6251490 commit 92910be

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1782
-61
lines changed

packages/components/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@
366366
"./components/hds/text/code.js": "./dist/_app_/components/hds/text/code.js",
367367
"./components/hds/text/display.js": "./dist/_app_/components/hds/text/display.js",
368368
"./components/hds/text.js": "./dist/_app_/components/hds/text.js",
369+
"./components/hds/theme-switcher.js": "./dist/_app_/components/hds/theme-switcher.js",
369370
"./components/hds/time.js": "./dist/_app_/components/hds/time.js",
370371
"./components/hds/time/range.js": "./dist/_app_/components/hds/time/range.js",
371372
"./components/hds/time/single.js": "./dist/_app_/components/hds/time/single.js",
@@ -394,6 +395,7 @@
394395
"./modifiers/hds-register-event.js": "./dist/_app_/modifiers/hds-register-event.js",
395396
"./modifiers/hds-tooltip.js": "./dist/_app_/modifiers/hds-tooltip.js",
396397
"./services/hds-intl.js": "./dist/_app_/services/hds-intl.js",
398+
"./services/hds-theming.js": "./dist/_app_/services/hds-theming.js",
397399
"./services/hds-time.js": "./dist/_app_/services/hds-time.js"
398400
}
399401
},
@@ -424,4 +426,4 @@
424426
"engines": {
425427
"node": ">= 18"
426428
}
427-
}
429+
}

packages/components/src/components.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ export { default as HdsTextCode } from './components/hds/text/code.ts';
327327
export { default as HdsTextDisplay } from './components/hds/text/display.ts';
328328
export * from './components/hds/text/types.ts';
329329

330+
// Theme Switcher
331+
export { default as HdsThemeSwitcher } from './components/hds/theme-switcher/index.ts';
332+
330333
// Time
331334
export { default as HdsTime } from './components/hds/time/index.ts';
332335
export { default as HdsTimeSingle } from './components/hds/time/single.ts';
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{{!
2+
Copyright (c) HashiCorp, Inc.
3+
SPDX-License-Identifier: MPL-2.0
4+
}}
5+
6+
<Hds::Dropdown @enableCollisionDetection={{true}} @matchToggleWidth={{@toggleIsFullWidth}} class="hds-theme-switcher-control" ...attributes as |D|>
7+
<D.ToggleButton @color="secondary" @size={{this.toggleSize}} @isFullWidth={{@toggleIsFullWidth}} @text={{this.toggleContent.label}} @icon={{this.toggleContent.icon}} />
8+
{{#each-in this._options as |key data|}}
9+
<D.Interactive @icon={{data.icon}} {{on "click" (fn this.setTheme data.theme)}}>{{data.label}}</D.Interactive>
10+
{{/each-in}}
11+
</Hds::Dropdown>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
import Component from '@glimmer/component';
7+
import { inject as service } from '@ember/service';
8+
import { action } from '@ember/object';
9+
10+
import type { HdsDropdownSignature } from '../dropdown/index.ts';
11+
import type { HdsDropdownToggleButtonSignature } from '../dropdown/toggle/button.ts';
12+
import type HdsThemingService from '../../../services/hds-theming.ts';
13+
import { type HdsThemes } from '../../../services/hds-theming.ts';
14+
15+
export const OPTIONS = {
16+
none: { theme: undefined, icon: 'minus', label: 'None' },
17+
system: { theme: 'system', icon: 'monitor', label: 'System' },
18+
light: { theme: 'light', icon: 'sun', label: 'Light' },
19+
dark: { theme: 'dark', icon: 'moon', label: 'Dark' },
20+
} as const;
21+
22+
export interface HdsThemeSwitcherSignature {
23+
Args: {
24+
toggleSize?: HdsDropdownToggleButtonSignature['Args']['size'];
25+
toggleIsFullWidth?: boolean;
26+
};
27+
Element: HdsDropdownSignature['Element'];
28+
}
29+
30+
export default class HdsThemeSwitcher extends Component<HdsThemeSwitcherSignature> {
31+
@service declare readonly hdsTheming: HdsThemingService;
32+
33+
_options = OPTIONS;
34+
35+
get toggleSize() {
36+
return this.args.toggleSize ?? 'small';
37+
}
38+
39+
get toggleContent() {
40+
switch (this.currentTheme) {
41+
case 'system':
42+
case 'light':
43+
case 'dark':
44+
return {
45+
label: OPTIONS[this.currentTheme].label,
46+
icon: OPTIONS[this.currentTheme].icon,
47+
};
48+
case undefined:
49+
default:
50+
return { label: 'Theme', icon: undefined };
51+
}
52+
}
53+
54+
get currentTheme() {
55+
return this.hdsTheming.currentTheme;
56+
}
57+
58+
@action
59+
setTheme(theme: HdsThemes): void {
60+
// we set the theme in the global service
61+
this.hdsTheming.setTheme(theme);
62+
}
63+
}

packages/components/src/services.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
*/
55

66
// This file is used to expose public services
7+
8+
export * from './services/hds-theming.ts';
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import Service from '@ember/service';
2+
import { tracked } from '@glimmer/tracking';
3+
4+
import type Owner from '@ember/owner';
5+
6+
export const LOCALSTORAGE_KEY = 'hds-current-theme';
7+
8+
export enum HdsThemeValues {
9+
System = 'system',
10+
Light = 'light',
11+
Dark = 'dark',
12+
}
13+
14+
export type HdsThemes = `${HdsThemeValues}` | undefined;
15+
16+
export const THEMES: string[] = Object.values(HdsThemeValues);
17+
18+
export default class HdsThemingService extends Service {
19+
@tracked currentTheme: HdsThemes = undefined;
20+
21+
constructor(owner: Owner) {
22+
super(owner);
23+
this.initializeTheme();
24+
}
25+
26+
initializeTheme() {
27+
const _initialTheme = localStorage.getItem(LOCALSTORAGE_KEY);
28+
if (
29+
_initialTheme === 'system' ||
30+
_initialTheme === 'light' ||
31+
_initialTheme === 'dark'
32+
) {
33+
this.setTheme(_initialTheme);
34+
}
35+
}
36+
37+
getTheme(): HdsThemes {
38+
return this.currentTheme;
39+
}
40+
41+
setTheme(theme: HdsThemes) {
42+
// console.log('setting HDS theme', theme);
43+
44+
if (theme === undefined) {
45+
localStorage.removeItem(LOCALSTORAGE_KEY);
46+
} else {
47+
localStorage.setItem(LOCALSTORAGE_KEY, theme);
48+
}
49+
50+
// IMPORTANT: for this to work, it needs to be the HTML tag (it's the `:root` in CSS)
51+
const rootElement = document.querySelector('html');
52+
53+
if (rootElement) {
54+
if (theme === undefined) {
55+
rootElement.removeAttribute('data-hds-theme');
56+
this.currentTheme = undefined;
57+
} else {
58+
rootElement.setAttribute('data-hds-theme', theme);
59+
this.currentTheme = theme;
60+
}
61+
}
62+
}
63+
}

packages/components/src/template-registry.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ import type HdsTagComponent from './components/hds/tag';
232232
import type HdsTooltipButtonComponent from './components/hds/tooltip-button';
233233
import type HdsToastComponent from './components/hds/toast';
234234
import type HdsTextCodeComponent from './components/hds/text/code';
235+
import type HdsThemeSwitcherComponent from './components/hds/theme-switcher';
235236
import type HdsTimeComponent from './components/hds/time';
236237
import type HdsTimeSingleComponent from './components/hds/time/single';
237238
import type HdsTimeRangeComponent from './components/hds/time/range';
@@ -1021,6 +1022,10 @@ export default interface HdsComponentsRegistry {
10211022
'Hds::Toast': typeof HdsToastComponent;
10221023
'hds/toast': typeof HdsToastComponent;
10231024

1025+
// ThemeSwitcher
1026+
'Hds::ThemeSwitcher': typeof HdsThemeSwitcherComponent;
1027+
'hds/theme-switcher': typeof HdsThemeSwitcherComponent;
1028+
10241029
// Time
10251030
'Hds::Time': typeof HdsTimeComponent;
10261031
'hds/time': typeof HdsTimeComponent;

showcase/app/components/mock/app/index.gts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,16 @@ import MockAppSidebarOldSideNav from './sidebar/side-nav';
1111
import MockAppMainPageHeader from './main/page-header';
1212
import MockAppMainGenericTextContent from './main/generic-text-content';
1313
import MockAppMainGenericAdvancedTable from './main/generic-advanced-table';
14+
import MockAppMainFormComplex from './main/form-complex';
15+
import MockAppMainTableComplex from './main/table-complex';
16+
import MockAppMainPagination from './main/pagination';
1417
import MockAppFooterAppFooter from './footer/app-footer';
1518

1619
// HDS components
17-
import { HdsAppFrame } from '@hashicorp/design-system-components/components';
20+
import {
21+
HdsAlert,
22+
HdsAppFrame,
23+
} from '@hashicorp/design-system-components/components';
1824

1925
// types
2026
import type { ComponentLike } from '@glint/template';
@@ -25,10 +31,14 @@ import type { MockAppSidebarOldSideNavSignature } from './sidebar/side-nav';
2531
import type { MockAppMainPageHeaderSignature } from './main/page-header';
2632
import type { MockAppMainGenericTextContentSignature } from './main/generic-text-content';
2733
import type { MockAppMainGenericAdvancedTableSignature } from './main/generic-advanced-table';
34+
import type { MockAppMainFormComplexSignature } from './main/form-complex';
35+
import type { MockAppMainTableComplexSignature } from './main/table-complex';
36+
import type { MockAppMainPaginationSignature } from './main/pagination';
2837
import type { MockAppFooterAppFooterSignature } from './footer/app-footer';
2938

3039
export interface MockAppSignature {
3140
Args: {
41+
hasPageAlert?: boolean;
3242
hasHeader?: HdsAppFrameSignature['Args']['hasHeader'];
3343
hasSidebar?: HdsAppFrameSignature['Args']['hasSidebar'];
3444
hasOldSidebar?: boolean;
@@ -52,6 +62,9 @@ export interface MockAppSignature {
5262
PageHeader?: ComponentLike<MockAppMainPageHeaderSignature>;
5363
GenericTextContent?: ComponentLike<MockAppMainGenericTextContentSignature>;
5464
GenericAdvancedTable?: ComponentLike<MockAppMainGenericAdvancedTableSignature>;
65+
FormComplex?: ComponentLike<MockAppMainFormComplexSignature>;
66+
TableComplex?: ComponentLike<MockAppMainTableComplexSignature>;
67+
Pagination?: ComponentLike<MockAppMainPaginationSignature>;
5568
},
5669
];
5770
footer?: [
@@ -92,12 +105,21 @@ export default class MockApp extends Component<MockAppSignature> {
92105
{{/if}}
93106
</Frame.Sidebar>
94107
<Frame.Main>
108+
{{#if @hasPageAlert}}
109+
<HdsAlert @type="page" @color="highlight" as |A|>
110+
<A.Title>Lorem ipsum</A.Title>
111+
<A.Description>Lorem ipsum dolor sit amet.</A.Description>
112+
</HdsAlert>
113+
{{/if}}
95114
<div class="mock-app-layout-main-content-wrapper">
96115
{{yield
97116
(hash
98117
PageHeader=MockAppMainPageHeader
99118
GenericTextContent=MockAppMainGenericTextContent
100119
GenericAdvancedTable=MockAppMainGenericAdvancedTable
120+
FormComplex=MockAppMainFormComplex
121+
TableComplex=MockAppMainTableComplex
122+
Pagination=MockAppMainPagination
101123
)
102124
to="main"
103125
}}

0 commit comments

Comments
 (0)