Skip to content

Commit

Permalink
feat: roadmap
Browse files Browse the repository at this point in the history
  • Loading branch information
KostaD02 committed Sep 8, 2024
1 parent 8fdc899 commit a95ea9a
Show file tree
Hide file tree
Showing 16 changed files with 422 additions and 3 deletions.
Binary file modified bun.lockb
Binary file not shown.
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@
"@angular/router": "^17.1.2",
"@angular/ssr": "^17.1.2",
"@webcontainer/api": "^1.1.9",
"d3-drag": "^3.0.0",
"d3-selection": "^3.0.0",
"d3-shape": "^3.2.0",
"d3-transition": "^3.0.1",
"d3-zoom": "^3.0.0",
"dagre": "^0.8.5",
"dagre-compound": "^0.0.13",
"express": "^4.18.2",
"file-saver": "^2.0.5",
"jszip": "^3.10.1",
Expand Down
5 changes: 5 additions & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ export const routes: Routes = [
},
],
},
{
path: 'roadmap',
title: 'roadmap', // TODO: ქართულად რა იქნება?
loadComponent: () => import('./features/roadmap/roadmap.component'),
},
{
path: '404',
loadComponent: () => import('./features/not-found/not-found.component'),
Expand Down
98 changes: 98 additions & 0 deletions src/app/features/roadmap/roadmap.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<nz-layout class="base">
@if (isBrowser) {
@if (vm$ | async; as vm) {
<section class="controls">
<aside class="articles">
<button
nz-button
[nzType]="!vm.part ? 'primary' : 'default'"
(click)="part$.next(null)"
>
სრული
</button>
@for (subject of subjects; track subject.parent) {
<button
nz-button
nzType="default"
[nzType]="
vm.part?.parent === subject.parent ? 'primary' : 'default'
"
(click)="part$.next(subject)"
>
{{ subject.title }}
</button>
}
</aside>
<aside class="direction">
@for (dir of directions; track $index) {
<button
nz-button
[nzType]="dir === vm.direction ? 'primary' : 'default'"
(click)="direction$.next(dir)"
>
{{ dir }}
</button>
}
</aside>
</section>
<nz-graph
nz-graph-zoom
[nzAutoSize]="true"
[nzRankDirection]="vm.direction"
[nzGraphData]="vm.roadmapNavigation"
[nzZoom]="1"
(nzGraphInitialized)="graphInitialized()"
>
<ng-container *nzGraphNode="let node">
<foreignObject
x="0"
y="0"
[attr.width]="node.width"
[attr.height]="node.height"
>
<xhtml:div class="graph-node leaf-node">
<div
class="title"
(click)="
drawer$.next({
node,
show: true,
})
"
>
{{ node.label }}
</div>
</xhtml:div>
</foreignObject>
</ng-container>
</nz-graph>
<nz-drawer
[nzTitle]="vm.part?.title"
[nzVisible]="vm.drawer?.show || false"
(nzOnClose)="drawer$.next(null)"
>
<ng-container *nzDrawerContent>
@if (vm.drawer?.node; as node) {
<h2>{{ node.label }}</h2>
<p>
@if (node['description']; as description) {
{{ description }}
} @else {
აღწერა მალე დაემატება 🚀
}
</p>
@if (node['routerLink']; as routerLink) {
<div class="article-link">
<a nz-button [routerLink]="routerLink" nzType="link">
გაეცანი სტატიას
</a>
</div>
}
}
</ng-container>
</nz-drawer>
}
} @else {
<sw-loader [isFullSize]="true"></sw-loader>
}
</nz-layout>
54 changes: 54 additions & 0 deletions src/app/features/roadmap/roadmap.component.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
nz-layout.base {
height: calc(100vh - 66px - 50px);

section {
&.controls {
width: 100%;
display: grid;
grid-template-columns: 1fr;
row-gap: 10px;
place-items: center;
padding: 10px 0;
}
}

nz-graph {
width: 100%;
height: 100%;

// TODO: update

.graph-node {
border: 1px solid #8cc8ff;
cursor: pointer;
font-size: 12px;
height: 100%;
border-radius: 0;
text-align: center;
word-break: break-all;
display: block;
}

.group-node {
border-width: 4px;
}

.leaf-node {
color: #1a90ff;
background: rgba(26, 144, 255, 0.15);
min-height: 30px;
height: fit-content;
}

.title {
padding: 4px;
word-break: keep-all;
}
}
}

.article-link {
display: flex;
justify-content: flex-end;
align-items: center;
}
22 changes: 22 additions & 0 deletions src/app/features/roadmap/roadmap.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { RoadmapComponent } from './roadmap.component';

describe('RoadmapComponent', () => {
let component: RoadmapComponent;
let fixture: ComponentFixture<RoadmapComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RoadmapComponent],
}).compileComponents();

