From fbb00cdecc51178f7894472c093fd0c9c1d5d68f Mon Sep 17 00:00:00 2001
From: Solomon Laing <solomonlaing@pm.me>
Date: Sun, 18 Apr 2021 21:07:04 +0930
Subject: [PATCH 1/5] started implementation of projects page. currently need
 to work out cors

---
 src/app/app-routing.module.ts                 |  4 +-
 src/app/app.module.ts                         |  6 +-
 .../project-card/project-card.component.html  |  1 +
 .../project-card/project-card.component.scss  |  0
 .../project-card.component.spec.ts            | 25 ++++++++
 .../project-card/project-card.component.ts    | 15 +++++
 .../projects/project/project.component.html   |  1 +
 .../projects/project/project.component.scss   |  0
 .../project/project.component.spec.ts         | 25 ++++++++
 src/app/projects/project/project.component.ts | 15 +++++
 src/app/projects/projects-routing.module.ts   | 21 +++++++
 src/app/projects/projects.component.html      |  6 +-
 src/app/projects/projects.component.ts        | 25 +++++++-
 src/app/projects/projects.module.ts           | 16 +++++
 src/app/projects/projects.service.spec.ts     | 16 +++++
 src/app/projects/projects.service.ts          | 60 +++++++++++++++++++
 src/app/shared/models/project.model.ts        |  6 ++
 17 files changed, 233 insertions(+), 9 deletions(-)
 create mode 100644 src/app/projects/project-card/project-card.component.html
 create mode 100644 src/app/projects/project-card/project-card.component.scss
 create mode 100644 src/app/projects/project-card/project-card.component.spec.ts
 create mode 100644 src/app/projects/project-card/project-card.component.ts
 create mode 100644 src/app/projects/project/project.component.html
 create mode 100644 src/app/projects/project/project.component.scss
 create mode 100644 src/app/projects/project/project.component.spec.ts
 create mode 100644 src/app/projects/project/project.component.ts
 create mode 100644 src/app/projects/projects-routing.module.ts
 create mode 100644 src/app/projects/projects.module.ts
 create mode 100644 src/app/projects/projects.service.spec.ts
 create mode 100644 src/app/projects/projects.service.ts
 create mode 100644 src/app/shared/models/project.model.ts

diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 65dc93b..63bd139 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -8,8 +8,8 @@ import { Pages } from './shared/models/pages.model';
 
 const routes: Routes = [
   { path: Pages.HOME, component: HomeComponent },
-  { path: Pages.PROJECTS, component: ProjectsComponent },
-  // { path: AppRoutes.CORE, loadChildren: () => import('./galler/gallery.module').then((m) => m.GalleryModule) }, // for future use
+  { path: Pages.PROJECTS, loadChildren: () => import('./projects/projects.module').then((m) => m.ProjectsModule) },
+  // { path: AppRoutes.CORE, loadChildren: () => import('./galler/gallery.module').then((m) => m.GalleryModule) }, // for future use maybe
   { path: Pages.LINKS, component: LinksComponent },
   { path: Pages.PET, component: PetComponent },
   { path: '**', redirectTo: Pages.HOME, pathMatch: 'full' }];
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index dfadf08..ab0f8ae 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -9,8 +9,8 @@ import { FooterComponent } from './footer/footer.component';
 import { SharedModule } from './shared/shared.module';
 import { HomeComponent } from './home/home.component';
 import { LinksComponent } from './links/links.component';
-import { ProjectsComponent } from './projects/projects.component';
 import { PetComponent } from './pet/pet.component';
