Skip to content

Commit

Permalink
feat: adds toolbar to the demo app
Browse files Browse the repository at this point in the history
- Added new demo tasks in VSCode for serving and affected tasks.
- Updated global styles in styles.scss for consistent layout.
- Refactored app.component to remove NxWelcomeComponent and implement a new layout with NavBarComponent.
- Improved app routing to include feature flags and home components.
- Removed deprecated NxWelcomeComponent.
- Updated feature flags service to use BehaviorSubject for state management.
- Enhanced dev-toolbar styles and component structure for better maintainability.
- Updated package-lock.json with new dependencies and versions.
  • Loading branch information
alfredoperez committed Dec 30, 2024
1 parent 7926089 commit 29cd138
Show file tree
Hide file tree
Showing 24 changed files with 1,090 additions and 1,039 deletions.
27 changes: 27 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,33 @@
"showReuseMessage": false
},
"problemMatcher": []
},
{
"label": "▶️ [Demo] Serve",
"type": "shell",
"command": "nx",
"args": ["serve", "ngx-dev-toolbar-demo"],
"problemMatcher": ["$tsc-watch"],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"group": "demo-tasks",
"close": false
},
"isBackground": true
},
{
"label": "🔄 Affected Tasks",
"type": "shell",
"command": "nx",
"args": ["affected", "-t", "lint,test,build,e2e"],

"presentation": {
"reveal": "always",
"panel": "dedicated",
"group": "affected-tasks",
"close": false
}
}
]
}
2 changes: 1 addition & 1 deletion apps/ngx-dev-toolbar-demo/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<app-nx-welcome></app-nx-welcome>

<router-outlet></router-outlet>
20 changes: 6 additions & 14 deletions apps/ngx-dev-toolbar-demo/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
import { TestBed } from '@angular/core/testing';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { NxWelcomeComponent } from './nx-welcome.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AppComponent, NxWelcomeComponent, RouterModule.forRoot([])],
imports: [AppComponent, NoopAnimationsModule, RouterModule.forRoot([])],
}).compileComponents();
});

it('should render title', () => {
it('should render app component', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain(
'Welcome ngx-dev-toolbar-demo'
);
});
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
})

