Refactor controls UI, styles; bump deps

Consolidate and refactor component styling and markup: remove component-specific SCSS for Conway's Game of Life and Pathfinding and drop their styleUrls, rename per-component .controls blocks to .controls-panel in pathfinding and sorting templates, and move the outer container class onto the mat-card. Add global styles in src/styles.scss for .controls-panel, grid/form sizing, container max-width, and sorting visualization (bar states and transitions). Also update package-lock.json with minor/patch dependency bumps for Angular CLI/devkit/schematics/@schematics/angular, @modelcontextprotocol/sdk and several transitive packages.
This commit is contained in:
2026-02-06 15:06:54 +01:00
parent 59148db295
commit 3795090cea
9 changed files with 212 additions and 67 deletions

180
package-lock.json generated
View File

@@ -306,13 +306,13 @@
}
},
"node_modules/@angular-devkit/schematics": {
"version": "21.1.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.1.2.tgz",
"integrity": "sha512-PA3gkiFhHUuXd2XuP7yzKg/9N++bjw+uOl473KwIsMuZwMPhncKa4+mUYBaffDoPqaujZvjfo6mjtCBuiBv05w==",
"version": "21.1.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.1.3.tgz",
"integrity": "sha512-Ps7bRl5uOcM7WpNJHbSls/jz5/wAI0ldkTlKyiBFA7RtNeQIABAV+hvlw5DJuEb1Lo5hnK0hXj90AyZdOxzY+w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-devkit/core": "21.1.2",
"@angular-devkit/core": "21.1.3",
"jsonc-parser": "3.3.1",
"magic-string": "0.30.21",
"ora": "9.0.0",
@@ -324,6 +324,34 @@
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": {
"version": "21.1.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.1.3.tgz",
"integrity": "sha512-huEXd1tWQHwwN+0VGRT+vSVplV0KNrGFUGJzkIW6iJE1SQElxn6etMai+pSd5DJcePkx6+SuscVsxbfwf70hnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"jsonc-parser": "3.3.1",
"picomatch": "4.0.3",
"rxjs": "7.8.2",
"source-map": "0.7.6"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^5.0.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@angular-eslint/builder": {
"version": "21.2.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.2.0.tgz",
@@ -565,19 +593,19 @@
}
},
"node_modules/@angular/cli": {
"version": "21.1.2",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.1.2.tgz",
"integrity": "sha512-AHjXCBl2PEilMJct6DX3ih5Fl5PiKpNDIj0ViTyVh1YcfpYjt6NzhVlV2o++8VNPNH/vMcmf2551LZIDProXXA==",
"version": "21.1.3",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.1.3.tgz",
"integrity": "sha512-UPtDcpKyrKZRPfym9gTovcibPzl2O/Woy7B8sm45sAnjDH+jDUCcCvuIak7GpH47shQkC2J4yvnHZbD4c6XxcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-devkit/architect": "0.2101.2",
"@angular-devkit/core": "21.1.2",
"@angular-devkit/schematics": "21.1.2",
"@angular-devkit/architect": "0.2101.3",
"@angular-devkit/core": "21.1.3",
"@angular-devkit/schematics": "21.1.3",
"@inquirer/prompts": "7.10.1",
"@listr2/prompt-adapter-inquirer": "3.0.5",
"@modelcontextprotocol/sdk": "1.25.2",
"@schematics/angular": "21.1.2",
"@modelcontextprotocol/sdk": "1.26.0",
"@schematics/angular": "21.1.3",
"@yarnpkg/lockfile": "1.1.0",
"algoliasearch": "5.46.2",
"ini": "6.0.0",
@@ -600,6 +628,53 @@
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular/cli/node_modules/@angular-devkit/architect": {
"version": "0.2101.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2101.3.tgz",
"integrity": "sha512-vKz8aPA62W+e9+pF6ct4CRDG/MjlIH7sWFGYkxPPRst2g46ZQsRkrzfMZAWv/wnt6OZ1OwyRuO3RW83EMhag8g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-devkit/core": "21.1.3",
"rxjs": "7.8.2"
},
"bin": {
"architect": "bin/cli.js"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular/cli/node_modules/@angular-devkit/core": {
"version": "21.1.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.1.3.tgz",
"integrity": "sha512-huEXd1tWQHwwN+0VGRT+vSVplV0KNrGFUGJzkIW6iJE1SQElxn6etMai+pSd5DJcePkx6+SuscVsxbfwf70hnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"jsonc-parser": "3.3.1",
"picomatch": "4.0.3",
"rxjs": "7.8.2",
"source-map": "0.7.6"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^5.0.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@angular/common": {
"version": "21.1.2",
"resolved": "https://registry.npmjs.org/@angular/common/-/common-21.1.2.tgz",
@@ -2388,13 +2463,13 @@
]
},
"node_modules/@modelcontextprotocol/sdk": {
"version": "1.25.2",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz",
"integrity": "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==",
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz",
"integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@hono/node-server": "^1.19.7",
"@hono/node-server": "^1.19.9",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1",
"content-type": "^1.0.5",
@@ -2402,14 +2477,15 @@
"cross-spawn": "^7.0.5",
"eventsource": "^3.0.2",
"eventsource-parser": "^3.0.0",
"express": "^5.0.1",
"express-rate-limit": "^7.5.0",
"jose": "^6.1.1",
"express": "^5.2.1",
"express-rate-limit": "^8.2.1",
"hono": "^4.11.4",
"jose": "^6.1.3",
"json-schema-typed": "^8.0.2",
"pkce-challenge": "^5.0.0",
"raw-body": "^3.0.0",
"zod": "^3.25 || ^4.0",
"zod-to-json-schema": "^3.25.0"
"zod-to-json-schema": "^3.25.1"
},
"engines": {
"node": ">=18"
@@ -4019,14 +4095,14 @@
]
},
"node_modules/@schematics/angular": {
"version": "21.1.2",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.1.2.tgz",
"integrity": "sha512-kxwxhCIUrj7DfzEtDSs/pi/w+aII/WQLpPfLgoQCWE8/95v60WnTfd1afmsXsFoxikKPxkwoPWtU2YbhSoX9MQ==",
"version": "21.1.3",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.1.3.tgz",
"integrity": "sha512-obJvWBhzRdsYL2msM4+8bQD21vFl3VxaVsuiq6iIfYsxhU5i2Iar2wM9NaRaIIqAYhZ8ehQQ/moB9BEbWvDCTw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@angular-devkit/core": "21.1.2",
"@angular-devkit/schematics": "21.1.2",
"@angular-devkit/core": "21.1.3",
"@angular-devkit/schematics": "21.1.3",
"jsonc-parser": "3.3.1"
},
"engines": {
@@ -4035,6 +4111,34 @@
"yarn": ">= 1.13.0"
}
},
"node_modules/@schematics/angular/node_modules/@angular-devkit/core": {
"version": "21.1.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.1.3.tgz",
"integrity": "sha512-huEXd1tWQHwwN+0VGRT+vSVplV0KNrGFUGJzkIW6iJE1SQElxn6etMai+pSd5DJcePkx6+SuscVsxbfwf70hnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
"jsonc-parser": "3.3.1",
"picomatch": "4.0.3",
"rxjs": "7.8.2",
"source-map": "0.7.6"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^5.0.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@sigstore/bundle": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz",
@@ -6314,11 +6418,14 @@
}
},
"node_modules/express-rate-limit": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz",
"integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==",
"version": "8.2.1",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz",
"integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==",
"dev": true,
"license": "MIT",
"dependencies": {
"ip-address": "10.0.1"
},
"engines": {
"node": ">= 16"
},
@@ -6329,6 +6436,16 @@
"express": ">= 4.11"
}
},
"node_modules/express-rate-limit/node_modules/ip-address": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
"integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 12"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -6712,12 +6829,11 @@
}
},
"node_modules/hono": {
"version": "4.11.7",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz",
"integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==",
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.8.tgz",
"integrity": "sha512-eVkB/CYCCei7K2WElZW9yYQFWssG0DhaDhVvr7wy5jJ22K+ck8fWW0EsLpB0sITUTvPnc97+rrbQqIr5iqiy9Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=16.9.0"
}

