Skip to content

Commit

Permalink
tryout split panels
Browse files Browse the repository at this point in the history
  • Loading branch information
vmarc committed Aug 14, 2024
1 parent 98fffc6 commit 37d2c3f
Show file tree
Hide file tree
Showing 8 changed files with 397 additions and 3 deletions.
18 changes: 16 additions & 2 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@sentry/cli": "^2.32.1",
"@swimlane/ngx-charts": "^20.5.0",
"@types/file-saver": "^2.0.7",
"angular-split": "^17.2.0",
"canvg": "^4.0.2",
"file-saver-es": "^2.0.5",
"immutable": "^5.0.0-beta.5",
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/app/app-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ export const appRoutes: Routes = [
loadComponent: () =>
import('./tryout/tabs/tryout-tabs-page.component').then((m) => m.TryoutTabsPageComponent),
},
{
path: 'tryout-panels',
loadComponent: () =>
import('./tryout/panels/tryout-panels-page.component').then(
(m) => m.TryoutPanelsPageComponent
),
},
{
path: 'tryout-panels-1',
loadComponent: () =>
import('./tryout/panels/tryout-panels-page-1.component').then(
(m) => m.TryoutPanelsPage1Component
),
},
{
path: 'analysis',
loadChildren: () => import('@app/analysis/analysis').then((m) => m.analysisRoutes),
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { PoiNameService } from '@app/services';
import { SpinnerInterceptor } from '@app/spinner';
import { SpinnerService } from '@app/spinner';
import * as Sentry from '@sentry/angular';
import { AngularSplitModule } from 'angular-split';
import { MarkdownModule } from 'ngx-markdown';
import { appRoutes } from './app-routes';
import { UserService } from './shared/user';
Expand All @@ -50,7 +51,8 @@ export const appConfig: ApplicationConfig = {
MatIconModule,
MatSidenavModule,
MatButtonModule,
MatDialogModule
MatDialogModule,
AngularSplitModule
),
{
provide: ErrorHandler,
Expand Down
90 changes: 90 additions & 0 deletions frontend/src/app/tryout/panels/resizeable.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Directive, ElementRef, Input, OnInit } from '@angular/core';

@Directive({
standalone: true,
selector: '[appResizable]',
})
export class ResizableDirective implements OnInit {
@Input() resizableGrabWidth = 8;
@Input() resizableMinWidth = 10;

dragging = false;

constructor(private el: ElementRef) {
const self = this;

const EventListenerMode = { capture: true };

function preventGlobalMouseEvents() {
document.body.style['pointer-events'] = 'none';
}

function restoreGlobalMouseEvents() {
document.body.style['pointer-events'] = 'auto';
}

const newWidth = (wid) => {
const newWidth = Math.max(this.resizableMinWidth, wid);
el.nativeElement.style.width = newWidth + 'px';
};

const mouseMoveG = (evt) => {
if (!this.dragging) {
return;
}
newWidth(evt.clientX - el.nativeElement.offsetLeft);
evt.stopPropagation();
};

const dragMoveG = (evt) => {
if (!this.dragging) {
return;
}
const newWidth =
Math.max(this.resizableMinWidth, evt.clientX - el.nativeElement.offsetLeft) + 'px';
el.nativeElement.style.width = evt.clientX - el.nativeElement.offsetLeft + 'px';
evt.stopPropagation();
};

const mouseUpG = (evt) => {
if (!this.dragging) {
return;
}
restoreGlobalMouseEvents();
this.dragging = false;
evt.stopPropagation();
};

const mouseDown = (evt) => {
if (this.inDragRegion(evt)) {
this.dragging = true;
preventGlobalMouseEvents();
evt.stopPropagation();
}
};

const mouseMove = (evt) => {
if (this.inDragRegion(evt) || this.dragging) {
el.nativeElement.style.cursor = 'col-resize';
} else {
el.nativeElement.style.cursor = 'default';
}
};

document.addEventListener('mousemove', mouseMoveG, true);
document.addEventListener('mouseup', mouseUpG, true);
el.nativeElement.addEventListener('mousedown', mouseDown, true);
el.nativeElement.addEventListener('mousemove', mouseMove, true);
}

ngOnInit(): void {
this.el.nativeElement.style['border-right'] = this.resizableGrabWidth + 'px solid darkgrey';
}

inDragRegion(evt) {
return (
this.el.nativeElement.clientWidth - evt.clientX + this.el.nativeElement.offsetLeft <
this.resizableGrabWidth
);
}
}
85 changes: 85 additions & 0 deletions frontend/src/app/tryout/panels/tryout-panels-menu.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ChangeDetectionStrategy } from '@angular/core';
import { Component } from '@angular/core';
import { MatIconButton } from '@angular/material/button';
import { MatButton } from '@angular/material/button';
import { MatIcon } from '@angular/material/icon';

