Added skilltree from about page to dataService

This commit is contained in:
AdamBtech
2025-06-02 21:16:02 +02:00
parent bec7a32d06
commit f23ec6d732
4 changed files with 263 additions and 224 deletions

183
assets/data/skilltree.json Normal file
View File

@@ -0,0 +1,183 @@
{
"id": "workstation",
"title": "Workstation/",
"isExpanded": true,
"isSelected": false,
"level": 0,
"hasChildren": true,
"visible": true,
"children": [
{
"id": "tools",
"title": "Tools/",
"isExpanded": true,
"isSelected": false,
"level": 1,
"hasChildren": true,
"visible": true,
"children": [
{
"id": "webstorm",
"title": "Webstorm/",
"isExpanded": false,
"isSelected": false,
"level": 2,
"hasChildren": false,
"visible": true
},
{
"id": "linux",
"title": "Linux_Debian/",
"isExpanded": false,
"isSelected": false,
"level": 2,
"hasChildren": false,
"visible": true
},
{
"id": "git",
"title": "Git/",
"isExpanded": false,
"isSelected": false,
"level": 2,
"hasChildren": false,
"visible": true
},
{
"id": "docker",
"title": "Docker/",
"isExpanded": false,
"isSelected": false,
"level": 2,
"hasChildren": false,
"visible": true
}
]
},
{
"id": "dev",
"title": "Dev/",
"isExpanded": true,
"isSelected": false,
"level": 1,
"hasChildren": true,
"visible": true,
"children": [
{
"id": "front",
"title": "Front/",
"isExpanded": true,
"isSelected": false,
"level": 2,
"hasChildren": true,
"visible": true,
"children": [
{
"id": "angular",
"title": "Angular/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
},
{
"id": "tailwind",
"title": "Tailwind_SASS/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
},
{
"id": "html-css",
"title": "HTML_CSS/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
}
]
},
{
"id": "back",
"title": "Back/",
"isExpanded": true,
"isSelected": false,
"level": 2,
"hasChildren": true,
"visible": true,
"children": [
{
"id": "nodejs",
"title": "NodeJS_Express/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
},
{
"id": "typescript",
"title": "Typescript/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
},
{
"id": "php",
"title": "PHP_Symfony/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
},
{
"id": "python",
"title": "Python_Django/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
}
]
},
{
"id": "data",
"title": "Data/",
"isExpanded": true,
"isSelected": false,
"level": 2,
"hasChildren": true,
"visible": true,
"children": [
{
"id": "postgresql",
"title": "PostgreSQL/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
},
{
"id": "mongodb",
"title": "MongoDB/",
"isExpanded": false,
"isSelected": false,
"level": 3,
"hasChildren": false,
"visible": true
}
]
}
]
}
]
}

View File

