diff --git a/modules/ui/src/app/components/empty-message/empty-message.component.html b/modules/ui/src/app/components/empty-message/empty-message.component.html index 022048d97..7a6c479d1 100644 --- a/modules/ui/src/app/components/empty-message/empty-message.component.html +++ b/modules/ui/src/app/components/empty-message/empty-message.component.html @@ -1,7 +1,27 @@ -
+ +
empty message image
- {{ header() }} - {{ message() }} + + {{ header() }} + {{ message() }} + +
diff --git a/modules/ui/src/app/components/empty-message/empty-message.component.scss b/modules/ui/src/app/components/empty-message/empty-message.component.scss index d42b8dadd..fe2959929 100644 --- a/modules/ui/src/app/components/empty-message/empty-message.component.scss +++ b/modules/ui/src/app/components/empty-message/empty-message.component.scss @@ -1,11 +1,51 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ @use 'variables'; @use 'colors'; -.empty-message { +.empty-message.vertical { display: flex; flex-direction: column; align-items: center; - gap: 16px; + gap: 12px; + text-align: center; + .empty-message-main { + padding-top: 12px; + } +} + +.empty-message.horizontal { + display: grid; + grid-template-columns: auto 1fr; + align-items: end; + gap: 32px; + max-width: 764px; + .empty-message-img { + grid-row: 1 / 3; + width: 288px; + height: 199px; + justify-self: end; + } + .empty-message-text { + align-self: start; + padding-top: 12px; + } + .empty-message-main { + padding-top: 8px; + } } .empty-message-header { @@ -22,6 +62,7 @@ line-height: 24px; letter-spacing: 0.1px; color: colors.$on-surface-variant; + display: block; } .empty-message-img { diff --git a/modules/ui/src/app/components/empty-message/empty-message.component.spec.ts b/modules/ui/src/app/components/empty-message/empty-message.component.spec.ts index de43363d4..7fecdbff0 100644 --- a/modules/ui/src/app/components/empty-message/empty-message.component.spec.ts +++ b/modules/ui/src/app/components/empty-message/empty-message.component.spec.ts @@ -1,3 +1,18 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { EmptyMessageComponent } from './empty-message.component'; diff --git a/modules/ui/src/app/components/empty-message/empty-message.component.ts b/modules/ui/src/app/components/empty-message/empty-message.component.ts index ba200eb14..43a6689a8 100644 --- a/modules/ui/src/app/components/empty-message/empty-message.component.ts +++ b/modules/ui/src/app/components/empty-message/empty-message.component.ts @@ -1,8 +1,24 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import { Component, input } from '@angular/core'; +import { CommonModule } from '@angular/common'; @Component({ selector: 'app-empty-message', - imports: [], + imports: [CommonModule], templateUrl: './empty-message.component.html', styleUrl: './empty-message.component.scss', }) @@ -10,4 +26,5 @@ export class EmptyMessageComponent { image = input(); header = input(); message = input(); + isHorizontal = input(false); } diff --git a/modules/ui/src/app/components/empty-page/empty-page.component.html b/modules/ui/src/app/components/empty-page/empty-page.component.html new file mode 100644 index 000000000..4d67a06cf --- /dev/null +++ b/modules/ui/src/app/components/empty-page/empty-page.component.html @@ -0,0 +1,22 @@ + + + + diff --git a/modules/ui/src/app/components/empty-page/empty-page.component.spec.ts b/modules/ui/src/app/components/empty-page/empty-page.component.spec.ts new file mode 100644 index 000000000..fb842f6c4 --- /dev/null +++ b/modules/ui/src/app/components/empty-page/empty-page.component.spec.ts @@ -0,0 +1,37 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EmptyPageComponent } from './empty-page.component'; + +describe('EmptyPageComponent', () => { + let component: EmptyPageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [EmptyPageComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(EmptyPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/modules/ui/src/app/components/empty-page/empty-page.component.ts b/modules/ui/src/app/components/empty-page/empty-page.component.ts new file mode 100644 index 000000000..b5cbb6eda --- /dev/null +++ b/modules/ui/src/app/components/empty-page/empty-page.component.ts @@ -0,0 +1,28 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Component, input } from '@angular/core'; +import { EmptyMessageComponent } from '../empty-message/empty-message.component'; + +@Component({ + selector: 'app-empty-page', + imports: [EmptyMessageComponent], + templateUrl: './empty-page.component.html', +}) +export class EmptyPageComponent { + image = input(); + header = input(); + message = input(); +} diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.html b/modules/ui/src/app/components/list-layout/list-layout.component.html new file mode 100644 index 000000000..dedf67cd1 --- /dev/null +++ b/modules/ui/src/app/components/list-layout/list-layout.component.html @@ -0,0 +1,22 @@ + + + +

{{ title() }}

+
+ +
+
diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.scss b/modules/ui/src/app/components/list-layout/list-layout.component.scss new file mode 100644 index 000000000..956a7b1c4 --- /dev/null +++ b/modules/ui/src/app/components/list-layout/list-layout.component.scss @@ -0,0 +1,35 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@use 'mixins'; +@use 'colors'; +@use 'variables'; + +.content-empty { + @include mixins.content-empty; +} + +.title { + color: colors.$on-surface; + font-family: variables.$font-primary; + font-size: 32px; + font-style: normal; + font-weight: 400; + line-height: 40px; + &-empty { + padding: 24px 0 8px 32px; + margin: 0; + } +} diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.spec.ts b/modules/ui/src/app/components/list-layout/list-layout.component.spec.ts new file mode 100644 index 000000000..14ab06cd5 --- /dev/null +++ b/modules/ui/src/app/components/list-layout/list-layout.component.spec.ts @@ -0,0 +1,37 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ListLayoutComponent } from './list-layout.component'; + +describe('ListLayoutComponent', () => { + let component: ListLayoutComponent; + let fixture: ComponentFixture>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ListLayoutComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ListLayoutComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.ts b/modules/ui/src/app/components/list-layout/list-layout.component.ts new file mode 100644 index 000000000..3c97549b4 --- /dev/null +++ b/modules/ui/src/app/components/list-layout/list-layout.component.ts @@ -0,0 +1,30 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Component, input, TemplateRef } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-list-layout', + imports: [CommonModule], + templateUrl: './list-layout.component.html', + styleUrl: './list-layout.component.scss', +}) +export class ListLayoutComponent { + title = input(''); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + emptyContent = input>(); + entities = input([]); +} diff --git a/modules/ui/src/app/pages/devices/devices.component.html b/modules/ui/src/app/pages/devices/devices.component.html index f6567b49e..18db165cc 100644 --- a/modules/ui/src/app/pages/devices/devices.component.html +++ b/modules/ui/src/app/pages/devices/devices.component.html @@ -14,7 +14,7 @@ limitations under the License. --> - +

Devices

@@ -36,21 +36,28 @@

Devices

+ + + + -
+ -
+
diff --git a/modules/ui/src/app/pages/devices/devices.component.scss b/modules/ui/src/app/pages/devices/devices.component.scss index 4b14c01b8..4e49b90f8 100644 --- a/modules/ui/src/app/pages/devices/devices.component.scss +++ b/modules/ui/src/app/pages/devices/devices.component.scss @@ -42,3 +42,10 @@ gap: 16px; overflow-y: auto; } + +.device-add-button { + font-family: variables.$font-text; + margin-bottom: 12px; + width: fit-content; + height: 56px; +} diff --git a/modules/ui/src/app/pages/devices/devices.component.spec.ts b/modules/ui/src/app/pages/devices/devices.component.spec.ts index 5c8a1602f..2de0b9bb4 100644 --- a/modules/ui/src/app/pages/devices/devices.component.spec.ts +++ b/modules/ui/src/app/pages/devices/devices.component.spec.ts @@ -103,9 +103,7 @@ describe('DevicesComponent', () => { }); it('should show only add device button if no device added', () => { - const button = compiled.querySelector( - '.device-repository-content-empty button' - ); + const button = compiled.querySelector('app-empty-page button'); expect(button).toBeTruthy(); }); diff --git a/modules/ui/src/app/pages/devices/devices.component.ts b/modules/ui/src/app/pages/devices/devices.component.ts index 5b8d74463..685a8ba12 100644 --- a/modules/ui/src/app/pages/devices/devices.component.ts +++ b/modules/ui/src/app/pages/devices/devices.component.ts @@ -52,6 +52,8 @@ import { ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatInputModule } from '@angular/material/input'; import { DeviceItemComponent } from '../../components/device-item/device-item.component'; +import { EmptyPageComponent } from '../../components/empty-page/empty-page.component'; +import { ListLayoutComponent } from '../../components/list-layout/list-layout.component'; export enum FormAction { Delete = 'Delete', @@ -80,6 +82,8 @@ export interface FormResponse { MatCheckboxModule, MatInputModule, DeviceItemComponent, + EmptyPageComponent, + ListLayoutComponent, ], providers: [DevicesStore], }) diff --git a/modules/ui/src/assets/icons/empty-devices.svg b/modules/ui/src/assets/icons/empty-devices.svg new file mode 100644 index 000000000..50a6e1e73 --- /dev/null +++ b/modules/ui/src/assets/icons/empty-devices.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +