diff --git a/.github/workflows/build-app-crm.yml b/.github/workflows/build-app-crm.yml index 2bfd89874a..77062edcad 100644 --- a/.github/workflows/build-app-crm.yml +++ b/.github/workflows/build-app-crm.yml @@ -46,4 +46,8 @@ jobs: - name: 'Generate live editing and build samples' run: npm run build:app-crm env: + # esbuild is a Go binary: Node heap flags do not limit it, GOMEMLIMIT/GOGC do. + # Without this the app build OOM-kills the runner ("The operation was canceled"). + GOMEMLIMIT: '6GiB' + GOGC: '50' NODE_OPTIONS: "--max_old_space_size=4096" diff --git a/.github/workflows/build-app-lob.yml b/.github/workflows/build-app-lob.yml index 699c333d3b..47fe1767ac 100644 --- a/.github/workflows/build-app-lob.yml +++ b/.github/workflows/build-app-lob.yml @@ -48,4 +48,8 @@ jobs: - name: 'Generate live editing and build samples' run: npm run build:app-lob env: + # esbuild is a Go binary: Node heap flags do not limit it, GOMEMLIMIT/GOGC do. + # Without this the app build OOM-kills the runner ("The operation was canceled"). + GOMEMLIMIT: '6GiB' + GOGC: '50' NODE_OPTIONS: "--max_old_space_size=4096" diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml index 3c19b5984f..ae90b48623 100644 --- a/.github/workflows/build-app.yml +++ b/.github/workflows/build-app.yml @@ -46,4 +46,8 @@ jobs: - name: 'Generate live editing and build samples' run: npm run build env: + # esbuild is a Go binary: Node heap flags do not limit it, GOMEMLIMIT/GOGC do. + # Without this the app build OOM-kills the runner ("The operation was canceled"). + GOMEMLIMIT: '6GiB' + GOGC: '50' NODE_OPTIONS: "--max_old_space_size=4096" diff --git a/angular.json b/angular.json index 1509ba457b..f3c2b57e3c 100644 --- a/angular.json +++ b/angular.json @@ -19,7 +19,12 @@ "tsConfig": "src/tsconfig.app.json", "assets": [ "src/assets", - "src/favicon.ico" + "src/favicon.ico", + { + "glob": "igniteui-{angular,angular-dark,fluent-light,fluent-dark,bootstrap-light,bootstrap-dark,indigo-light,indigo-dark}.css", + "input": "node_modules/igniteui-angular/styles", + "output": "assets/themes" + } ], "styles": [ "src/styles.scss" diff --git a/live-editing/configs/ButtonConfigGenerator.ts b/live-editing/configs/ButtonConfigGenerator.ts index 5dc013ef22..fbdecc8022 100644 --- a/live-editing/configs/ButtonConfigGenerator.ts +++ b/live-editing/configs/ButtonConfigGenerator.ts @@ -1,48 +1,95 @@ -import { IgxButtonGroupModule } from 'igniteui-angular/button-group'; -import { IgxButtonModule, IgxRippleModule } from 'igniteui-angular/directives'; -import { IgxIconModule } from 'igniteui-angular/icon'; -import { AppModuleConfig, Config, IConfigGenerator } from 'igniteui-live-editing' +import { Config, IConfigGenerator } from 'igniteui-live-editing' import { BaseAppConfig } from './BaseConfig'; -import { ButtonsRoundnessComponent } from '../../src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample'; export class ButtonConfigGenerator implements IConfigGenerator { public generateConfigs(): Config[] { const configs = new Array(); - // buttons sample 1 + // button overview configs.push(new Config({ - component: 'ButtonsSample1Component', + component: 'ButtonOverviewComponent', appConfig: BaseAppConfig, - shortenComponentPathBy: "/data-entries/buttons/" + shortenComponentPathBy: "/data-entries/button/" })); - // buttons roundness + // flat button configs.push(new Config({ - component: 'ButtonsDisabledComponent', + component: 'ButtonFlatComponent', appConfig: BaseAppConfig, - shortenComponentPathBy: "/data-entries/buttons/" + shortenComponentPathBy: "/data-entries/button/" })); - // buttons display density + // button interaction states configs.push(new Config({ - component: 'ButtonsDisplayDensityComponent', + component: 'ButtonInteractionStatesComponent', appConfig: BaseAppConfig, - shortenComponentPathBy: "/data-entries/buttons/" + shortenComponentPathBy: "/data-entries/button/" })); + // button layout configs.push(new Config({ - component: 'ButtonsRoundnessComponent', + component: 'ButtonLayoutComponent', appConfig: BaseAppConfig, - shortenComponentPathBy: "/data-entries/buttons/" + shortenComponentPathBy: "/data-entries/button/" })); - // button style + // contained button configs.push(new Config({ - component: 'ButtonsStyleComponent', - additionalFiles: ["/src/app/data-entries/buttons/buttons-style/layout.scss"], + component: 'ButtonContainedComponent', appConfig: BaseAppConfig, - shortenComponentPathBy: "/data-entries/buttons/" + shortenComponentPathBy: "/data-entries/button/" + })); + + // floating action button + configs.push(new Config({ + component: 'ButtonFabComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/button/" + })); + + // outlined button + configs.push(new Config({ + component: 'ButtonOutlinedComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/button/" + })); + + // button states + configs.push(new Config({ + component: 'ButtonStatesComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/button/" + })); + + // button size + configs.push(new Config({ + component: 'ButtonSizeComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/button/" + })); + + // download button + configs.push(new Config({ + component: 'ButtonDownloadComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/button/" + })); + + // button styling + configs.push(new Config({ + component: 'ButtonStylingComponent', + additionalFiles: ["/src/app/data-entries/button/button-styling/layout.scss"], + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/button/" + })); + + // button tailwind styling + configs.push(new Config({ + component: 'ButtonTailwindStylingComponent', + additionalFiles: ["/src/app/data-entries/button/button-tailwind-styling/layout.scss"], + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/button/" })); return configs; diff --git a/live-editing/configs/GridConfigGenerator.ts b/live-editing/configs/GridConfigGenerator.ts index 0675968292..472080951b 100644 --- a/live-editing/configs/GridConfigGenerator.ts +++ b/live-editing/configs/GridConfigGenerator.ts @@ -574,6 +574,11 @@ export class GridConfigGenerator implements IConfigGenerator { additionalFiles: ['/src/app/directives/prevent-scroll.directive.ts', '/src/app/data/customers.ts', '/src/app/grid/grid-sample-pinning-styling/layout.scss'], appConfig: BaseAppConfig })); + configs.push(new Config({ + component: 'GridThemingComponent', + additionalFiles: ['/src/app/directives/prevent-scroll.directive.ts', '/src/app/data/invoiceData.ts'], + appConfig: BaseAppConfig + })); configs.push(new Config({ component: 'GridGroupByStylingComponent', additionalFiles: ['/src/app/directives/prevent-scroll.directive.ts', '/src/app/data/invoiceData.ts', '/src/app/grid/grid-groupby-styling/layout.scss'], diff --git a/live-editing/configs/PivotGridConfigGenerator.ts b/live-editing/configs/PivotGridConfigGenerator.ts index 7f7fb25e2e..c7c720c47b 100644 --- a/live-editing/configs/PivotGridConfigGenerator.ts +++ b/live-editing/configs/PivotGridConfigGenerator.ts @@ -83,7 +83,7 @@ export class PivotGridConfigGenerator implements IConfigGenerator { })); configs.push(new Config({ - additionalFiles: ['/src/app/directives/prevent-scroll.directive.ts', '/src/app/data/dataToAnalyze.ts'], + additionalFiles: ['/src/app/data/pivot-data.ts', '/src/app/pivot-grid/pivot-styling/layout.scss'], appConfig: BaseAppConfig, component: 'PivotStylingComponent' })); diff --git a/live-editing/configs/SwitchConfigGenerator.ts b/live-editing/configs/SwitchConfigGenerator.ts index 3e92e34182..6000f24dbe 100644 --- a/live-editing/configs/SwitchConfigGenerator.ts +++ b/live-editing/configs/SwitchConfigGenerator.ts @@ -7,16 +7,37 @@ export class SwitchConfigGenerator implements IConfigGenerator { public generateConfigs(): Config[] { const configs = new Array(); - // switch sample 1 + // switch overview configs.push(new Config({ - component: 'SwitchSample1Component', + component: 'SwitchOverviewComponent', appConfig: BaseAppConfig, shortenComponentPathBy: "/data-entries/switch/" })); - // switch sample 2 + // switch enabled configs.push(new Config({ - component: 'SwitchSample2Component', + component: 'SwitchEnabledComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/switch/" + })); + + // switch disabled + configs.push(new Config({ + component: 'SwitchDisabledComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/switch/" + })); + + // switch selected + configs.push(new Config({ + component: 'SwitchSelectedComponent', + appConfig: BaseAppConfig, + shortenComponentPathBy: "/data-entries/switch/" + })); + + // switch layout + configs.push(new Config({ + component: 'SwitchLayoutComponent', appConfig: BaseAppConfig, shortenComponentPathBy: "/data-entries/switch/" })); @@ -24,7 +45,6 @@ export class SwitchConfigGenerator implements IConfigGenerator { // switch styling configs.push(new Config({ component: 'SwitchStylingComponent', - additionalFiles: ["/src/app/data-entries/switch/switch-styling/layout.scss"], appConfig: BaseAppConfig, shortenComponentPathBy: "/data-entries/switch/" })); diff --git a/live-editing/configs/ThemingConfigGenerator.ts b/live-editing/configs/ThemingConfigGenerator.ts index 3c0a10d09e..9d29d32b4e 100644 --- a/live-editing/configs/ThemingConfigGenerator.ts +++ b/live-editing/configs/ThemingConfigGenerator.ts @@ -72,6 +72,22 @@ export class ThemingConfigGenerator implements IConfigGenerator { shortenComponentPathBy: '/theming/angular/' })); + configs.push(new Config({ + component: 'GridThemePlaygroundComponent', + additionalFiles: [ + '/src/app/theming/grid-theme-playground/theme-color-field.component.ts', + '/src/app/theming/grid-theme-playground/theme-color-field.component.html', + '/src/app/theming/grid-theme-playground/theme-color-field.component.scss', + '/src/app/theming/grid-theme-playground/color-utils.ts', + '/src/app/data/invoiceData.ts', + '/src/app/data/pivot-data.ts', + '/src/app/data/singersData.ts', + '/src/app/tree-grid/data/employees-flat-avatars.ts' + ], + appConfig: BaseAppConfig, + shortenComponentPathBy: '/theming/grid-theme-playground/' + })); + configs.push(new Config({ component: 'TailwindSampleComponent', appConfig: BaseAppConfig, diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 1046547447..10970e42e6 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,6 +1,7 @@ import { Component, HostListener, OnInit, DOCUMENT, inject } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import { ThemeService } from './services/theme.service'; @Component({ selector: 'app-root', @@ -10,50 +11,22 @@ import { RouterOutlet } from '@angular/router'; }) export class AppComponent implements OnInit { private document = inject(DOCUMENT); + private themeService = inject(ThemeService); public title = 'Samples'; - private theme = 'default-theme'; - private styleElem: HTMLStyleElement; - private typefacesLoaded = ['Titillium Web', 'Roboto']; - private typefaceUrl = 'https://fonts.googleapis.com/css?family='; public ngOnInit() { - this.createThemeStyle(); + this.document.body.classList.add('custom-body'); + this.themeService.init(); } - // eslint-disable-next-line @typescript-eslint/member-ordering + /** + * Samples are embedded in the documentation as iframes and the theming + * widget shown next to each of them posts the visitor's theme selection + * down into the sample. Anything that is not such a message is left alone. + */ @HostListener('window:message', ['$event']) protected onMessage(e: MessageEvent) { - if (e.origin === e.data.origin && typeof e.data.themeStyle === 'string') { - this.styleElem.textContent = e.data.themeStyle; - const typeface = window.getComputedStyle(this.document.body).fontFamily.replace(/[\'\"]/g, ''); - if (!(typeface.match(/,/g) || []).length && - !this.typefacesLoaded.includes(typeface)) { - this.typefacesLoaded.push(typeface); - this.createTypefaceLink(typeface); - } - } else if (e.origin === e.data.origin && typeof e.data.theme === 'string') { - this.document.body.classList.remove(this.theme); - this.document.body.classList.add(e.data.theme); - this.theme = e.data.theme; - } - } - - private createTypefaceLink(typeface: string) { - let typefaceElem = this.document.getElementById('igniteui-theme-typeface') as HTMLLinkElement; - if (!typefaceElem) { - typefaceElem = this.document.createElement('link'); - typefaceElem.rel = 'stylesheet'; - typefaceElem.id = 'igniteui-theme-typeface'; - this.document.head.appendChild(typefaceElem); - } - typefaceElem.href = this.typefaceUrl + typeface.split(' ').join('+'); - } - - private createThemeStyle() { - this.styleElem = this.document.createElement('style'); - this.styleElem.id = 'igniteui-theme'; - this.document.head.appendChild(this.styleElem); - this.document.body.classList.add('custom-body'); + this.themeService.handleMessage(e); } } diff --git a/src/app/app.routes.server.ts b/src/app/app.routes.server.ts index 85274dd7e2..2960e62832 100644 --- a/src/app/app.routes.server.ts +++ b/src/app/app.routes.server.ts @@ -49,6 +49,16 @@ export const serverRoutes: ServerRoute[] = [ path: 'samples/lists/**', renderMode: RenderMode.Client // TODO: Fails with Prerender }, + { + // Hosts grid previews, and grids fail under Prerender like every other + // grid route below. Must precede the theming/** globs. + path: 'theming/grid-theme-playground', + renderMode: RenderMode.Client + }, + { + path: 'samples/theming/grid-theme-playground', + renderMode: RenderMode.Client + }, { path: 'theming/**', renderMode: RenderMode.Prerender diff --git a/src/app/data-entries/button/_bootstrap-button-theme.scss b/src/app/data-entries/button/_bootstrap-button-theme.scss new file mode 100644 index 0000000000..6ce81fd333 --- /dev/null +++ b/src/app/data-entries/button/_bootstrap-button-theme.scss @@ -0,0 +1,61 @@ +@use 'igniteui-angular/theming' as *; +@use 'igniteui-angular/lib/core/styles/components/button/button-component' as button; +@use 'igniteui-angular/lib/core/styles/themes/presets/igniteui-bootstrap-light'; +@use 'igniteui-theming/sass/typography/presets' as typography-presets; + +:host ::ng-deep { + @include typography( + $font-family: typography-presets.$bootstrap-typeface, + $type-scale: typography-presets.$bootstrap-type-scale + ); + + @include button( + $flat: flat-button-theme( + $schema: $light-bootstrap-schema, + $foreground: color($light-bootstrap-palette, 'primary'), + $hover-foreground: color($light-bootstrap-palette, 'primary'), + $disabled-foreground: color($light-bootstrap-palette, 'primary', 200) + ), + $contained: contained-button-theme( + $schema: $light-bootstrap-schema, + $background: color($light-bootstrap-palette, 'primary'), + $foreground: var(--ig-gray-50), + $hover-background: color($light-bootstrap-palette, 'primary', 600), + $hover-foreground: var(--ig-gray-50), + $focus-background: color($light-bootstrap-palette, 'primary', 800), + $focus-foreground: var(--ig-gray-50), + $focus-hover-background: color($light-bootstrap-palette, 'primary', 600), + $focus-hover-foreground: var(--ig-gray-50), + $disabled-background: color($light-bootstrap-palette, 'primary', 50), + $disabled-foreground: color($light-bootstrap-palette, 'primary', 200) + ), + $outlined: outlined-button-theme( + $schema: $light-bootstrap-schema, + $foreground: color($light-bootstrap-palette, 'primary'), + $hover-background: color($light-bootstrap-palette, 'primary'), + $hover-foreground: var(--ig-gray-50), + $disabled-foreground: color($light-bootstrap-palette, 'primary', 200), + $disabled-border-color: color($light-bootstrap-palette, 'primary', 50) + ), + $fab: fab-button-theme( + $schema: $light-bootstrap-schema, + $background: color($light-bootstrap-palette, 'secondary'), + $foreground: var(--ig-gray-50), + $hover-background: color($light-bootstrap-palette, 'primary'), + $hover-foreground: var(--ig-gray-50), + $disabled-background: color($light-bootstrap-palette, 'gray', 300), + $disabled-foreground: color($light-bootstrap-palette, 'gray', 500), + $resting-shadow: none, + $hover-shadow: none + ) + ); + @include button.component(); + + [igxButton] { + --ig-size: var(--ig-size-medium); + } + + button[igxButton='fab'] { + --ig-size: var(--ig-size-large); + } +} diff --git a/src/app/data-entries/button/button-contained/button-contained.component.html b/src/app/data-entries/button/button-contained/button-contained.component.html new file mode 100644 index 0000000000..48a7b7ad3d --- /dev/null +++ b/src/app/data-entries/button/button-contained/button-contained.component.html @@ -0,0 +1,7 @@ +
+ +
diff --git a/src/app/data-entries/button/button-contained/button-contained.component.scss b/src/app/data-entries/button/button-contained/button-contained.component.scss new file mode 100644 index 0000000000..2bfc8c5087 --- /dev/null +++ b/src/app/data-entries/button/button-contained/button-contained.component.scss @@ -0,0 +1,11 @@ +@use '../_bootstrap-button-theme'; + +.button-sample { + display: flex; + padding: 2.5rem; +} + +.button-sample button { + width: 46%; + margin: auto; +} diff --git a/src/app/data-entries/button/button-contained/button-contained.component.ts b/src/app/data-entries/button/button-contained/button-contained.component.ts new file mode 100644 index 0000000000..7caea5fad4 --- /dev/null +++ b/src/app/data-entries/button/button-contained/button-contained.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-contained', + styleUrls: ['./button-contained.component.scss'], + templateUrl: './button-contained.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonContainedComponent { } diff --git a/src/app/data-entries/button/button-download/button-download.component.html b/src/app/data-entries/button/button-download/button-download.component.html new file mode 100644 index 0000000000..165292aa2e --- /dev/null +++ b/src/app/data-entries/button/button-download/button-download.component.html @@ -0,0 +1,3 @@ + diff --git a/src/app/data-entries/button/button-download/button-download.component.scss b/src/app/data-entries/button/button-download/button-download.component.scss new file mode 100644 index 0000000000..54492fe328 --- /dev/null +++ b/src/app/data-entries/button/button-download/button-download.component.scss @@ -0,0 +1,11 @@ +@use '../_bootstrap-button-theme'; + +.button-sample { + display: flex; + padding: 2.5rem; +} + +.button-sample a { + width: 46%; + margin: auto; +} diff --git a/src/app/data-entries/button/button-download/button-download.component.ts b/src/app/data-entries/button/button-download/button-download.component.ts new file mode 100644 index 0000000000..f382891209 --- /dev/null +++ b/src/app/data-entries/button/button-download/button-download.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; + +@Component({ + selector: 'app-button-download', + styleUrls: ['./button-download.component.scss'], + templateUrl: './button-download.component.html', + imports: [IgxButtonDirective] +}) +export class ButtonDownloadComponent { } diff --git a/src/app/data-entries/button/button-fab/button-fab.component.html b/src/app/data-entries/button/button-fab/button-fab.component.html new file mode 100644 index 0000000000..8eaaad311b --- /dev/null +++ b/src/app/data-entries/button/button-fab/button-fab.component.html @@ -0,0 +1,7 @@ +
+ +
diff --git a/src/app/data-entries/button/button-fab/button-fab.component.scss b/src/app/data-entries/button/button-fab/button-fab.component.scss new file mode 100644 index 0000000000..8bb51245de --- /dev/null +++ b/src/app/data-entries/button/button-fab/button-fab.component.scss @@ -0,0 +1,11 @@ +@use '../_bootstrap-button-theme'; + +.button-sample { + display: flex; + padding: 2rem; +} + +.button-sample button { + width: 45%; + margin: auto; +} diff --git a/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.ts b/src/app/data-entries/button/button-fab/button-fab.component.ts similarity index 55% rename from src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.ts rename to src/app/data-entries/button/button-fab/button-fab.component.ts index 6d07452311..d611bb25ea 100644 --- a/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.ts +++ b/src/app/data-entries/button/button-fab/button-fab.component.ts @@ -3,9 +3,9 @@ import { IgxButtonDirective } from 'igniteui-angular/directives'; import { IgxIconComponent } from 'igniteui-angular/icon'; @Component({ - selector: 'app-buttons-sample-6', - styleUrls: ['./buttons-sample-6.component.scss'], - templateUrl: './buttons-sample-6.component.html', + selector: 'app-button-fab', + styleUrls: ['./button-fab.component.scss'], + templateUrl: './button-fab.component.html', imports: [IgxButtonDirective, IgxIconComponent] }) -export class ButtonsSample6Component { } +export class ButtonFabComponent { } diff --git a/src/app/data-entries/button/button-flat/button-flat.component.html b/src/app/data-entries/button/button-flat/button-flat.component.html new file mode 100644 index 0000000000..c5c68089a8 --- /dev/null +++ b/src/app/data-entries/button/button-flat/button-flat.component.html @@ -0,0 +1,7 @@ +
+ +
diff --git a/src/app/data-entries/button/button-flat/button-flat.component.scss b/src/app/data-entries/button/button-flat/button-flat.component.scss new file mode 100644 index 0000000000..2bfc8c5087 --- /dev/null +++ b/src/app/data-entries/button/button-flat/button-flat.component.scss @@ -0,0 +1,11 @@ +@use '../_bootstrap-button-theme'; + +.button-sample { + display: flex; + padding: 2.5rem; +} + +.button-sample button { + width: 46%; + margin: auto; +} diff --git a/src/app/data-entries/button/button-flat/button-flat.component.ts b/src/app/data-entries/button/button-flat/button-flat.component.ts new file mode 100644 index 0000000000..ab6dcb1229 --- /dev/null +++ b/src/app/data-entries/button/button-flat/button-flat.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-flat', + styleUrls: ['./button-flat.component.scss'], + templateUrl: './button-flat.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonFlatComponent { } diff --git a/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.html b/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.html new file mode 100644 index 0000000000..fca47f84e6 --- /dev/null +++ b/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.html @@ -0,0 +1,12 @@ +
+ @for (state of states; track state.value) { +
+ {{ state.label }} + +
+ } +
diff --git a/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.scss b/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.scss new file mode 100644 index 0000000000..bb5a34685d --- /dev/null +++ b/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.scss @@ -0,0 +1,48 @@ +@use '../_bootstrap-button-theme'; +@use "igniteui-angular/theming" as *; + +.button-container { + display: flex; + justify-content: center; + align-items: center; + gap: 2rem; + padding: 1rem; +} + +.button-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.75rem; + --hover-background: var(--ig-contained-button-hover-background); + --hover-foreground: var(--ig-contained-button-hover-foreground); + --focus-background: var(--ig-contained-button-focus-background); + --focus-foreground: var(--ig-contained-button-focus-foreground); + --focus-hover-background: var(--ig-contained-button-focus-hover-background); + --focus-hover-foreground: var(--ig-contained-button-focus-hover-foreground); +} + +.button-label { + color: var(--ig-gray-600); + font-family: "Aktiv Grotesk", sans-serif; + font-size: 13px; + font-weight: 400; + font-style: normal; + line-height: 20px; + letter-spacing: 0.3px; +} + +.button-item button.state-hover { + background: var(--hover-background); + color: var(--hover-foreground); +} + +.button-item button.state-focused { + background: var(--focus-background); + color: var(--focus-foreground); +} + +.button-item button.state-focused-hover { + background: var(--focus-hover-background); + color: var(--focus-hover-foreground); +} diff --git a/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.ts b/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.ts new file mode 100644 index 0000000000..0e2ddee7da --- /dev/null +++ b/src/app/data-entries/button/button-interaction-states/button-interaction-states.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-interaction-states', + styleUrls: ['./button-interaction-states.component.scss'], + templateUrl: './button-interaction-states.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonInteractionStatesComponent { + public states = [ + { label: 'Idle', value: 'idle' }, + { label: 'Hover', value: 'state-hover' }, + { label: 'Focused', value: 'state-focused' }, + { label: 'Focused & Hover', value: 'state-focused-hover' } + ]; +} diff --git a/src/app/data-entries/button/button-layout/button-layout.component.html b/src/app/data-entries/button/button-layout/button-layout.component.html new file mode 100644 index 0000000000..ac8ca6e9f2 --- /dev/null +++ b/src/app/data-entries/button/button-layout/button-layout.component.html @@ -0,0 +1,8 @@ +
+
+
+
+
+
+
+
diff --git a/src/app/data-entries/button/button-layout/button-layout.component.scss b/src/app/data-entries/button/button-layout/button-layout.component.scss new file mode 100644 index 0000000000..770c65f296 --- /dev/null +++ b/src/app/data-entries/button/button-layout/button-layout.component.scss @@ -0,0 +1,26 @@ +@use '../_bootstrap-button-theme'; + +.button-container { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + width: 100%; + box-sizing: border-box; + padding: 2.5rem; +} + +.button-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.75rem; +} + +.button-container button { + --ig-font-family: 'Titillium Web', sans-serif; + --ig-button-text-transform: uppercase; + + font-size: 0.85rem; + letter-spacing: 1px; +} diff --git a/src/app/data-entries/button/button-layout/button-layout.component.ts b/src/app/data-entries/button/button-layout/button-layout.component.ts new file mode 100644 index 0000000000..f7c82fea63 --- /dev/null +++ b/src/app/data-entries/button/button-layout/button-layout.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-layout', + styleUrls: ['./button-layout.component.scss'], + templateUrl: './button-layout.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonLayoutComponent { +} diff --git a/src/app/data-entries/button/button-outlined/button-outlined.component.html b/src/app/data-entries/button/button-outlined/button-outlined.component.html new file mode 100644 index 0000000000..b5f35da49f --- /dev/null +++ b/src/app/data-entries/button/button-outlined/button-outlined.component.html @@ -0,0 +1,7 @@ +
+ +
diff --git a/src/app/data-entries/button/button-outlined/button-outlined.component.scss b/src/app/data-entries/button/button-outlined/button-outlined.component.scss new file mode 100644 index 0000000000..2bfc8c5087 --- /dev/null +++ b/src/app/data-entries/button/button-outlined/button-outlined.component.scss @@ -0,0 +1,11 @@ +@use '../_bootstrap-button-theme'; + +.button-sample { + display: flex; + padding: 2.5rem; +} + +.button-sample button { + width: 46%; + margin: auto; +} diff --git a/src/app/data-entries/button/button-outlined/button-outlined.component.ts b/src/app/data-entries/button/button-outlined/button-outlined.component.ts new file mode 100644 index 0000000000..41cff29372 --- /dev/null +++ b/src/app/data-entries/button/button-outlined/button-outlined.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-outlined', + styleUrls: ['./button-outlined.component.scss'], + templateUrl: './button-outlined.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonOutlinedComponent { } diff --git a/src/app/data-entries/button/button-overview/button-overview.component.html b/src/app/data-entries/button/button-overview/button-overview.component.html new file mode 100644 index 0000000000..b4963b3145 --- /dev/null +++ b/src/app/data-entries/button/button-overview/button-overview.component.html @@ -0,0 +1,15 @@ +
+ +
+ + + + + + +
+ + +
+
+
diff --git a/src/app/data-entries/button/button-overview/button-overview.component.scss b/src/app/data-entries/button/button-overview/button-overview.component.scss new file mode 100644 index 0000000000..e464378d47 --- /dev/null +++ b/src/app/data-entries/button/button-overview/button-overview.component.scss @@ -0,0 +1,39 @@ +@use '../_bootstrap-button-theme'; + +.form { + display: flex; + justify-content: center; + gap: 1.25rem; + padding: 2.5rem; +} + +.form igx-avatar { + --ig-size: var(--ig-size-large); +} + +.fields { + display: flex; + flex-direction: column; + gap: 1rem; + max-width: 260px; + width: 100%; +} + +:host ::ng-deep .fields .igx-input-group__bundle { + background-color: var(--ig-gray-50); +} + +:host ::ng-deep .fields igx-input-group, +:host ::ng-deep .fields igx-input-group .igx-input-group__input { + --ig-size: var(--ig-size-medium); +} + +:host ::ng-deep .fields .igx-input-group__input { + margin: 0; +} +.actions { + display: flex; + justify-content: flex-end; + gap: 1rem; + margin-top: 0.5rem; +} diff --git a/src/app/data-entries/button/button-overview/button-overview.component.ts b/src/app/data-entries/button/button-overview/button-overview.component.ts new file mode 100644 index 0000000000..48c8c8b098 --- /dev/null +++ b/src/app/data-entries/button/button-overview/button-overview.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { IgxAvatarComponent } from 'igniteui-angular/avatar'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxInputDirective, IgxInputGroupComponent } from 'igniteui-angular/input-group'; + +@Component({ + selector: 'app-button-overview', + styleUrls: ['./button-overview.component.scss'], + templateUrl: './button-overview.component.html', + imports: [IgxAvatarComponent, IgxButtonDirective, IgxInputGroupComponent, IgxInputDirective] +}) +export class ButtonOverviewComponent { } diff --git a/src/app/data-entries/button/button-size/button-size.component.html b/src/app/data-entries/button/button-size/button-size.component.html new file mode 100644 index 0000000000..9f0156c2ed --- /dev/null +++ b/src/app/data-entries/button/button-size/button-size.component.html @@ -0,0 +1,20 @@ +
+
ContainedOutlinedFlatFab
+ @for (size of sizes; track size) { +
+ {{ size | titlecase }} + @for (variant of variants; track variant) { + + } + +
+ } +
diff --git a/src/app/data-entries/button/button-size/button-size.component.scss b/src/app/data-entries/button/button-size/button-size.component.scss new file mode 100644 index 0000000000..2b0a6afd17 --- /dev/null +++ b/src/app/data-entries/button/button-size/button-size.component.scss @@ -0,0 +1,63 @@ +@use '../_bootstrap-button-theme'; + +:host { + display: flex; + justify-content: center; + align-items: center; +} + +.size-grid { + display: flex; + flex-direction: column; + gap: 1.25rem; + padding: 1rem; + width: 100%; + box-sizing: border-box; + overflow: hidden; +} + +.size-row { + display: grid; + grid-template-columns: 70px repeat(4, minmax(0, 1fr)); + align-items: center; + justify-items: center; + column-gap: 1rem; + row-gap: 0.5rem; + width: 100%; +} + +.size-header { + display: grid; + grid-template-columns: 70px repeat(4, minmax(0, 1fr)); + align-items: center; + justify-items: center; + column-gap: 1rem; + width: 100%; + color: var(--ig-gray-600); + font: 13px/20px "Aktiv Grotesk", sans-serif; + letter-spacing: .3px; +} + +.size-label { + justify-self: start; + color: var(--ig-gray-600); + font: 400 13px/20px "Aktiv Grotesk", sans-serif; + letter-spacing: .3px; +} + +.size-row button { + width: auto; + transform: scale(.9); +} + +.size-small { + --ig-size: var(--ig-size-small) !important; +} + +.size-medium { + --ig-size: var(--ig-size-medium) !important; +} + +.size-large { + --ig-size: var(--ig-size-large) !important; +} diff --git a/src/app/data-entries/button/button-size/button-size.component.ts b/src/app/data-entries/button/button-size/button-size.component.ts new file mode 100644 index 0000000000..916c5da122 --- /dev/null +++ b/src/app/data-entries/button/button-size/button-size.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { TitleCasePipe } from '@angular/common'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-size', + styleUrls: ['./button-size.component.scss'], + templateUrl: './button-size.component.html', + imports: [IgxButtonDirective, IgxIconComponent, TitleCasePipe] +}) +export class ButtonSizeComponent { + public sizes = ['large', 'medium', 'small']; + public variants = ['contained', 'outlined', 'flat']; +} diff --git a/src/app/data-entries/button/button-states/button-states.component.html b/src/app/data-entries/button/button-states/button-states.component.html new file mode 100644 index 0000000000..cd4424548e --- /dev/null +++ b/src/app/data-entries/button/button-states/button-states.component.html @@ -0,0 +1,30 @@ +
+
+ +
+
+ +
+
+ +
+
+ +
+
diff --git a/src/app/data-entries/button/button-states/button-states.component.scss b/src/app/data-entries/button/button-states/button-states.component.scss new file mode 100644 index 0000000000..ac098876d8 --- /dev/null +++ b/src/app/data-entries/button/button-states/button-states.component.scss @@ -0,0 +1,16 @@ +@use '../_bootstrap-button-theme'; + +.button-container { + display: flex; + justify-content: center; + align-items: center; + gap: 2rem; + padding: 2rem; +} + +.button-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 1.5rem; +} diff --git a/src/app/data-entries/button/button-states/button-states.component.ts b/src/app/data-entries/button/button-states/button-states.component.ts new file mode 100644 index 0000000000..398a2c54d5 --- /dev/null +++ b/src/app/data-entries/button/button-states/button-states.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-states', + styleUrls: ['./button-states.component.scss'], + templateUrl: './button-states.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonStatesComponent { } diff --git a/src/app/data-entries/button/button-styling/button-styling.component.html b/src/app/data-entries/button/button-styling/button-styling.component.html new file mode 100644 index 0000000000..6954e7df30 --- /dev/null +++ b/src/app/data-entries/button/button-styling/button-styling.component.html @@ -0,0 +1,14 @@ +
+
+ + + + +
+
diff --git a/src/app/data-entries/button/button-styling/button-styling.component.scss b/src/app/data-entries/button/button-styling/button-styling.component.scss new file mode 100644 index 0000000000..4637a2ccee --- /dev/null +++ b/src/app/data-entries/button/button-styling/button-styling.component.scss @@ -0,0 +1,39 @@ +@use "layout.scss"; + +// CSS variables approach + +.confirm-button { + --background: #1275c4; + --foreground: #fff; + --hover-background: #1275c4; + --hover-foreground: #fff; + &:hover { --hover-background: #0b4f8a; } +} + +.send-button { + --background: transparent; + --border-color: #8a2be2; + --foreground: #8a2be2; + --hover-border-color: #8a2be2; + --hover-foreground: #8a2be2; + --icon-color: #8a2be2; + --icon-color-hover: #8a2be2; + &:hover { --hover-background: #8a2be2; --hover-border-color: #6a1bb1; --hover-foreground: #fff; --icon-color-hover: #fff; } +} + +.cancel-button { + --foreground: #1275c4; + --hover-foreground: #1275c4; + &:hover { --hover-background: #dbeeff; --hover-foreground: #063b68; } +} + +.add-button { + --background: #4caf50; + --foreground: #000; + --hover-background: #4caf50; + --hover-foreground: #000; + --icon-color: #000; + --icon-color-hover: #000; + --border-radius: 999px; + &:hover { --hover-background: #257a2b; --hover-foreground: #fff; --icon-color-hover: #fff; } +} diff --git a/src/app/data-entries/button/button-styling/button-styling.component.ts b/src/app/data-entries/button/button-styling/button-styling.component.ts new file mode 100644 index 0000000000..eb66365452 --- /dev/null +++ b/src/app/data-entries/button/button-styling/button-styling.component.ts @@ -0,0 +1,12 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-styling', + encapsulation: ViewEncapsulation.None, + styleUrls: ['./button-styling.component.scss'], + templateUrl: './button-styling.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonStylingComponent { } diff --git a/src/app/data-entries/button/button-styling/layout.scss b/src/app/data-entries/button/button-styling/layout.scss new file mode 100644 index 0000000000..a77566283c --- /dev/null +++ b/src/app/data-entries/button/button-styling/layout.scss @@ -0,0 +1,41 @@ +@use "igniteui-angular/theming" as *; +@use "igniteui-angular/lib/core/styles/components/button/button-component" as button; +@use "igniteui-angular/lib/core/styles/themes/presets/igniteui-bootstrap-light"; + +.bootstrap-theme { + ::ng-deep { + @include button( + $flat: flat-button-theme($schema: $light-bootstrap-schema), + $contained: contained-button-theme($schema: $light-bootstrap-schema), + $outlined: outlined-button-theme($schema: $light-bootstrap-schema), + $fab: fab-button-theme($schema: $light-bootstrap-schema) + ); + @include button.component(); + } +} + +.button-row button.confirm-button, +.button-row button.send-button, +.button-row button.cancel-button { + height: 40px; + min-height: 40px; + width: 90%; +} + +.button-grid { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + gap: 1.5rem; + padding: 1rem; +} + +.button-row { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + align-items: center; + justify-items: center; + gap: 3rem; +} diff --git a/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.html b/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.html new file mode 100644 index 0000000000..0a6427ed84 --- /dev/null +++ b/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.html @@ -0,0 +1,14 @@ +
+
+ + + + +
+
diff --git a/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.scss b/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.scss new file mode 100644 index 0000000000..f0ca253bc3 --- /dev/null +++ b/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.scss @@ -0,0 +1,6 @@ +@use "layout.scss"; + +.confirm-button { --hover-background: #3730a3; --hover-foreground: #fff; } +.send-button { --hover-background: #db2777; --hover-border-color: #be185d; --hover-foreground: #fff; --icon-color-hover: #fff; } +.cancel-button { --hover-background: #fef3c7; --hover-foreground: #78350f; } +.add-button { --hover-background: #0f766e; --hover-foreground: #fff; --icon-color-hover: #fff; } diff --git a/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.ts b/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.ts new file mode 100644 index 0000000000..70ea8e811c --- /dev/null +++ b/src/app/data-entries/button/button-tailwind-styling/button-tailwind-styling.component.ts @@ -0,0 +1,12 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxIconComponent } from 'igniteui-angular/icon'; + +@Component({ + selector: 'app-button-tailwind-styling', + encapsulation: ViewEncapsulation.None, + styleUrls: ['./button-tailwind-styling.component.scss'], + templateUrl: './button-tailwind-styling.component.html', + imports: [IgxButtonDirective, IgxIconComponent] +}) +export class ButtonTailwindStylingComponent { } diff --git a/src/app/data-entries/button/button-tailwind-styling/layout.scss b/src/app/data-entries/button/button-tailwind-styling/layout.scss new file mode 100644 index 0000000000..df3c97ac6d --- /dev/null +++ b/src/app/data-entries/button/button-tailwind-styling/layout.scss @@ -0,0 +1,56 @@ +@use "igniteui-angular/theming" as *; +@use "igniteui-angular/lib/core/styles/components/button/button-component" as button; +@use "igniteui-angular/lib/core/styles/themes/presets/igniteui-bootstrap-light"; + +:host { + ::ng-deep { + @include button( + $flat: flat-button-theme($schema: $light-bootstrap-schema), + $contained: contained-button-theme($schema: $light-bootstrap-schema), + $outlined: outlined-button-theme($schema: $light-bootstrap-schema), + $fab: fab-button-theme($schema: $light-bootstrap-schema) + ); + @include button.component(); + } +} + +.button-row button.confirm-button, +.button-row button.send-button, +.button-row button.cancel-button { + height: 40px; + min-height: 40px; + width: 90%; +} + +.confirm-button { + --background: #4338ca; + --foreground: #fff; + --hover-background: #4338ca; + --hover-foreground: #fff; +} + +.send-button { + --background: transparent; + --border-color: #db2777; + --foreground: #db2777; + --hover-border-color: #db2777; + --hover-foreground: #db2777; + --icon-color: #db2777; + --icon-color-hover: #db2777; +} + +.cancel-button { + --foreground: #b45309; + --hover-foreground: #b45309; +} + +.add-button { + --background: #14b8a6; + --foreground: #000; + --hover-background: #14b8a6; + --hover-foreground: #000; + --icon-color: #fff; + --icon-color-hover: #fff; + --border-radius: 9999px; + background-color: #14b8a6; +} diff --git a/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.html b/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.html deleted file mode 100644 index 34d38c8158..0000000000 --- a/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.scss b/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.scss deleted file mode 100644 index 932b31c68c..0000000000 --- a/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 8px; -} diff --git a/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.ts b/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.ts deleted file mode 100644 index c3542a0796..0000000000 --- a/src/app/data-entries/buttons/buttons-disabled-sample/buttons-disabled-sample.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-disabled-sample', - styleUrls: ['./buttons-disabled-sample.scss'], - templateUrl: './buttons-disabled-sample.html', - imports: [IgxButtonDirective] -}) -export class ButtonsDisabledComponent { } diff --git a/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.html b/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.html deleted file mode 100644 index 853533d488..0000000000 --- a/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.html +++ /dev/null @@ -1,27 +0,0 @@ -
-
- -
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
diff --git a/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.scss b/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.scss deleted file mode 100644 index 38b1bb22b2..0000000000 --- a/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.scss +++ /dev/null @@ -1,15 +0,0 @@ -.buttons-sample { - display: flex; - flex-flow: row wrap; -} - -.button-sample { - display: flex; - flex: 1 0 20%; - align-items: center; - justify-content: space-evenly; -} - -.density-chooser { - margin-bottom: 24px; -} diff --git a/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.ts b/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.ts deleted file mode 100644 index 841a908270..0000000000 --- a/src/app/data-entries/buttons/buttons-display-density/buttons-display-density.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, HostBinding, OnInit } from '@angular/core'; -import { IgxButtonGroupComponent } from 'igniteui-angular/button-group'; -import { IgxButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives'; -import { IgxIconComponent } from 'igniteui-angular/icon'; - -@Component({ - selector: 'app-buttons-display-density', - styleUrls: ['./buttons-display-density.component.scss'], - templateUrl: './buttons-display-density.component.html', - imports: [IgxButtonGroupComponent, IgxButtonDirective, IgxRippleDirective, IgxIconComponent] -}) -export class ButtonsDisplayDensityComponent implements OnInit { - public size = 'large'; - public sizes; - - public ngOnInit(): void { - this.sizes = [ - { label: 'large', selected: this.size === 'large', togglable: true }, - { label: 'medium', selected: this.size === 'medium', togglable: true }, - { label: 'small', selected: this.size === 'small', togglable: true } - ]; - } - - @HostBinding('style.--ig-size') - protected get sizeStyle() { - return `var(--ig-size-${this.size})`; - } - - public selectSize(event) { - this.size = this.sizes[event.index].label; - } -} diff --git a/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.html b/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.html deleted file mode 100644 index 0c93305128..0000000000 --- a/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.html +++ /dev/null @@ -1,22 +0,0 @@ -
-
-
-
- -
-
- -
-
- -
-
- -
-
-
-
diff --git a/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.scss b/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.scss deleted file mode 100644 index 81efc9eb5e..0000000000 --- a/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.scss +++ /dev/null @@ -1,44 +0,0 @@ -@use '../../../../variables' as *; - -$flatBtn: flat-button-theme( - $border-radius: .5 -); - -$containedBtn: contained-button-theme( - $border-radius: 30px -); - -$fabBtn: fab-button-theme( - $border-radius: 10% -); - -$iconBtn: flat-icon-button-theme( - $border-radius: 12px -); - -.flat { - @include tokens($flatBtn); -} - -.contained { - @include tokens($containedBtn); -} - -.fab { - @include tokens($fabBtn); -} - -.icon { - @include tokens($iconBtn); -} - -.buttons-sample { - display: flex; -} - -.buttons-sample_item { - display: flex; - align-items: center; - justify-content: center; - flex: 1; -} diff --git a/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.ts b/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.ts deleted file mode 100644 index c791699b35..0000000000 --- a/src/app/data-entries/buttons/buttons-roundness-sample/buttons-roundness-sample.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective, IgxIconButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives'; -import { IgxIconComponent } from 'igniteui-angular/icon'; - -@Component({ - selector: 'app-buttons-roundness-sample', - styleUrls: ['./buttons-roundness-sample.scss'], - templateUrl: './buttons-roundness-sample.html', - imports: [IgxButtonDirective, IgxRippleDirective, IgxIconComponent, IgxIconButtonDirective] -}) -export class ButtonsRoundnessComponent {} diff --git a/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.html b/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.html deleted file mode 100644 index 2a08fc960d..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
- -
-
- -
-
- -
-
diff --git a/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.scss b/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.scss deleted file mode 100644 index 9d1157d397..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.scss +++ /dev/null @@ -1,13 +0,0 @@ -.wrapper { - display: flex; - flex-flow: row wrap; -} - -.button-sample { - display: flex; - flex-flow: row wrap; - justify-content: center; - align-items: center; - flex: 1 0 30%; - margin: 16px 0; -} diff --git a/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.ts b/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.ts deleted file mode 100644 index 6e81376588..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-1/buttons-sample-1.component.ts +++ /dev/null @@ -1,11 +0,0 @@ - -import { Component, OnInit } from '@angular/core'; -import { IgxButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-sample-1', - styleUrls: ['./buttons-sample-1.component.scss'], - templateUrl: './buttons-sample-1.component.html', - imports: [IgxButtonDirective, IgxRippleDirective] -}) -export class ButtonsSample1Component { } diff --git a/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.html b/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.html deleted file mode 100644 index a0a5a22826..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.scss b/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.scss deleted file mode 100644 index 932b31c68c..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 8px; -} diff --git a/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.ts b/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.ts deleted file mode 100644 index 048e47f634..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-2/buttons-sample-2.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-sample-2', - styleUrls: ['./buttons-sample-2.component.scss'], - templateUrl: './buttons-sample-2.component.html', - imports: [IgxButtonDirective] -}) -export class ButtonsSample2Component { } diff --git a/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.html b/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.html deleted file mode 100644 index dbd51e8aa4..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.scss b/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.scss deleted file mode 100644 index 932b31c68c..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 8px; -} diff --git a/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.ts b/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.ts deleted file mode 100644 index 95c52d74d6..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-3/buttons-sample-3.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-sample-3', - styleUrls: ['./buttons-sample-3.component.scss'], - templateUrl: './buttons-sample-3.component.html', - imports: [IgxButtonDirective, IgxRippleDirective] -}) -export class ButtonsSample3Component { } diff --git a/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.html b/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.html deleted file mode 100644 index ea82ea38fe..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.html +++ /dev/null @@ -1 +0,0 @@ -Span diff --git a/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.scss b/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.scss deleted file mode 100644 index 932b31c68c..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 8px; -} diff --git a/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.ts b/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.ts deleted file mode 100644 index e0aa368980..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-4/buttons-sample-4.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-sample-4', - styleUrls: ['./buttons-sample-4.component.scss'], - templateUrl: './buttons-sample-4.component.html', - imports: [IgxButtonDirective, IgxRippleDirective] -}) -export class ButtonsSample4Component { } diff --git a/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.html b/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.html deleted file mode 100644 index a05ed23958..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.scss b/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.scss deleted file mode 100644 index 932b31c68c..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 8px; -} diff --git a/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.ts b/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.ts deleted file mode 100644 index ea471e6e36..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-5/buttons-sample-5.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-sample-5', - styleUrls: ['./buttons-sample-5.component.scss'], - templateUrl: './buttons-sample-5.component.html', - imports: [IgxButtonDirective] -}) -export class ButtonsSample5Component { } diff --git a/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.html b/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.html deleted file mode 100644 index 8c8f119053..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.scss b/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.scss deleted file mode 100644 index 03448c1a67..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-6/buttons-sample-6.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 1rem; -} diff --git a/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.html b/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.html deleted file mode 100644 index 39863f9e05..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.scss b/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.scss deleted file mode 100644 index 932b31c68c..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 8px; -} diff --git a/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.ts b/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.ts deleted file mode 100644 index 532edeff95..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-7/buttons-sample-7.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxIconButtonDirective } from 'igniteui-angular/directives'; -import { IgxIconComponent } from 'igniteui-angular/icon'; - -@Component({ - selector: 'app-buttons-sample-7', - styleUrls: ['./buttons-sample-7.component.scss'], - templateUrl: './buttons-sample-7.component.html', - imports: [IgxIconButtonDirective, IgxIconComponent] -}) -export class ButtonsSample7Component { } diff --git a/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.html b/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.html deleted file mode 100644 index ec9a161264..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.scss b/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.scss deleted file mode 100644 index 932b31c68c..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.btn { - margin: 8px; -} diff --git a/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.ts b/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.ts deleted file mode 100644 index 77b080c3a4..0000000000 --- a/src/app/data-entries/buttons/buttons-sample-8/buttons-sample-8.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-sample-8', - styleUrls: ['./buttons-sample-8.component.scss'], - templateUrl: './buttons-sample-8.component.html', - imports: [IgxButtonDirective] -}) -export class ButtonsSample8Component { } diff --git a/src/app/data-entries/buttons/buttons-style/buttons-style.component.html b/src/app/data-entries/buttons/buttons-style/buttons-style.component.html deleted file mode 100644 index 8eee79e1d3..0000000000 --- a/src/app/data-entries/buttons/buttons-style/buttons-style.component.html +++ /dev/null @@ -1,22 +0,0 @@ -@for (item of range; let i = $index; track i) { -
-
- -
-
- -
-
- -
-
- -
-
- -
- -
-} \ No newline at end of file diff --git a/src/app/data-entries/buttons/buttons-style/buttons-style.component.scss b/src/app/data-entries/buttons/buttons-style/buttons-style.component.scss deleted file mode 100644 index 67df53853d..0000000000 --- a/src/app/data-entries/buttons/buttons-style/buttons-style.component.scss +++ /dev/null @@ -1,241 +0,0 @@ -@use "layout.scss"; -@use "igniteui-angular/theming" as *; -@use "sass:map"; - -// CSS variables approach - -$list: ( - "sample-1": ( - "primary": #000, - "secondary": rgba(0, 0, 0, 0.75), - "active": rgba(0, 0, 0, 0.95), - "focus": #fff, - "hover": #4096ff, - "foreground": rgba(0, 0, 0, 0.88), - "border": #d9d9d9, - "active-foreground": #0958d9, - "flat-foreground": #69b1ff, - "flat-background": rgba(0, 0, 0, 0.04), - "flat-active": rgba(0, 0, 0, 0.15), - "flat-hover": rgba(0, 0, 0, 0.06), - ), - "sample-2": ( - "primary": #1677ff, - "secondary": #4096ff, - "active": #0958d9, - "focus": #fff, - "flat-background": #e6f4ff, - "flat-hover": #bae0ff, - "flat-active": #91caff, - ), - "sample-3": ( - "primary": #ff4d4f, - "secondary": #ff7875, - "active": #d9363e, - "focus": #fff, - "flat-background": #fff2f0, - "flat-hover": #ffdfdc, - "flat-active": #ffccc7, - ), - "sample-4": ( - "primary": #eb2f96, - "secondary": #f759ab, - "active": #c41d7f, - "focus": #fff, - "flat-background": #fff0f6, - "flat-hover": #ffd6e7, - "flat-active": #ffadd2, - ), - "sample-5": ( - "primary": #722ed1, - "secondary": #9254de, - "active": #531dab, - "focus": #fff, - "flat-background": #f9f0ff, - "flat-hover": #efdbff, - "flat-active": #d3adf7, - ), - "sample-6": ( - "primary": #13c2c2, - "secondary": #36cfc9, - "active": #08979c, - "focus": #fff, - "flat-background": #e6fffb, - "flat-hover": #b5f5ec, - "flat-active": #b5f5ec, - ), -); - -@each $variant, $style in $list { - .buttons-#{$variant} [igxbutton="contained"] { - --background: #{map-get($style, "primary")}; - --hover-background: #{map-get($style, "secondary")}; - --active-background: #{map-get($style, "active")}; - --focus-visible-background: #{map-get($style, "primary")}; - --focus-visible-foreground: #{map-get($style, "focus")}; - --focus-hover-background: #{map-get($style, "secondary")}; - --focus-hover-foreground: #{map-get($style, "focus")}; - --focus-background: #{map-get($style, "active")}; - } - - @if $variant == "sample-1" { - .buttons-#{$variant} [igxbutton="outlined"] { - --foreground: #{map-get($style, "foreground")}; - --border-color: #{map-get($style, "border")}; - --hover-foreground: #{map-get($style, "hover")}; - --hover-border-color: #{map-get($style, "hover")}; - --active-foreground: #{map-get($style, "active-foreground")}; - --active-border-color: #{map-get($style, "active-foreground")}; - --focus-hover-background: #{map-get($style, "focus")}; - --focus-hover-foreground: #{map-get($style, "hover")}; - --focus-background: #{map-get($style, "focus")}; - --focus-foreground: #{map-get($style, "active-foreground")}; - --focus-visible-border-color: #{map-get($style, "border")}; - } - - .buttons-#{$variant} [igxbutton="flat"] { - --foreground: #{map-get($style, "foreground")}; - --active-foreground: #{map-get($style, "foreground")}; - } - - .buttons-#{$variant} .filled [igxbutton="flat"] { - --background: #{map-get($style, "flat-background")}; - --hover-background: #{map-get($style, "flat-hover")}; - --focus-visible-background: #{map-get($style, "flat-background")}; - } - - .buttons-#{$variant} .filled [igxbutton="flat"], - .buttons-#{$variant} .text [igxbutton="flat"] { - --hover-foreground: #{map-get($style, "foreground")}; - --focus-hover-background: #{map-get($style, "flat-hover")}; - --focus-background: #{map-get($style, "flat-active")}; - --focus-foreground: #{map-get($style, "foreground")}; - --focus-hover-foreground: #{map-get($style, "foreground")}; - --active-background: #{map-get($style, "flat-active")}; - } - - .buttons-#{$variant} .text [igxbutton="flat"] { - --hover-background: #{map-get($style, "flat-background")}; - } - - .buttons-#{$variant} .link [igxbutton="flat"] { - --hover-foreground: #{map-get($style, "flat-foreground")}; - --active-foreground: #{map-get($style, "active-foreground")}; - } - } - - @else { - .buttons-#{$variant} [igxbutton="outlined"] { - --foreground: #{map-get($style, "primary")}; - --border-color: #{map-get($style, "primary")}; - --hover-foreground: #{map-get($style, "secondary")}; - --hover-border-color: #{map-get($style, "secondary")}; - --active-foreground: #{map-get($style, "active")}; - --active-border-color: #{map-get($style, "active")}; - --focus-hover-background: #{map-get($style, "focus")}; - --focus-hover-foreground: #{map-get($style, "secondary")}; - --focus-background: #{map-get($style, "focus")}; - --focus-foreground: #{map-get($style, "active")}; - --focus-visible-border-color: #{map-get($style, "primary")}; - } - - .buttons-#{$variant} .filled [igxbutton="flat"] { - --background: #{map-get($style, "flat-background")}; - --hover-background: #{map-get($style, "flat-hover")}; - --hover-foreground: #{map-get($style, "primary")}; - --active-foreground: #{map-get($style, "primary")}; - --focus-visible-background: #{map-get($style, "flat-background")}; - --focus-hover-foreground: #{map-get($style, "primary")}; - --focus-foreground: #{map-get($style, "primary")}; - } - - .buttons-#{$variant} .filled [igxbutton="flat"], - .buttons-#{$variant} .text [igxbutton="flat"] { - --active-background: #{map-get($style, "flat-active")}; - } - - .buttons-#{$variant} .text [igxbutton="flat"], - .buttons-#{$variant} .link [igxbutton="flat"] { - --hover-foreground: #{map-get($style, "secondary")}; - --active-foreground: #{map-get($style, "active")}; - --focus-hover-foreground: #{map-get($style, "secondary")}; - --focus-foreground: #{map-get($style, "active")}; - } - - .buttons-#{$variant} [igxbutton="flat"] { - --foreground: #{map-get($style, "primary")}; - --focus-hover-background: #{map-get($style, "flat-hover")}; - --focus-background: #{map-get($style, "flat-active")}; - } - - .buttons-#{$variant} .text [igxbutton="flat"] { - --hover-background: #{map-get($style, "flat-background")}; - } - } - - .buttons-#{$variant} [igxbutton="flat"], - .buttons-#{$variant} [igxbutton="outlined"] { - --focus-visible-foreground: #{map-get($style, "primary")}; - } - - .buttons-#{$variant} [igxbutton="outlined"], - .buttons-#{$variant} .text [igxbutton="flat"], - .buttons-#{$variant} .link [igxbutton="flat"] { - --focus-visible-background: transparent; - } -} - -.button-sample [igxbutton="contained"] { - --foreground: #fff; - --hover-foreground: #fff; - --active-foreground: #fff; -} - -.button-sample [igxbutton="outlined"] { - --background: transparent; - --hover-background: transparent; - --active-background: transparent; -} - -// Sass theme approach - -// $custom-contained-theme: contained-button-theme( -// $background: #f9f0ff, -// $foreground: #722ed1, -// $hover-background: #efdbff, -// $hover-foreground: #9254de, -// $active-foreground: #531dab, -// $active-background: #dfc2fa, -// $focus-visible-background: #d3adf7 -// ); - -// $custom-outlined-theme: outlined-button-theme( -// $background: #fff2f0, -// $foreground: #ff4d4f, -// $border-color: #ff4d4f, -// $hover-background: #ffdfdc, -// $hover-foreground: #ff7875, -// $hover-border-color: #ff7875, -// $focus-visible-background: #ffccc7, -// $focus-visible-foreground: #d9363e, -// $focus-border-color: #d9363e -// ); - -// $custom-flat-theme: flat-button-theme( -// $background: #e6fffb, -// $foreground: #13c2c2, -// $hover-background: #b5f5ec, -// $hover-foreground: #36cfc9, -// $active-foreground: #08979c, -// $focus-visible-background: #b5f5ec, -// $focus-visible-foreground: #08979c -// ); - -// .button-sample { -// @include tokens($custom-contained-theme); -// @include tokens($custom-outlined-theme); -// } - -// .button-sample.filled { -// @include tokens($custom-flat-theme); -// } diff --git a/src/app/data-entries/buttons/buttons-style/buttons-style.component.ts b/src/app/data-entries/buttons/buttons-style/buttons-style.component.ts deleted file mode 100644 index ce5d497395..0000000000 --- a/src/app/data-entries/buttons/buttons-style/buttons-style.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective } from 'igniteui-angular/directives'; -import { THEME_TOKEN, ThemeToken } from 'igniteui-angular/core'; - -@Component({ - selector: 'app-buttons-style', - styleUrls: ['./buttons-style.component.scss'], - templateUrl: './buttons-style.component.html', - imports: [IgxButtonDirective], - providers: [{provide: THEME_TOKEN, useFactory: () => new ThemeToken('bootstrap')}] -}) -export class ButtonsStyleComponent { - range = Array(6); -} diff --git a/src/app/data-entries/buttons/buttons-style/layout.scss b/src/app/data-entries/buttons/buttons-style/layout.scss deleted file mode 100644 index 43cf337fa2..0000000000 --- a/src/app/data-entries/buttons/buttons-style/layout.scss +++ /dev/null @@ -1,47 +0,0 @@ -@use "igniteui-angular/theming" as *; -@use "igniteui-angular/lib/core/styles/components/button/button-component" as button; -@use 'sass:map'; - -:host { - ::ng-deep { - @include button($flat: flat-button-theme($schema: $light-bootstrap-schema), - $contained: contained-button-theme($schema: $light-bootstrap-schema), - $outlined: outlined-button-theme($schema: $light-bootstrap-schema), - $fab: fab-button-theme($schema: $light-bootstrap-schema)); - @include button.component(); - } -} - -[class^=buttons-sample] { - display: flex; - margin: 1rem rem(8px) rem(8px) 1rem; -} - -.button-sample { - margin-right: 1rem; -} - -.dashed button{ - border-style: dashed; -} - -[class^="buttons-sample"]:hover .link button { - background: none; -} - -[igxbutton] { - --ig-button-font-weight: 400; - --ig-button-text-transform: capitalize; - min-height: rem(24px); - outline: rem(1px) solid #fff; -} - -.button-sample button { - --ig-size: var(--ig-size-medium); - padding: 0px rem(7px); - min-width: unset; -} - -.button-sample .igx-button { - --ig-font-family: 'alibaba-sans', sans-serif; -} \ No newline at end of file diff --git a/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.html b/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.html deleted file mode 100644 index 51cc42daa2..0000000000 --- a/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
- -
-
- -
-
- -
-
- -
-
diff --git a/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.scss b/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.scss deleted file mode 100644 index a60d456faa..0000000000 --- a/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.scss +++ /dev/null @@ -1 +0,0 @@ -@use "layout.scss"; diff --git a/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.ts b/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.ts deleted file mode 100644 index 2bbd669b48..0000000000 --- a/src/app/data-entries/buttons/buttons-tailwind-style/buttons-tailwind-style.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxButtonDirective } from 'igniteui-angular/directives'; - -@Component({ - selector: 'app-buttons-tailwind-style', - styleUrls: ['./buttons-tailwind-style.component.scss'], - templateUrl: './buttons-tailwind-style.component.html', - imports: [IgxButtonDirective] -}) -export class ButtonsTailwindStyleComponent {} diff --git a/src/app/data-entries/buttons/buttons-tailwind-style/layout.scss b/src/app/data-entries/buttons/buttons-tailwind-style/layout.scss deleted file mode 100644 index 36396d2d00..0000000000 --- a/src/app/data-entries/buttons/buttons-tailwind-style/layout.scss +++ /dev/null @@ -1,9 +0,0 @@ -.buttons-sample { - display: flex; - margin: 8px; -} - -.button-sample { - display: flex; - margin-right: 16px; -} \ No newline at end of file diff --git a/src/app/data-entries/data-entries-routes-data.ts b/src/app/data-entries/data-entries-routes-data.ts index 5e710a28e7..c12dffbf41 100644 --- a/src/app/data-entries/data-entries-routes-data.ts +++ b/src/app/data-entries/data-entries-routes-data.ts @@ -13,19 +13,17 @@ export const dataEntriesRoutesData = { "button-group-size": { displayName: "Button Group Size", parentName: "Button Group" }, "button-group-styling": { displayName: "Button Group Styling", parentName: "Button Group" }, "button-group-tailwind-styling": { displayName: "Button Group Tailwind Styling", parentName: "Button Group" }, - "buttons-sample-1": { displayName: "Overview", parentName: "Buttons" }, - "buttons-sample-2": { displayName: "Flat Button", parentName: "Buttons" }, - "buttons-sample-3": { displayName: "Button Ripple", parentName: "Buttons" }, - "buttons-sample-4": { displayName: "Span Button", parentName: "Buttons" }, - "buttons-sample-5": { displayName: "Contained Button", parentName: "Buttons" }, - "buttons-sample-6": { displayName: "Floating Action Button", parentName: "Buttons" }, - "buttons-sample-7": { displayName: "Icon Button", parentName: "Buttons" }, - "buttons-sample-8": { displayName: "Outlined Button", parentName: "Buttons" }, - "buttons-disabled-sample": { displayName: "Disabled Button", parentName: "Buttons" }, - "buttons-display-density": { displayName: "Display Density", parentName: "Buttons" }, - "buttons-roundness-sample": { displayName: "Components Roundness", parentName: "Buttons" }, - "buttons-style": { displayName: "Button Style", parentName: "Buttons" }, - "buttons-tailwind-style": { displayName: "Button Tailwind Style", parentName: "Buttons" }, + "button-overview": { displayName: "Overview", parentName: "Button" }, + "button-flat": { displayName: "Flat Button", parentName: "Button" }, + "button-interaction-states": { displayName: "Button Interaction States", parentName: "Button" }, + "button-layout": { displayName: "Button Layout", parentName: "Button" }, + "button-contained": { displayName: "Contained Button", parentName: "Button" }, + "button-fab": { displayName: "Floating Action Button", parentName: "Button" }, + "button-states": { displayName: "Button States", parentName: "Button" }, + "button-size": { displayName: "Button Size", parentName: "Button" }, + "button-download": { displayName: "Download Button", parentName: "Button" }, + "button-styling": { displayName: "Button Style", parentName: "Button" }, + "button-tailwind-styling": { displayName: "Button Tailwind Style", parentName: "Button" }, "checkbox-sample-1": { displayName: "Simple Checkbox", parentName: "Checkbox" }, "checkbox-sample-2": { displayName: "Multiple Checkboxes", parentName: "Checkbox" }, "checkbox-sample-3": { displayName: "Indeterminate Checkbox", parentName: "Checkbox" }, @@ -69,8 +67,11 @@ export const dataEntriesRoutesData = { "radio-styling-sample": { displayName: "Styling Radio Buttons", parentName: "Radio" }, "radio-tailwind-styling-sample": { displayName: "Tailwind Styling Radio Buttons", parentName: "Radio" }, "rating-form": { displayName: "Rating in Form", parentName: "Rating" }, - "switch-sample-1": { displayName: "Switch Overview", parentName: "Switch" }, - "switch-sample-2": { displayName: "Multiple Switches", parentName: "Switch" }, + "switch-overview": { displayName: "Switch Overview", parentName: "Switch" }, + "switch-enabled": { displayName: "Enabled Switches", parentName: "Switch" }, + "switch-disabled": { displayName: "Disabled Switches", parentName: "Switch" }, + "switch-selected": { displayName: "Selected Switches", parentName: "Switch" }, + "switch-layout": { displayName: "Switch Label Position", parentName: "Switch" }, "switch-styling": { displayName: "Styled Switches", parentName: "Switch" }, "switch-tailwind-styling": { displayName: "Tailwind Styled Switches", parentName: "Switch" }, "select-sample-1": { displayName: "Simple Select", parentName: "Select" }, diff --git a/src/app/data-entries/data-entries.routes.ts b/src/app/data-entries/data-entries.routes.ts index 8bc329cfcc..8132650c35 100644 --- a/src/app/data-entries/data-entries.routes.ts +++ b/src/app/data-entries/data-entries.routes.ts @@ -11,19 +11,18 @@ import { ButtonGroupSelectionComponent } from './buttonGroup/button-group-select import { ButtonGroupSizeComponent } from './buttonGroup/button-group-size/button-group-size.component'; import { ButtonGroupStylingComponent } from './buttonGroup/button-group-styling/button-group-styling.component'; import { ButtonGroupTailwindStylingComponent } from './buttonGroup/button-group-tailwind-styling/button-group-tailwind-styling.component'; -import { ButtonsDisabledComponent } from './buttons/buttons-disabled-sample/buttons-disabled-sample'; -import { ButtonsDisplayDensityComponent } from './buttons/buttons-display-density/buttons-display-density.component'; -import { ButtonsRoundnessComponent } from './buttons/buttons-roundness-sample/buttons-roundness-sample'; -import { ButtonsSample1Component } from './buttons/buttons-sample-1/buttons-sample-1.component'; -import { ButtonsSample2Component } from './buttons/buttons-sample-2/buttons-sample-2.component'; -import { ButtonsSample3Component } from './buttons/buttons-sample-3/buttons-sample-3.component'; -import { ButtonsSample4Component } from './buttons/buttons-sample-4/buttons-sample-4.component'; -import { ButtonsSample5Component } from './buttons/buttons-sample-5/buttons-sample-5.component'; -import { ButtonsSample6Component } from './buttons/buttons-sample-6/buttons-sample-6.component'; -import { ButtonsSample7Component } from './buttons/buttons-sample-7/buttons-sample-7.component'; -import { ButtonsSample8Component } from './buttons/buttons-sample-8/buttons-sample-8.component'; -import { ButtonsStyleComponent } from './buttons/buttons-style/buttons-style.component'; -import { ButtonsTailwindStyleComponent } from './buttons/buttons-tailwind-style/buttons-tailwind-style.component'; +import { ButtonStatesComponent } from './button/button-states/button-states.component'; +import { ButtonSizeComponent } from './button/button-size/button-size.component'; +import { ButtonDownloadComponent } from './button/button-download/button-download.component'; +import { ButtonOverviewComponent } from './button/button-overview/button-overview.component'; +import { ButtonFlatComponent } from './button/button-flat/button-flat.component'; +import { ButtonInteractionStatesComponent } from './button/button-interaction-states/button-interaction-states.component'; +import { ButtonLayoutComponent } from './button/button-layout/button-layout.component'; +import { ButtonContainedComponent } from './button/button-contained/button-contained.component'; +import { ButtonFabComponent } from './button/button-fab/button-fab.component'; +import { ButtonOutlinedComponent } from './button/button-outlined/button-outlined.component'; +import { ButtonStylingComponent } from './button/button-styling/button-styling.component'; +import { ButtonTailwindStylingComponent } from './button/button-tailwind-styling/button-tailwind-styling.component'; import { CheckboxSample1Component } from './checkbox/checkbox-sample-1/checkbox-sample-1.component'; import { CheckboxSample2Component } from './checkbox/checkbox-sample-2/checkbox-sample-2.component'; import { CheckboxSample3Component } from './checkbox/checkbox-sample-3/checkbox-sample-3.component'; @@ -67,8 +66,11 @@ import { SelectSample2Component } from './select/select-sample-2/select-sample-2 import { SelectSample4Component } from './select/select-sample-4/select-sample-4.component'; import { SelectStylingComponent } from './select/select-styling/select-styling.component'; import { SelectTailwindStylingComponent } from './select/select-tailwind-styling/select-tailwind-styling.component'; -import { SwitchSample1Component } from './switch/switch-sample-1/switch-sample-1.component'; -import { SwitchSample2Component } from './switch/switch-sample-2/switch-sample-2.component'; +import { SwitchOverviewComponent } from './switch/switch-overview/switch-overview.component'; +import { SwitchEnabledComponent } from './switch/switch-enabled/switch-enabled.component'; +import { SwitchDisabledComponent } from './switch/switch-disabled/switch-disabled.component'; +import { SwitchSelectedComponent } from './switch/switch-selected/switch-selected.component'; +import { SwitchLayoutComponent } from './switch/switch-layout/switch-layout.component'; import { SwitchStylingComponent } from './switch/switch-styling/switch-styling.component'; import { SwitchTailwindStylingComponent } from './switch/switch-tailwind-styling/switch-tailwind-styling.component'; import { RatingInFormComponent } from './rating/rating-form/rating-form.component'; @@ -97,9 +99,9 @@ export const DataEntriesRoutes: Routes = [ path: 'movie' }, { - component: ButtonsDisplayDensityComponent, - data: dataEntriesRoutesData['buttons-display-density'], - path: 'buttons-display-density' + component: ButtonSizeComponent, + data: dataEntriesRoutesData['button-size'], + path: 'button-size' }, { component: ButtonGroupOverviewComponent, @@ -152,64 +154,59 @@ export const DataEntriesRoutes: Routes = [ path: 'button-group-tailwind-styling' }, { - component: ButtonsRoundnessComponent, - data: dataEntriesRoutesData['buttons-roundness-sample'], - path: 'buttons-roundness-sample' + component: ButtonOverviewComponent, + data: dataEntriesRoutesData['button-overview'], + path: 'button-overview' }, { - component: ButtonsSample1Component, - data: dataEntriesRoutesData['buttons-sample-1'], - path: 'buttons-sample-1' + component: ButtonFlatComponent, + data: dataEntriesRoutesData['button-flat'], + path: 'button-flat' }, { - component: ButtonsSample2Component, - data: dataEntriesRoutesData['buttons-sample-2'], - path: 'buttons-sample-2' + component: ButtonInteractionStatesComponent, + data: dataEntriesRoutesData['button-interaction-states'], + path: 'button-interaction-states' }, { - component: ButtonsSample3Component, - data: dataEntriesRoutesData['buttons-sample-3'], - path: 'buttons-sample-3' + component: ButtonLayoutComponent, + data: dataEntriesRoutesData['button-layout'], + path: 'button-layout' }, { - component: ButtonsSample4Component, - data: dataEntriesRoutesData['buttons-sample-4'], - path: 'buttons-sample-4' + component: ButtonContainedComponent, + data: dataEntriesRoutesData['button-contained'], + path: 'button-contained' }, { - component: ButtonsSample5Component, - data: dataEntriesRoutesData['buttons-sample-5'], - path: 'buttons-sample-5' + component: ButtonFabComponent, + data: dataEntriesRoutesData['button-fab'], + path: 'button-fab' }, { - component: ButtonsSample6Component, - data: dataEntriesRoutesData['buttons-sample-6'], - path: 'buttons-sample-6' + component: ButtonOutlinedComponent, + data: dataEntriesRoutesData['button-outlined'], + path: 'button-outlined' }, { - component: ButtonsSample7Component, - data: dataEntriesRoutesData['buttons-sample-7'], - path: 'buttons-sample-7' + component: ButtonStatesComponent, + data: dataEntriesRoutesData['button-states'], + path: 'button-states' }, { - component: ButtonsSample8Component, - data: dataEntriesRoutesData['buttons-sample-8'], - path: 'buttons-sample-8' + component: ButtonDownloadComponent, + data: dataEntriesRoutesData['button-download'], + path: 'button-download' }, { - component: ButtonsDisabledComponent, - data: dataEntriesRoutesData['buttons-disabled-sample'], - path: 'buttons-disabled-sample' + component: ButtonStylingComponent, + data: dataEntriesRoutesData['button-styling'], + path: 'button-styling' }, { - component: ButtonsStyleComponent, - data: dataEntriesRoutesData['buttons-style'], - path: 'buttons-style' - }, - { - component: ButtonsTailwindStyleComponent, - data: dataEntriesRoutesData['buttons-tailwind-style'], - path: 'buttons-tailwind-style' + component: ButtonTailwindStylingComponent, + data: dataEntriesRoutesData['button-tailwind-styling'], + path: 'button-tailwind-styling' }, { component: CheckboxSample1Component, @@ -427,14 +424,29 @@ export const DataEntriesRoutes: Routes = [ path: 'rating-form' }, { - component: SwitchSample1Component, - data: dataEntriesRoutesData['switch-sample-1'], - path: 'switch-sample-1' + component: SwitchOverviewComponent, + data: dataEntriesRoutesData['switch-overview'], + path: 'switch-overview' + }, + { + component: SwitchEnabledComponent, + data: dataEntriesRoutesData['switch-enabled'], + path: 'switch-enabled' + }, + { + component: SwitchDisabledComponent, + data: dataEntriesRoutesData['switch-disabled'], + path: 'switch-disabled' + }, + { + component: SwitchSelectedComponent, + data: dataEntriesRoutesData['switch-selected'], + path: 'switch-selected' }, { - component: SwitchSample2Component, - data: dataEntriesRoutesData['switch-sample-2'], - path: 'switch-sample-2' + component: SwitchLayoutComponent, + data: dataEntriesRoutesData['switch-layout'], + path: 'switch-layout' }, { component: SwitchStylingComponent, diff --git a/src/app/data-entries/switch/switch-bootstrap.scss b/src/app/data-entries/switch/switch-bootstrap.scss new file mode 100644 index 0000000000..3212de8336 --- /dev/null +++ b/src/app/data-entries/switch/switch-bootstrap.scss @@ -0,0 +1,65 @@ +@use "igniteui-angular/theming" as *; + +// Bootstrap switch geometry, aligned with the Bootstrap form-switch proportions. +@mixin bootstrap-switch { + :host ::ng-deep igx-switch { + --switch-width: #{rem(32px)}; + --switch-height: #{rem(16px)}; + --switch-thumb-size: #{rem(9px)}; + --switch-on-offset: #{rem(3px)}; + --switch-off-offset: #{rem(3px)}; + + ::ng-deep { + .igx-switch__composite { + box-sizing: border-box; + } + + .igx-switch__composite-thumb { + width: #{rem(9px)}; + height: #{rem(9px)}; + min-width: #{rem(9px)}; + box-shadow: none; + } + + .igx-switch__thumb { + width: #{rem(9px)}; + height: #{rem(9px)}; + min-width: #{rem(9px)}; + } + + .igx-switch__composite-thumb, + .igx-switch__thumb { + inline-size: #{rem(9px)}; + block-size: #{rem(9px)}; + min-inline-size: #{rem(9px)}; + max-inline-size: #{rem(9px)}; + min-block-size: #{rem(9px)}; + max-block-size: #{rem(9px)}; + } + } + + &.igx-switch--checked:not(.igx-switch--disabled) ::ng-deep .igx-switch__composite-thumb { + transform: translateX(#{rem(18px)}); + } + + &.igx-switch--checked:not(.igx-switch--disabled) ::ng-deep .igx-switch__composite { + background: var(--ig-primary-500); + } + + &.igx-switch--disabled ::ng-deep .igx-switch__composite-thumb { + transform: translateX(#{rem(3px)}) translateY(-1px); + } + + &.igx-switch--disabled.igx-switch--checked ::ng-deep .igx-switch__composite-thumb { + transform: translateX(#{rem(18px)}) translateY(0); + } + } + + :host ::ng-deep igx-switch.igx-switch--disabled.igx-switch--checked .igx-switch__composite-thumb { + transform: translateX(#{rem(18px)}) translateY(0); + } + + :host ::ng-deep igx-switch:not(.igx-switch--disabled) { + --track-on-color: var(--ig-primary-500); + } +} diff --git a/src/app/data-entries/switch/switch-disabled/switch-disabled.component.html b/src/app/data-entries/switch/switch-disabled/switch-disabled.component.html new file mode 100644 index 0000000000..280874ac2c --- /dev/null +++ b/src/app/data-entries/switch/switch-disabled/switch-disabled.component.html @@ -0,0 +1,14 @@ +
+
+ Disabled Checked + + Power + +
+
+ Disabled Unchecked + + Power + +
+
diff --git a/src/app/data-entries/switch/switch-disabled/switch-disabled.component.scss b/src/app/data-entries/switch/switch-disabled/switch-disabled.component.scss new file mode 100644 index 0000000000..7adeb2efb1 --- /dev/null +++ b/src/app/data-entries/switch/switch-disabled/switch-disabled.component.scss @@ -0,0 +1,38 @@ +@use "igniteui-angular/theming" as *; +@use "sass:map"; +@use "../switch-bootstrap" as switch-bootstrap; + +@include switch-bootstrap.bootstrap-switch; + +:host { + display: flex; + min-block-size: 100%; + box-sizing: border-box; + place-content: center; + place-items: center; + padding: 16px; + + @include tokens(switch-theme($schema: map.get($light-bootstrap-schema, switch))); +} + +.states { + --variant-gap: 60px; + --label-gap: 30px; + + display: flex; + align-items: center; + justify-content: center; + gap: var(--variant-gap); + + .states__variant { + display: flex; + align-items: center; + gap: var(--label-gap); + } + + .states__label { + font: 500 14px / 24px "Aktiv Grotesk", sans-serif; + letter-spacing: 0.1px; + color: var(--ig-gray-600); + } +} diff --git a/src/app/data-entries/switch/switch-disabled/switch-disabled.component.ts b/src/app/data-entries/switch/switch-disabled/switch-disabled.component.ts new file mode 100644 index 0000000000..0dba8b971d --- /dev/null +++ b/src/app/data-entries/switch/switch-disabled/switch-disabled.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { IgxSwitchComponent } from 'igniteui-angular/switch'; + +@Component({ + selector: 'app-switch-disabled', + styleUrls: ['./switch-disabled.component.scss'], + templateUrl: './switch-disabled.component.html', + imports: [IgxSwitchComponent] +}) +export class SwitchDisabledComponent { } diff --git a/src/app/data-entries/switch/switch-enabled/switch-enabled.component.html b/src/app/data-entries/switch/switch-enabled/switch-enabled.component.html new file mode 100644 index 0000000000..4ca5c510c4 --- /dev/null +++ b/src/app/data-entries/switch/switch-enabled/switch-enabled.component.html @@ -0,0 +1,28 @@ +
+ + Hover + Focused + Focused & Hover + + Enabled / On + + Power + + + Power + + + Power + + + Enabled / Off + + Power + + + Power + + + Power + +
diff --git a/src/app/data-entries/switch/switch-enabled/switch-enabled.component.scss b/src/app/data-entries/switch/switch-enabled/switch-enabled.component.scss new file mode 100644 index 0000000000..331ca49c32 --- /dev/null +++ b/src/app/data-entries/switch/switch-enabled/switch-enabled.component.scss @@ -0,0 +1,40 @@ +@use "igniteui-angular/theming" as *; +@use "sass:map"; +@use "../switch-bootstrap" as switch-bootstrap; + +@include switch-bootstrap.bootstrap-switch; + +:host { + display: flex; + place-content: center; + place-items: center; + padding: 16px; + + @include tokens(switch-theme($schema: map.get($light-bootstrap-schema, switch))); +} + +.states { + display: grid; + grid-template-columns: repeat(4, auto); + align-items: center; + gap: 32px 24px; + + .states__column, + .states__row { + font: 500 14px / 24px "Aktiv Grotesk", sans-serif; + letter-spacing: 0.1px; + color: var(--ig-gray-600); + } + + .states__column { + text-align: center; + } + + .states__row { + text-align: end; + } + + igx-switch { + justify-self: center; + } +} diff --git a/src/app/data-entries/switch/switch-enabled/switch-enabled.component.ts b/src/app/data-entries/switch/switch-enabled/switch-enabled.component.ts new file mode 100644 index 0000000000..8eaf65933b --- /dev/null +++ b/src/app/data-entries/switch/switch-enabled/switch-enabled.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { IgxSwitchComponent } from 'igniteui-angular/switch'; + +@Component({ + selector: 'app-switch-enabled', + styleUrls: ['./switch-enabled.component.scss'], + templateUrl: './switch-enabled.component.html', + imports: [IgxSwitchComponent] +}) +export class SwitchEnabledComponent { } diff --git a/src/app/data-entries/switch/switch-layout/switch-layout.component.html b/src/app/data-entries/switch/switch-layout/switch-layout.component.html new file mode 100644 index 0000000000..0458faa19e --- /dev/null +++ b/src/app/data-entries/switch/switch-layout/switch-layout.component.html @@ -0,0 +1,14 @@ +
+
+ Label Before + + Power + +
+
+ Label After + + Power + +
+
diff --git a/src/app/data-entries/switch/switch-layout/switch-layout.component.scss b/src/app/data-entries/switch/switch-layout/switch-layout.component.scss new file mode 100644 index 0000000000..c281c73024 --- /dev/null +++ b/src/app/data-entries/switch/switch-layout/switch-layout.component.scss @@ -0,0 +1,39 @@ +@use "igniteui-angular/theming" as *; +@use "sass:map"; +@use "../switch-bootstrap" as switch-bootstrap; + +@include switch-bootstrap.bootstrap-switch; + +:host { + display: flex; + min-block-size: 100%; + box-sizing: border-box; + place-content: center; + place-items: center; + padding: 16px; + + @include tokens(switch-theme($schema: map.get($light-bootstrap-schema, switch))); +} + +.variants { + --variant-gap: 60px; + --label-gap: 30px; + + display: flex; + inline-size: 100%; + align-items: center; + justify-content: center; + gap: var(--variant-gap); + + .variants__item { + display: flex; + align-items: center; + gap: var(--label-gap); + } + + .variants__label { + font: 500 14px / 24px "Aktiv Grotesk", sans-serif; + letter-spacing: 0.1px; + color: var(--ig-gray-600); + } +} diff --git a/src/app/data-entries/switch/switch-layout/switch-layout.component.ts b/src/app/data-entries/switch/switch-layout/switch-layout.component.ts new file mode 100644 index 0000000000..d9bef05a86 --- /dev/null +++ b/src/app/data-entries/switch/switch-layout/switch-layout.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { IgxSwitchComponent } from 'igniteui-angular/switch'; + +@Component({ + selector: 'app-switch-layout', + styleUrls: ['./switch-layout.component.scss'], + templateUrl: './switch-layout.component.html', + imports: [IgxSwitchComponent] +}) +export class SwitchLayoutComponent { } diff --git a/src/app/data-entries/switch/switch-overview/switch-overview.component.html b/src/app/data-entries/switch/switch-overview/switch-overview.component.html new file mode 100644 index 0000000000..2d0fe64c1b --- /dev/null +++ b/src/app/data-entries/switch/switch-overview/switch-overview.component.html @@ -0,0 +1,27 @@ +
+
Notifications
+
+ + + Push notifications + Deliver alerts to this device + + +
+
+ + + Weekly digest + Summary email every Monday + + +
+
+ + + SMS alerts + Unavailable on your plan + + +
+
diff --git a/src/app/data-entries/switch/switch-overview/switch-overview.component.scss b/src/app/data-entries/switch/switch-overview/switch-overview.component.scss new file mode 100644 index 0000000000..289bdc2420 --- /dev/null +++ b/src/app/data-entries/switch/switch-overview/switch-overview.component.scss @@ -0,0 +1,65 @@ +@use "igniteui-angular/theming" as *; +@use "sass:map"; +@use "../switch-bootstrap" as switch-bootstrap; + +@include switch-bootstrap.bootstrap-switch; + +:host { + display: flex; + place-content: center; + place-items: center; + padding: 16px; + + @include tokens(switch-theme($schema: map.get($light-bootstrap-schema, switch))); +} + +.notifications { + inline-size: 100%; + max-inline-size: 384px; + background: var(--ig-surface-500); + border-radius: 4px; + overflow: hidden; + + .notifications__title { + margin: 0; + padding: 16px; + font: 400 10px / 16px "Titillium Web", sans-serif; + letter-spacing: 1.5px; + text-transform: uppercase; + color: var(--ig-primary-500); + } + + .notifications__row { + padding-block: 12px; + padding-inline: 16px; + + igx-switch { + inline-size: 100%; + justify-content: space-between; + gap: 16px; + transform: translateX(-10px); + + ::ng-deep .igx-switch__composite { + transform: translateX(8px); + } + } + } +} + +.option { + display: flex; + flex-direction: column; + gap: 2px; + text-align: start; + white-space: normal; + + .option__label { + font-size: 16px; + color: var(--ig-gray-900); + } + + .option__hint { + font-size: 13px; + color: var(--ig-gray-700); + } +} diff --git a/src/app/data-entries/switch/switch-overview/switch-overview.component.ts b/src/app/data-entries/switch/switch-overview/switch-overview.component.ts new file mode 100644 index 0000000000..88946f53fe --- /dev/null +++ b/src/app/data-entries/switch/switch-overview/switch-overview.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { IgxSwitchComponent } from 'igniteui-angular/switch'; + +@Component({ + selector: 'app-switch-overview', + styleUrls: ['./switch-overview.component.scss'], + templateUrl: './switch-overview.component.html', + imports: [IgxSwitchComponent] +}) +export class SwitchOverviewComponent { } diff --git a/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.html b/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.html deleted file mode 100644 index f6c2ce336f..0000000000 --- a/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.html +++ /dev/null @@ -1,3 +0,0 @@ - - Simple switch - diff --git a/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.scss b/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.scss deleted file mode 100644 index 5bc4862429..0000000000 --- a/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -:host { - display: block; - padding: 16px; -} diff --git a/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.ts b/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.ts deleted file mode 100644 index 906229df20..0000000000 --- a/src/app/data-entries/switch/switch-sample-1/switch-sample-1.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { IgxSwitchComponent } from 'igniteui-angular/switch'; - -@Component({ - selector: 'app-switch-sample-1', - styleUrls: ['./switch-sample-1.component.scss'], - templateUrl: './switch-sample-1.component.html', - imports: [IgxSwitchComponent] -}) -export class SwitchSample1Component { } diff --git a/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.html b/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.html deleted file mode 100644 index 82bb5ae9f7..0000000000 --- a/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.html +++ /dev/null @@ -1,6 +0,0 @@ -@for (setting of settings; track setting) { - - {{ setting.name }} - -} - diff --git a/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.scss b/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.scss deleted file mode 100644 index 7ccd0c810c..0000000000 --- a/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.scss +++ /dev/null @@ -1,9 +0,0 @@ -:host { - display: flex; - flex-flow: column nowrap; - padding: 16px; -} - -igx-switch { - margin-top: 24px; -} diff --git a/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.ts b/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.ts deleted file mode 100644 index 54c4e0d49a..0000000000 --- a/src/app/data-entries/switch/switch-sample-2/switch-sample-2.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component } from '@angular/core'; - -import { IgxSwitchComponent } from 'igniteui-angular/switch'; - -@Component({ - selector: 'app-switch-sample-2', - styleUrls: ['./switch-sample-2.component.scss'], - templateUrl: './switch-sample-2.component.html', - imports: [IgxSwitchComponent] -}) -export class SwitchSample2Component { - public settings = [ - { name: 'WiFi', state: false}, - { name: 'Bluetooth', state: true}, - { name: 'Device visibility', state: false} - ]; -} diff --git a/src/app/data-entries/switch/switch-selected/switch-selected.component.html b/src/app/data-entries/switch/switch-selected/switch-selected.component.html new file mode 100644 index 0000000000..223f269045 --- /dev/null +++ b/src/app/data-entries/switch/switch-selected/switch-selected.component.html @@ -0,0 +1,17 @@ +
+ On + + Power + + + Power + + + Off + + Power + + + Power + +
diff --git a/src/app/data-entries/switch/switch-selected/switch-selected.component.scss b/src/app/data-entries/switch/switch-selected/switch-selected.component.scss new file mode 100644 index 0000000000..58683f9b6e --- /dev/null +++ b/src/app/data-entries/switch/switch-selected/switch-selected.component.scss @@ -0,0 +1,33 @@ +@use "igniteui-angular/theming" as *; +@use "sass:map"; +@use "../switch-bootstrap" as switch-bootstrap; + +@include switch-bootstrap.bootstrap-switch; + +:host { + display: flex; + place-content: center; + place-items: center; + padding: 16px; + + @include tokens(switch-theme($schema: map.get($light-bootstrap-schema, switch))); +} + +.states { + display: grid; + grid-template-columns: repeat(3, auto); + align-items: center; + gap: 32px; + transform: translateY(16px); + + .states__row { + text-align: end; + font: 500 14px / 24px "Aktiv Grotesk", sans-serif; + letter-spacing: 0.1px; + color: var(--ig-gray-600); + } + + .states__disabled { + margin-inline-start: 16px; + } +} diff --git a/src/app/data-entries/switch/switch-selected/switch-selected.component.ts b/src/app/data-entries/switch/switch-selected/switch-selected.component.ts new file mode 100644 index 0000000000..706b5c9295 --- /dev/null +++ b/src/app/data-entries/switch/switch-selected/switch-selected.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { IgxSwitchComponent } from 'igniteui-angular/switch'; + +@Component({ + selector: 'app-switch-selected', + styleUrls: ['./switch-selected.component.scss'], + templateUrl: './switch-selected.component.html', + imports: [IgxSwitchComponent] +}) +export class SwitchSelectedComponent { } diff --git a/src/app/data-entries/switch/switch-styling/layout.scss b/src/app/data-entries/switch/switch-styling/layout.scss deleted file mode 100644 index 6e92f5d995..0000000000 --- a/src/app/data-entries/switch/switch-styling/layout.scss +++ /dev/null @@ -1,59 +0,0 @@ -@use "igniteui-angular/theming" as *; -@use 'sass:map'; - -:host { - ::ng-deep { - $_switch-schema: map.get($light-fluent-schema, switch); - @include tokens(switch-theme($schema: $_switch-schema)); - - // Note: This is not the standard approach for styling the component. - // We're using it here solely to mirror the UI5 sample. - - igx-switch:hover .igx-switch__thumb { - --border-hover-color: #fff; - } - - .igx-switch__composite { - width: rem(44px); - height: rem(20px); - padding-left: rem(2px); - } - - .igx-switch__composite-thumb { - width: rem(25px); - height: 1rem; - min-width: rem(25px); - transform: translateX(-0.5px); - } - - .igx-switch__thumb { - width: rem(25px); - height: 1rem; - min-width: rem(25px); - } - - .igx-switch--checked .igx-switch__composite .igx-switch__composite-thumb { - transform: translateX(0.85rem); - } - - .igx-switch--focused .igx-switch__composite::after { - border-radius: 1rem; - box-shadow: 0 0 0 rem(2px) var(--focus-outline-color); - } - } -} - -igx-switch { - margin-top: rem(24px); - width: max-content; -} - -igx-switch:hover { - --track-off-color: #637d97; -} - -.switch-wrapper { - display: flex; - flex-flow: column nowrap; - padding: 2rem; -} \ No newline at end of file diff --git a/src/app/data-entries/switch/switch-styling/switch-styling.component.html b/src/app/data-entries/switch/switch-styling/switch-styling.component.html index db4efd584c..9904fecca5 100644 --- a/src/app/data-entries/switch/switch-styling/switch-styling.component.html +++ b/src/app/data-entries/switch/switch-styling/switch-styling.component.html @@ -1,8 +1,22 @@ -
- @for (setting of settings; track setting) { - - {{ setting.name }} - - } -
+ + + + + Two-factor authentication + Extra sign-in verification + + + + + + + + + + Authenticator app + Security key + Backup codes + + + diff --git a/src/app/data-entries/switch/switch-styling/switch-styling.component.scss b/src/app/data-entries/switch/switch-styling/switch-styling.component.scss index 656327aab1..49bbd9abd2 100644 --- a/src/app/data-entries/switch/switch-styling/switch-styling.component.scss +++ b/src/app/data-entries/switch/switch-styling/switch-styling.component.scss @@ -1,40 +1,137 @@ -@use "layout.scss"; @use "igniteui-angular/theming" as *; +@use "sass:map"; +@use "../switch-bootstrap" as switch-bootstrap; -// CSS variables approach - -igx-switch { - --thumb-on-color: #e3f0ff; - --thumb-off-color: #fff; - --thumb-off-hover-color: #ededed; - --track-on-color: #0064d9; - --track-off-color: #788fa6; - --track-on-hover-color: #0058bf; - --border-radius-track: 1rem; - --focus-outline-color: #0032a5; - --border-on-color: transparent; - --border-color: transparent; - --border-on-hover-color: transparent; - --border-hover-color: transparent; -} - -// Sass theme approach - -// $custom-switch-theme: switch-theme( -// $thumb-on-color: #e3f0ff, -// $track-on-color: #0064d9, -// $track-on-hover-color: #0058bf, -// $thumb-off-color: #fff, -// $thumb-off-hover-color: #ededed, -// $track-off-color: #788fa6, -// $border-radius-track: 1rem, -// $focus-outline-color: #0032a5, -// $border-on-color: transparent, -// $border-on-hover-color: transparent, -// $border-color: transparent, -// $border-hover-color: transparent, -// ); - -// :host { -// @include tokens($custom-switch-theme); -// } +@include switch-bootstrap.bootstrap-switch; + +:host ::ng-deep igx-switch .igx-switch__thumb { + min-width: 10px; + transform: translateY(-1px); +} + +:host ::ng-deep igx-switch .igx-switch__ripple { + display: none; +} + +:host { + display: flex; + place-content: center; + place-items: center; + min-block-size: 100%; + padding: 1rem; + + @include tokens(switch-theme($schema: map.get($light-bootstrap-schema, switch))); + @include tokens(radio-theme($schema: map.get($light-bootstrap-schema, radio))); +} + +.security { + display: block; + inline-size: 100%; + max-inline-size: 348px; + background: var(--ig-surface-500); + border: rem(1px) solid var(--ig-gray-300); + border-radius: rem(16px); + box-shadow: 0 rem(1px) rem(3px) rgb(0 0 0 / 12%); + overflow: hidden; + + igx-expansion-panel-header { + display: block !important; + } + + ::ng-deep igx-expansion-panel-header > div { + padding: rem(12px) rem(16px) !important; + gap: rem(16px) !important; + } + + igx-expansion-panel-title { + flex: 1 1 auto; + min-inline-size: 0; + } + + igx-expansion-panel-icon { + flex: 0 0 auto; + transform: none; + margin-inline-start: 0; + } + + igx-expansion-panel-body { + display: block; + padding-inline-start: rem(5px); + border-block-start: rem(1px) solid var(--ig-gray-300); + } + + igx-switch { + inline-size: rem(43px); + block-size: rem(24px); + transform: translateX(rem(2px)); + } + + igx-radio-group { + display: flex; + flex-direction: column; + gap: rem(8px); + margin-inline-start: rem(10px); + } +} + +.option { + display: flex; + flex-direction: column; + gap: rem(2px); + text-align: start; + white-space: normal; + min-inline-size: 0; + + .option__label { + font: 600 #{rem(16px)} / #{rem(24px)} "Aktiv Grotesk", sans-serif; + letter-spacing: #{rem(0.15px)}; + color: var(--ig-gray-700); + } + + .option__hint { + font: 500 #{rem(14px)} / #{rem(24px)} "Aktiv Grotesk", sans-serif; + letter-spacing: #{rem(0.1px)}; + color: var(--ig-gray-600); + } +} + +igx-radio { + font: 600 #{rem(12px)} / #{rem(16px)} "Aktiv Grotesk", sans-serif; + letter-spacing: #{rem(0.15px)}; + color: var(--ig-primary-900); + + --fill-color: var(--ig-primary-500); + --fill-color-hover: var(--ig-primary-500); + --fill-hover-border-color: var(--ig-primary-500); +} + +:host ::ng-deep igx-radio.igx-radio--checked .igx-radio__composite::after { + background: transparent; + border-color: transparent; +} + +:host ::ng-deep igx-radio.igx-radio--checked .igx-radio__composite::before { + transform: none !important; +} + +:host ::ng-deep igx-radio .igx-radio__composite::before, +:host ::ng-deep igx-radio .igx-radio__composite::after { + width: 16px; + height: 16px; +} + +:host ::ng-deep igx-radio .igx-radio__label { + transform: translateY(-2px); +} + +:host ::ng-deep igx-radio .igx-radio__composite, +:host ::ng-deep igx-radio .igx-radio__composite::before, +:host ::ng-deep igx-radio .igx-radio__composite::after { + animation: none !important; + transition: none !important; +} + +:host ::ng-deep igx-radio .igx-radio__ripple { + opacity: 0; + pointer-events: none; +} diff --git a/src/app/data-entries/switch/switch-styling/switch-styling.component.ts b/src/app/data-entries/switch/switch-styling/switch-styling.component.ts index 31793317e2..a2ddb55ffb 100644 --- a/src/app/data-entries/switch/switch-styling/switch-styling.component.ts +++ b/src/app/data-entries/switch/switch-styling/switch-styling.component.ts @@ -1,16 +1,32 @@ import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { IgxSwitchComponent } from 'igniteui-angular/switch'; +import { IgxRadioComponent, IgxRadioGroupDirective, RadioGroupAlignment } from 'igniteui-angular/radio'; +import { + IgxExpansionPanelBodyComponent, + IgxExpansionPanelComponent, + IgxExpansionPanelHeaderComponent, + IgxExpansionPanelIconDirective, + IgxExpansionPanelTitleDirective +} from 'igniteui-angular/expansion-panel'; @Component({ selector: 'app-switch-styling', styleUrls: ['./switch-styling.component.scss'], templateUrl: './switch-styling.component.html', - imports: [IgxSwitchComponent] + imports: [ + IgxSwitchComponent, + IgxRadioComponent, + IgxRadioGroupDirective, + IgxExpansionPanelComponent, + IgxExpansionPanelHeaderComponent, + IgxExpansionPanelTitleDirective, + IgxExpansionPanelIconDirective, + IgxExpansionPanelBodyComponent, + FormsModule + ] }) export class SwitchStylingComponent { - public settings = [ - { name: 'WiFi', state: false }, - { name: 'Bluetooth', state: true }, - { name: 'Device visibility', state: false } - ]; + public alignment = RadioGroupAlignment.vertical; + public method = 'app'; } diff --git a/src/app/data-entries/switch/switch-tailwind-styling/layout.scss b/src/app/data-entries/switch/switch-tailwind-styling/layout.scss deleted file mode 100644 index 0988ab89bd..0000000000 --- a/src/app/data-entries/switch/switch-tailwind-styling/layout.scss +++ /dev/null @@ -1,9 +0,0 @@ -igx-switch { - margin-bottom: 24px; -} - -.switch-wrapper { - display: flex; - flex-flow: column nowrap; - padding: 16px; -} diff --git a/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.html b/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.html index 1a54d792c9..955b3e531b 100644 --- a/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.html +++ b/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.html @@ -1,7 +1,19 @@ -
- @for (setting of settings; track setting) { - - {{ setting.name }} - - } +
+
+ Dashboard + + + + Dark mode + + +
+
+
Revenue overview
+

+ $84,290 this month, up 12% from July.
+ Your top-performing channel is Direct, driving 41% of total revenue. +

+
diff --git a/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.scss b/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.scss index a60d456faa..e5b4f5cd37 100644 --- a/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.scss +++ b/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.scss @@ -1 +1,18 @@ -@use "layout.scss"; +@use "../switch-bootstrap" as switch-bootstrap; + +@include switch-bootstrap.bootstrap-switch; + +:host ::ng-deep igx-switch .igx-switch__thumb { + min-width: 10px; +} + +:host ::ng-deep igx-switch .igx-switch__ripple { + display: none; +} + +:host { + display: flex; + place-content: center; + place-items: center; + padding: 40px; +} diff --git a/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.ts b/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.ts index e49904ee31..f758af0066 100644 --- a/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.ts +++ b/src/app/data-entries/switch/switch-tailwind-styling/switch-tailwind-styling.component.ts @@ -1,17 +1,20 @@ -import { Component } from '@angular/core'; - +import { Component, inject } from '@angular/core'; import { IgxSwitchComponent } from 'igniteui-angular/switch'; +import { IgxIconComponent, IgxIconService } from 'igniteui-angular/icon'; + +const darkModeIcon = + ''; @Component({ selector: 'app-switch-tailwind-styling', styleUrls: ['./switch-tailwind-styling.component.scss'], templateUrl: './switch-tailwind-styling.component.html', - imports: [IgxSwitchComponent] + imports: [IgxSwitchComponent, IgxIconComponent] }) export class SwitchTailwindStylingComponent { - public settings = [ - { name: 'WiFi', state: false}, - { name: 'Bluetooth', state: true}, - { name: 'Device visibility', state: false} - ]; + public isDarkMode = true; + + constructor() { + inject(IgxIconService).addSvgIconFromText('dark_mode', darkModeIcon, 'material'); + } } diff --git a/src/app/grid/grid-routes-data.ts b/src/app/grid/grid-routes-data.ts index 57923487fe..10860e02df 100644 --- a/src/app/grid/grid-routes-data.ts +++ b/src/app/grid/grid-routes-data.ts @@ -4,6 +4,7 @@ export const gridsRoutesData = { 'grid-groupby': { displayName: 'Grid GroupBy', parentName: 'Grid' }, 'grid-cellMerge': { displayName: 'Grid Cell Merge', parentName: 'Grid' }, 'grid-cellMerge-custom': { displayName: 'Grid Cell Merge Custom', parentName: 'Grid' }, + 'grid-theming': { displayName: 'Grid Theming', parentName: 'Grid' }, 'grid-groupby-custom': {displayName: 'Grid GroupBy Custom', parentName: 'Grid'}, 'grid-groupby-paging': { displayName: 'Grid GroupBy Paging', parentName: 'Grid' }, 'grid-groupby-styling': { displayName: 'Grid GroupBy Styling', parentName: 'Grid' }, diff --git a/src/app/grid/grid-theming/grid-theming.component.html b/src/app/grid/grid-theming/grid-theming.component.html new file mode 100644 index 0000000000..6a044abecf --- /dev/null +++ b/src/app/grid/grid-theming/grid-theming.component.html @@ -0,0 +1,64 @@ +
+
+ Pick a theme + + + @for (theme of themes; track theme.class) { + + } + + +

+ Custom themes, not built-in: each is a grid-theme() with its + own background and accent. +

+
+ + + + + Invoices + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/app/grid/grid-theming/grid-theming.component.scss b/src/app/grid/grid-theming/grid-theming.component.scss new file mode 100644 index 0000000000..29578f9aa5 --- /dev/null +++ b/src/app/grid/grid-theming/grid-theming.component.scss @@ -0,0 +1,145 @@ +@use "igniteui-angular/theming" as *; + +$studio-bg: #faf4ed; +$studio-accent: #907aa9; +$ledger-bg: #eceff4; +$ledger-accent: #5e81ac; +$editorial-bg: #333c43; +$editorial-accent: #a7c080; +$midnight-bg: #282a36; +$midnight-accent: #bd93f9; + +:host { + display: block; + padding: 16px; +} + +.theme-studio { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0.6; + + @include tokens(grid-theme( + $background: $studio-bg, + $foreground: #575279, + $accent-color: $studio-accent, + $header-background: #fffaf3, + $header-border-color: #dfdad9, + $row-border-color: #f2e9e1, + $grid-border-color: #dfdad9, + $grid-shadow: (0 1px 3px rgba(87, 82, 121, 0.10), 0 1px 2px rgba(87, 82, 121, 0.06)) + )); +} + +.theme-ledger { + --ig-size: var(--ig-size-small); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $background: $ledger-bg, + $foreground: #2e3440, + $accent-color: $ledger-accent, + $header-background: #d8dee9, + $row-odd-background: #eceff4, + $row-even-background: #e5e9f0, + $body-column-border-color-odd: #d8dee9, + $body-column-border-color-even: #d8dee9, + $row-border-color: #d8dee9, + $grid-border-color: #c8d0dc + )); +} + +.theme-editorial { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $editorial-bg, + $foreground: #d3c6aa, + $accent-color: $editorial-accent, + $header-background: #3a464c, + $row-border-color: #333c43, + $grid-border-color: #333c43 + )); +} + +.theme-midnight { + --ig-size: var(--ig-size-medium); + --ig-radius-factor: 0.25; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $midnight-bg, + $foreground: #f8f8f2, + $accent-color: $midnight-accent, + $header-background: #21222c, + $body-column-border-color-odd: #44475a, + $body-column-border-color-even: #44475a, + $row-border-color: #44475a, + $grid-border-color: #44475a + )); +} + +.grid-theming-sample { + display: flex; + flex-direction: column; + gap: 16px; +} + +.theme-picker { + --ig-button-group-elevation: 0; + + display: flex; + flex-direction: column; + gap: 6px; + align-self: flex-start; +} + +.theme-picker__label { + font-size: 12px; + font-weight: 500; + letter-spacing: 0.04em; + color: var(--ig-gray-700); +} + +.theme-picker__hint { + margin: 0; + font-size: 12px; + line-height: 1.45; + color: var(--ig-gray-600); + + code { + font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; + font-size: 11px; + } +} + +.theme-swatch { + display: inline-block; + min-width: 14px; + aspect-ratio: 1; + border-radius: 50%; + border: 1px solid var(--ig-gray-300); + vertical-align: -2px; + background: linear-gradient(135deg, var(--swatch-bg) 0 50%, var(--swatch-accent) 50% 100%); +} + +.theme-swatch--studio { + --swatch-bg: #{$studio-bg}; + --swatch-accent: #{$studio-accent}; +} + +.theme-swatch--ledger { + --swatch-bg: #{$ledger-bg}; + --swatch-accent: #{$ledger-accent}; +} + +.theme-swatch--editorial { + --swatch-bg: #{$editorial-bg}; + --swatch-accent: #{$editorial-accent}; +} + +.theme-swatch--midnight { + --swatch-bg: #{$midnight-bg}; + --swatch-accent: #{$midnight-accent}; +} diff --git a/src/app/grid/grid-theming/grid-theming.component.ts b/src/app/grid/grid-theming/grid-theming.component.ts new file mode 100644 index 0000000000..97fe513f41 --- /dev/null +++ b/src/app/grid/grid-theming/grid-theming.component.ts @@ -0,0 +1,53 @@ +import { Component, signal } from '@angular/core'; +import { IgxButtonGroupComponent } from 'igniteui-angular/button-group'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxNumberSummaryOperand, IgxSummaryResult } from 'igniteui-angular/core'; +import { IgxColumnComponent, IgxGridToolbarActionsComponent, IgxGridToolbarComponent, IgxGridToolbarHidingComponent, IgxGridToolbarPinningComponent, IgxGridToolbarTitleComponent } from 'igniteui-angular/grids/core'; +import { IgxGridComponent } from 'igniteui-angular/grids/grid'; +import { IgxPaginatorComponent } from 'igniteui-angular/paginator'; +import { INVOICE_DATA } from '../../data/invoiceData'; +import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive'; +class CompactSummary extends IgxNumberSummaryOperand { + public override operate(data?: any[]): IgxSummaryResult[] { + return super.operate(data).filter(r => r.key === 'count' || r.key === 'sum'); + } +} + +@Component({ + selector: 'app-grid-theming', + styleUrls: ['./grid-theming.component.scss'], + templateUrl: './grid-theming.component.html', + imports: [ + IgxButtonDirective, + IgxButtonGroupComponent, + IgxColumnComponent, + IgxGridComponent, + IgxGridToolbarActionsComponent, + IgxGridToolbarComponent, + IgxGridToolbarHidingComponent, + IgxGridToolbarPinningComponent, + IgxGridToolbarTitleComponent, + IgxPaginatorComponent, + IgxPreventDocumentScrollDirective + ] +}) +export class GridThemingComponent { + public data = INVOICE_DATA; + public compactSummary = CompactSummary; + public themes = [ + { label: 'Studio', class: 'theme-studio', swatch: 'theme-swatch--studio' }, + { label: 'Ledger', class: 'theme-ledger', swatch: 'theme-swatch--ledger' }, + { label: 'Editorial', class: 'theme-editorial', swatch: 'theme-swatch--editorial' }, + { label: 'Midnight', class: 'theme-midnight', swatch: 'theme-swatch--midnight' } + ]; + + public activeTheme = signal(this.themes[0].class); + + public selectTheme(args: { index: number }) { + this.activeTheme.set(this.themes[args.index].class); + } + + public formatCurrency(value: number) { + return '$' + value.toFixed(2); + } +} diff --git a/src/app/grid/grid-validation-style/grid-validation-style.component.ts b/src/app/grid/grid-validation-style/grid-validation-style.component.ts index 89c22dfaed..ccf4d404d8 100644 --- a/src/app/grid/grid-validation-style/grid-validation-style.component.ts +++ b/src/app/grid/grid-validation-style/grid-validation-style.component.ts @@ -14,7 +14,7 @@ import { NgTemplateOutlet } from '@angular/common'; export class GridValidationStyleComponent { @ViewChild('grid', { read: IgxGridComponent, static: true }) public grid: IgxGridComponent; public data: any[]; - public rowStyles = { + public rowStyles: any = { background: (row: RowType) => row.validation.status === 'INVALID' ? '#FF000033' : '#00000000' }; public cellStyles = { diff --git a/src/app/grid/grids.routes.ts b/src/app/grid/grids.routes.ts index be9950dbc9..c5ded8e028 100644 --- a/src/app/grid/grids.routes.ts +++ b/src/app/grid/grids.routes.ts @@ -31,6 +31,7 @@ import { GridGroupByCustomSampleComponent } from './grid-groupby-custom-sample/g import { GridGroupByPagingSampleComponent } from './grid-group-by-paging-sample/grid-group-by-paging-sample.component'; import { GridGroupBySampleComponent } from './grid-groupby-sample/grid-groupby-sample.component'; import { GridGroupByStylingComponent } from './grid-groupby-styling/grid-groupby-styling.component'; +import { GridThemingComponent } from './grid-theming/grid-theming.component'; import { GridGroupBySummarySampleComponent } from './grid-groupby-summary-sample/grid-groupby-summary-sample.component'; import { GridGroupBySummaryStylingSampleComponent } from './grid-groupby-summary-styling-sample/grid-groupby-summary-styling-sample.component'; import { GridMovingSampleComponent } from './grid-moving-sample/grid-moving-sample.component'; @@ -168,6 +169,11 @@ export const GridsRoutes: Routes = [ data: gridsRoutesData['grid-cellMerge-custom'], path: 'grid-cellMerge-custom' }, + { + component: GridThemingComponent, + data: gridsRoutesData['grid-theming'], + path: 'grid-theming' + }, { component: GridGroupByStylingComponent, data: gridsRoutesData['grid-groupby-styling'], diff --git a/src/app/hierarchical-grid/hgrid-rowStyle-sample/hgrid-rowStyles.component.ts b/src/app/hierarchical-grid/hgrid-rowStyle-sample/hgrid-rowStyles.component.ts index ae92b4259b..cb950623cf 100644 --- a/src/app/hierarchical-grid/hgrid-rowStyle-sample/hgrid-rowStyles.component.ts +++ b/src/app/hierarchical-grid/hgrid-rowStyle-sample/hgrid-rowStyles.component.ts @@ -18,12 +18,12 @@ export class HGridRowStylesSampleComponent implements OnInit { private hierarchicalGrid: IgxHierarchicalGridComponent; public localdata; - public rowStyles = { + public rowStyles: any = { background:(row: RowType) => row.data['HasGrammyAward'] ? '#eeddd3' : '#f0efeb', 'border-left': (row: RowType) => row.data['HasGrammyAward'] ? '2px solid #dda15e' : null }; - public childRowStyles = { + public childRowStyles: any = { 'border-left': (row: RowType) => row.data['BillboardReview'] > 70 ? '3.5px solid #dda15e' : null }; constructor() { } diff --git a/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.html b/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.html index 7028f9adae..8f27753f0c 100644 --- a/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.html +++ b/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.html @@ -1,36 +1,67 @@
- - - - -
- -
-
-
- - - +
+ Pick a theme - - - - - - - - - - - - + + @for (theme of themes; track theme.class) { + + } + - - - - - - - +

+ Custom themes, not built-in: each is a grid-theme() with its + own background and accent. +

+
+ + + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.scss b/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.scss index 2c0d35a3be..9a14ff29e1 100644 --- a/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.scss +++ b/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.scss @@ -1,16 +1,141 @@ @use "layout.scss"; @use "igniteui-angular/theming" as *; -$background: #292826; -$foreground: #eeece1; -$accent: #ffcd0f; - -$custom-grid: grid-theme( - $background: $background, - $foreground: $foreground, - $accent-color: $accent, -); - -:host { - @include tokens($custom-grid); +$studio-bg: #faf4ed; +$studio-accent: #907aa9; +$ledger-bg: #eceff4; +$ledger-accent: #5e81ac; +$editorial-bg: #333c43; +$editorial-accent: #a7c080; +$midnight-bg: #282a36; +$midnight-accent: #bd93f9; + +.theme-studio { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0.6; + + @include tokens(grid-theme( + $background: $studio-bg, + $foreground: #575279, + $accent-color: $studio-accent, + $header-background: #fffaf3, + $header-border-color: #dfdad9, + $row-border-color: #f2e9e1, + $grid-border-color: #dfdad9, + $grid-shadow: (0 1px 3px rgba(87, 82, 121, 0.10), 0 1px 2px rgba(87, 82, 121, 0.06)) + )); +} + +.theme-ledger { + --ig-size: var(--ig-size-small); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $background: $ledger-bg, + $foreground: #2e3440, + $accent-color: $ledger-accent, + $header-background: #d8dee9, + $row-odd-background: #eceff4, + $row-even-background: #e5e9f0, + $body-column-border-color-odd: #d8dee9, + $body-column-border-color-even: #d8dee9, + $row-border-color: #d8dee9, + $grid-border-color: #c8d0dc + )); +} + +.theme-editorial { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $editorial-bg, + $foreground: #d3c6aa, + $accent-color: $editorial-accent, + $header-background: #3a464c, + $row-border-color: #333c43, + $grid-border-color: #333c43 + )); +} + +.theme-midnight { + --ig-size: var(--ig-size-medium); + --ig-radius-factor: 0.25; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $midnight-bg, + $foreground: #f8f8f2, + $accent-color: $midnight-accent, + $header-background: #21222c, + $body-column-border-color-odd: #44475a, + $body-column-border-color-even: #44475a, + $row-border-color: #44475a, + $grid-border-color: #44475a + )); +} + +.grid__wrapper { + display: flex; + flex-direction: column; + gap: 16px; +} + +.theme-picker { + --ig-button-group-elevation: 0; + + display: flex; + flex-direction: column; + gap: 6px; + align-self: flex-start; +} + +.theme-picker__label { + font-size: 12px; + font-weight: 500; + letter-spacing: 0.04em; + color: var(--ig-gray-700); +} + +.theme-picker__hint { + margin: 0; + font-size: 12px; + line-height: 1.45; + color: var(--ig-gray-600); + + code { + font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; + font-size: 11px; + } +} + +.theme-swatch { + display: inline-block; + min-width: 14px; + aspect-ratio: 1; + border-radius: 50%; + border: 1px solid var(--ig-gray-300); + vertical-align: -2px; + background: linear-gradient(135deg, var(--swatch-bg) 0 50%, var(--swatch-accent) 50% 100%); +} + +.theme-swatch--studio { + --swatch-bg: #{$studio-bg}; + --swatch-accent: #{$studio-accent}; +} + +.theme-swatch--ledger { + --swatch-bg: #{$ledger-bg}; + --swatch-accent: #{$ledger-accent}; +} + +.theme-swatch--editorial { + --swatch-bg: #{$editorial-bg}; + --swatch-accent: #{$editorial-accent}; +} + +.theme-swatch--midnight { + --swatch-bg: #{$midnight-bg}; + --swatch-accent: #{$midnight-accent}; } diff --git a/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.ts b/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.ts index fcc915ddfc..91bd07fa4c 100644 --- a/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.ts +++ b/src/app/hierarchical-grid/hierarchical-grid-styling/hierarchical-grid-styling.component.ts @@ -1,4 +1,6 @@ -import { Component } from '@angular/core'; +import { Component, signal } from '@angular/core'; +import { IgxButtonGroupComponent } from 'igniteui-angular/button-group'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; import { IgxCellTemplateDirective, IgxColumnComponent } from 'igniteui-angular/grids/core'; import { IgxHierarchicalGridComponent, IgxRowIslandComponent } from 'igniteui-angular/grids/hierarchical-grid'; import { SINGERS } from '../../data/singersData'; @@ -8,7 +10,7 @@ import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scro selector: 'app-hierarchical-grid-styling', styleUrls: ['./hierarchical-grid-styling.component.scss'], templateUrl: 'hierarchical-grid-styling.component.html', - imports: [IgxHierarchicalGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxCellTemplateDirective, IgxRowIslandComponent] + imports: [IgxHierarchicalGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxCellTemplateDirective, IgxRowIslandComponent, IgxButtonGroupComponent, IgxButtonDirective] }) export class HGridStylingComponent { @@ -16,11 +18,23 @@ export class HGridStylingComponent { public col: IgxColumnComponent; public pWidth: string; public nWidth: string; + public themes = [ + { label: 'Studio', class: 'theme-studio', swatch: 'theme-swatch--studio' }, + { label: 'Ledger', class: 'theme-ledger', swatch: 'theme-swatch--ledger' }, + { label: 'Editorial', class: 'theme-editorial', swatch: 'theme-swatch--editorial' }, + { label: 'Midnight', class: 'theme-midnight', swatch: 'theme-swatch--midnight' } + ]; + + public activeTheme = signal(this.themes[0].class); constructor() { this.localdata = SINGERS; } + public selectTheme(args: { index: number }) { + this.activeTheme.set(this.themes[args.index].class); + } + public onResize(event) { this.col = event.column; this.pWidth = event.prevWidth; diff --git a/src/app/hierarchical-grid/hierarchical-grid-styling/layout.scss b/src/app/hierarchical-grid/hierarchical-grid-styling/layout.scss index b620c7ade6..e2bcf0bd0e 100644 --- a/src/app/hierarchical-grid/hierarchical-grid-styling/layout.scss +++ b/src/app/hierarchical-grid/hierarchical-grid-styling/layout.scss @@ -1,12 +1,18 @@ +// Fits the smallest row density. .photo { vertical-align: middle; - max-height: 62px; + max-block-size: 24px; + border-radius: 50%; } .cell__inner_2 { margin: 1px } +:host { + display: block; +} + .grid__wrapper{ padding: 10px; } diff --git a/src/app/hierarchical-grid/hierarchical-grid-validation-style/hierarchical-grid-validation-style.component.ts b/src/app/hierarchical-grid/hierarchical-grid-validation-style/hierarchical-grid-validation-style.component.ts index 49871eb70b..ffc614547d 100644 --- a/src/app/hierarchical-grid/hierarchical-grid-validation-style/hierarchical-grid-validation-style.component.ts +++ b/src/app/hierarchical-grid/hierarchical-grid-validation-style/hierarchical-grid-validation-style.component.ts @@ -17,7 +17,7 @@ export class HGridValidationStyleComponent { @ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true }) public hierarchicalGrid: IgxHierarchicalGridComponent; @ViewChild('childGrid', { static: true }) private childGrid: IgxRowIslandComponent; public localData: Singer[]; - public rowStyles = { + public rowStyles: any = { background: (row: RowType) => row.validation.status === 'INVALID' ? '#FF000033' : '#00000000' }; public cellStyles = { diff --git a/src/app/index/index.component.scss b/src/app/index/index.component.scss index f6cb2bd6a5..5b2502768b 100644 --- a/src/app/index/index.component.scss +++ b/src/app/index/index.component.scss @@ -3,19 +3,21 @@ } .main { + display: flex; + flex-direction: column; width: calc(100% - 300px); + height: 100%; } -.content { - width: 100%; - // height: calc(100% - 56px); - height: 100%; +.content { + width: 100%; + flex: 1 1 auto; max-height: 1000px; min-width: 300px; min-height: 300px; justify-content: center; align-items: stretch; - overflow: auto; + overflow: auto; } .navdrawer-ellipsis { diff --git a/src/app/pivot-grid/pivot-styling/pivot-styling.component.html b/src/app/pivot-grid/pivot-styling/pivot-styling.component.html index 08df70c02f..f94ecf55aa 100644 --- a/src/app/pivot-grid/pivot-styling/pivot-styling.component.html +++ b/src/app/pivot-grid/pivot-styling/pivot-styling.component.html @@ -1,2 +1,32 @@ - - \ No newline at end of file +
+
+ Pick a theme + + + @for (theme of themes; track theme.class) { + + } + + +

+ Custom themes, not built-in: each is a grid-theme() with its + own background and accent. +

+
+ + + +
diff --git a/src/app/pivot-grid/pivot-styling/pivot-styling.component.scss b/src/app/pivot-grid/pivot-styling/pivot-styling.component.scss index 238acf9733..d703a350ad 100644 --- a/src/app/pivot-grid/pivot-styling/pivot-styling.component.scss +++ b/src/app/pivot-grid/pivot-styling/pivot-styling.component.scss @@ -1,16 +1,141 @@ @use "layout.scss"; @use "igniteui-angular/theming" as *; -$background: #292826; -$foreground: #eeece1; -$accent: #ffcd0f; - -$custom-grid: grid-theme( - $background: $background, - $foreground: $foreground, - $accent-color: $accent, -); - -igx-pivot-grid { - @include tokens($custom-grid); +$studio-bg: #faf4ed; +$studio-accent: #907aa9; +$ledger-bg: #eceff4; +$ledger-accent: #5e81ac; +$editorial-bg: #333c43; +$editorial-accent: #a7c080; +$midnight-bg: #282a36; +$midnight-accent: #bd93f9; + +.theme-studio { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0.6; + + @include tokens(grid-theme( + $background: $studio-bg, + $foreground: #575279, + $accent-color: $studio-accent, + $header-background: #fffaf3, + $header-border-color: #dfdad9, + $row-border-color: #f2e9e1, + $grid-border-color: #dfdad9, + $grid-shadow: (0 1px 3px rgba(87, 82, 121, 0.10), 0 1px 2px rgba(87, 82, 121, 0.06)) + )); +} + +.theme-ledger { + --ig-size: var(--ig-size-small); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $background: $ledger-bg, + $foreground: #2e3440, + $accent-color: $ledger-accent, + $header-background: #d8dee9, + $row-odd-background: #eceff4, + $row-even-background: #e5e9f0, + $body-column-border-color-odd: #d8dee9, + $body-column-border-color-even: #d8dee9, + $row-border-color: #d8dee9, + $grid-border-color: #c8d0dc + )); +} + +.theme-editorial { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $editorial-bg, + $foreground: #d3c6aa, + $accent-color: $editorial-accent, + $header-background: #3a464c, + $row-border-color: #333c43, + $grid-border-color: #333c43 + )); +} + +.theme-midnight { + --ig-size: var(--ig-size-medium); + --ig-radius-factor: 0.25; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $midnight-bg, + $foreground: #f8f8f2, + $accent-color: $midnight-accent, + $header-background: #21222c, + $body-column-border-color-odd: #44475a, + $body-column-border-color-even: #44475a, + $row-border-color: #44475a, + $grid-border-color: #44475a + )); +} + +.pivot-theming-sample { + display: flex; + flex-direction: column; + gap: 16px; +} + +.theme-picker { + --ig-button-group-elevation: 0; + + display: flex; + flex-direction: column; + gap: 6px; + align-self: flex-start; +} + +.theme-picker__label { + font-size: 12px; + font-weight: 500; + letter-spacing: 0.04em; + color: var(--ig-gray-700); +} + +.theme-picker__hint { + margin: 0; + font-size: 12px; + line-height: 1.45; + color: var(--ig-gray-600); + + code { + font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; + font-size: 11px; + } +} + +.theme-swatch { + display: inline-block; + min-width: 14px; + aspect-ratio: 1; + border-radius: 50%; + border: 1px solid var(--ig-gray-300); + vertical-align: -2px; + background: linear-gradient(135deg, var(--swatch-bg) 0 50%, var(--swatch-accent) 50% 100%); +} + +.theme-swatch--studio { + --swatch-bg: #{$studio-bg}; + --swatch-accent: #{$studio-accent}; +} + +.theme-swatch--ledger { + --swatch-bg: #{$ledger-bg}; + --swatch-accent: #{$ledger-accent}; +} + +.theme-swatch--editorial { + --swatch-bg: #{$editorial-bg}; + --swatch-accent: #{$editorial-accent}; +} + +.theme-swatch--midnight { + --swatch-bg: #{$midnight-bg}; + --swatch-accent: #{$midnight-accent}; } diff --git a/src/app/pivot-grid/pivot-styling/pivot-styling.component.ts b/src/app/pivot-grid/pivot-styling/pivot-styling.component.ts index b85a70c4fe..039ae0185f 100644 --- a/src/app/pivot-grid/pivot-styling/pivot-styling.component.ts +++ b/src/app/pivot-grid/pivot-styling/pivot-styling.component.ts @@ -1,6 +1,8 @@ -import { Component, ChangeDetectionStrategy } from "@angular/core"; +import { Component, ChangeDetectionStrategy, signal } from "@angular/core"; import { DATA } from '../../data/pivot-data'; +import { IgxButtonGroupComponent } from 'igniteui-angular/button-group'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; import { IPivotConfiguration, IgxPivotNumericAggregate } from 'igniteui-angular/grids/core'; import { IgxPivotGridComponent } from 'igniteui-angular/grids/pivot-grid'; @@ -9,24 +11,38 @@ import { IgxPivotGridComponent } from 'igniteui-angular/grids/pivot-grid'; styleUrls: ['./pivot-styling.component.scss'], templateUrl: './pivot-styling.component.html', changeDetection: ChangeDetectionStrategy.Eager, - imports: [IgxPivotGridComponent] + imports: [IgxPivotGridComponent, IgxButtonGroupComponent, IgxButtonDirective] }) export class PivotStylingComponent { public data = DATA; + public themes = [ + { label: 'Studio', class: 'theme-studio', swatch: 'theme-swatch--studio' }, + { label: 'Ledger', class: 'theme-ledger', swatch: 'theme-swatch--ledger' }, + { label: 'Editorial', class: 'theme-editorial', swatch: 'theme-swatch--editorial' }, + { label: 'Midnight', class: 'theme-midnight', swatch: 'theme-swatch--midnight' } + ]; + + public activeTheme = signal(this.themes[0].class); + public pivotConfigHierarchy: IPivotConfiguration = { columns: [ { memberName: 'Product', memberFunction: (data) => data.Product.Name, enabled: true - } + } ], rows: [ { - memberName: 'Seller', - memberFunction: (data) => data.Seller.Name, - enabled: true + memberName: 'City', + memberFunction: (data) => data.Seller.City, + enabled: true, + childLevel: { + memberName: 'Seller', + memberFunction: (data) => data.Seller.Name, + enabled: true + } } ], values: [ @@ -42,4 +58,8 @@ export class PivotStylingComponent { ], filters: null }; + + public selectTheme(args: { index: number }) { + this.activeTheme.set(this.themes[args.index].class); + } } diff --git a/src/app/services/theme.service.spec.ts b/src/app/services/theme.service.spec.ts new file mode 100644 index 0000000000..aa97a511dd --- /dev/null +++ b/src/app/services/theme.service.spec.ts @@ -0,0 +1,56 @@ +import { DOCUMENT, PLATFORM_ID, signal } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { THEME_TOKEN, type IgxTheme } from 'igniteui-angular/core'; +import { THEME_MESSAGE, ThemeService } from './theme.service'; + +describe('ThemeService theme validation', () => { + let service: ThemeService; + let document: Document; + + beforeEach(() => { + document = window.document.implementation.createHTMLDocument(); + TestBed.configureTestingModule({ + providers: [ + { provide: DOCUMENT, useValue: document }, + { provide: PLATFORM_ID, useValue: 'browser' }, + { provide: THEME_TOKEN, useValue: signal('material') } + ] + }); + service = TestBed.inject(ThemeService); + service.init(); + }); + + for (const theme of ['toString', 'constructor', '__proto__', 'hasOwnProperty']) { + it(`rejects inherited theme key ${theme}`, () => { + const link = document.getElementById('igniteui-theme'); + const href = link.getAttribute('href'); + + expect(service.handleMessage(new MessageEvent('message', { + data: { type: THEME_MESSAGE, theme } + }))).toBeFalse(); + expect(service.theme()).toBe('material'); + expect(link.getAttribute('href')).toBe(href); + + expect(service.set(theme, 'dark')).toBeTrue(); + expect(service.theme()).toBe('material'); + expect(service.mode()).toBe('dark'); + expect(link.getAttribute('href')).toBe('assets/themes/igniteui-angular-dark.css'); + }); + } + + for (const [theme, stylesheet] of [ + ['material', 'igniteui-angular.css'], + ['fluent', 'igniteui-fluent-light.css'], + ['bootstrap', 'igniteui-bootstrap-light.css'], + ['indigo', 'igniteui-indigo-light.css'] + ] as const) { + it(`accepts supported theme ${theme}`, () => { + expect(service.handleMessage(new MessageEvent('message', { + data: { type: THEME_MESSAGE, theme } + }))).toBeTrue(); + expect(service.theme()).toBe(theme); + expect(document.getElementById('igniteui-theme').getAttribute('href')) + .toBe(`assets/themes/${stylesheet}`); + }); + } +}); diff --git a/src/app/services/theme.service.ts b/src/app/services/theme.service.ts new file mode 100644 index 0000000000..bc24357df4 --- /dev/null +++ b/src/app/services/theme.service.ts @@ -0,0 +1,231 @@ +import { isPlatformBrowser } from '@angular/common'; +import { DOCUMENT, Injectable, PLATFORM_ID, inject, signal } from '@angular/core'; +import { THEME_TOKEN, type IgxTheme } from 'igniteui-angular/core'; + +/** + * Message type posted by the documentation site's theming widget into the + * sample iframe. See `ThemeService.handleMessage`. + */ +export const THEME_MESSAGE = 'igd-sample-theme'; + +/** Color modes the theming widget can request. */ +export type ThemeMode = 'light' | 'dark' | 'system'; + +/** `system` resolved against the OS preference. */ +export type ColorScheme = 'light' | 'dark'; + +/** + * Prebuilt Ignite UI stylesheets, one per theme/scheme pair. They are copied + * out of `igniteui-angular/styles` into `assets/themes` at build time - see the + * `assets` section of angular.json. + */ +const THEME_STYLESHEETS: Record> = { + material: { light: 'igniteui-angular.css', dark: 'igniteui-angular-dark.css' }, + fluent: { light: 'igniteui-fluent-light.css', dark: 'igniteui-fluent-dark.css' }, + bootstrap: { light: 'igniteui-bootstrap-light.css', dark: 'igniteui-bootstrap-dark.css' }, + indigo: { light: 'igniteui-indigo-light.css', dark: 'igniteui-indigo-dark.css' } +}; + +const THEMES_PATH = 'assets/themes/'; + +/** Id of the `` in index.html that carries the active theme. */ +const THEME_LINK_ID = 'igniteui-theme'; + +const TYPEFACE_URL = 'https://fonts.googleapis.com/css?family='; +const TYPEFACE_WEIGHTS = ':300,400,600,700'; + +/** + * Font families that never need to be fetched: generic CSS keywords and the + * system fonts the Bootstrap theme is built on. + */ +const LOCAL_FAMILIES = new Set([ + 'sans-serif', 'serif', 'monospace', 'cursive', 'fantasy', + 'system-ui', 'ui-sans-serif', 'ui-serif', 'ui-monospace', + 'segoe ui', 'helvetica', 'helvetica neue', 'arial', 'roboto' +]); + +const isTheme = (value: unknown): value is IgxTheme => + typeof value === 'string' && Object.hasOwn(THEME_STYLESHEETS, value); + +const isMode = (value: unknown): value is ThemeMode => + value === 'light' || value === 'dark' || value === 'system'; + +/** + * Swaps the Ignite UI theme of the samples application at runtime. + * + * Samples are embedded in the documentation as iframes and the site's theming + * widget posts the visitor's selection into them, so the whole application has + * to be able to move between the Material, Fluent, Bootstrap and Indigo themes + * (each in a light and a dark variant) without reloading. That is done by + * pointing a single `` at one of the prebuilt stylesheets instead of + * compiling a single theme into `styles.scss`. + */ +@Injectable({ providedIn: 'root' }) +export class ThemeService { + private document = inject(DOCUMENT); + private themeToken = inject(THEME_TOKEN); + private isBrowser = isPlatformBrowser(inject(PLATFORM_ID)); + + /** The selected theme. */ + public readonly theme = signal('material'); + + /** The selected color mode, `system` included. */ + public readonly mode = signal('light'); + + /** The color mode actually in effect, with `system` already resolved. */ + public readonly colorScheme = signal('light'); + + private prefersDark: MediaQueryList; + private typefaces = new Set(); + + /** + * Applies the initial theme and starts following the OS color preference. + * Safe to call more than once. + */ + public init(): void { + if (this.isBrowser && !this.prefersDark) { + this.prefersDark = this.document.defaultView?.matchMedia('(prefers-color-scheme: dark)'); + // Only relevant while the widget is on `system`; `apply` ignores it otherwise. + this.prefersDark?.addEventListener('change', () => this.apply()); + } + + this.apply(); + } + + /** + * Handles a `message` event coming from the documentation site. + * + * The widget posts `{ type: 'igd-sample-theme', theme, themeName, mode }` + * once when the iframe loads and again on every change. The message is + * trusted for its shape rather than for its origin - the documentation is + * served from a number of hosts, and the only thing acted upon is a choice + * between the four known themes and the three known modes. + * + * @returns whether the message was recognized and applied. + */ + public handleMessage(event: MessageEvent): boolean { + const data = event.data; + + if (!data || (data.type !== THEME_MESSAGE && data.event !== THEME_MESSAGE)) { + return false; + } + + return this.set(data.theme ?? data.themeName, data.mode); + } + + /** + * Switches to `theme` / `mode`. Unknown or missing values leave the + * corresponding part of the selection untouched. + * + * @returns whether anything was recognized. + */ + public set(theme?: unknown, mode?: unknown): boolean { + let known = false; + + if (isTheme(theme)) { + this.theme.set(theme); + known = true; + } + + if (isMode(mode)) { + this.mode.set(mode); + known = true; + } + + if (known) { + this.apply(); + } + + return known; + } + + private apply(): void { + if (!this.isBrowser) { + return; + } + + const theme = this.theme(); + const scheme = this.resolveScheme(); + this.colorScheme.set(scheme); + + // Exposed for samples that need to react to the selection. Deliberately + // not used to paint a page background: the documentation's Sample + // component owns the surface behind the iframe. + const root = this.document.documentElement; + root.dataset.igTheme = theme; + root.dataset.igMode = scheme; + + const href = THEMES_PATH + THEME_STYLESHEETS[theme][scheme]; + const link = this.themeLink(); + + if (!link.getAttribute('href')?.endsWith(href)) { + link.addEventListener('load', () => this.loadTypeface(), { once: true }); + link.href = href; + } + + // Components such as igx-input-group render differently per theme and + // take the theme from this token rather than from the stylesheet. + this.themeToken.set(theme); + } + + private resolveScheme(): ColorScheme { + const mode = this.mode(); + + if (mode !== 'system') { + return mode; + } + + return this.prefersDark?.matches ? 'dark' : 'light'; + } + + private themeLink(): HTMLLinkElement { + let link = this.document.getElementById(THEME_LINK_ID) as HTMLLinkElement; + + if (!link) { + link = this.document.createElement('link'); + link.id = THEME_LINK_ID; + link.rel = 'stylesheet'; + // Ahead of everything else in the head, so that the application's + // own styles keep overriding the theme as they do in index.html. + this.document.head.insertBefore(link, this.document.head.firstChild); + } + + return link; + } + + /** + * Each theme comes with its own typeface. Once a theme stylesheet is in + * place, take the first family off `--ig-font-family` and pick it up from + * Google Fonts unless it is one the browser already has. + */ + private loadTypeface(): void { + const view = this.document.defaultView; + + if (!view) { + return; + } + + const family = view.getComputedStyle(this.document.body) + .getPropertyValue('--ig-font-family') + .split(',')[0] + .trim() + .replace(/['"]/g, ''); + + if (!family || family.startsWith('-') || LOCAL_FAMILIES.has(family.toLowerCase())) { + return; + } + + if (this.typefaces.has(family)) { + return; + } + + this.typefaces.add(family); + + // A link per family, so that switching back to an earlier theme does + // not have to fetch its typeface again. + const link = this.document.createElement('link'); + link.rel = 'stylesheet'; + link.href = TYPEFACE_URL + family.split(' ').join('+') + TYPEFACE_WEIGHTS; + this.document.head.appendChild(link); + } +} diff --git a/src/app/theming/grid-theme-playground/color-utils.ts b/src/app/theming/grid-theme-playground/color-utils.ts new file mode 100644 index 0000000000..9c3ed49e08 --- /dev/null +++ b/src/app/theming/grid-theme-playground/color-utils.ts @@ -0,0 +1,12 @@ +/** Normalizes free-typed color text to a 6-digit uppercase hex string, or null if invalid. */ +export function normalizeHexColor(raw: string): string | null { + let value = raw.trim(); + if (!value) return null; + if (!value.startsWith('#')) value = '#' + value; + + if (/^#[0-9a-fA-F]{3}$/.test(value)) { + value = '#' + value[1] + value[1] + value[2] + value[2] + value[3] + value[3]; + } + + return /^#[0-9a-fA-F]{6}$/.test(value) ? value.toUpperCase() : null; +} diff --git a/src/app/theming/grid-theme-playground/grid-theme-playground.component.html b/src/app/theming/grid-theme-playground/grid-theme-playground.component.html new file mode 100644 index 0000000000..fb39188573 --- /dev/null +++ b/src/app/theming/grid-theme-playground/grid-theme-playground.component.html @@ -0,0 +1,223 @@ +
+ +
+
+ + @switch (preview()) { + @case ('grid') { + + + + + + + + + } + @case ('tree') { + @defer (on immediate) { + + + +
+ + {{ cell.value }} +
+
+
+ + + +
+ } @placeholder { +
Loading preview…
+ } + } + @case ('hierarchical') { + @defer (on immediate) { + + + + + + + + + + + + } @placeholder { +
Loading preview…
+ } + } + @case ('pivot') { + @defer (on immediate) { + + + } @placeholder { +
Loading preview…
+ } + } + } +
+
+
+ + + +
Theme code
+
+ +
+ + + + SCSS + + + +
+
+
+ + + + CSS variables + + + +
+
+
+
+
+ +
+ +
+
diff --git a/src/app/theming/grid-theme-playground/grid-theme-playground.component.scss b/src/app/theming/grid-theme-playground/grid-theme-playground.component.scss new file mode 100644 index 0000000000..2a0e5ce636 --- /dev/null +++ b/src/app/theming/grid-theme-playground/grid-theme-playground.component.scss @@ -0,0 +1,173 @@ +@use "igniteui-angular/theming" as *; + +:host { + display: block; + block-size: 100%; +} + +.playground { + display: flex; + align-items: stretch; + gap: 20px; + padding: 16px; + box-sizing: border-box; + block-size: 100%; + min-block-size: 520px; + overflow: hidden; +} + +.playground__stage { + @include tokens(grid-theme( + $background: #08002e, + $accent-color: #ff7d52 + )); +} + +.playground__rail { + --ig-size: var(--ig-size-medium); + --ig-button-group-elevation: 0; + + flex: 0 0 280px; + display: flex; + flex-direction: column; + gap: 12px; + min-block-size: 0; + overflow-y: auto; + padding-inline-end: 4px; + + igx-expansion-panel-title { + font-size: 13px; + font-weight: 600; + letter-spacing: 0.04em; + color: var(--ig-gray-700); + } +} + +.playground__hint { + margin: 0 0 10px; + font-size: 12px; + line-height: 1.45; + color: var(--ig-gray-600); +} + +.playground__fields { + display: flex; + flex-direction: column; + gap: 14px; +} + +.playground__control { + display: flex; + flex-direction: column; + gap: 6px; +} + +.playground__label { + font-size: 12px; + color: var(--ig-gray-700); +} + +.playground__actions { + position: sticky; + inset-block-end: 0; + z-index: 1; + display: flex; + gap: 8px; + padding-block: 8px; + background: var(--ig-surface-500); + border-block-start: 1px solid var(--ig-gray-200); + + button { + flex: 1; + } +} + +.playground__dialog-title { + font-size: 16px; + font-weight: 600; +} + +.playground__dialog-body { + --ig-size: var(--ig-size-medium); + --ig-icon-size: 18px; + --ig-h5-font-size: 14px; + --ig-h5-font-weight: 600; + --ig-expansion-panel-border-radius: 4px; + --ig-expansion-panel-header-background: var(--ig-gray-100); + + inline-size: min(680px, 80vw); + + ::ng-deep .igx-expansion-panel__body { + padding: 0; + } +} + +.playground__copy { + margin-inline-start: auto; +} + +.playground__export { + border: 1px solid var(--ig-gray-300); + border-radius: 6px; + overflow: hidden; +} + +.playground__code { + ::ng-deep pre.shiki { + margin: 0; + padding: 10px 12px; + font-size: 13px; + line-height: 1.5; + font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; + max-block-size: 55vh; + overflow: auto; + overscroll-behavior: contain; + } +} + +.playground__loading { + display: grid; + place-items: center; + block-size: 100%; + color: var(--ig-gray-600); + font-size: 13px; +} + +.playground__preview { + flex: 1 1 auto; + min-inline-size: 0; + min-block-size: 0; + display: flex; + flex-direction: column; + gap: 12px; +} + +.playground__stage { + flex: 1 1 auto; + min-block-size: 0; + overflow: hidden; +} + +.playground__cell { + display: flex; + align-items: center; + gap: 8px; + height: 100%; +} + +@media (max-width: 860px) { + .playground { + flex-direction: column; + block-size: auto; + overflow: visible; + } + + .playground__rail { + flex: 0 0 auto; + overflow: visible; + } + + .playground__stage { + min-block-size: 460px; + } +} diff --git a/src/app/theming/grid-theme-playground/grid-theme-playground.component.ts b/src/app/theming/grid-theme-playground/grid-theme-playground.component.ts new file mode 100644 index 0000000000..8e5a916563 --- /dev/null +++ b/src/app/theming/grid-theme-playground/grid-theme-playground.component.ts @@ -0,0 +1,315 @@ +import { Component, ElementRef, afterNextRender, computed, inject, signal, viewChild } from '@angular/core'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { IgxAccordionComponent } from 'igniteui-angular/accordion'; +import { IgxAvatarComponent } from 'igniteui-angular/avatar'; +import { IgxButtonGroupComponent } from 'igniteui-angular/button-group'; +import { IgxNumberSummaryOperand, IgxSummaryResult } from 'igniteui-angular/core'; +import { IgxIconComponent } from 'igniteui-angular/icon'; +import { IgxDialogActionsDirective, IgxDialogComponent, IgxDialogTitleDirective } from 'igniteui-angular/dialog'; +import { IgxButtonDirective, IgxIconButtonDirective } from 'igniteui-angular/directives'; +import { IGX_EXPANSION_PANEL_DIRECTIVES } from 'igniteui-angular/expansion-panel'; +import { IgxCellTemplateDirective, IgxColumnComponent, IPivotConfiguration, IgxPivotNumericAggregate } from 'igniteui-angular/grids/core'; +import { IgxGridComponent } from 'igniteui-angular/grids/grid'; +import { IgxHierarchicalGridComponent, IgxRowIslandComponent } from 'igniteui-angular/grids/hierarchical-grid'; +import { IgxPivotGridComponent } from 'igniteui-angular/grids/pivot-grid'; +import { IgxTreeGridComponent } from 'igniteui-angular/grids/tree-grid'; +import { IgxPaginatorComponent } from 'igniteui-angular/paginator'; +import { IgxSwitchComponent } from 'igniteui-angular/switch'; +import { INVOICE_DATA } from '../../data/invoiceData'; +import { DATA as PIVOT_DATA } from '../../data/pivot-data'; +import { SINGERS } from '../../data/singersData'; +import { EMPLOYEE_FLAT_AVATARS_DATA } from '../../tree-grid/data/employees-flat-avatars'; +import { ThemeColorFieldComponent } from './theme-color-field.component'; + +type TokenKey = 'background' | 'accentColor' | 'foreground' | 'headerBackground' | 'headerForeground'; + +interface TokenDescriptor { + key: TokenKey; + cssVar: string; + scss: string; + label: string; +} +class CompactSummary extends IgxNumberSummaryOperand { + public override operate(data?: any[]): IgxSummaryResult[] { + return super.operate(data).filter(r => r.key === 'count' || r.key === 'sum'); + } +} +const PRIMARY_TOKENS: TokenDescriptor[] = [ + { key: 'background', cssVar: '--ig-grid-background', scss: '$background', label: 'Background' }, + { key: 'accentColor', cssVar: '--ig-grid-accent-color', scss: '$accent-color', label: 'Accent' }, + { key: 'foreground', cssVar: '--ig-grid-foreground', scss: '$foreground', label: 'Foreground' } +]; +const HEADER_TOKENS: TokenDescriptor[] = [ + { key: 'headerBackground', cssVar: '--ig-grid-header-background', scss: '$header-background', label: 'Header background' }, + { key: 'headerForeground', cssVar: '--ig-grid-header-text-color', scss: '$header-text-color', label: 'Header foreground' } +]; + +const ALL_TOKENS = [...PRIMARY_TOKENS, ...HEADER_TOKENS]; + +const EMPTY_COLORS: Record = { + background: '', accentColor: '', foreground: '', headerBackground: '', headerForeground: '' +}; +/** What Sass emits for header text once $header-background is declared. */ +const HEADER_TEXT_ON_HEADER = 'hsla(from color(from var(--ig-grid-header-background) var(--y-contrast)) h 0 l/1)'; +const DIVIDER = 'hsl(from color-mix(in srgb, var(--ig-grid-foreground) 16%, var(--ig-grid-background)) h s l/0.38)'; +const ZEBRA = 'color-mix(in srgb, var(--ig-grid-foreground) 4%, var(--ig-grid-background))'; +const NO_DIVIDER = 'var(--ig-grid-background)'; + +@Component({ + selector: 'app-grid-theme-playground', + styleUrls: ['./grid-theme-playground.component.scss'], + templateUrl: './grid-theme-playground.component.html', + imports: [ + IgxAccordionComponent, IGX_EXPANSION_PANEL_DIRECTIVES, IgxAvatarComponent, IgxButtonDirective, + IgxButtonGroupComponent, IgxCellTemplateDirective, IgxColumnComponent, + IgxDialogActionsDirective, IgxDialogComponent, IgxDialogTitleDirective, IgxGridComponent, + IgxHierarchicalGridComponent, IgxIconButtonDirective, IgxIconComponent, IgxPaginatorComponent, IgxPivotGridComponent, IgxRowIslandComponent, + IgxSwitchComponent, IgxTreeGridComponent, ThemeColorFieldComponent + ] +}) +export class GridThemePlaygroundComponent { + protected readonly primaryTokens = PRIMARY_TOKENS; + protected readonly headerTokens = HEADER_TOKENS; + protected readonly compactSummary = CompactSummary; + + protected readonly colors = signal>({ ...EMPTY_COLORS }); + protected readonly size = signal<'small' | 'medium' | 'large'>('medium'); + protected readonly radiusFactor = signal(0.4); + protected readonly horizontalDividers = signal(true); + protected readonly verticalDividers = signal(false); + protected readonly zebra = signal(false); + protected readonly preview = signal<'grid' | 'tree' | 'hierarchical' | 'pivot'>('grid'); + + protected readonly copied = signal<'scss' | 'css' | null>(null); + + protected readonly sizes = [ + { label: 'Small', selected: false }, + { label: 'Medium', selected: true }, + { label: 'Large', selected: false } + ]; + protected readonly roundnessOptions = [ + { label: 'Square', selected: false }, + { label: 'Soft', selected: true }, + { label: 'Round', selected: false } + ]; + protected readonly previews = [ + { label: 'Flat', selected: true }, + { label: 'Tree', selected: false }, + { label: 'Hierarchical', selected: false }, + { label: 'Pivot', selected: false } + ]; + + public readonly data = INVOICE_DATA; + public readonly treeData = EMPLOYEE_FLAT_AVATARS_DATA(); + public readonly hierarchicalData = SINGERS; + public readonly pivotData = PIVOT_DATA; + + public pivotConfig: IPivotConfiguration = { + columns: [{ memberName: 'Product', memberFunction: (data) => data.Product.Name, enabled: true }], + rows: [{ + memberName: 'City', + memberFunction: (data) => data.Seller.City, + enabled: true, + childLevel: { memberName: 'Seller', memberFunction: (data) => data.Seller.Name, enabled: true } + }], + values: [{ + member: 'NumberOfUnits', + aggregate: { aggregator: IgxPivotNumericAggregate.sum, key: 'sum', label: 'Sum' }, + enabled: true + }], + filters: null + }; + + private readonly sanitizer = inject(DomSanitizer); + + protected readonly scssHtml = signal(null); + protected readonly cssHtml = signal(null); + + private highlighter: { codeToHtml: (code: string, opts: { lang: string; theme: string }) => string } | null = null; + + private readonly stage = viewChild.required>('stage'); + /** The compiled theme, read from the stylesheet: the CSS export needs every + * token, not just the roots, to work in an app with no grid-theme(). */ + private readonly themeTokens = signal<[string, string][]>([]); + + constructor() { + afterNextRender(() => { + this.seedFromStylesheet(); + this.readCompiledTheme(); + }); + } + protected readonly previewStyle = computed>(() => { + const style: Record = {}; + const colors = this.colors(); + + for (const token of ALL_TOKENS) { + if (colors[token.key]) { + style[token.cssVar] = colors[token.key]; + } + } + if (colors.headerBackground && !colors.headerForeground) { + style['--ig-grid-header-text-color'] = HEADER_TEXT_ON_HEADER; + } + + style['--ig-size'] = `var(--ig-size-${this.size()})`; + style['--ig-radius-factor'] = `${this.radiusFactor()}`; + style['--ig-grid-row-border-color'] = this.horizontalDividers() ? DIVIDER : NO_DIVIDER; + + const columnRule = this.verticalDividers() ? DIVIDER : NO_DIVIDER; + style['--ig-grid-body-column-border-color-odd'] = columnRule; + style['--ig-grid-body-column-border-color-even'] = columnRule; + + if (this.zebra()) { + style['--ig-grid-row-even-background'] = ZEBRA; + } + + return style; + }); + protected readonly exportScss = computed(() => { + const colors = this.colors(); + const themeLines = ALL_TOKENS + .filter(token => colors[token.key]) + .map(token => ` ${token.scss}: ${colors[token.key]},`); + + if (!this.horizontalDividers()) { + themeLines.push(` $row-border-color: ${NO_DIVIDER},`); + } + if (this.verticalDividers()) { + themeLines.push(` $body-column-border-color-odd: ${DIVIDER},`); + themeLines.push(` $body-column-border-color-even: ${DIVIDER},`); + } + if (this.zebra()) { + themeLines.push(` $row-even-background: ${ZEBRA},`); + } + + const varLines = [ + ` --ig-size: var(--ig-size-${this.size()});`, + ` --ig-radius-factor: ${this.radiusFactor()};` + ]; + + if (!themeLines.length) { + return `.my-grid {\n${varLines.join('\n')}\n}`; + } + + return `.my-grid {\n${varLines.join('\n')}\n\n @include tokens(grid-theme(\n${themeLines.join('\n')}\n ));\n}`; + }); + + protected readonly exportCss = computed(() => { + const overrides = this.previewStyle(); + const base = this.themeTokens(); + + if (!base.length) { + const lines = Object.entries(overrides).map(([name, value]) => ` ${name}: ${value};`); + return `/* Overrides only -- requires a grid-theme() base to derive from. */\n.my-grid {\n${lines.join('\n')}\n}`; + } + + const emitted = new Set(); + const lines = base.map(([name, value]) => { + emitted.add(name); + return ` ${name}: ${overrides[name] ?? value};`; + }); + const extras = Object.entries(overrides) + .filter(([name]) => !emitted.has(name)) + .map(([name, value]) => ` ${name}: ${value};`); + + return `.my-grid {\n${[...extras, ...lines].join('\n')}\n}`; + }); + + protected setColor(key: TokenKey, value: string): void { + this.colors.update(current => ({ ...current, [key]: value })); + } + + protected reset(): void { + this.colors.set({ ...EMPTY_COLORS }); + this.size.set('medium'); + this.radiusFactor.set(0.4); + this.horizontalDividers.set(true); + this.verticalDividers.set(false); + this.zebra.set(false); + this.seedFromStylesheet(); + } + + protected async showCode(dialog: IgxDialogComponent): Promise { + if (!this.highlighter) { + const [core, engine, scss, css, theme] = await Promise.all([ + import('shiki/core'), + import('shiki/engine/javascript'), + import('shiki/langs/scss.mjs'), + import('shiki/langs/css.mjs'), + import('shiki/themes/dark-plus.mjs') + ]); + + this.highlighter = await core.createHighlighterCore({ + themes: [theme.default], + langs: [scss.default, css.default], + engine: engine.createJavaScriptRegexEngine() + }); + } + + const render = (code: string | null, lang: string) => code + ? this.sanitizer.bypassSecurityTrustHtml(this.highlighter.codeToHtml(code, { lang, theme: 'dark-plus' })) + : null; + + this.scssHtml.set(render(this.exportScss(), 'scss')); + this.cssHtml.set(render(this.exportCss(), 'css')); + dialog.open(); + } + + protected copy(code: string | null, format: 'scss' | 'css'): void { + if (!code) return; + navigator.clipboard.writeText(code).then(() => { + this.copied.set(format); + setTimeout(() => this.copied.set(null), 2000); + }); + } + + protected onSize(args: { index: number }): void { + this.size.set((['small', 'medium', 'large'] as const)[args.index]); + } + + protected onRoundness(args: { index: number }): void { + this.radiusFactor.set([0, 0.4, 1][args.index]); + } + + protected onPreview(args: { index: number }): void { + this.preview.set((['grid', 'tree', 'hierarchical', 'pivot'] as const)[args.index]); + } + private readCompiledTheme(): void { + const tokens: [string, string][] = []; + + for (const sheet of Array.from(document.styleSheets)) { + let rules: CSSRuleList; + + try { + rules = sheet.cssRules; + } catch { + continue; // cross-origin sheet, not ours + } + + for (const rule of Array.from(rules)) { + if (!(rule instanceof CSSStyleRule) || !rule.selectorText.includes('playground__stage')) { + continue; + } + + for (let i = 0; i < rule.style.length; i++) { + const name = rule.style.item(i); + if (name.startsWith('--ig-')) { + tokens.push([name, rule.style.getPropertyValue(name).trim()]); + } + } + } + } + + this.themeTokens.set(tokens); + } + + private seedFromStylesheet(): void { + const styles = getComputedStyle(this.stage().nativeElement); + + this.colors.update(current => ({ + ...current, + background: styles.getPropertyValue('--ig-grid-background').trim(), + accentColor: styles.getPropertyValue('--ig-grid-accent-color').trim() + })); + } +} diff --git a/src/app/theming/grid-theme-playground/theme-color-field.component.html b/src/app/theming/grid-theme-playground/theme-color-field.component.html new file mode 100644 index 0000000000..69afda312c --- /dev/null +++ b/src/app/theming/grid-theme-playground/theme-color-field.component.html @@ -0,0 +1,20 @@ +
+ {{ label() }} + + + + + + + + + @if (value()) { + + + + } + +
diff --git a/src/app/theming/grid-theme-playground/theme-color-field.component.scss b/src/app/theming/grid-theme-playground/theme-color-field.component.scss new file mode 100644 index 0000000000..f06f7a1d6a --- /dev/null +++ b/src/app/theming/grid-theme-playground/theme-color-field.component.scss @@ -0,0 +1,76 @@ +.color-field { + display: flex; + flex-direction: column; + gap: 6px; + + &__label { + font-size: 12px; + color: var(--ig-gray-700); + } + + igx-input-group { + --ig-input-group-focused-border-color: var(--ig-gray-500); + + [igxInput] { + font-size: 13px; + font-weight: 400; + } + } + + &__swatch-wrap { + position: relative; + width: 28px; + height: 28px; + flex-shrink: 0; + + input[type='color'] { + appearance: none; + position: absolute; + inset: 0; + opacity: 0; + width: 100%; + height: 100%; + cursor: pointer; + border: none; + padding: 0; + margin: 0; + } + } + + &__swatch { + position: absolute; + inset: 0; + border-radius: 5px; + border: 1px solid var(--ig-gray-400); + pointer-events: none; + } + + // "auto" -- the token is deriving rather than being overridden. + &__swatch--auto { + background: repeating-linear-gradient( + 45deg, + var(--ig-gray-200) 0 4px, + var(--ig-gray-100) 4px 8px + ); + } + + &__reset { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border: none; + border-radius: 4px; + background: transparent; + color: var(--ig-gray-600); + font-size: 14px; + cursor: pointer; + transition: color 120ms ease, background 120ms ease; + + &:hover { + color: var(--ig-gray-700); + background: var(--ig-gray-100); + } + } +} diff --git a/src/app/theming/grid-theme-playground/theme-color-field.component.ts b/src/app/theming/grid-theme-playground/theme-color-field.component.ts new file mode 100644 index 0000000000..47e532ae51 --- /dev/null +++ b/src/app/theming/grid-theme-playground/theme-color-field.component.ts @@ -0,0 +1,48 @@ +import { ChangeDetectionStrategy, Component, input, output } from '@angular/core'; +import { IgxInputGroupComponent, IgxInputDirective, IgxPrefixDirective, IgxSuffixDirective } from 'igniteui-angular/input-group'; +import { normalizeHexColor } from './color-utils'; + +@Component({ + selector: 'app-theme-color-field', + changeDetection: ChangeDetectionStrategy.OnPush, + templateUrl: './theme-color-field.component.html', + styleUrl: './theme-color-field.component.scss', + imports: [IgxInputGroupComponent, IgxInputDirective, IgxPrefixDirective, IgxSuffixDirective] +}) +export class ThemeColorFieldComponent { + public readonly label = input.required(); + public readonly value = input(''); + /** Seed for the native colour wheel while the value is empty ("auto"). */ + public readonly fallback = input('#808080'); + public readonly valueChange = output(); + + private pendingFrame: number | null = null; + private latestPickedValue: string | null = null; + protected onPick(event: Event): void { + this.latestPickedValue = (event.target as HTMLInputElement).value; + if (this.pendingFrame !== null) return; + + this.pendingFrame = requestAnimationFrame(() => { + this.pendingFrame = null; + if (this.latestPickedValue !== null) { + this.valueChange.emit(this.latestPickedValue); + this.latestPickedValue = null; + } + }); + } + + protected onTextChange(event: Event): void { + const inputEl = event.target as HTMLInputElement; + const normalized = normalizeHexColor(inputEl.value); + if (normalized) { + this.valueChange.emit(normalized); + inputEl.value = normalized; + } else { + inputEl.value = this.value(); + } + } + + protected reset(): void { + this.valueChange.emit(''); + } +} diff --git a/src/app/theming/theming-routes-data.ts b/src/app/theming/theming-routes-data.ts index a3a73cff12..91182ac677 100644 --- a/src/app/theming/theming-routes-data.ts +++ b/src/app/theming/theming-routes-data.ts @@ -12,5 +12,6 @@ export const themingRoutesData = { 'roundness': { displayName: 'Roundness', parentName: 'Themes' }, 'angular-sample': { displayName: 'Angular Material Theming', parentName: 'Themes' }, 'bootstrap-sample': { displayName: 'Bootstrap Theming', parentName: 'Themes' }, - 'card-sample-shadow': { displayName: 'card-sample-shadow', parentName: 'Shadows' } + 'card-sample-shadow': { displayName: 'card-sample-shadow', parentName: 'Shadows' }, + 'grid-theme-playground': { displayName: 'Grid Theme Playground', parentName: 'Themes' } }; diff --git a/src/app/theming/theming.routes.ts b/src/app/theming/theming.routes.ts index 2a0cd5e31b..b1e0d0aac8 100644 --- a/src/app/theming/theming.routes.ts +++ b/src/app/theming/theming.routes.ts @@ -4,6 +4,7 @@ import { AnimationsSample2Component } from './animations/animations-sample-2/ani import { AngularMaterialComponent } from './angular/angular-sample.component'; import { BootstrapComponent } from './bootstrap/bootstrap-sample.component'; import { DefaultThemeSampleComponent } from './default-theme-sample/default-theme-sample.component'; +import { GridThemePlaygroundComponent } from './grid-theme-playground/grid-theme-playground.component'; import { DisplayDensityComponent } from './display-density/display-density.component'; import { RoundnessComponent } from './roundness/roundness-sample.component'; import { CardSampleShadowComponent} from './shadows/card-sample-shadow/card-sample-shadow'; @@ -68,5 +69,10 @@ export const ThemingRoutes: Routes = [ component: TailwindSampleComponent, data: themingRoutesData['tailwind-sample'], path: 'tailwind-sample' + }, + { + component: GridThemePlaygroundComponent, + data: themingRoutesData['grid-theme-playground'], + path: 'grid-theme-playground' } ]; diff --git a/src/app/tree-grid/tree-grid-rowStyles-sample/tree-grid-rowStyle.component.ts b/src/app/tree-grid/tree-grid-rowStyles-sample/tree-grid-rowStyle.component.ts index b18c2bcc1a..324867face 100644 --- a/src/app/tree-grid/tree-grid-rowStyles-sample/tree-grid-rowStyle.component.ts +++ b/src/app/tree-grid/tree-grid-rowStyles-sample/tree-grid-rowStyle.component.ts @@ -25,7 +25,7 @@ export class TreeGridRowStylesComponent implements OnInit { row.data['Title'].includes('Senior') ? '#f8f9fa' : null; // eslint-disable-next-line @typescript-eslint/member-ordering - public rowStyles = { + public rowStyles: any = { background: this.background, 'border-left': (row: RowType) => row.data['Title'] === 'CEO' || row.data['Title'].includes('President') ? '2px solid' : null, diff --git a/src/app/tree-grid/tree-grid-style/layout.scss b/src/app/tree-grid/tree-grid-style/layout.scss index 0fda2fbb55..5c88726269 100644 --- a/src/app/tree-grid/tree-grid-style/layout.scss +++ b/src/app/tree-grid/tree-grid-style/layout.scss @@ -1,5 +1,9 @@ +:host { + display: block; +} + .grid__wrapper { - margin: 10px; + padding: 10px; } .cell__inner { diff --git a/src/app/tree-grid/tree-grid-style/tree-grid-style.component.html b/src/app/tree-grid/tree-grid-style/tree-grid-style.component.html index 9eeff6a075..751efd7181 100644 --- a/src/app/tree-grid/tree-grid-style/tree-grid-style.component.html +++ b/src/app/tree-grid/tree-grid-style/tree-grid-style.component.html @@ -1,6 +1,38 @@
- - +
+ Pick a theme + + + @for (theme of themes; track theme.class) { + + } + + +

+ Custom themes, not built-in: each is a grid-theme() with its + own background and accent. +

+
+ + +
@@ -8,8 +40,8 @@
- - - + + +
diff --git a/src/app/tree-grid/tree-grid-style/tree-grid-style.component.scss b/src/app/tree-grid/tree-grid-style/tree-grid-style.component.scss index 2c0d35a3be..9a14ff29e1 100644 --- a/src/app/tree-grid/tree-grid-style/tree-grid-style.component.scss +++ b/src/app/tree-grid/tree-grid-style/tree-grid-style.component.scss @@ -1,16 +1,141 @@ @use "layout.scss"; @use "igniteui-angular/theming" as *; -$background: #292826; -$foreground: #eeece1; -$accent: #ffcd0f; - -$custom-grid: grid-theme( - $background: $background, - $foreground: $foreground, - $accent-color: $accent, -); - -:host { - @include tokens($custom-grid); +$studio-bg: #faf4ed; +$studio-accent: #907aa9; +$ledger-bg: #eceff4; +$ledger-accent: #5e81ac; +$editorial-bg: #333c43; +$editorial-accent: #a7c080; +$midnight-bg: #282a36; +$midnight-accent: #bd93f9; + +.theme-studio { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0.6; + + @include tokens(grid-theme( + $background: $studio-bg, + $foreground: #575279, + $accent-color: $studio-accent, + $header-background: #fffaf3, + $header-border-color: #dfdad9, + $row-border-color: #f2e9e1, + $grid-border-color: #dfdad9, + $grid-shadow: (0 1px 3px rgba(87, 82, 121, 0.10), 0 1px 2px rgba(87, 82, 121, 0.06)) + )); +} + +.theme-ledger { + --ig-size: var(--ig-size-small); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $background: $ledger-bg, + $foreground: #2e3440, + $accent-color: $ledger-accent, + $header-background: #d8dee9, + $row-odd-background: #eceff4, + $row-even-background: #e5e9f0, + $body-column-border-color-odd: #d8dee9, + $body-column-border-color-even: #d8dee9, + $row-border-color: #d8dee9, + $grid-border-color: #c8d0dc + )); +} + +.theme-editorial { + --ig-size: var(--ig-size-large); + --ig-radius-factor: 0; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $editorial-bg, + $foreground: #d3c6aa, + $accent-color: $editorial-accent, + $header-background: #3a464c, + $row-border-color: #333c43, + $grid-border-color: #333c43 + )); +} + +.theme-midnight { + --ig-size: var(--ig-size-medium); + --ig-radius-factor: 0.25; + + @include tokens(grid-theme( + $schema: $dark-material-schema, + $background: $midnight-bg, + $foreground: #f8f8f2, + $accent-color: $midnight-accent, + $header-background: #21222c, + $body-column-border-color-odd: #44475a, + $body-column-border-color-even: #44475a, + $row-border-color: #44475a, + $grid-border-color: #44475a + )); +} + +.grid__wrapper { + display: flex; + flex-direction: column; + gap: 16px; +} + +.theme-picker { + --ig-button-group-elevation: 0; + + display: flex; + flex-direction: column; + gap: 6px; + align-self: flex-start; +} + +.theme-picker__label { + font-size: 12px; + font-weight: 500; + letter-spacing: 0.04em; + color: var(--ig-gray-700); +} + +.theme-picker__hint { + margin: 0; + font-size: 12px; + line-height: 1.45; + color: var(--ig-gray-600); + + code { + font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; + font-size: 11px; + } +} + +.theme-swatch { + display: inline-block; + min-width: 14px; + aspect-ratio: 1; + border-radius: 50%; + border: 1px solid var(--ig-gray-300); + vertical-align: -2px; + background: linear-gradient(135deg, var(--swatch-bg) 0 50%, var(--swatch-accent) 50% 100%); +} + +.theme-swatch--studio { + --swatch-bg: #{$studio-bg}; + --swatch-accent: #{$studio-accent}; +} + +.theme-swatch--ledger { + --swatch-bg: #{$ledger-bg}; + --swatch-accent: #{$ledger-accent}; +} + +.theme-swatch--editorial { + --swatch-bg: #{$editorial-bg}; + --swatch-accent: #{$editorial-accent}; +} + +.theme-swatch--midnight { + --swatch-bg: #{$midnight-bg}; + --swatch-accent: #{$midnight-accent}; } diff --git a/src/app/tree-grid/tree-grid-style/tree-grid-style.component.ts b/src/app/tree-grid/tree-grid-style/tree-grid-style.component.ts index 653f39c22b..f2a2472061 100644 --- a/src/app/tree-grid/tree-grid-style/tree-grid-style.component.ts +++ b/src/app/tree-grid/tree-grid-style/tree-grid-style.component.ts @@ -1,21 +1,35 @@ -import { Component, OnInit } from '@angular/core'; -import { EMPLOYEE_FLAT_AVATARS_DATA } from '../data/employees-flat-avatars'; -import { IgxTreeGridComponent } from 'igniteui-angular/grids/tree-grid'; -import { IgxCellTemplateDirective, IgxColumnComponent } from 'igniteui-angular/grids/core'; +import { Component, OnInit, signal } from '@angular/core'; import { IgxAvatarComponent } from 'igniteui-angular/avatar'; +import { IgxButtonGroupComponent } from 'igniteui-angular/button-group'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; +import { IgxCellTemplateDirective, IgxColumnComponent } from 'igniteui-angular/grids/core'; +import { IgxTreeGridComponent } from 'igniteui-angular/grids/tree-grid'; +import { EMPLOYEE_FLAT_AVATARS_DATA } from '../data/employees-flat-avatars'; import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive'; @Component({ selector: 'app-tree-grid-style', styleUrls: ['./tree-grid-style.component.scss'], templateUrl: './tree-grid-style.component.html', - imports: [IgxTreeGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxCellTemplateDirective, IgxAvatarComponent] + imports: [IgxTreeGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxCellTemplateDirective, IgxAvatarComponent, IgxButtonGroupComponent, IgxButtonDirective] }) export class TreeGridStyleComponent implements OnInit { public data: any[]; + public themes = [ + { label: 'Studio', class: 'theme-studio', swatch: 'theme-swatch--studio' }, + { label: 'Ledger', class: 'theme-ledger', swatch: 'theme-swatch--ledger' }, + { label: 'Editorial', class: 'theme-editorial', swatch: 'theme-swatch--editorial' }, + { label: 'Midnight', class: 'theme-midnight', swatch: 'theme-swatch--midnight' } + ]; + + public activeTheme = signal(this.themes[0].class); public ngOnInit() { this.data = EMPLOYEE_FLAT_AVATARS_DATA(); } + + public selectTheme(args: { index: number }) { + this.activeTheme.set(this.themes[args.index].class); + } } diff --git a/src/app/tree-grid/tree-grid-validation-style/tree-grid-validation-style.component.ts b/src/app/tree-grid/tree-grid-validation-style/tree-grid-validation-style.component.ts index dad7ada413..b6d515bcd4 100644 --- a/src/app/tree-grid/tree-grid-validation-style/tree-grid-validation-style.component.ts +++ b/src/app/tree-grid/tree-grid-validation-style/tree-grid-validation-style.component.ts @@ -17,7 +17,7 @@ export class TreeGridValidationStyleComponent implements OnInit { public data: IEmployee[]; public columns: any[]; public selectionMode = 'multiple'; - public rowStyles = { + public rowStyles: any = { background: (row: RowType) => row.cells.find(c => c.validation.errors !== null && c.validation.errors !== undefined) ? '#FF000033' : '#00000000' }; public cellStyles = { diff --git a/src/index.html b/src/index.html index 9920eced30..65e26031de 100644 --- a/src/index.html +++ b/src/index.html @@ -12,6 +12,12 @@ + + + diff --git a/src/server.ts b/src/server.ts index 72bf56bec2..3af8c6cd81 100644 --- a/src/server.ts +++ b/src/server.ts @@ -46,7 +46,13 @@ app.use('/**', (req, res, next) => { .then((response) => response ? writeResponseToNodeResponse(response, res) : next() ) - .catch(next); + .catch((error: unknown) => { + if (error instanceof Error && error.name === 'AbortError') { + return; + } + + next(error); + }); }); /** diff --git a/src/styles.scss b/src/styles.scss index 8c144ff6dd..03a2dd70b9 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -5,6 +5,14 @@ @use 'app-layout'; @import "tailwindcss"; +// The Ignite UI theme itself is deliberately NOT compiled into this file. Every +// sample is embedded in the documentation next to a theming widget that can +// switch it between the Material, Fluent, Bootstrap and Indigo themes in light +// or dark, so the theme is loaded as a swappable stylesheet instead - see the +// `igniteui-theme` link in index.html, the `assets/themes` entry in angular.json +// and `src/app/services/theme.service.ts`. A theme compiled in here would sit +// later in the cascade and win over the one the visitor picked. + // Specifies large size for all components to match the previous defaults // This may not be needed for your project. Please consult https://www.infragistics.com/products/ignite-ui-angular/angular/components/general/update-guide for more details. :root { @@ -19,6 +27,13 @@ body { margin: 0; } +// Nothing here paints a page background per color mode on purpose. The sample +// is embedded in an iframe and the documentation's Sample component draws the +// surface behind it from the same mode the theming widget posts down here, so +// the iframe is left transparent for it to show through. `ThemeService` still +// reflects `data-ig-theme` / `data-ig-mode` onto the root element for samples +// that need to react to the selection themselves. + body.custom-body:has( app-badge-overview, app-badge-styling, @@ -34,16 +49,8 @@ body.custom-body:has( background: transparent; } -@include core(); -@include typography(); -@include theme( - $palette: $palette, - $schema: $schema -); - -:root { - @include palette($palette); -} +// `core()`, `typography()`, `theme()` and the root palette all ship inside the +// prebuilt stylesheets loaded through the `igniteui-theme` link (see above). .light-theme { @include light-theme($palette);