Skip to content

Commit

Permalink
Fix sizing/overflow issues (#399)
Browse files Browse the repository at this point in the history
* Add truncation to breadcrumbs => adapt to the screen size, add @rx-angular/cdk and /template
* Fix shrinking sidebar, fix sidebar sidescroll, fix overflowing tooltips
* Fix entity heading overflow issue
  • Loading branch information
floydnant authored Apr 16, 2023
1 parent 9b27361 commit e66b924
Show file tree
Hide file tree
Showing 22 changed files with 631 additions and 250 deletions.
490 changes: 288 additions & 202 deletions client-v2/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions client-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
"@ngrx/effects": "^14.3.2",
"@ngrx/store": "^14.3.2",
"@ngrx/store-devtools": "^14.3.2",
"@rx-angular/cdk": "^14.0.0",
"@rx-angular/template": "^14.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.5.0",
"zone.js": "^0.12.0"
Expand Down
8 changes: 8 additions & 0 deletions client-v2/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ import { LayoutModule } from '@angular/cdk/layout'
import { IntersectionDirective } from './directives/intersection.directive'
import { EntityDescriptionComponent } from './components/molecules/entity-description/entity-description.component'
import { ApplicationinsightsAngularpluginErrorService } from '@microsoft/applicationinsights-angularplugin-js'
import { LetModule } from '@rx-angular/template/let'
import { IfModule } from '@rx-angular/template/if'
import { ForModule } from '@rx-angular/template/for'
import { PushModule } from '@rx-angular/template/push'

@NgModule({
declarations: [
Expand Down Expand Up @@ -141,6 +145,10 @@ import { ApplicationinsightsAngularpluginErrorService } from '@microsoft/applica
OverlayModule,
CdkTreeModule,
LayoutModule,
LetModule,
IfModule,
ForModule,
PushModule,
],
providers: [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
@apply inline-flex overflow-x-auto
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<span
class="inline-block cursor-text outline-none"
class="inline-block cursor-text overflow-x-auto outline-none"
[innerText]="text$ | async"
[class.show-placeholder]="!(textDomState$ | async)"
[class]="editorClass"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
:host-context(.no-delay) {
--reveal-delay: 0ms;
}
:host {
@apply box-border block max-w-xs rounded-lg border border-tinted-600/60 bg-tinted-700 glass py-1 px-2 text-sm text-tinted-100 shadow-xl;
@apply box-border block max-w-xs rounded-lg border border-tinted-600/60 bg-tinted-700 py-1 px-2 text-sm text-tinted-100 shadow-xl glass overflow-hidden;

animation: reveal 130ms 280ms forwards;
animation: reveal 130ms var(--reveal-delay, 280ms) forwards;
scale: 0.8;
opacity: 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
<ng-container *ngIf="asTemplate as template">
<ng-template [ngTemplateOutlet]="template"></ng-template>
</ng-container>

<ng-content></ng-content>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Inject, TemplateRef } from '@angular/core'
import { ChangeDetectionStrategy, Component, Inject, Optional, TemplateRef } from '@angular/core'
import { InjectionToken } from '@angular/core'

export type TooltipData = TemplateRef<void> | string
Expand All @@ -14,7 +14,7 @@ export const TOOLTIP_DATA = new InjectionToken<TooltipData>('tooltip.data')
},
})
export class TooltipComponent {
constructor(@Inject(TOOLTIP_DATA) public tooltipData: TooltipData) {}
constructor(@Optional() @Inject(TOOLTIP_DATA) public tooltipData?: TooltipData) {}

get asString(): string | false {
return typeof this.tooltipData === 'string' ? this.tooltipData : false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,80 @@
<!-- @TODO: Fix the header width issue (breadcrumbs taking more than allowed) -->
<div
class="breadcrumbs | flex w-full flex-wrap py-2 px-4 text-tinted-300"
class="breadcrumbs | flex w-full overflow-x-auto py-2 px-4 text-tinted-300"
cdkMenuBar
data-test-name="breadcrumbs-container"
#breadcrumbsContainer
>
<div *ngFor="let breadcrumb of breadcrumbs; let isLast = last; trackBy: trackByFn" class="flex max-w-[80%]">
<button
class="breadcrumb | menu-item | max-w-[20ch] truncate py-0.5 px-1.5"
[class.text-tinted-100]="isLast"
cdkMenuItem
[cdkContextMenuTriggerFor]="menu"
[routerLink]="breadcrumb.route"
#trigger="cdkContextMenuTriggerFor"
data-test-name="breadcrumb"
>
<!-- appTooltip="Here will be more information" -->
<ng-template #menu>
<app-drop-down
*ngIf="breadcrumb.contextMenuItems?.length"
[items]="breadcrumb.contextMenuItems!"
[rootTrigger]="trigger"
></app-drop-down>
<div *rxFor="let breadcrumb of breadcrumbs$; let isLast = last; trackBy: trackByFn" class="flex max-w-[80%]">
<!-- @TODO: some fuckery is going on here with the cdkMenuItem, destroying the menu bar flow and not acting like a proper menu item -->
<ng-container *ngIf="isTruncationBreadcrumb(breadcrumb)">
<button
class="truncation-breadcrumb | menu-item | truncate py-0.5 px-1.5 font-bold"
cdkMenuItem
cdkOverlayOrigin
#trigger="cdkOverlayOrigin"
(click)="isOverlayOpen$.next(!isOverlayOpen$.value)"
data-test-name="truncation-breadcrumb"
>
...
</button>

<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="trigger"
[cdkConnectedOverlayOpen]="(isOverlayOpen$ | async) ?? false"
(overlayOutsideClick)="closeOverlayDelayed()"
>
<app-tooltip class="bottom no-delay !border-tinted-800 !bg-tinted-900/70 !px-1">
<div class="flex flex-col text-base" cdkMenu data-test-name="truncated-breadcrumbs-container">
<div
*rxFor="
let truncatedBreadcrumb of breadcrumb.truncated;
let index = index;
trackBy: trackByFn
"
[style]="{ marginLeft: 0.5 * index + 'rem' }"
>
<ng-container
*ngTemplateOutlet="
breadcrumbTemplate;
context: { breadcrumb: truncatedBreadcrumb, isLast: false }
"
></ng-container>
</div>
</div>
</app-tooltip>
</ng-template>
</ng-container>

<ng-container *ngIf="!isTruncationBreadcrumb(breadcrumb)">
<ng-container *ngTemplateOutlet="breadcrumbTemplate; context: { breadcrumb, isLast }"></ng-container>
</ng-container>

<app-entity-page-label [pageTitle]="breadcrumb.title" [pageIcon]="breadcrumb.icon"></app-entity-page-label>
</button>
<span class="seperator | mx-0.5 text-tinted-500" *ngIf="!isLast">/</span>
<span class="separator | mx-0.5 text-tinted-500" *ngIf="!isLast">/</span>
</div>
</div>

<ng-template #breadcrumbTemplate let-breadcrumb="breadcrumb" let-isLast="isLast">
<button
*ngIf="!isTruncationBreadcrumb(breadcrumb)"
class="breadcrumb | menu-item | max-w-[20ch] truncate py-0.5 px-1.5"
[class.text-tinted-100]="isLast"
cdkMenuItem
[cdkContextMenuTriggerFor]="menu"
[routerLink]="breadcrumb.route"
(click)="closeOverlayDelayed()"
#trigger="cdkContextMenuTriggerFor"
data-test-name="breadcrumb"
>
<!-- appTooltip="Here will be more information" -->
<ng-template #menu>
<app-drop-down
*ngIf="breadcrumb.contextMenuItems?.length"
[items]="breadcrumb.contextMenuItems!"
[rootTrigger]="trigger"
></app-drop-down>
</ng-template>

<app-entity-page-label [pageTitle]="breadcrumb.title" [pageIcon]="breadcrumb.icon"></app-entity-page-label>
</button>
</ng-template>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'

import { BreadcrumbsComponent } from './breadcrumbs.component'
import { menuServiceMock } from 'src/app/utils/unit-test.mocks'

describe('BreadcrumbsComponent', () => {
let component: BreadcrumbsComponent
Expand All @@ -9,6 +10,7 @@ describe('BreadcrumbsComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [BreadcrumbsComponent],
providers: [menuServiceMock],
}).compileComponents()

fixture = TestBed.createComponent(BreadcrumbsComponent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@ import { EntityPageLabelComponent } from '../../atoms/entity-page-label/entity-p
import { IconsModule } from '../../atoms/icons/icons.module'
import { DropDownComponent, MenuItem } from '../drop-down/drop-down.component'
import { Breadcrumb, BreadcrumbsComponent } from './breadcrumbs.component'
import { OverlayModule } from '@angular/cdk/overlay'
import { DeviceService } from 'src/app/services/device.service'
import { TooltipComponent } from '../../atoms/tooltip/tooltip.component'
import { ForModule } from '@rx-angular/template/for'
import { menuServiceMock } from 'src/app/utils/unit-test.mocks'

const defaultTemplate = `<app-breadcrumbs [breadcrumbs]="breadcrumbs"></app-breadcrumbs>`
const setupComponent = (breadcrumbs: Breadcrumb[], template = defaultTemplate) => {
cy.mount(template, {
componentProperties: {
breadcrumbs,
},
imports: [CdkMenuModule, IconsModule],
declarations: [BreadcrumbsComponent, EntityPageLabelComponent, DropDownComponent],
componentProperties: { breadcrumbs },
imports: [CdkMenuModule, IconsModule, OverlayModule, ForModule],
declarations: [BreadcrumbsComponent, EntityPageLabelComponent, DropDownComponent, TooltipComponent],
providers: [DeviceService, menuServiceMock],
})
}

describe('BreadcrumbsComponent', () => {
it('displays given breadcrumbs', () => {
cy.viewport('macbook-13')
const breadcrumbs: Breadcrumb[] = [
{ title: 'Root list', icon: 'workspace', route: '/' },
{ title: 'Nested list', icon: 'workspace', route: '/nested' },
Expand All @@ -32,6 +37,7 @@ describe('BreadcrumbsComponent', () => {
// @TODO: Navigation through clicking a breadcrumb must be tested in e2e

it('can open a context menu', () => {
cy.viewport('macbook-13')
const menuItems: MenuItem[] = [{ title: 'test' }]
const breadcrumbs: Breadcrumb[] = [
{ title: 'Root list', icon: 'workspace', route: '/', contextMenuItems: menuItems },
Expand All @@ -44,4 +50,59 @@ describe('BreadcrumbsComponent', () => {
cy.get(testName('breadcrumb')).first().rightclick()
cy.get(testName('drop-down-menu')).should('exist')
})

describe('Truncation', () => {
const menuItems: MenuItem[] = [{ title: 'test' }]
const breadcrumbs: Breadcrumb[] = [
{ title: 'Root list', icon: 'workspace', route: '/', contextMenuItems: menuItems },
{ title: '1. Nested list', icon: 'workspace', route: '/ne', contextMenuItems: menuItems },
{ title: '2. Nested list', icon: 'workspace', route: '/ne/ne', contextMenuItems: menuItems },
{ title: '3. Nested list', icon: 'workspace', route: '/ne/ne/ne', contextMenuItems: menuItems },
{ title: '4. Nested list', icon: 'workspace', route: '/ne/ne/ne/ne', contextMenuItems: menuItems },
{ title: '5. Nested list', icon: 'workspace', route: '/ne/ne/ne/ne/ne', contextMenuItems: menuItems },
{ title: '6. Nested list', icon: 'workspace', route: '/ne/ne/ne/ne/ne/ne', contextMenuItems: menuItems },
]

it('truncates breadcrumbs on tablets', () => {
cy.viewport('ipad-mini')
setupComponent(breadcrumbs)

cy.get(testName('breadcrumb')).should('have.length', 4)
cy.get(testName('truncation-breadcrumb')).should('exist')
})
it('truncates breadcrumbs on desktops', () => {
cy.viewport('macbook-13')
setupComponent(breadcrumbs)

cy.get(testName('breadcrumb')).should('have.length', 7)
cy.get(testName('truncation-breadcrumb')).should('not.exist')
})

it('truncates breadcrumbs on mobile', () => {
cy.viewport('iphone-6')
setupComponent(breadcrumbs)

cy.get(testName('breadcrumb')).should('have.length', 1)
cy.get(testName('truncation-breadcrumb')).should('exist')
})

it('can show the truncated breadcrumbs', () => {
setupComponent(breadcrumbs)

cy.get(testName('truncation-breadcrumb')).click()
cy.get(testName('truncated-breadcrumbs-container')).within(() => {
cy.get(testName('breadcrumb')).should('have.length', 5)
})
})

it('can access context menu', () => {
setupComponent(breadcrumbs)

cy.get(testName('truncation-breadcrumb')).click()
cy.get(testName('truncated-breadcrumbs-container')).within(() => {
cy.get(testName('breadcrumb')).first().rightclick()
})
cy.get(testName('drop-down-menu')).should('exist')
})
})
})
Loading

0 comments on commit e66b924

Please sign in to comment.