@@ -1,6 +1,14 @@
import { Component, input, signal, computed } from '@angular/core'; import {
Component,
input,
signal,
computed,
inject,
effect,
} from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { type NeuralProfileNode } from '../../../shared/models/about.model'; import { type NeuralProfileNode } from '../../../shared/models/about.model';
import { DataService } from '../../../shared/services/data.service';
@Component({ @Component({
selector: 'app-neural-profile-tree', selector: 'app-neural-profile-tree',
@@ -10,203 +18,51 @@ import { type NeuralProfileNode } from '../../../shared/models/about.model';
styleUrl: './neural-profile-tree.component.css', styleUrl: './neural-profile-tree.component.css',
}) })
export class NeuralProfileTreeComponent { export class NeuralProfileTreeComponent {
// Input for external data (optional) private readonly dataService = inject(DataService);
// Input for external data (optional override)
externalData = input<NeuralProfileNode[]>([]); externalData = input<NeuralProfileNode[]>([]);
// Internal tree state and interaction signals // Internal tree state and interaction signals
private treeState = signal<NeuralProfileNode[]>(this.getInitialData()); private treeState = signal<NeuralProfileNode[]>([]);
public hoveredNodeId = signal<string | null>(null); public hoveredNodeId = signal<string | null>(null);
public selectedNodeId = signal<string | null>(null); public selectedNodeId = signal<string | null>(null);
// Computed flattened tree for rendering // Computed flattened tree for rendering
treeData = computed(() => this.flattenTreeWithVisibility(this.treeState())); treeData = computed(() => this.flattenTreeWithVisibility(this.treeState()));
private getInitialData(): NeuralProfileNode[] { // Computed to determine data source
return [ private dataSource = computed(() => {
{ const external = this.externalData();
id: 'workstation', const fromService = this.dataService.skills();
title: 'Workstation/',
isExpanded: true, console.log('External data:', external);
isSelected: false, console.log('Service data:', fromService);
level: 0, console.log(
hasChildren: true, 'Service data type:',
visible: true, Array.isArray(fromService) ? 'array' : typeof fromService,
children: [ );
{
id: 'tools', // Use external data if provided, otherwise use service data
title: 'Tools/', let data = external.length > 0 ? external : fromService;
isExpanded: true,
isSelected: false, // Ensure data is an array - if it's a single object, wrap it in an array
level: 1, if (data && !Array.isArray(data)) {
hasChildren: true, console.log('Converting single object to array');
visible: true, data = [data];
children: [ }
{
id: 'webstorm', // Ensure data is actually an array
title: 'Webstorm/', return Array.isArray(data) ? data : [];
isExpanded: false, });
isSelected: false,
level: 2, constructor() {
hasChildren: false, // Effect to update tree state when data source changes
visible: true, effect(() => {
}, const data = this.dataSource();
{ console.log('Neural profile data updated:', data);
id: 'linux', this.treeState.set(data);
title: 'Linux_Debian/', });
isExpanded: false,
isSelected: false,
level: 2,
hasChildren: false,
visible: true,
},
{
id: 'git',
title: 'Git/',
isExpanded: false,
isSelected: false,
level: 2,
hasChildren: false,
visible: true,
},
{
id: 'docker',
title: 'Docker/',
isExpanded: false,
isSelected: false,
level: 2,
hasChildren: false,
visible: true,
},
],
},
{
id: 'dev',
title: 'Dev/',
isExpanded: true,
isSelected: false,
level: 1,
hasChildren: true,
visible: true,
children: [
{
id: 'front',
title: 'Front/',
isExpanded: true,
isSelected: false,
level: 2,
hasChildren: true,
visible: true,
children: [
{
id: 'angular',
title: 'Angular/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
{
id: 'tailwind',
title: 'Tailwind_SASS/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
{
id: 'html-css',
title: 'HTML_CSS/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
],
},
{
id: 'back',
title: 'Back/',
isExpanded: true,
isSelected: false,
level: 2,
hasChildren: true,
visible: true,
children: [
{
id: 'nodejs',
title: 'NodeJS_Express/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
{
id: 'typescript',
title: 'Typescript/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
{
id: 'php',
title: 'PHP_Symfony/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
{
id: 'python',
title: 'Python_Django/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
],
},
{
id: 'data',
title: 'Data/',
isExpanded: true,
isSelected: false,
level: 2,
hasChildren: true,
visible: true,
children: [
{
id: 'postgresql',
title: 'PostgreSQL/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
{
id: 'mongodb',
title: 'MongoDB/',
isExpanded: false,
isSelected: false,
level: 3,
hasChildren: false,
visible: true,
},
],
},
],
},
],
},
];
} }
private flattenTreeWithVisibility( private flattenTreeWithVisibility(
@@ -269,7 +125,7 @@ export class NeuralProfileTreeComponent {
}); });
} }
// NEW METHOD: Handle chip cell hover // Handle chip cell hover
hoverChipChild(childId: string): void { hoverChipChild(childId: string): void {
this.hoveredNodeId.set(childId); this.hoveredNodeId.set(childId);
} }

View File

@@ -2,6 +2,7 @@ import { Injectable, signal, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { type Project } from '../models/project.model'; import { type Project } from '../models/project.model';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { NeuralProfileNode } from '../models/about.model';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@@ -11,9 +12,11 @@ export class DataService {
// Private signals for state management // Private signals for state management
private _projects = signal<Project[]>([]); private _projects = signal<Project[]>([]);
private _skills = signal<NeuralProfileNode[]>([]);
// Public readonly signals // Public readonly signals
readonly projects = this._projects.asReadonly(); readonly projects = this._projects.asReadonly();
readonly skills = this._skills.asReadonly();
constructor() { constructor() {
console.log('DataService initialized'); console.log('DataService initialized');
@@ -22,52 +25,49 @@ export class DataService {
private async loadInitialData(): Promise<void> { private async loadInitialData(): Promise<void> {
try { try {
console.log('Starting to load projects...'); console.log('Starting to load data...');
const projects = await this.fetchProjects(); const [projects, skills] = await Promise.all([
this.fetchProjects(),
this.fetchSkills(),
]);
console.log('Projects loaded successfully:', projects); console.log('Projects loaded successfully:', projects);
console.log('Skills loaded successfully:', skills);
console.log('Number of projects:', projects.length); console.log('Number of projects:', projects.length);
console.log('Number of skills:', skills.length);
this._projects.set(projects); this._projects.set(projects);
console.log('Projects signal updated'); this._skills.set(skills);
console.log('All data signals updated');
} catch (error) { } catch (error) {
console.error('Error loading data:', error); console.error('Error loading data:', error);
// Fallback to hardcoded data for debugging
console.log('Loading fallback data...');
const fallbackProjects: Project[] = [
{
id: 'portfolio',
title: 'PORTFOLIO_SYSTEM.EXE',
status: '[MISSION_ACTIVE]',
classification: 'Personal Showcase Platform',
objective: 'Professional presentation interface with NieR aesthetic',
statusDescription: 'LIVE | CONTINUOUS_UPDATE',
techStack: ['ANGULAR', 'TYPESCRIPT', 'TAILWIND', 'VERCEL'],
demoUrl: 'https://adambenyekkoudev.vercel.app/',
codeUrl: 'https://github.com/adam-benyekkou/angular_portfolio',
isRedacted: false,
},
{
id: 'redacted-1',
title: 'REDACTED_PROJECT_1',
status: '[REDACTED]',
classification: '',
objective: '',
statusDescription: '',
techStack: [],
isRedacted: true,
},
];
this._projects.set(fallbackProjects);
console.log('Fallback data loaded');
} }
} }
private async fetchProjects(): Promise<Project[]> { private async fetchProjects(): Promise<Project[]> {
console.log('Fetching projects from assets/data/projects.json'); console.log('Fetching projects from data/projects.json');
const result = await firstValueFrom( const result = await firstValueFrom(
this.http.get<Project[]>('data/projects.json'), this.http.get<Project[]>('data/projects.json'),
); );
console.log('HTTP request completed:', result); console.log('Projects HTTP request completed:', result);
return result; return result;
} }
private async fetchSkills(): Promise<NeuralProfileNode[]> {
console.log('Fetching skills from data/skilltree.json');
const result = await firstValueFrom(
this.http.get<NeuralProfileNode[] | NeuralProfileNode>(
'data/skilltree.json',
),
);
console.log('Skills HTTP request completed:', result);
// If the JSON contains a single object instead of an array, wrap it in an array
if (result && !Array.isArray(result)) {
console.log('Converting single skill object to array');
return [result as NeuralProfileNode];
}
return Array.isArray(result) ? result : [];
}
} }