From 712d7857db621aaa11b67d37f56fb2eb310612b0 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Thu, 6 Feb 2025 10:55:26 +0000 Subject: [PATCH 1/3] #5 Started on creating page to handle API requests to https://git.luke-else.co.uk --- src/lib/api/git.ts | 26 +++++++++++++++++++++++++ src/lib/components/Toasts/Toasts.svelte | 2 +- src/lib/{store.ts => stores.ts} | 17 +++++++++++++++- src/lib/types.ts | 13 +++++++++++++ src/main.svelte | 2 +- src/routes/contact/+page.svelte | 2 +- src/routes/repos/+page.svelte | 23 +++++++++++++++++++--- 7 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 src/lib/api/git.ts rename src/lib/{store.ts => stores.ts} (68%) create mode 100644 src/lib/types.ts diff --git a/src/lib/api/git.ts b/src/lib/api/git.ts new file mode 100644 index 0000000..df39d44 --- /dev/null +++ b/src/lib/api/git.ts @@ -0,0 +1,26 @@ +import type { GitRepo } from "../types"; + +const API_BASE_URL = "https://git.luke-else.co.uk/api/v1"; +// const ACCESS_TOKEN = import.meta.env.VITE_GITEA_TOKEN; + +export async function fetchRepos(): Promise { + try { + console.log("Fetching repos..."); + const response = await fetch(`${API_BASE_URL}/repos/search`, { + headers: { + // "Authorization": `token ${ACCESS_TOKEN}`, + "Content-Type": "application/json" + } + }); + + if (!response.ok) { + throw new Error(`Error: ${response.statusText}`); + } + + const data: { data: GitRepo[] } = await response.json(); + return data.data; // Extract the list of repositories + } catch (error) { + console.error("Failed to fetch repos:", error); + return []; + } +} \ No newline at end of file diff --git a/src/lib/components/Toasts/Toasts.svelte b/src/lib/components/Toasts/Toasts.svelte index 3977df4..5a0bc71 100644 --- a/src/lib/components/Toasts/Toasts.svelte +++ b/src/lib/components/Toasts/Toasts.svelte @@ -1,7 +1,7 @@ {#if $toasts} diff --git a/src/lib/store.ts b/src/lib/stores.ts similarity index 68% rename from src/lib/store.ts rename to src/lib/stores.ts index 9d46f52..41f1da4 100644 --- a/src/lib/store.ts +++ b/src/lib/stores.ts @@ -1,6 +1,12 @@ import { ToastType, type Toast } from "$lib/toast"; import { writable, type Writable } from "svelte/store"; +import type { GitRepo } from "./types"; +import { fetchRepos } from "./api/git"; + +//////////////////////////////////////// +// Toast Stores +//////////////////////////////////////// export const toasts: Writable = writable([]); export const addToast = (toast: Toast) => { @@ -25,4 +31,13 @@ export const addToast = (toast: Toast) => { export const dismissToast = (id: number) => { toasts.update((all) => all.filter((t) => t.id !== id)); -}; \ No newline at end of file +}; + +//////////////////////////////////////// +// Git Repo Stores +//////////////////////////////////////// +export const repos = writable([]); + +export async function loadRepos() { + repos.set(await fetchRepos()); +} \ No newline at end of file diff --git a/src/lib/types.ts b/src/lib/types.ts new file mode 100644 index 0000000..93b1ebf --- /dev/null +++ b/src/lib/types.ts @@ -0,0 +1,13 @@ +export interface GitRepo { + id: number; + name: string; + full_name: string; + description: string; + html_url: string; + private: boolean; + fork: boolean; + owner: { + login: string; + avatar_url: string; + }; +} \ No newline at end of file diff --git a/src/main.svelte b/src/main.svelte index 5b3f3ff..87b57d1 100644 --- a/src/main.svelte +++ b/src/main.svelte @@ -1,7 +1,7 @@ + +

My Projects