@Component({
selector: 'kpn-tryout-panels-menu',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div>
<div [class]="menuItemClasses('analysis')">
<button mat-icon-button (click)="select('analysis')">
<mat-icon svgIcon="analysis" />
</button>
</div>
<div [class]="menuItemClasses('layers')">
<button mat-icon-button (click)="select('layers')">
<mat-icon svgIcon="layers" />
</button>
</div>
<div [class]="menuItemClasses('link')">
<button mat-icon-button (click)="select('link')">
<mat-icon svgIcon="link" />
</button>
</div>
<div [class]="menuItemClasses('changes')">
<button mat-icon-button (click)="select('changes')">
<mat-icon svgIcon="changes" />
</button>
</div>
<div [class]="menuItemClasses('external-link')">
<button mat-icon-button (click)="select('external-link')">
<mat-icon svgIcon="external-link" />
</button>
</div>
<div [class]="menuItemClasses('output')">
<button mat-icon-button (click)="select('output')">
<mat-icon svgIcon="output" />
</button>
</div>
<div [class]="menuItemClasses('overview')">
<button mat-icon-button (click)="select('overview')">
<mat-icon svgIcon="overview" />
</button>
</div>
<div [class]="menuItemClasses('video')">
<button mat-icon-button (click)="select('video')">
<mat-icon svgIcon="video" />
</button>
</div>
</div>
`,
styles: `
.icon-menu-item {
display: block;
}
.icon-menu-item-selected {
border-top: 1px solid lightgray;
border-bottom: 1px solid lightgray;
background-color: rgb(250, 250, 250);
}
.icon-menu-item-unselected {
border-right: 1px solid lightgray;
}
`,
standalone: true,
imports: [MatButton, MatIcon, MatIconButton],
})
export class TryoutPanelsMenuComponent {
selected = 'analysis';

menuItemClasses(name: string): string {
if (this.selected === name) {
return 'icon-menu-item icon-menu-item-selected';
}
return 'icon-menu-item icon-menu-item-unselected';
}

select(name: string): void {
this.selected = name;
}
}
102 changes: 102 additions & 0 deletions frontend/src/app/tryout/panels/tryout-panels-page-1.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { ChangeDetectionStrategy } from '@angular/core';
import { Component } from '@angular/core';
import { MatButton } from '@angular/material/button';
import { MatToolbar } from '@angular/material/toolbar';
import { RouterLink } from '@angular/router';
import { SpinnerComponent } from '@app/spinner';
import { ResizableDirective } from './resizeable.directive';
import { TryoutPanelsMenuComponent } from './tryout-panels-menu.component';

@Component({
selector: 'kpn-tryout-panels-page-1',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<header>
<mat-toolbar>
<button mat-button routerLink="/" class="toolbar-app-name">
<div i18n="@@toolbar.title">knooppuntnet</div>
</button>
<kpn-spinner />
</mat-toolbar>
</header>
<main class="page-contents">
<div class="container">
<kpn-tryout-panels-menu />
<div class="div1" appResizable>
<p>Sidebar contents</p>
</div>
<div class="div2" [resizableMinWidth]="30" appResizable>
<p>Text details</p>
</div>
<div class="div3" appResizable>
<p>Map</p>
</div>
</div>
</main>
`,
styles: `
.toolbar-app-name {
margin-left: 8px;
font-size: 20px;
font-weight: 400;
letter-spacing: 0.0125em;
}
mat-toolbar {
border-bottom: solid 1px lightgray;
}
.mat-toolbar-row,
.mat-toolbar-single-row {
height: 47px;
}
.page-contents {
display: flex;
min-height: calc(100vh - 48px);
flex-direction: column;
}
.container {
display: flex;
justify-content: flex-start;
flex-direction: row;
}
.div1 {
position: relative;
width: 20vw;
height: calc(100vh - 48px);
flex-grow: 0;
background-color: rgb(250, 250, 250);
}
.div2 {
position: relative;
width: 40vw;
height: calc(100vh - 48px);
flex-grow: 0;
}
.div3 {
position: relative;
width: 40vw;
height: calc(100vh - 48px);
flex-grow: 0;
}
p {
padding: 1em;
}
`,
standalone: true,
imports: [
ResizableDirective,
MatButton,
MatToolbar,
RouterLink,
SpinnerComponent,
TryoutPanelsMenuComponent,
],
})
export class TryoutPanelsPage1Component {}
Loading

0 comments on commit 37d2c3f

Please sign in to comment.