From 655dbeef1ff8e499a18dcc67e87be6c28bc1253a Mon Sep 17 00:00:00 2001 From: larissa-kamily-brisa <138057627+larissa-kamily-brisa@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:08:22 -0300 Subject: [PATCH] style: adding dark theme styles in smart table (#1180) * style: adding dark theme styles in smart table * style: making changes requested in review * test: correcting sort button tests --- .../src/lib/pagination/_pagination.theme.scss | 44 +++++++ .../smart-table/smart-table.component.html | 2 +- .../smart-table/smart-table.component.spec.ts | 116 ++++++++++------- .../lib/smart-table/smart-table.component.ts | 6 +- projects/ion/src/lib/table/_table.theme.scss | 53 ++++++++ .../ion/src/lib/table/table.component.spec.ts | 117 +++++++++++------- projects/ion/src/lib/table/table.component.ts | 6 +- projects/ion/src/lib/utils/baseTable.ts | 37 ++++-- 8 files changed, 279 insertions(+), 102 deletions(-) diff --git a/projects/ion/src/lib/pagination/_pagination.theme.scss b/projects/ion/src/lib/pagination/_pagination.theme.scss index 6ae4956e3..e74a8a665 100644 --- a/projects/ion/src/lib/pagination/_pagination.theme.scss +++ b/projects/ion/src/lib/pagination/_pagination.theme.scss @@ -43,9 +43,53 @@ $default: ( ), ); +$dark: ( + text: ( + font-family: ion-theme(font-family-main), + font-weight: 600, + font-size: 14px, + ), + size: ( + sm: ( + size: 24px, + border-radius: 6px, + ), + md: ( + size: 32px, + border-radius: 8px, + ), + ), + page: ( + border-color: ion-theme(neutral-1), + background-color: ion-theme(neutral-4), + text-color: ion-theme(neutral-1), + hover: ( + border-color: ion-theme(primary-6), + background-color: ion-theme(primary-3), + text-color: ion-theme(primary-6), + ), + active: ( + border-color: ion-theme(primary-5), + background-color: ion-theme(neutral-4), + text-color: ion-theme(primary-5), + ), + selected: ( + border-color: ion-theme(primary-3), + background-color: ion-theme(neutral-4), + text-color: ion-theme(primary-3), + ), + disabled: ( + border-color: ion-theme(neutral-3), + background-color: ion-theme(neutral-6), + text-color: ion-theme(neutral-3), + ), + ), +); + @include register-component( pagination, ( default: $default, + dark: $dark, ) ); diff --git a/projects/ion/src/lib/smart-table/smart-table.component.html b/projects/ion/src/lib/smart-table/smart-table.component.html index 23d22a788..b87b3cc50 100644 --- a/projects/ion/src/lib/smart-table/smart-table.component.html +++ b/projects/ion/src/lib/smart-table/smart-table.component.html @@ -90,7 +90,7 @@ [attr.data-testid]="'row-' + index" [class.last-row]="last && !config.pagination" [ngClass]="{ - old: index % 2 === 0, + odd: index % 2 === 0, even: index % 2 !== 0, checked: row.selected }" diff --git a/projects/ion/src/lib/smart-table/smart-table.component.spec.ts b/projects/ion/src/lib/smart-table/smart-table.component.spec.ts index bb7c9d41f..3399c7bfe 100644 --- a/projects/ion/src/lib/smart-table/smart-table.component.spec.ts +++ b/projects/ion/src/lib/smart-table/smart-table.component.spec.ts @@ -21,6 +21,7 @@ import { EventTable, } from '../table/utilsTable'; import { IonTagModule } from '../tag/tag.module'; +import { IonFormattedThemes, IonThemeService } from '../theme'; import { IonTooltipModule } from '../tooltip/tooltip.module'; import { PipesModule } from '../utils/pipes/pipes.module'; import { SafeAny } from '../utils/safe-any'; @@ -28,12 +29,15 @@ import { IonSmartTableProps } from './../core/types/smart-table'; import { StatusType } from './../core/types/status'; import { IonLinkModule } from './../link/link.module'; import { IonSmartTableComponent } from './smart-table.component'; +import { + DARK_DISABLED_COLOR, + DARK_ENABLED_COLOR, + DISABLED_COLOR, + ENABLED_COLOR, +} from '../utils/baseTable'; registerLocaleData(localePT, 'pt-BR'); -const disabledArrowColor = 'var(--ion-neutral-4)'; -const enabledArrowColor = 'var(--ion-primary-6)'; - const columnTrigger = 'click'; const columns: Column[] = [ @@ -148,6 +152,18 @@ const propsWithPopover: IonSmartTableProps = { } as SafeAny, }; +const DEFAULT_THEME_CONFIG = { + key: 'light', +} as IonFormattedThemes; + +const DARK_THEME_CONFIG = { + key: 'dark', +} as IonFormattedThemes; + +const ionThemeServiceMock: Partial = { + theme: DEFAULT_THEME_CONFIG, +}; + const sut = async ( customProps: IonSmartTableProps = defaultProps ): Promise => { @@ -166,6 +182,7 @@ const sut = async ( IonSpinnerModule, IonLinkModule, ], + providers: [{ provide: IonThemeService, useValue: ionThemeServiceMock }], }); }; @@ -173,7 +190,6 @@ describe('IonSmartTableComponent', () => { beforeEach(async () => { await sut(); }); - it('should render table', async () => { expect(screen.getByTestId('ion-table')); }); @@ -966,47 +982,57 @@ describe('Table > Differents columns data type', () => { expect(screen.queryAllByTestId('sort-by-year')).toHaveLength(0); }); - it('should render arrow down blue when sort desc', async () => { - const orderBy = columns[0].key; - await sut(tableDifferentColumns); - fireEvent.click(screen.getByTestId('sort-by-' + orderBy)); - const arrowUp = screen.getByTestId('sort-by-' + orderBy).children[0]; - const arrowDown = screen.getByTestId('sort-by-' + orderBy).children[1]; - expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); - expect(arrowDown).toHaveAttribute('fill', enabledArrowColor); - }); - - it('should render arrow up blue when sort asc', async () => { - tableDifferentColumns.config.columns = [ - { - label: 'Albuns', - sort: true, - key: 'albuns', - }, - ]; - await sut(tableDifferentColumns); - fireEvent.click(screen.getByTestId('sort-by-albuns')); - fireEvent.click(screen.getByTestId('sort-by-albuns')); - const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; - const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; - expect(arrowUp).toHaveAttribute('fill', enabledArrowColor); - expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); - }); - - it('should render arrow up and arrow down gray when not sorted', async () => { - tableDifferentColumns.config.columns = [ - { - label: 'Albuns', - sort: true, - key: 'albuns', - }, - ]; - await sut(tableDifferentColumns); - const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; - const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; - expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); - expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); - }); + describe.each([ + { + label: 'default', + themeConfig: DEFAULT_THEME_CONFIG, + enabledArrowColor: ENABLED_COLOR, + disabledArrowColor: DISABLED_COLOR, + }, + { + label: 'dark', + themeConfig: DARK_THEME_CONFIG, + enabledArrowColor: DARK_ENABLED_COLOR, + disabledArrowColor: DARK_DISABLED_COLOR, + }, + ])( + '$label theme', + ({ themeConfig, enabledArrowColor, disabledArrowColor }) => { + beforeEach(async () => { + ionThemeServiceMock.theme = cloneDeep(themeConfig); + tableDifferentColumns.config.columns = [ + { label: 'Albuns', sort: true, key: 'albuns' }, + ]; + await sut(tableDifferentColumns); + }); + + it('should render arrow down in primary color when sort desc', () => { + const orderBy = tableDifferentColumns.config.columns[0].key; + fireEvent.click(screen.getByTestId('sort-by-' + orderBy)); + const arrowUp = screen.getByTestId('sort-by-' + orderBy).children[0]; + const arrowDown = screen.getByTestId('sort-by-' + orderBy) + .children[1]; + expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); + expect(arrowDown).toHaveAttribute('fill', enabledArrowColor); + }); + + it('should render arrow up in primary color when sort asc', () => { + fireEvent.click(screen.getByTestId('sort-by-albuns')); + fireEvent.click(screen.getByTestId('sort-by-albuns')); + const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; + const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; + expect(arrowUp).toHaveAttribute('fill', enabledArrowColor); + expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); + }); + + it('should render arrow up and arrow down in neutral color when not sorted', () => { + const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; + const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; + expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); + expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); + }); + } + ); it('should only emit sort action after a given debounce time', async () => { const debounceTime = 2000; diff --git a/projects/ion/src/lib/smart-table/smart-table.component.ts b/projects/ion/src/lib/smart-table/smart-table.component.ts index f6a20d4b4..f40b9611b 100644 --- a/projects/ion/src/lib/smart-table/smart-table.component.ts +++ b/projects/ion/src/lib/smart-table/smart-table.component.ts @@ -1,3 +1,4 @@ +import { IonThemeService } from './../theme/theme.service'; import { AfterViewChecked, ChangeDetectorRef, @@ -38,7 +39,10 @@ export class IonSmartTableComponent public sortWithDebounce: (column: Column) => void; private firstLoad = true; - constructor(private cdr: ChangeDetectorRef) { + constructor( + private cdr: ChangeDetectorRef, + protected ionThemeService: IonThemeService + ) { super(); } diff --git a/projects/ion/src/lib/table/_table.theme.scss b/projects/ion/src/lib/table/_table.theme.scss index a623afc27..e3a6726dd 100644 --- a/projects/ion/src/lib/table/_table.theme.scss +++ b/projects/ion/src/lib/table/_table.theme.scss @@ -52,9 +52,62 @@ $default: ( ), ); +$dark: ( + border-radius: 8px, + header-divider-color: ion-theme(neutral-1), + sort-button: ( + hover-background-color: ion-theme(neutral-7), + focus-background-color: ion-theme(primary-1), + active-background-color: ion-theme(primary-4), + disabled-hover-background-color: ion-theme(neutral-6), + ), + row: ( + th: ( + background-color: ion-theme(neutral-5), + text: ( + font-size: 16px, + font-weight: 600, + line-height: 22px, + color: ion-theme(neutral-1), + ), + ), + td: ( + icon-color: ion-theme(primary-3), + text: ( + font-size: 14px, + font-weight: 400, + line-height: 20px, + color: ion-theme(neutral-1), + ), + ), + hover-background-color: ion-theme(primary-8), + odd-background-color: ion-theme(neutral-6), + even-background-color: ion-theme(neutral-5), + checkbox-shadow: -2px 0 0 0 ion-theme(primary-8), + ), + no-data: ( + text-color: ion-theme(neutral-1), + background-color: ion-theme(neutral-5), + icon-color: ion-theme(neutral-1), + ), + footer: ( + divider-color: ion-theme(neutral-3), + background-color: ion-theme(neutral-5), + text: ( + font-family: ion-theme(font-family-main), + font-style: normal, + font-weight: 400, + font-size: 14px, + line-height: 20px, + color: ion-theme(neutral-1), + ), + ), +); + @include register-component( table, ( default: $default, + dark: $dark, ) ); diff --git a/projects/ion/src/lib/table/table.component.spec.ts b/projects/ion/src/lib/table/table.component.spec.ts index 402ef170f..f27068844 100644 --- a/projects/ion/src/lib/table/table.component.spec.ts +++ b/projects/ion/src/lib/table/table.component.spec.ts @@ -34,12 +34,16 @@ import { ColumnType, ConfigTable, } from './utilsTable'; +import { IonFormattedThemes, IonThemeService } from '../theme'; +import { + DARK_DISABLED_COLOR, + DARK_ENABLED_COLOR, + DISABLED_COLOR, + ENABLED_COLOR, +} from '../utils/baseTable'; registerLocaleData(localePT, 'pt-BR'); -const disabledArrowColor = 'var(--ion-neutral-4)'; -const enabledArrowColor = 'var(--ion-primary-6)'; - const columns: Column[] = [ { key: 'id', @@ -111,6 +115,18 @@ const propsWithPopover: IonTableProps = { } as SafeAny, }; +const DEFAULT_THEME_CONFIG = { + key: 'light', +} as IonFormattedThemes; + +const DARK_THEME_CONFIG = { + key: 'dark', +} as IonFormattedThemes; + +const ionThemeServiceMock: Partial = { + theme: DEFAULT_THEME_CONFIG, +}; + const sut = async ( customProps: IonTableProps = defaultProps ): Promise => { @@ -129,6 +145,7 @@ const sut = async ( IonSpinnerModule, IonLinkModule, ], + providers: [{ provide: IonThemeService, useValue: ionThemeServiceMock }], }); }; @@ -287,6 +304,7 @@ describe('Table > Changes', () => { IonSpinnerModule, IonLinkModule, ], + providers: [{ provide: IonThemeService, useValue: ionThemeServiceMock }], }); const newData = [{ name: 'Meteora', deleted: false, id: 2 }]; propsToChange.config.data = [...newData]; @@ -311,6 +329,7 @@ describe('Table > Changes', () => { IonSpinnerModule, IonLinkModule, ], + providers: [{ provide: IonThemeService, useValue: ionThemeServiceMock }], }); propsToChange.config.data = []; rerender(propsToChange); @@ -788,46 +807,57 @@ describe('Table > Differents columns data type', () => { expect(screen.queryAllByTestId('btn-sort-by-year')).toHaveLength(0); }); - it('should render arrow down blue when sort desc', async () => { - await sut(tableDifferentColumns); - fireEvent.click(screen.getByTestId('sort-by-id')); - const arrowUp = screen.getByTestId('sort-by-id').children[0]; - const arrowDown = screen.getByTestId('sort-by-id').children[1]; - expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); - expect(arrowDown).toHaveAttribute('fill', enabledArrowColor); - }); - - it('should render arrow up blue when sort asc', async () => { - tableDifferentColumns.config.columns = [ - { - label: 'Albuns', - sort: true, - key: 'albuns', - }, - ]; - await sut(JSON.parse(JSON.stringify(tableDifferentColumns))); - fireEvent.click(screen.getByTestId('sort-by-albuns')); - fireEvent.click(screen.getByTestId('sort-by-albuns')); - const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; - const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; - expect(arrowUp).toHaveAttribute('fill', enabledArrowColor); - expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); - }); - - it('should render arrow up and arrow down gray when not sorted', async () => { - tableDifferentColumns.config.columns = [ - { - label: 'Albuns', - sort: true, - key: 'albuns', - }, - ]; - await sut(JSON.parse(JSON.stringify(tableDifferentColumns))); - const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; - const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; - expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); - expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); - }); + describe.each([ + { + label: 'default', + themeConfig: DEFAULT_THEME_CONFIG, + enabledArrowColor: ENABLED_COLOR, + disabledArrowColor: DISABLED_COLOR, + }, + { + label: 'dark', + themeConfig: DARK_THEME_CONFIG, + enabledArrowColor: DARK_ENABLED_COLOR, + disabledArrowColor: DARK_DISABLED_COLOR, + }, + ])( + '$label theme', + ({ themeConfig, enabledArrowColor, disabledArrowColor }) => { + beforeEach(async () => { + ionThemeServiceMock.theme = cloneDeep(themeConfig); + tableDifferentColumns.config.columns = [ + { label: 'Albuns', sort: true, key: 'albuns' }, + ]; + await sut(tableDifferentColumns); + }); + + it('should render arrow down in primary color when sort desc', () => { + const orderBy = tableDifferentColumns.config.columns[0].key; + fireEvent.click(screen.getByTestId('sort-by-' + orderBy)); + const arrowUp = screen.getByTestId('sort-by-' + orderBy).children[0]; + const arrowDown = screen.getByTestId('sort-by-' + orderBy) + .children[1]; + expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); + expect(arrowDown).toHaveAttribute('fill', enabledArrowColor); + }); + + it('should render arrow up in primary color when sort asc', () => { + fireEvent.click(screen.getByTestId('sort-by-albuns')); + fireEvent.click(screen.getByTestId('sort-by-albuns')); + const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; + const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; + expect(arrowUp).toHaveAttribute('fill', enabledArrowColor); + expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); + }); + + it('should render arrow up and arrow down in neutral color when not sorted', () => { + const arrowUp = screen.getByTestId('sort-by-albuns').children[0]; + const arrowDown = screen.getByTestId('sort-by-albuns').children[1]; + expect(arrowUp).toHaveAttribute('fill', disabledArrowColor); + expect(arrowDown).toHaveAttribute('fill', disabledArrowColor); + }); + } + ); }); }); @@ -1110,6 +1140,7 @@ const sutCustomRowTemplate = async ( IonSpinnerModule, IonLinkModule, ], + providers: [{ provide: IonThemeService, useValue: ionThemeServiceMock }], }); }; diff --git a/projects/ion/src/lib/table/table.component.ts b/projects/ion/src/lib/table/table.component.ts index 611fd780c..6d78753b2 100644 --- a/projects/ion/src/lib/table/table.component.ts +++ b/projects/ion/src/lib/table/table.component.ts @@ -1,3 +1,4 @@ +import { IonThemeService } from './../theme/theme.service'; import { ChangeDetectorRef, Component, @@ -32,7 +33,10 @@ export class IonTableComponent public mainCheckBoxState: CheckBoxStates = 'enabled'; public smartData = []; - constructor(private cdr: ChangeDetectorRef) { + constructor( + private cdr: ChangeDetectorRef, + protected ionThemeService: IonThemeService + ) { super(); } diff --git a/projects/ion/src/lib/utils/baseTable.ts b/projects/ion/src/lib/utils/baseTable.ts index a7cdcdf40..d42c76027 100644 --- a/projects/ion/src/lib/utils/baseTable.ts +++ b/projects/ion/src/lib/utils/baseTable.ts @@ -1,3 +1,4 @@ +import { IonThemeService } from './../theme/theme.service'; import { EventEmitter } from '@angular/core'; import { CurrencyPipeStrategy } from '../../core/pipes/currency.pipe'; @@ -12,8 +13,11 @@ import { } from '../core/types'; import { ActionTable, BaseRow, Column, ConfigTable } from '../table/utilsTable'; -const DISABLED_COLOR = 'var(--ion-neutral-4)'; -const ENABLED_COLOR = 'var(--ion-primary-6)'; +export const DISABLED_COLOR = 'var(--ion-neutral-4)'; +export const ENABLED_COLOR = 'var(--ion-primary-6)'; + +export const DARK_DISABLED_COLOR = 'var(--ion-neutral-3)'; +export const DARK_ENABLED_COLOR = 'var(--ion-primary-3)'; export abstract class BaseTable< RowType extends BaseRow, @@ -24,12 +28,13 @@ export abstract class BaseTable< public events: EventEmitter; public mainCheckBoxState: CheckBoxStates = 'enabled'; + protected abstract ionThemeService: IonThemeService; + public abstract sort(column: Column): void; public abstract paginationEvents(event: PageEvent): void; public abstract emitRowsSelected(): void; - public checkState(): void { if (this.mainCheckBoxState === CheckBoxEvent.indeterminate) { this.uncheckAllRows(); @@ -69,21 +74,31 @@ export abstract class BaseTable< } public fillColor(column: Column, upArrow: boolean): string { + const isDarkTheme = this.ionThemeService.theme.key === 'dark'; if (column.desc === null || column.desc === undefined) { - return DISABLED_COLOR; + return isDarkTheme ? DARK_DISABLED_COLOR : DISABLED_COLOR; } return upArrow - ? this.fillColorArrowUp(column) - : this.fillColorArrowDown(column); + ? this.fillArrow(column, 'up') + : this.fillArrow(column, 'down'); } - public fillColorArrowUp(column: Column): string { - return column.desc ? DISABLED_COLOR : ENABLED_COLOR; - } + public fillArrow(column: Column, direction: string): string { + const isDarkTheme = this.ionThemeService.theme.key === 'dark'; + + const themeMap = { + up: { + dark: column.desc ? DARK_DISABLED_COLOR : DARK_ENABLED_COLOR, + light: column.desc ? DISABLED_COLOR : ENABLED_COLOR, + }, + down: { + dark: column.desc ? DARK_ENABLED_COLOR : DARK_DISABLED_COLOR, + light: column.desc ? ENABLED_COLOR : DISABLED_COLOR, + }, + }; - public fillColorArrowDown(column: Column): string { - return column.desc ? ENABLED_COLOR : DISABLED_COLOR; + return isDarkTheme ? themeMap[direction].dark : themeMap[direction].light; } public handleEvent(row: RowType, action: (row: RowType) => void): void {