Merge pull request 'development' (#18) from development into main
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 27s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 27s
Reviewed-on: #18
This commit is contained in:
commit
b9c4ec540a
@ -6,6 +6,7 @@ node_modules
|
|||||||
|
|
||||||
.git
|
.git
|
||||||
.gitattributes
|
.gitattributes
|
||||||
|
.gitea
|
||||||
|
|
||||||
.eslintignore
|
.eslintignore
|
||||||
.eslintrc.cjs
|
.eslintrc.cjs
|
||||||
|
14
src/app.html
14
src/app.html
@ -95,6 +95,20 @@
|
|||||||
box-shadow: .3em .3em .3em var(--header);
|
box-shadow: .3em .3em .3em var(--header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
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 {
|
@keyframes animationName {
|
||||||
0% { opacity:0; }
|
0% { opacity:0; }
|
||||||
50% { opacity:1; }
|
50% { opacity:1; }
|
||||||
|
49
src/lib/api/git.ts
Normal file
49
src/lib/api/git.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import type { GitRepo } from "../types";
|
||||||
|
|
||||||
|
const API_BASE_URL = "https://git.luke-else.co.uk/api/v1";
|
||||||
|
|
||||||
|
|
||||||
|
export async function fetchRepos(): Promise<GitRepo[]> {
|
||||||
|
try {
|
||||||
|
console.log("Fetching repos...");
|
||||||
|
const response = await fetch(`${API_BASE_URL}/repos/search?sort=updated&order=desc&limit=12`, {
|
||||||
|
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 [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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`;
|
||||||
|
}
|
@ -20,7 +20,9 @@
|
|||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
scroll-snap-align: start;
|
scroll-snap-align: start;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
box-shadow: .25em .25em .5em var(--hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover {
|
.card:hover {
|
||||||
box-shadow: .5em .5em .5em var(--hover);
|
box-shadow: .5em .5em .5em var(--hover);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Toast from "./Toast.svelte";
|
import Toast from "./Toast.svelte";
|
||||||
|
|
||||||
import { dismissToast, toasts } from "$lib/store";
|
import { dismissToast, toasts } from "$lib/stores";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $toasts}
|
{#if $toasts}
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { ToastType, type Toast } from "$lib/toast";
|
import { ToastType, type Toast } from "$lib/toast";
|
||||||
import { writable, type Writable } from "svelte/store";
|
import { writable, type Writable } from "svelte/store";
|
||||||
|
import type { GitRepo } from "./types";
|
||||||
|
import { fetchRepos } from "./api/git";
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// Toast Stores
|
||||||
|
////////////////////////////////////////
|
||||||
export const toasts: Writable<Toast[]> = writable([]);
|
export const toasts: Writable<Toast[]> = writable([]);
|
||||||
|
|
||||||
export const addToast = (toast: Toast) => {
|
export const addToast = (toast: Toast) => {
|
||||||
@ -25,4 +31,13 @@ export const addToast = (toast: Toast) => {
|
|||||||
|
|
||||||
export const dismissToast = (id: number) => {
|
export const dismissToast = (id: number) => {
|
||||||
toasts.update((all) => all.filter((t) => t.id !== id));
|
toasts.update((all) => all.filter((t) => t.id !== id));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// Git Repo Stores
|
||||||
|
////////////////////////////////////////
|
||||||
|
export const repos = writable<GitRepo[]>([]);
|
||||||
|
|
||||||
|
export async function loadRepos() {
|
||||||
|
repos.set(await fetchRepos());
|
||||||
|
}
|
14
src/lib/types.ts
Normal file
14
src/lib/types.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export interface GitRepo {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
language: string;
|
||||||
|
size: number;
|
||||||
|
updated_at: Date;
|
||||||
|
html_url: string;
|
||||||
|
private: boolean;
|
||||||
|
fork: boolean;
|
||||||
|
owner: {
|
||||||
|
login: string;
|
||||||
|
avatar_url: string;
|
||||||
|
};
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getJson } from "$lib/data";
|
import { getJson } from "$lib/data";
|
||||||
import { Toast, ToastType } from "$lib/toast";
|
import { Toast, ToastType } from "$lib/toast";
|
||||||
import { addToast } from "$lib/store";
|
import { addToast } from "$lib/stores";
|
||||||
|
|
||||||
import Skills from './skills.svelte';
|
import Skills from './skills.svelte';
|
||||||
|
|
||||||
@ -14,6 +14,7 @@
|
|||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
padding: .2em 2em 2em 2em;
|
padding: .2em 2em 2em 2em;
|
||||||
box-shadow: .5em .5em .5em var(--glow);
|
box-shadow: .5em .5em .5em var(--glow);
|
||||||
|
margin-bottom: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-container {
|
.flex-container {
|
||||||
@ -61,22 +62,6 @@
|
|||||||
font-size: 1.5em;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{#await getJson('/json/me.json')}
|
{#await getJson('/json/me.json')}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Card from '$lib/components/Cards/Card.svelte';
|
import Card from '$lib/components/Cards/Card.svelte';
|
||||||
import { Toast, ToastType } from "$lib/toast";
|
import { Toast, ToastType } from "$lib/toast";
|
||||||
import { addToast } from "$lib/store";
|
import { addToast } from "$lib/stores";
|
||||||
|
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
const sent = $page.url.searchParams.get('sent');
|
const sent = $page.url.searchParams.get('sent');
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
<h1>Repos</h1>
|
<script lang="ts">
|
||||||
<p>Stay tuned! This is still in development.</p>
|
import { onMount } from "svelte";
|
||||||
<p>Come back later to find out what projects I'm currently working on!</p>
|
import { Toast, ToastType } from "$lib/toast";
|
||||||
|
import { repos, loadRepos, addToast } from "$lib/stores";
|
||||||
|
import { timeSince } from "$lib/api/git";
|
||||||
|
import Card from "$lib/components/Cards/Card.svelte";
|
||||||
|
|
||||||
|
onMount(loadRepos);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>My Projects</h1>
|
||||||
|
<p>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 <a href="https://git.luke-else.co.uk">Click Here</a>.</p>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{#if $repos.length > 0}
|
||||||
|
<div style="display: none;">{addToast(new Toast("See a snapshot of my latest work.", ToastType.Info, true, 8_000))}</div>
|
||||||
|
<div class="cards">
|
||||||
|
{#each $repos as repo}
|
||||||
|
<Card>
|
||||||
|
<div slot="header">
|
||||||
|
<h2>{repo.name}</h2>
|
||||||
|
{repo.language}
|
||||||
|
</div>
|
||||||
|
<div slot="content">
|
||||||
|
<p class="not-required">{@html repo.description}</p>
|
||||||
|
</div>
|
||||||
|
<div slot="footer">
|
||||||
|
<!-- svelte-ignore a11y-invalid-attribute -->
|
||||||
|
<a href="{repo.html_url}">{repo.name}</a>
|
||||||
|
{timeSince(repo.updated_at)}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<p>Loading repositories...</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
@ -44,7 +44,12 @@
|
|||||||
{
|
{
|
||||||
"duration" : "September 2022 - Present",
|
"duration" : "September 2022 - Present",
|
||||||
"title" : "Thales UK - Software Engineer",
|
"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. <br /><br /> 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",
|
"duration" : "September 2020 - July 2022",
|
||||||
@ -54,7 +59,7 @@
|
|||||||
{
|
{
|
||||||
"duration" : "September 2015 - July 2020",
|
"duration" : "September 2015 - July 2020",
|
||||||
"title" : "The Norton Knatchbull School (GCSEs)",
|
"title" : "The Norton Knatchbull School (GCSEs)",
|
||||||
"description" : "FSMQ (C) <br /> Maths (8) <br /> Geography (<b>9</b>) <br /> Biology (<b>9</b>) <br /> Chemistry (<b>9</b>) <br /> Physics (<b>9</b>) <br /> Spanish (7) <br /> English (Literature & Language) (7, 7) <br /> Computer Science (<b>9</b>)"
|
"description" : "Computer Science (<b>9</b>) <br /> Physics (<b>9</b>) <br /> Chemistry (<b>9</b>) <br /> Biology (<b>9</b>) <br /> Geography (<b>9</b>) <br /> FSMQ (C) <br /> Maths (8) <br /> Spanish (7) <br /> English (Literature & Language) (7, 7) <br />"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user