View File

@@ -30,7 +30,6 @@ interface GridPos { row: number; col: number }
FormsModule
],
templateUrl: './conway-gol.html',
styleUrl: './conway-gol.scss',
})
export class ConwayGol implements AfterViewInit {

View File

@@ -1,6 +1,5 @@
import {Component, Input} from '@angular/core';
import {TranslatePipe} from "@ngx-translate/core";
import {UrlConstants} from "../../../constants/UrlConstants";
import {AlgorithmInformation} from './information.models';
@Component({

View File

@@ -6,18 +6,18 @@
<app-information [algorithmInformation]="algoInformation"/>
<div class="controls-container">
<div class="controls">
<div class="controls-panel">
<button matButton="filled" (click)="visualize('dijkstra')">{{ 'PATHFINDING.DIJKSTRA' | translate }}</button>
<button matButton="filled" (click)="visualize('astar')">{{ 'PATHFINDING.ASTAR' | translate }}</button>
</div>
<div class="controls">
<div class="controls-panel">
<button matButton="filled" (click)="createCase({withWalls: true, scenario: 'normal'})">{{ 'PATHFINDING.NORMAL_CASE' | translate }}</button>
<button matButton="filled" (click)="createCase({withWalls: true, scenario: 'random'})">{{ 'PATHFINDING.RANDOM_CASE' | translate }}</button>
<button matButton="filled" (click)="createCase({withWalls: true, scenario: 'edge'})">{{ 'PATHFINDING.EDGE_CASE' | translate }}</button>
<button matButton="filled" (click)="createCase({withWalls: false, scenario: 'normal'})">{{ 'PATHFINDING.CLEAR_BOARD' | translate }}</button>
</div>
<div class="controls">
<div class="controls-panel">
<mat-button-toggle-group [(ngModel)]="selectedNodeType" aria-label="Node Type Selection">
<mat-button-toggle [value]="NodeType.Start">{{ 'PATHFINDING.START_NODE' | translate }}</mat-button-toggle>
<mat-button-toggle [value]="NodeType.End">{{ 'PATHFINDING.END_NODE' | translate }}</mat-button-toggle>
@@ -25,8 +25,7 @@
<mat-button-toggle [value]="NodeType.None">{{ 'PATHFINDING.CLEAR_NODE' | translate }}</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div class="controls">
<div class="controls-panel">
<div class="grid-size">
<mat-form-field appearance="outline" class="grid-field">
<mat-label>{{ 'ALGORITHM.GRID_HEIGHT' | translate }}</mat-label>
@@ -63,11 +62,10 @@
<span><span class="legend-color visited"></span> {{ 'PATHFINDING.VISITED' | translate }}</span>
<span><span class="legend-color path"></span> {{ 'PATHFINDING.PATH' | translate }}</span>
</div>
</div>
<div class="results-container">
<p>{{ 'PATHFINDING.PATH_LENGTH' | translate }}: {{ pathLength }}</p>
<p>{{ 'PATHFINDING.EXECUTION_TIME' | translate }}: {{ executionTime | number:'1.2-2' }} ms</p>
<div class="controls-panel">
<p>{{ 'PATHFINDING.PATH_LENGTH' | translate }}: {{ pathLength }}</p>
<p>{{ 'PATHFINDING.EXECUTION_TIME' | translate }}: {{ executionTime | number:'1.2-2' }} ms</p>
</div>
</div>
<canvas #gridCanvas></canvas>

View File

@@ -1,16 +0,0 @@
.controls {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-bottom: 1rem;
align-items: center;
mat-button-toggle-group {
border-radius: 4px;
overflow: hidden;
}
}
.grid-field {
width: 150px;
}

View File

@@ -43,7 +43,6 @@ interface GridPos { row: number; col: number }
Information
],
templateUrl: './pathfinding.component.html',
styleUrls: ['./pathfinding.component.scss']
})
export class PathfindingComponent implements AfterViewInit {
private readonly pathfindingService = inject(PathfindingService);

View File

@@ -1,5 +1,4 @@
<div class="container">
<mat-card class="sorting-card">
<mat-card class="container sorting-card">
<mat-card-header>
<mat-card-title>{{ 'SORTING.TITLE' | translate }}</mat-card-title>
</mat-card-header>
@@ -40,7 +39,7 @@
</button>
</div>
<div class="info-panel">
<div class="controls-panel">
<p>{{ 'SORTING.EXECUTION_TIME' | translate }}: {{ executionTime }} ms</p>
</div>
<div class="visualization-area">
@@ -56,4 +55,3 @@
</div>
</mat-card-content>
</mat-card>
</div>

View File

@@ -110,6 +110,12 @@ a {
transition:
box-shadow 200ms ease,
transform 200ms ease;
&.container {
width: 100%;
max-width: 1200px;
padding: 20px;
}
}
.mat-mdc-card::before {
@@ -239,10 +245,21 @@ a {
.controls-panel {
display: flex;
gap: 10px;
margin-bottom: 20px;
gap: 1rem;
margin-bottom: 1rem;
align-items: center;
flex-wrap: wrap;
margin-top: 10px;
font-size: 0.9em;
mat-button-toggle-group {
border-radius: 4px;
overflow: hidden;
}
mat-form-field {
width: 200px;
}
}
.grid-size {
@@ -250,6 +267,10 @@ a {
gap: 0.75rem;
align-items: center;
flex-wrap: wrap;
.grid-field {
width: 150px;
}
}
canvas {
@@ -288,3 +309,34 @@ canvas {
flex-direction: column;
margin-bottom: 1rem;
}
/* Sorting Visualization */
.sorting-visualization-area {
display: flex;
align-items: flex-end;
height: 300px; /* Max height for bars */
border-bottom: 1px solid #ccc;
margin-bottom: 20px;
gap: 1px;
background-color: #f0f0f0;
.sorting-bar {
flex-grow: 1;
background-color: #424242; /* Default unsorted color */
transition: height 0.05s ease-in-out, background-color 0.05s ease-in-out;
width: 10px; /* Default width, flex-grow will adjust */
min-width: 1px; /* Ensure bars are always visible */
&.unsorted {
background-color: #424242;
}
&.comparing {
background-color: #ffeb3b; /* Yellow for comparing */
}
&.sorted {
background-color: #4caf50; /* Green for sorted */
}
}
}