+import { HttpClientModule } from '@angular/common/http';
 
 @NgModule({
   declarations: [
@@ -20,13 +20,13 @@ import { PetComponent } from './pet/pet.component';
     FooterComponent,
     HomeComponent,
     LinksComponent,
-    ProjectsComponent,
     PetComponent
   ],
   imports: [
     SharedModule,
     BrowserModule,
-    AppRoutingModule
+    AppRoutingModule,
+    HttpClientModule
   ],
   providers: [],
   bootstrap: [AppComponent]
diff --git a/src/app/projects/project-card/project-card.component.html b/src/app/projects/project-card/project-card.component.html
new file mode 100644
index 0000000..98ff4ff
--- /dev/null
+++ b/src/app/projects/project-card/project-card.component.html
@@ -0,0 +1 @@
+<p>project-card works!</p>
diff --git a/src/app/projects/project-card/project-card.component.scss b/src/app/projects/project-card/project-card.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/projects/project-card/project-card.component.spec.ts b/src/app/projects/project-card/project-card.component.spec.ts
new file mode 100644
index 0000000..8815d7d
--- /dev/null
+++ b/src/app/projects/project-card/project-card.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ProjectCardComponent } from './project-card.component';
+
+describe('ProjectCardComponent', () => {
+  let component: ProjectCardComponent;
+  let fixture: ComponentFixture<ProjectCardComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ ProjectCardComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ProjectCardComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/projects/project-card/project-card.component.ts b/src/app/projects/project-card/project-card.component.ts
new file mode 100644
index 0000000..06ce8d9
--- /dev/null
+++ b/src/app/projects/project-card/project-card.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-project-card',
+  templateUrl: './project-card.component.html',
+  styleUrls: ['./project-card.component.scss']
+})
+export class ProjectCardComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
diff --git a/src/app/projects/project/project.component.html b/src/app/projects/project/project.component.html
new file mode 100644
index 0000000..8ea00ea
--- /dev/null
+++ b/src/app/projects/project/project.component.html
@@ -0,0 +1 @@
+<p>project works!</p>
diff --git a/src/app/projects/project/project.component.scss b/src/app/projects/project/project.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/projects/project/project.component.spec.ts b/src/app/projects/project/project.component.spec.ts
new file mode 100644
index 0000000..e0f0d74
--- /dev/null
+++ b/src/app/projects/project/project.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ProjectComponent } from './project.component';
+
+describe('ProjectComponent', () => {
+  let component: ProjectComponent;
+  let fixture: ComponentFixture<ProjectComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ ProjectComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ProjectComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/projects/project/project.component.ts b/src/app/projects/project/project.component.ts
new file mode 100644
index 0000000..e4e21ec
--- /dev/null
+++ b/src/app/projects/project/project.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-project',
+  templateUrl: './project.component.html',
+  styleUrls: ['./project.component.scss']
+})
+export class ProjectComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
diff --git a/src/app/projects/projects-routing.module.ts b/src/app/projects/projects-routing.module.ts
new file mode 100644
index 0000000..74cf277
--- /dev/null
+++ b/src/app/projects/projects-routing.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { ProjectComponent } from './project/project.component';
+import { ProjectsComponent } from './projects.component';
+
+const routes: Routes = [
+    {
+        path: '',
+        component: ProjectsComponent
+    },
+    {
+        path: ':id',
+        component: ProjectComponent
+    }
+];
+
+@NgModule({
+    imports: [RouterModule.forChild(routes)],
+    exports: [RouterModule]
+})
+export class ProjectsRoutingModule {}
diff --git a/src/app/projects/projects.component.html b/src/app/projects/projects.component.html
index 885859a..b8607a9 100644
--- a/src/app/projects/projects.component.html
+++ b/src/app/projects/projects.component.html
@@ -1 +1,5 @@
-<p>projects works!</p>
+<h2>Projects on git</h2>
+<p>These are my projects as can be found on my <a href="https://gitlab.inkletblot.com/explore">gitlab</a>. Mainly my programming projects that are quality enough for me to be happy for the world to see them. There are more in the works but they are currently private.</p>
+
+<h2>Projects of a personal nature</h2>
+<p>This is (will be) a summary of my personal projects be they my homelab, general electronics projects, or anything else.</p>
\ No newline at end of file
diff --git a/src/app/projects/projects.component.ts b/src/app/projects/projects.component.ts
index 1172d9c..17af914 100644
--- a/src/app/projects/projects.component.ts
+++ b/src/app/projects/projects.component.ts
@@ -1,18 +1,37 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Subject } from 'rxjs/internal/Subject';
+import { takeUntil } from 'rxjs/operators';
 import { NavService } from '../nav/nav.service';
 import { Pages } from '../shared/models/pages.model';
+import { Project } from '../shared/models/project.model';
+import { ProjectsService } from './projects.service';
 
 @Component({
   selector: 'app-projects',
   templateUrl: './projects.component.html',
   styleUrls: ['./projects.component.scss']
 })