+ +{#if $repos.length > 0} +
    + {#each $repos as repo} +
  • + {repo.name} - {repo.description} +
  • + {/each} +
+{:else} +

Loading repositories...

+{/if} From 9da13b76d3157835e0c31a2b1e89f5b749f8f0a3 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Sun, 9 Feb 2025 17:35:54 +0000 Subject: [PATCH 2/3] #5 Repos are now displayed on the webpage - Additional stlying required. --- .dockerignore | 1 + src/app.html | 15 ++++++++++++++ src/lib/api/git.ts | 4 ++-- src/lib/types.ts | 5 +++-- src/main.svelte | 16 --------------- src/routes/repos/+page.svelte | 37 ++++++++++++++++++++++++----------- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/.dockerignore b/.dockerignore index af098af..e4ee886 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,7 @@ node_modules .git .gitattributes +.gitea .eslintignore .eslintrc.cjs diff --git a/src/app.html b/src/app.html index a664528..d772768 100644 --- a/src/app.html +++ b/src/app.html @@ -95,6 +95,21 @@ box-shadow: .3em .3em .3em var(--header); } + .container { + padding-top: 3em; + max-width: 90%; + margin: auto; + } + + .cards { + display: flex; + flex-wrap: wrap; + flex-direction: row; + gap: 3em 3em; + padding: 2em 0em 2em 0em; + transition: all 0.2s; + } + @keyframes animationName { 0% { opacity:0; } 50% { opacity:1; } diff --git a/src/lib/api/git.ts b/src/lib/api/git.ts index df39d44..bb44000 100644 --- a/src/lib/api/git.ts +++ b/src/lib/api/git.ts @@ -1,12 +1,12 @@ import type { GitRepo } from "../types"; const API_BASE_URL = "https://git.luke-else.co.uk/api/v1"; -// const ACCESS_TOKEN = import.meta.env.VITE_GITEA_TOKEN; + export async function fetchRepos(): Promise { try { console.log("Fetching repos..."); - const response = await fetch(`${API_BASE_URL}/repos/search`, { + const response = await fetch(`${API_BASE_URL}/repos/search?sort=updated&order=desc&limit=12`, { headers: { // "Authorization": `token ${ACCESS_TOKEN}`, "Content-Type": "application/json" diff --git a/src/lib/types.ts b/src/lib/types.ts index 93b1ebf..881c386 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,8 +1,9 @@ export interface GitRepo { - id: number; name: string; - full_name: string; description: string; + language: string; + size: number; + updated_at: Date; html_url: string; private: boolean; fork: boolean; diff --git a/src/main.svelte b/src/main.svelte index 87b57d1..3214fba 100644 --- a/src/main.svelte +++ b/src/main.svelte @@ -61,22 +61,6 @@ font-size: 1.5em; } - /* Skills Cards CSS */ - .container { - padding-top: 3em; - max-width: 90%; - margin: auto; - } - - .cards { - display: flex; - flex-wrap: wrap; - flex-direction: row; - gap: 3em 3em; - padding: 2em 0em 2em 0em; - transition: all 0.2s; - } - {#await getJson('/json/me.json')} diff --git a/src/routes/repos/+page.svelte b/src/routes/repos/+page.svelte index 64e2911..88d0848 100644 --- a/src/routes/repos/+page.svelte +++ b/src/routes/repos/+page.svelte @@ -1,20 +1,35 @@

My Projects

-{#if $repos.length > 0} -
    - {#each $repos as repo} -
  • - {repo.name} - {repo.description} -
  • - {/each} -
-{:else} -

Loading repositories...

-{/if} +
+ {#if $repos.length > 0} +
+ {#each $repos as repo} + +
+

{repo.name}

+ {repo.language} +
+
+

{@html repo.description}

+
+
+ + {repo.name} + {repo.size}KiB + {repo.updated_at} +
+
+ {/each} +
+ {:else} +

Loading repositories...

+ {/if} +
From 71dc20c0ca3e39aa719ca68c3e316629c1f05cd0 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Sun, 9 Feb 2025 20:03:48 +0000 Subject: [PATCH 3/3] #5 Styled cards, changed content in me.json --- src/app.html | 1 - src/lib/api/git.ts | 23 +++++++++++++++++++++++ src/lib/components/Cards/Card.svelte | 2 ++ src/main.svelte | 1 + src/routes/repos/+page.svelte | 9 ++++++--- static/json/me.json | 9 +++++++-- 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/app.html b/src/app.html index d772768..bfd3cb5 100644 --- a/src/app.html +++ b/src/app.html @@ -96,7 +96,6 @@ } .container { - padding-top: 3em; max-width: 90%; margin: auto; } diff --git a/src/lib/api/git.ts b/src/lib/api/git.ts index bb44000..cdef558 100644 --- a/src/lib/api/git.ts +++ b/src/lib/api/git.ts @@ -23,4 +23,27 @@ export async function fetchRepos(): Promise { console.error("Failed to fetch repos:", error); return []; } +} + +export function timeSince(inputDate: Date | string): string { + const date = new Date(inputDate); // Ensure it's a Date object + if (isNaN(date.getTime())) { + throw new Error("Invalid date provided"); + } + + const now: Date = new Date(); + const diffInMs: number = now.getTime() - date.getTime(); + const diffInSeconds: number = Math.floor(diffInMs / 1000); + const diffInMinutes: number = Math.floor(diffInSeconds / 60); + const diffInHours: number = Math.floor(diffInMinutes / 60); + const diffInDays: number = Math.floor(diffInHours / 24); + const diffInMonths: number = Math.floor(diffInDays / 30); // Approximate + const diffInYears: number = Math.floor(diffInDays / 365); // Approximate + + if (diffInDays === 0) return "Today"; + if (diffInDays === 1) return "Yesterday"; + if (diffInDays < 7) return `${diffInDays} days ago`; + if (diffInDays < 30) return `${Math.floor(diffInDays / 7)} week${diffInDays >= 14 ? 's' : ''} ago`; + if (diffInMonths < 12) return `${diffInMonths} month${diffInMonths > 1 ? 's' : ''} ago`; + return `${diffInYears} year${diffInYears > 1 ? 's' : ''} ago`; } \ No newline at end of file diff --git a/src/lib/components/Cards/Card.svelte b/src/lib/components/Cards/Card.svelte index c5f4ab9..d13957c 100644 --- a/src/lib/components/Cards/Card.svelte +++ b/src/lib/components/Cards/Card.svelte @@ -20,7 +20,9 @@ border-radius: .5em; scroll-snap-align: start; transition: all 0.2s; + box-shadow: .25em .25em .5em var(--hover); } + .card:hover { box-shadow: .5em .5em .5em var(--hover); } diff --git a/src/main.svelte b/src/main.svelte index 3214fba..ef2b849 100644 --- a/src/main.svelte +++ b/src/main.svelte @@ -14,6 +14,7 @@ border-radius: 1em; padding: .2em 2em 2em 2em; box-shadow: .5em .5em .5em var(--glow); + margin-bottom: 4em; } .flex-container { diff --git a/src/routes/repos/+page.svelte b/src/routes/repos/+page.svelte index 88d0848..017d0b1 100644 --- a/src/routes/repos/+page.svelte +++ b/src/routes/repos/+page.svelte @@ -1,15 +1,19 @@

My Projects

+

This here is a list of my most recently worked on projects. Note this does not show any private repositories. For more in depth information Click Here.

{#if $repos.length > 0} +
{addToast(new Toast("See a snapshot of my latest work.", ToastType.Info, true, 8_000))}
{#each $repos as repo} @@ -23,8 +27,7 @@
{repo.name} - {repo.size}KiB - {repo.updated_at} + {timeSince(repo.updated_at)}
{/each} diff --git a/static/json/me.json b/static/json/me.json index 1ac2375..df11f9d 100644 --- a/static/json/me.json +++ b/static/json/me.json @@ -44,7 +44,12 @@ { "duration" : "September 2022 - Present", "title" : "Thales UK - Software Engineer", - "description" : "As a software engineering apprentice at Thales UK, I find myself partaking in agile / scrum development methodologies in a strong team of 6 other engineers. The team iterates on a pre-existing system designed for the MOD, written in C++, using internal frameworks to assist.

To extend this, the apprenticeship includes allocated time for studying a Digital and Thechnology Solutions degree with the University of Warwick, including modules relevant to business management, devlopment processes and data integrity etc..." + "description" : "As a software engineering apprentice at Thales UK, I find myself partaking in agile / scrum development methodologies in a strong team of 6 other engineers. The team iterates on a pre-existing system designed for the MOD, written in C++, using internal frameworks to assist." + }, + { + "duration" : "September 2022 - Present", + "title" : "University of Warwick - Digital and Technology Solutions", + "description" : "The apprenticeship includes allocated time for studying a Digital and Thechnology Solutions degree with the University of Warwick, including modules relevant to business management, devlopment processes and data integrity etc..." }, { "duration" : "September 2020 - July 2022", @@ -54,7 +59,7 @@ { "duration" : "September 2015 - July 2020", "title" : "The Norton Knatchbull School (GCSEs)", - "description" : "FSMQ (C)
Maths (8)
Geography (9)
Biology (9)
Chemistry (9)
Physics (9)
Spanish (7)
English (Literature & Language) (7, 7)
Computer Science (9)" + "description" : "Computer Science (9)
Physics (9)
Chemistry (9)
Biology (9)
Geography (9)
FSMQ (C)
Maths (8)
Spanish (7)
English (Literature & Language) (7, 7)
" } ] } \ No newline at end of file