fixture = TestBed.createComponent(RoadmapComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
126 changes: 126 additions & 0 deletions src/app/features/roadmap/roadmap.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { AsyncPipe, isPlatformBrowser } from '@angular/common';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import {
inject,
Component,
ViewChild,
PLATFORM_ID,
ChangeDetectionStrategy,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import {
tap,
map,
delay,
switchMap,
combineLatest,
BehaviorSubject,
} from 'rxjs';
import {
NzGraphData,
NzRankDirection,
NzGraphComponent,
NzGraphZoomDirective,
} from 'ng-zorro-antd/graph';
import { NzGraphModule } from 'ng-zorro-antd/graph';
import { NzDrawerModule } from 'ng-zorro-antd/drawer';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzLayoutComponent } from 'ng-zorro-antd/layout';
import { LoaderComponent } from '@app-shared/ui';
import { ROADMAP_NAVIGATION } from '@app-shared/providers';
import { RoadmapDrawer, RoadmapPart } from '@app-shared/interfaces/roadmap';

@Component({
selector: 'sw-roadmap',
standalone: true,
imports: [
NzGraphModule,
NzButtonModule,
NzDrawerModule,
NzGraphComponent,
NzGraphZoomDirective,
NzLayoutComponent,
LoaderComponent,
RouterLink,
AsyncPipe,
],
templateUrl: './roadmap.component.html',
styleUrl: './roadmap.component.less',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class RoadmapComponent {
@ViewChild(NzGraphComponent) nzGraphComponent!: NzGraphComponent;
@ViewChild(NzGraphZoomDirective) zoomController!: NzGraphZoomDirective;

readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
readonly roadmapNavigationBase = inject(ROADMAP_NAVIGATION);

readonly ZOOM_MS = 500;
readonly subjects = this.roadmapNavigationBase.parentParts;
readonly directions: NzRankDirection[] = ['LR', 'RL', 'TB', 'BT'];

readonly part$ = new BehaviorSubject<RoadmapPart | null>(null);
readonly drawer$ = new BehaviorSubject<RoadmapDrawer | null>(null);
readonly direction$ = new BehaviorSubject<NzRankDirection>(
this.directions[0],
);

readonly roadmapNavigation$ = this.part$.pipe(
map(
(part) =>
new NzGraphData(
part
? this.buildGraphData(part)
: this.roadmapNavigationBase.graphData,
),
),
);

readonly vm$ = combineLatest([
this.part$,
this.drawer$,
this.direction$,
this.roadmapNavigation$,
]).pipe(
map(([part, drawer, direction, roadmapNavigation]) => ({
part,
drawer,
direction,
roadmapNavigation,
})),
);

readonly focus$ = combineLatest([
this.direction$,
this.roadmapNavigation$,
]).pipe(switchMap(() => this.part$));

constructor() {
if (this.isBrowser) {
this.focus$
.pipe(
takeUntilDestroyed(),
delay(this.ZOOM_MS),
tap((part) => {
this.zoomController?.focus(part?.parent || 0, this.ZOOM_MS * 2);
}),
)
.subscribe();
}
}

graphInitialized() {
this.zoomController?.focus(0, this.ZOOM_MS * 2);
}

private buildGraphData(part: RoadmapPart) {
return {
nodes: this.roadmapNavigationBase.graphData.nodes.filter(
(node) => node.id === part.parent || node['parent'] === part.parent,
),
edges: this.roadmapNavigationBase.graphData.edges.filter(
(node) => node.v === part.parent,
),
};
}
}
2 changes: 1 addition & 1 deletion src/app/shared/consts/doc-navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TYPESCRIPT_GUIDE_NAV } from './doc-navigation/ts';

export const DEFAULT_DOC_NAVIGATION: BaseNavigationTreeNode[] = [
{
title: 'გზამკლევი',
title: 'Front-end-ის გზამკლევი',
path: 'guides',
children: [
HTML_CSS_GUIDE_NAV,
Expand Down
6 changes: 5 additions & 1 deletion src/app/shared/consts/doc-navigation/js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ export const JAVASCRIPT_GUIDE_NAV: BaseNavigationTreeNode = {
path: 'javascript',
children: [
{ title: 'შესავალი', path: 'introduction' },
{ title: 'რა არის JavaScript', path: 'what-is-javascript' },
{
title: 'რა არის JavaScript',
path: 'what-is-javascript',
description: 'სატესტო',
},
{ title: 'ცვლადი', path: 'variable' },
{ title: 'მონაცემთა ტიპები', path: 'data-types' },
{ title: 'ოპერაციები და ოპერატორები', path: 'operations-operators' },
Expand Down
4 changes: 4 additions & 0 deletions src/app/shared/consts/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ export const HEADER_NAVIGATION: Navigation[] = [
title: 'ედიტორი',
routerLink: '/playground',
},
{
title: 'roadmap', // TODO: ქართულად რა იქნება?
routerLink: '/roadmap',
},
];
1 change: 1 addition & 0 deletions src/app/shared/interfaces/navigation-tree-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface BaseNavigationTreeNode {
path: string;
depricated?: boolean;
children?: BaseNavigationTreeNode[];
description?: string;
}

export interface NavigationTreeNode extends BaseNavigationTreeNode {
Expand Down
17 changes: 17 additions & 0 deletions src/app/shared/interfaces/roadmap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NzGraphDataDef, NzGraphNodeDef } from 'ng-zorro-antd/graph';

export interface Roadmap {
graphData: NzGraphDataDef;
parentParts: RoadmapPart[];
}

export interface RoadmapPart {
depth: number;
parent: number;
title: string;
}

export interface RoadmapDrawer {
show: boolean;
node: NzGraphNodeDef;
}
Loading

0 comments on commit a95ea9a

Please sign in to comment.