-export class ProjectsComponent implements OnInit {
+export class ProjectsComponent implements OnInit, OnDestroy {
+  _unsubscribe$: Subject<boolean> = new Subject();
 
-  constructor(private navService:NavService) { }
+  uncategorizedProjects: Array<Project>;
+
+  constructor(private navService: NavService, private projectsService: ProjectsService) { }
 
   ngOnInit(): void {
     this.navService.setPageTitle(Pages.PROJECTS);
+
+    this.projectsService.allProjects$
+        .pipe(takeUntil(this._unsubscribe$))
+        .subscribe((result: Project[]) => {
+            this.uncategorizedProjects = result;
+        });
+    this.projectsService.getInvoicesToApprove();
+  }
+
+  ngOnDestroy(): void {
+      this._unsubscribe$.next(false);
+      this._unsubscribe$.complete();
   }
 
 }
diff --git a/src/app/projects/projects.module.ts b/src/app/projects/projects.module.ts
new file mode 100644
index 0000000..bd6f109
--- /dev/null
+++ b/src/app/projects/projects.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ProjectCardComponent } from './project-card/project-card.component';
+import { ProjectComponent } from './project/project.component';
+import { ProjectsComponent } from './projects.component';
+import { ProjectsRoutingModule } from './projects-routing.module';
+
+@NgModule({
+  declarations: [ProjectsComponent, ProjectCardComponent, ProjectComponent],
+  imports: [
+    CommonModule,
+    ProjectsRoutingModule
+  ],
+  providers: []
+})
+export class ProjectsModule { }
diff --git a/src/app/projects/projects.service.spec.ts b/src/app/projects/projects.service.spec.ts
new file mode 100644
index 0000000..96c6dcc
--- /dev/null
+++ b/src/app/projects/projects.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { ProjectsService } from './projects.service';
+
+describe('ProjectsService', () => {
+  let service: ProjectsService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(ProjectsService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/src/app/projects/projects.service.ts b/src/app/projects/projects.service.ts
new file mode 100644
index 0000000..384962d
--- /dev/null
+++ b/src/app/projects/projects.service.ts
@@ -0,0 +1,60 @@
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { BehaviorSubject } from 'rxjs';
+import { Project } from '../shared/models/project.model';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ProjectsService {
+
+  private _allProjects = new BehaviorSubject<Array<Project>>([]);
+  readonly allProjects$ = this._allProjects.asObservable();
+
+  private set allProjects(projects: Array<Project>) {
+      this._allProjects.next(projects);
+  }
+  private get allProjects(): Array<Project> {
+      return this._allProjects.getValue();
+  }
+
+  private _apiErrored = new BehaviorSubject<boolean>(false);
+  readonly apiErrored$ = this._apiErrored.asObservable();
+
+  private set apiErrored(errored: boolean) {
+      this._apiErrored.next(errored);
+  }
+  private get apiErrored(): boolean {
+      return this._apiErrored.getValue();
+  }
+
+  /**
+   * I am actively avoiding any kind of environment management, this is a very basic site and currently this is the only api call.
+   */
+
+  private PROJECT_API_URL = "https://cms.inkletblot.com/"
+
+  constructor(private http: HttpClient) { }
+
+  httpOptions = {
+      headers: new HttpHeaders({
+          'Content-Type': 'application/json'
+      })
+  };
+
+  getInvoicesToApprove(): void {
+    this.http
+        .get(`${this.PROJECT_API_URL}`, this.httpOptions)
+        .subscribe(
+            (response: Project[]) => {
+                if (response) {
+                    this.allProjects = response;
+                    // filter out different categories here currently only one
+                }
+            },
+            (error) => {
+                this.apiErrored = true;
+            }
+        );
+    }
+}
diff --git a/src/app/shared/models/project.model.ts b/src/app/shared/models/project.model.ts
new file mode 100644
index 0000000..f5b9aab
--- /dev/null
+++ b/src/app/shared/models/project.model.ts
@@ -0,0 +1,6 @@
+export interface Project {
+    title: string,
+    description: string,
+    ct: string,
+    body: string
+}
\ No newline at end of file
-- 
GitLab


From 036f48b3f08ad9991e963d0101e13c2170bac69a Mon Sep 17 00:00:00 2001
From: Solomon Laing <solomonlaing@pm.me>
Date: Tue, 20 Apr 2021 19:30:30 +0930
Subject: [PATCH 2/5] Got api request working.

I added the necessary header to the api server and then changed the content type of the request to text/plain to disabled the preflight OPTIONS request which the server was erroring on.
Not sure about the security of all this but it's a very basic website and I don't think it'll be an issue.
---
 src/app/projects/projects.service.ts | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/app/projects/projects.service.ts b/src/app/projects/projects.service.ts
index 384962d..a0e5e72 100644
--- a/src/app/projects/projects.service.ts
+++ b/src/app/projects/projects.service.ts
@@ -32,13 +32,13 @@ export class ProjectsService {
    * I am actively avoiding any kind of environment management, this is a very basic site and currently this is the only api call.
    */
 
-  private PROJECT_API_URL = "https://cms.inkletblot.com/"
+  private PROJECT_API_URL = "https://cms.inkletblot.com/api/json"
 
   constructor(private http: HttpClient) { }
 
   httpOptions = {
       headers: new HttpHeaders({
-          'Content-Type': 'application/json'
+          'Content-Type': 'text/plain'
       })
   };
 
@@ -48,7 +48,16 @@ export class ProjectsService {
         .subscribe(
             (response: Project[]) => {
                 if (response) {
-                    this.allProjects = response;
+                    // using text/plain so as to not get the preflight options request
+                    // as such : Project[] does not work as expected and objects must be parsed.
+                    for (let project of response) {
+                        this.allProjects.push({
+                            title : project.title,
+                            description : project.description,
+                            ct : project.ct,
+                            body : project.body
+                        });
+                    }
                     // filter out different categories here currently only one
                 }
             },
-- 
GitLab


From 17e74a18a35e6940e537ea47f74d9bbb2d933b9c Mon Sep 17 00:00:00 2001
From: Solomon Laing <solomonlaing@pm.me>
Date: Mon, 26 Apr 2021 20:05:45 +0930
Subject: [PATCH 3/5] got basic implementation of project cards and the
 suppporting services/routing working. need to style project page now and will
 have first pass done

---
 src/app/app-routing.module.ts                 |  2 +
 src/app/app.module.ts                         |  4 +-
 src/app/page404/page404.component.html        |  2 +
 src/app/page404/page404.component.scss        |  5 +++
 src/app/page404/page404.component.spec.ts     | 25 +++++++++++
 src/app/page404/page404.component.ts          | 15 +++++++
 .../project-card/project-card.component.html  |  5 ++-
 .../project-card/project-card.component.scss  | 22 ++++++++++
 .../project-card/project-card.component.ts    |  6 ++-
 .../projects/project/project.component.html   |  1 +
 src/app/projects/project/project.component.ts | 43 +++++++++++++++++--
 src/app/projects/projects.component.html      |  5 ++-
 src/app/projects/projects.service.ts          | 42 +++++++++++++++++-
 src/app/shared/models/pages.model.ts          |  3 +-
 src/app/shared/models/project.model.ts        |  1 +
 15 files changed, 172 insertions(+), 9 deletions(-)
 create mode 100644 src/app/page404/page404.component.html
 create mode 100644 src/app/page404/page404.component.scss
 create mode 100644 src/app/page404/page404.component.spec.ts
 create mode 100644 src/app/page404/page404.component.ts

diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 63bd139..6001582 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
 import { RouterModule, Routes } from '@angular/router';
 import { HomeComponent } from './home/home.component';
 import { LinksComponent } from './links/links.component';
+import { Page404Component } from './page404/page404.component';
 import { PetComponent } from './pet/pet.component';
 import { ProjectsComponent } from './projects/projects.component';
 import { Pages } from './shared/models/pages.model';
@@ -12,6 +13,7 @@ const routes: Routes = [
   // { path: AppRoutes.CORE, loadChildren: () => import('./galler/gallery.module').then((m) => m.GalleryModule) }, // for future use maybe
   { path: Pages.LINKS, component: LinksComponent },
   { path: Pages.PET, component: PetComponent },
+  { path: Pages.PAGE_404, component: Page404Component },
   { path: '**', redirectTo: Pages.HOME, pathMatch: 'full' }];
 
 @NgModule({
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index ab0f8ae..1464527 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -11,6 +11,7 @@ import { HomeComponent } from './home/home.component';
 import { LinksComponent } from './links/links.component';
 import { PetComponent } from './pet/pet.component';
 import { HttpClientModule } from '@angular/common/http';
+import { Page404Component } from './page404/page404.component';
 
 @NgModule({
   declarations: [
@@ -20,7 +21,8 @@ import { HttpClientModule } from '@angular/common/http';
     FooterComponent,
     HomeComponent,
     LinksComponent,
-    PetComponent
+    PetComponent,
+    Page404Component
   ],
   imports: [
     SharedModule,
diff --git a/src/app/page404/page404.component.html b/src/app/page404/page404.component.html
new file mode 100644
index 0000000..e5abac8
--- /dev/null
+++ b/src/app/page404/page404.component.html
@@ -0,0 +1,2 @@
+<h1>Page Not Found?</h1>
+<h3>Sorry.</h3>
\ No newline at end of file
diff --git a/src/app/page404/page404.component.scss b/src/app/page404/page404.component.scss
new file mode 100644
index 0000000..e026e1c
--- /dev/null
+++ b/src/app/page404/page404.component.scss
@@ -0,0 +1,5 @@
+:host {
+    display: flex;
+    flex-direction: column;
+    text-align: center;
+}
\ No newline at end of file
diff --git a/src/app/page404/page404.component.spec.ts b/src/app/page404/page404.component.spec.ts
new file mode 100644
index 0000000..38b4072
--- /dev/null
+++ b/src/app/page404/page404.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { Page404Component } from './page404.component';
+
+describe('Page404Component', () => {
+  let component: Page404Component;
+  let fixture: ComponentFixture<Page404Component>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ Page404Component ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(Page404Component);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/page404/page404.component.ts b/src/app/page404/page404.component.ts
new file mode 100644
index 0000000..ca07c7a
--- /dev/null
+++ b/src/app/page404/page404.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-page404',
+  templateUrl: './page404.component.html',
+  styleUrls: ['./page404.component.scss']
+})
+export class Page404Component implements OnInit {
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
diff --git a/src/app/projects/project-card/project-card.component.html b/src/app/projects/project-card/project-card.component.html
index 98ff4ff..6cc1921 100644
--- a/src/app/projects/project-card/project-card.component.html
+++ b/src/app/projects/project-card/project-card.component.html
@@ -1 +1,4 @@
-<p>project-card works!</p>
+<a routerLink="{{project.slug}}">
+    <h2>{{project.title}}</h2>
+    <p>{{project.description}}</p>
+</a>
\ No newline at end of file
diff --git a/src/app/projects/project-card/project-card.component.scss b/src/app/projects/project-card/project-card.component.scss
index e69de29..d902910 100644
--- a/src/app/projects/project-card/project-card.component.scss
+++ b/src/app/projects/project-card/project-card.component.scss
@@ -0,0 +1,22 @@
+@use 'src/app/shared/styles/_variables.color' as colors;
+
+:host {
+    flex-direction: column;
+    display: flex;
+    background-color: colors.$inklets-color-bg;
+    margin-bottom: 20px;
+
+    a {
+        color: colors.$inklets-color-white;
+        border: colors.$inklets-color-highlight-bg 2px dashed;
+        background-color: colors.$inklets-color-fg;
+        text-decoration: none;
+        padding: 0 20px 0 20px;
+    }
+
+    a:hover {
+        background-color: colors.$inklets-color-highlight-fg;
+        color: colors.$inklets-color-black;
+    }
+
+}
\ No newline at end of file
diff --git a/src/app/projects/project-card/project-card.component.ts b/src/app/projects/project-card/project-card.component.ts
index 06ce8d9..fcc7491 100644
--- a/src/app/projects/project-card/project-card.component.ts
+++ b/src/app/projects/project-card/project-card.component.ts
@@ -1,4 +1,5 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
+import { Project } from 'src/app/shared/models/project.model';
 
 @Component({
   selector: 'app-project-card',
@@ -7,6 +8,9 @@ import { Component, OnInit } from '@angular/core';
 })
 export class ProjectCardComponent implements OnInit {
 
+  @Input()
+  project: Project;
+
   constructor() { }
 
   ngOnInit(): void {
diff --git a/src/app/projects/project/project.component.html b/src/app/projects/project/project.component.html
index 8ea00ea..dc66179 100644
--- a/src/app/projects/project/project.component.html
+++ b/src/app/projects/project/project.component.html
@@ -1 +1,2 @@
 <p>project works!</p>
+{{project.title}}
diff --git a/src/app/projects/project/project.component.ts b/src/app/projects/project/project.component.ts
index e4e21ec..ce93a3e 100644
--- a/src/app/projects/project/project.component.ts
+++ b/src/app/projects/project/project.component.ts
@@ -1,15 +1,52 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { Project } from 'src/app/shared/models/project.model';
+import { ProjectsService } from '../projects.service';
 
 @Component({
   selector: 'app-project',
   templateUrl: './project.component.html',
   styleUrls: ['./project.component.scss']
 })
-export class ProjectComponent implements OnInit {
+export class ProjectComponent implements OnInit, OnDestroy {
+  _unsubscribe$: Subject<boolean> = new Subject();
 
-  constructor() { }
+  project: Project = {
+    title: '',
+    description: '',
+    slug: '',
+    ct: '',
+    body: '',
+  };
+
+  constructor(
+    private route: ActivatedRoute,
+    private projectsService: ProjectsService
+    ) { }
 
   ngOnInit(): void {
+    let id: string;
+    this.route.paramMap.subscribe((params) => {
+        id = params.get('id');
+    });
+
+    this.projectsService.getProject(id);
+
+    this.projectsService.currentProject$
+    .pipe(takeUntil(this._unsubscribe$))
+    .subscribe((result: Project) => {
+      if (!!result) {
+        this.project = result;
+      }
+    });
+
+  }
+
+  ngOnDestroy(): void {
+      this._unsubscribe$.next(false);
+      this._unsubscribe$.complete();
   }
 
 }
diff --git a/src/app/projects/projects.component.html b/src/app/projects/projects.component.html
index b8607a9..4a04f43 100644
--- a/src/app/projects/projects.component.html
+++ b/src/app/projects/projects.component.html
@@ -2,4 +2,7 @@
 <p>These are my projects as can be found on my <a href="https://gitlab.inkletblot.com/explore">gitlab</a>. Mainly my programming projects that are quality enough for me to be happy for the world to see them. There are more in the works but they are currently private.</p>
 
 <h2>Projects of a personal nature</h2>
-<p>This is (will be) a summary of my personal projects be they my homelab, general electronics projects, or anything else.</p>
\ No newline at end of file
+<p>This is (will be) a summary of my personal projects be they my homelab, general electronics projects, or anything else.</p>
+
+<app-project-card *ngFor="let project of uncategorizedProjects" [project]="project">
+</app-project-card>
\ No newline at end of file
diff --git a/src/app/projects/projects.service.ts b/src/app/projects/projects.service.ts
index a0e5e72..fa29dfb 100644
--- a/src/app/projects/projects.service.ts
+++ b/src/app/projects/projects.service.ts
@@ -1,5 +1,6 @@
 import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { Injectable } from '@angular/core';
+import { Router } from '@angular/router';
 import { BehaviorSubject } from 'rxjs';
 import { Project } from '../shared/models/project.model';
 
@@ -18,6 +19,16 @@ export class ProjectsService {
       return this._allProjects.getValue();
   }
 
+  private _currentProject = new BehaviorSubject<Project>(null);
+  readonly currentProject$ = this._currentProject.asObservable();
+
+  private set currentProject(project: Project) {
+      this._currentProject.next(project);
+  }
+  private get currentProject(): Project {
+      return this._currentProject.getValue();
+  }
+
   private _apiErrored = new BehaviorSubject<boolean>(false);
   readonly apiErrored$ = this._apiErrored.asObservable();
 
@@ -34,7 +45,7 @@ export class ProjectsService {
 
   private PROJECT_API_URL = "https://cms.inkletblot.com/api/json"
 
-  constructor(private http: HttpClient) { }
+  constructor(private http: HttpClient, private router: Router) { }
 
   httpOptions = {
       headers: new HttpHeaders({
@@ -50,11 +61,13 @@ export class ProjectsService {
                 if (response) {
                     // using text/plain so as to not get the preflight options request
                     // as such : Project[] does not work as expected and objects must be parsed.
+                    this.allProjects = []
                     for (let project of response) {
                         this.allProjects.push({
                             title : project.title,
                             description : project.description,
                             ct : project.ct,
+                            slug : this.generateSlug(project.title),
                             body : project.body
                         });
                     }
@@ -66,4 +79,31 @@ export class ProjectsService {
             }
         );
     }
+
+    /**
+     * This is not very efficient code but I'm not planning on having that many projects and (if this turns into a blog) blog posts
+     * If this does become a general blog, then I will make this a bit more efficient.
+     * @param id slug of project to get
+     */
+    getProject(id: string): void {
+        let found = false;
+        this.allProjects.forEach((project) => {
+            if (project.slug === id) {
+                found = true;
+                this.currentProject = project;
+            }
+        })
+        if (!found) {
+            this.router.navigate(['not-found'])
+        }
+    }
+
+    /**
+     * Currently this is very basic and assumes that generated slug will be unique, it may be updated in future.
+     * @param input string to use for generating the slug
+     * @returns a slug representation of the input string
+     */
+    generateSlug(input: string): string {
+        return input.toLocaleLowerCase().split(" ").join("-");
+    }
 }
diff --git a/src/app/shared/models/pages.model.ts b/src/app/shared/models/pages.model.ts
index da77482..0619761 100644
--- a/src/app/shared/models/pages.model.ts
+++ b/src/app/shared/models/pages.model.ts
@@ -6,5 +6,6 @@ export enum Pages {
     PROJECTS = 'projects',
     GALLERY = 'gallery',
     LINKS = 'links',
-    PET = 'pet'
+    PET = 'pet',
+    PAGE_404 = 'not-found' 
 }
\ No newline at end of file
diff --git a/src/app/shared/models/project.model.ts b/src/app/shared/models/project.model.ts
index f5b9aab..28dec90 100644
--- a/src/app/shared/models/project.model.ts
+++ b/src/app/shared/models/project.model.ts
@@ -2,5 +2,6 @@ export interface Project {
     title: string,
     description: string,
     ct: string,
+    slug: string,
     body: string
 }
\ No newline at end of file
-- 
GitLab


From 5d754396da0c4e79ced37356da7b3a637f061e25 Mon Sep 17 00:00:00 2001
From: Solomon Laing <solomonlaing@pm.me>
Date: Sun, 6 Jun 2021 12:07:29 +0930
Subject: [PATCH 4/5] updated code (started to) for new api, npm install is
 busted due to out of date deps I think, moving to different computer

---
 src/app/projects/projects.service.ts   | 22 ++--------------------
 src/app/shared/models/project.model.ts |  7 +++----
 2 files changed, 5 insertions(+), 24 deletions(-)

diff --git a/src/app/projects/projects.service.ts b/src/app/projects/projects.service.ts
index fa29dfb..c77cffc 100644
--- a/src/app/projects/projects.service.ts
+++ b/src/app/projects/projects.service.ts
@@ -43,7 +43,7 @@ export class ProjectsService {
    * I am actively avoiding any kind of environment management, this is a very basic site and currently this is the only api call.
    */
 
-  private PROJECT_API_URL = "https://cms.inkletblot.com/api/json"
+  private PROJECT_API_URL = "https://cms.inkletblot.com/"
 
   constructor(private http: HttpClient, private router: Router) { }
 
@@ -61,16 +61,7 @@ export class ProjectsService {
                 if (response) {
                     // using text/plain so as to not get the preflight options request
                     // as such : Project[] does not work as expected and objects must be parsed.
-                    this.allProjects = []
-                    for (let project of response) {
-                        this.allProjects.push({
-                            title : project.title,
-                            description : project.description,
-                            ct : project.ct,
-                            slug : this.generateSlug(project.title),
-                            body : project.body
-                        });
-                    }
+                    this.allProjects = response;
                     // filter out different categories here currently only one
                 }
             },
@@ -97,13 +88,4 @@ export class ProjectsService {
             this.router.navigate(['not-found'])
         }
     }
-
-    /**
-     * Currently this is very basic and assumes that generated slug will be unique, it may be updated in future.
-     * @param input string to use for generating the slug
-     * @returns a slug representation of the input string
-     */
-    generateSlug(input: string): string {
-        return input.toLocaleLowerCase().split(" ").join("-");
-    }
 }
diff --git a/src/app/shared/models/project.model.ts b/src/app/shared/models/project.model.ts
index 28dec90..196064d 100644
--- a/src/app/shared/models/project.model.ts
+++ b/src/app/shared/models/project.model.ts
@@ -1,7 +1,6 @@
 export interface Project {
-    title: string,
-    description: string,
-    ct: string,
     slug: string,
-    body: string
+    date: string,
+    category: string,
+    content: string
 }
\ No newline at end of file
-- 
GitLab


From ac430a46d1edc4f0be24d0f53f4f0a2b307e786e Mon Sep 17 00:00:00 2001
From: Solomon Laing <solomonlaing@pm.me>
Date: Sun, 6 Jun 2021 13:27:11 +0930
Subject: [PATCH 5/5] first release of projects ready

---
 .../project-card/project-card.component.html  |  3 +-
 .../project-card/project-card.component.scss  |  2 +-
 .../projects/project/project.component.html   |  3 +-
 .../projects/project/project.component.scss   | 10 +++
 src/app/projects/project/project.component.ts | 11 +--
 src/app/projects/projects.component.ts        |  2 +-
 src/app/projects/projects.service.ts          | 27 +++++-
 src/app/shared/models/project.model.ts        |  1 +
 src/styles.scss                               | 90 +++++++++++++++++++
 9 files changed, 134 insertions(+), 15 deletions(-)

diff --git a/src/app/projects/project-card/project-card.component.html b/src/app/projects/project-card/project-card.component.html
index 6cc1921..b257702 100644
--- a/src/app/projects/project-card/project-card.component.html
+++ b/src/app/projects/project-card/project-card.component.html
@@ -1,4 +1,3 @@
 <a routerLink="{{project.slug}}">
-    <h2>{{project.title}}</h2>
-    <p>{{project.description}}</p>
+    {{project.title + " - " + project.date}}
 </a>
\ No newline at end of file
diff --git a/src/app/projects/project-card/project-card.component.scss b/src/app/projects/project-card/project-card.component.scss
index d902910..11d9562 100644
--- a/src/app/projects/project-card/project-card.component.scss
+++ b/src/app/projects/project-card/project-card.component.scss
@@ -11,7 +11,7 @@
         border: colors.$inklets-color-highlight-bg 2px dashed;
         background-color: colors.$inklets-color-fg;
         text-decoration: none;
-        padding: 0 20px 0 20px;
+        padding: 5px 20px 5px 20px;
     }
 
     a:hover {
diff --git a/src/app/projects/project/project.component.html b/src/app/projects/project/project.component.html
index dc66179..c6545ee 100644
--- a/src/app/projects/project/project.component.html
+++ b/src/app/projects/project/project.component.html
@@ -1,2 +1 @@
-<p>project works!</p>
-{{project.title}}
+<span [innerHTML]="project.content"></span>
diff --git a/src/app/projects/project/project.component.scss b/src/app/projects/project/project.component.scss
index e69de29..7bfa459 100644
--- a/src/app/projects/project/project.component.scss
+++ b/src/app/projects/project/project.component.scss
@@ -0,0 +1,10 @@
+@use 'src/app/shared/styles/_variables.color' as colors;
+
+:host {
+    display: flex;
+    flex-direction: column;
+    flex-grow: 1;
+    overflow-y: auto;
+    padding: 0 20px 0 20px;
+    margin: 0 140px 10px 140px;
+}
\ No newline at end of file
diff --git a/src/app/projects/project/project.component.ts b/src/app/projects/project/project.component.ts
index ce93a3e..9325d51 100644
--- a/src/app/projects/project/project.component.ts
+++ b/src/app/projects/project/project.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
@@ -8,17 +8,18 @@ import { ProjectsService } from '../projects.service';
 @Component({
   selector: 'app-project',
   templateUrl: './project.component.html',
+  // encapsulation: ViewEncapsulation.None,
   styleUrls: ['./project.component.scss']
 })
 export class ProjectComponent implements OnInit, OnDestroy {
   _unsubscribe$: Subject<boolean> = new Subject();
 
   project: Project = {
-    title: '',
-    description: '',
     slug: '',
-    ct: '',
-    body: '',
+    title: '',
+    date: '',
+    category: '',
+    content: '',
   };
 
   constructor(
diff --git a/src/app/projects/projects.component.ts b/src/app/projects/projects.component.ts
index 17af914..6da1e8b 100644
--- a/src/app/projects/projects.component.ts
+++ b/src/app/projects/projects.component.ts
@@ -26,7 +26,7 @@ export class ProjectsComponent implements OnInit, OnDestroy {
         .subscribe((result: Project[]) => {
             this.uncategorizedProjects = result;
         });
-    this.projectsService.getInvoicesToApprove();
+    this.projectsService.getProjects();
   }
 
   ngOnDestroy(): void {
diff --git a/src/app/projects/projects.service.ts b/src/app/projects/projects.service.ts
index c77cffc..fc374fb 100644
--- a/src/app/projects/projects.service.ts
+++ b/src/app/projects/projects.service.ts
@@ -43,7 +43,7 @@ export class ProjectsService {
    * I am actively avoiding any kind of environment management, this is a very basic site and currently this is the only api call.
    */
 
-  private PROJECT_API_URL = "https://cms.inkletblot.com/"
+  private PROJECT_API_URL = "https://cms.inkletblot.com"
 
   constructor(private http: HttpClient, private router: Router) { }
 
@@ -53,9 +53,9 @@ export class ProjectsService {
       })
   };
 
-  getInvoicesToApprove(): void {
+  getProjects(): void {
     this.http
-        .get(`${this.PROJECT_API_URL}`, this.httpOptions)
+        .get(`${this.PROJECT_API_URL}/posts`, this.httpOptions)
         .subscribe(
             (response: Project[]) => {
                 if (response) {
@@ -71,6 +71,25 @@ export class ProjectsService {
         );
     }
 
+    getSingleProject(id: string): void {
+      this.http
+          .get(`${this.PROJECT_API_URL}/post/${id}`, this.httpOptions)
+          .subscribe(
+              (response: Project) => {
+                  if (response) {
+                      // using text/plain so as to not get the preflight options request
+                      // as such : Project[] does not work as expected and objects must be parsed.
+                      this.currentProject = response;
+                      // filter out different categories here currently only one
+                  }
+              },
+              (error) => {
+                  this.apiErrored = true;
+                  this.router.navigate(['not-found'])
+              }
+          );
+      }
+
     /**
      * This is not very efficient code but I'm not planning on having that many projects and (if this turns into a blog) blog posts
      * If this does become a general blog, then I will make this a bit more efficient.
@@ -85,7 +104,7 @@ export class ProjectsService {
             }
         })
         if (!found) {
-            this.router.navigate(['not-found'])
+            this.getSingleProject(id)
         }
     }
 }
diff --git a/src/app/shared/models/project.model.ts b/src/app/shared/models/project.model.ts
index 196064d..522b454 100644
--- a/src/app/shared/models/project.model.ts
+++ b/src/app/shared/models/project.model.ts
@@ -1,5 +1,6 @@
 export interface Project {
     slug: string,
+    title: string,
     date: string,
     category: string,
     content: string
diff --git a/src/styles.scss b/src/styles.scss
index 9e71b2c..e5950b8 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -10,4 +10,94 @@ body {
     font-family: Roboto, 'Helvetica Neue', sans-serif;
     background-color: colors.$inklets-color-black;
     color: colors.$inklets-color-white;
+}
+
+/*
+
+    Codehilite styles for api content
+
+*/
+pre { line-height: 125%; }
+td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+td.linenos .special { color: #979797; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+span.linenos.special { color: #979797; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+.codehilite .hll { background-color: #ffffcc }
+.codehilite { background: #000000; padding: 5px; }
+.codehilite .c { color: #408080; font-style: italic } /* Comment */
+.codehilite .err { border: 1px solid #FF0000 } /* Error */
+.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
+.codehilite .o { color: #666666 } /* Operator */
+.codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
+.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
+.codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
+.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
+.codehilite .gd { color: #A00000 } /* Generic.Deleted */
+.codehilite .ge { font-style: italic } /* Generic.Emph */
+.codehilite .gr { color: #FF0000 } /* Generic.Error */
+.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.codehilite .gi { color: #00A000 } /* Generic.Inserted */
+.codehilite .go { color: #888888 } /* Generic.Output */
+.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.codehilite .gs { font-weight: bold } /* Generic.Strong */
+.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.codehilite .gt { color: #0044DD } /* Generic.Traceback */
+.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
+.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.codehilite .kt { color: #B00040 } /* Keyword.Type */
+.codehilite .m { color: #666666 } /* Literal.Number */
+.codehilite .s { color: #BA2121 } /* Literal.String */
+.codehilite .na { color: #7D9029 } /* Name.Attribute */
+.codehilite .nb { color: #008000 } /* Name.Builtin */
+.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.codehilite .no { color: #880000 } /* Name.Constant */
+.codehilite .nd { color: #AA22FF } /* Name.Decorator */
+.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.codehilite .nf { color: #0000FF } /* Name.Function */
+.codehilite .nl { color: #A0A000 } /* Name.Label */
+.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.codehilite .nv { color: #19177C } /* Name.Variable */
+.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
+.codehilite .mb { color: #666666 } /* Literal.Number.Bin */
+.codehilite .mf { color: #666666 } /* Literal.Number.Float */
+.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
+.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
+.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
+.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
+.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
+.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
+.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
+.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
+.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.codehilite .sx { color: #008000 } /* Literal.String.Other */
+.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
+.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
+.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
+.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.codehilite .fm { color: #0000FF } /* Name.Function.Magic */
+.codehilite .vc { color: #19177C } /* Name.Variable.Class */
+.codehilite .vg { color: #19177C } /* Name.Variable.Global */
+.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
+.codehilite .vm { color: #19177C } /* Name.Variable.Magic */
+.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
+
+
+* a {
+    text-decoration: none;
+    color: colors.$inklets-color-fg;
+}
+
+* a:hover {
+    color: colors.$inklets-color-highlight-fg;
 }
\ No newline at end of file
-- 
GitLab