it(`should have as title 'ngx-dev-toolbar-demo'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('ngx-dev-toolbar-demo');
});
});
97 changes: 89 additions & 8 deletions apps/ngx-dev-toolbar-demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,94 @@
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { NxWelcomeComponent } from './nx-welcome.component';
import { CommonModule } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { RouterOutlet } from '@angular/router';
import {
DevToolbarComponent,
DevToolbarFeatureFlagsService,
Flag,
} from 'ngx-dev-toolbar';
import { firstValueFrom, map } from 'rxjs';
import { NavBarComponent } from './components/nav-bar/nav-bar.component';
import { FeatureFlagsService } from './services/feature-flags.service';

@Component({
imports: [NxWelcomeComponent, RouterModule],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
standalone: true,
imports: [CommonModule, RouterOutlet, NavBarComponent, DevToolbarComponent],
template: `
@if (useNewLayout() ) {
<!-- New Modern Layout -->
<div class="modern-layout">
<app-nav-bar />
<main class="modern-content">
<router-outlet />
</main>
</div>
} @else {
<!-- Original Layout -->
<div class="original-layout">
<app-nav-bar />
<main class="content">
<router-outlet />
</main>
</div>
}
<ndt-toolbar></ndt-toolbar>
`,
styles: [
`
.modern-layout {
min-height: 100vh;
background: #f8f9fa;
.modern-content {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
margin-top: 2rem;
}
}
.original-layout {
.content {
padding: 1rem;
}
}
`,
],
})
export class AppComponent {
title = 'ngx-dev-toolbar-demo';
export class AppComponent implements OnInit {
featureFlagsService = inject(FeatureFlagsService);
devToolbarFeatureFlagsService = inject(DevToolbarFeatureFlagsService);

useNewLayout = toSignal(
this.featureFlagsService.select('newDemoApplicationLayout')
);

ngOnInit(): void {
this.loadFlags();
}

private async loadFlags(): Promise<void> {
// Gets the flags from the application and sets them in the dev toolbar
const flags: Flag[] = await firstValueFrom(
this.featureFlagsService.flags$.pipe(
map((flags) =>
flags.map(
(flag) =>
({
id: flag.name,
name: flag.name,
description: flag.description,
isEnabled: flag.enabled,
} as Flag)
)
)
)
);
this.devToolbarFeatureFlagsService.set(flags);
}
}
10 changes: 4 additions & 6 deletions apps/ngx-dev-toolbar-demo/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { ApplicationConfig } from '@angular/core';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideRouter } from '@angular/router';
import { appRoutes } from './app.routes';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(appRoutes),
],
providers: [provideRouter(routes), provideAnimations()],
};
17 changes: 15 additions & 2 deletions apps/ngx-dev-toolbar-demo/src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import { Route } from '@angular/router';
import { Routes } from '@angular/router';

export const appRoutes: Route[] = [];
export const routes: Routes = [
{
path: '',
loadComponent: () =>
import('./features/home/home.component').then((m) => m.HomeComponent),
},
{
path: 'feature-flags',
loadComponent: () =>
import('./features/feature-flags/feature-flags.component').then(
(m) => m.FeatureFlagsComponent
),
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive } from '@angular/router';

@Component({
selector: 'app-nav-bar',
standalone: true,
imports: [CommonModule, RouterLink, RouterLinkActive],
template: `
<nav class="nav-bar">
<div class="nav-content">
<a routerLink="/" class="nav-brand">Demo App</a>
<div class="nav-links">
<a
routerLink="/"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>Home</a
>
<a routerLink="/feature-flags" routerLinkActive="active"
>Feature Flags</a
>
</div>
</div>
</nav>
`,
styles: [
`
.nav-bar {
background: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.nav-content {
max-width: 1200px;
margin: 0 auto;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-brand {
font-size: 1.25rem;
font-weight: bold;
text-decoration: none;
color: #333;
}
.nav-links {
display: flex;
gap: 1.5rem;
a {
text-decoration: none;
color: #666;
transition: color 0.2s;
&:hover,
&.active {
color: #2196f3;
}
}
}
`,
],
})
export class NavBarComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { CommonModule } from '@angular/common';
import { Component, inject } from '@angular/core';
import { FeatureFlagsService } from '../../services/feature-flags.service';

@Component({
selector: 'app-feature-flags',
standalone: true,
imports: [CommonModule],
template: `
<div class="feature-flags-container">
<h1>Feature Flags</h1>
<div class="flags-list">
@for (flag of flags$ | async; track flag.name) {
<div class="flag-item">
<div class="flag-info">
<h3>{{ flag.name }}</h3>
<p>{{ flag.description }}</p>
</div>
<label class="switch">
<input
type="checkbox"
[checked]="flag.enabled"
(change)="toggleFlag(flag.name)"
/>
<span class="slider"></span>
</label>
</div>
}
</div>
</div>
`,
styles: [
`
.feature-flags-container {
padding: 2rem;
max-width: 800px;
margin: 0 auto;
}
.flags-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.flag-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background: #f5f5f5;
border-radius: 8px;
}
.flag-info h3 {
margin: 0;
font-size: 1.1rem;
}
.flag-info p {
margin: 0.5rem 0 0;
color: #666;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: 0.4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: '';
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
transition: 0.4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #2196f3;
}
input:checked + .slider:before {
transform: translateX(26px);
}
`,
],
})
export class FeatureFlagsComponent {
private readonly featureFlagsService = inject(FeatureFlagsService);
flags$ = this.featureFlagsService.flags$;

toggleFlag(flagName: string): void {
this.featureFlagsService.toggleFlag(flagName);
}
}
Loading

0 comments on commit 29cd138

Please sign in to comment.