development #18
@@ -6,6 +6,7 @@ node_modules
 | 
			
		||||
 | 
			
		||||
.git
 | 
			
		||||
.gitattributes
 | 
			
		||||
.gitea
 | 
			
		||||
 | 
			
		||||
.eslintignore
 | 
			
		||||
.eslintrc.cjs
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								src/app.html
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/app.html
									
									
									
									
									
								
							@@ -95,6 +95,20 @@
 | 
			
		||||
				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 {
 | 
			
		||||
				0%   { opacity:0; }
 | 
			
		||||
				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;
 | 
			
		||||
        scroll-snap-align: start;
 | 
			
		||||
		transition: all 0.2s;
 | 
			
		||||
        box-shadow: .25em .25em .5em var(--hover);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .card:hover {
 | 
			
		||||
        box-shadow: .5em .5em .5em var(--hover);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import Toast from "./Toast.svelte";
 | 
			
		||||
 | 
			
		||||
  import { dismissToast, toasts } from "$lib/store";
 | 
			
		||||
  import { dismissToast, toasts } from "$lib/stores";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if $toasts}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Toast[]> = 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));
 | 
			
		||||
};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// 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">
 | 
			
		||||
    import { getJson } from "$lib/data";
 | 
			
		||||
	import { Toast, ToastType } from "$lib/toast";
 | 
			
		||||
    import { addToast } from "$lib/store";
 | 
			
		||||
    import { addToast } from "$lib/stores";
 | 
			
		||||
 | 
			
		||||
    import Skills from './skills.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 {
 | 
			
		||||
@@ -61,22 +62,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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
{#await getJson('/json/me.json')}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    import Card from '$lib/components/Cards/Card.svelte';
 | 
			
		||||
    import { Toast, ToastType } from "$lib/toast";
 | 
			
		||||
    import { addToast } from "$lib/store";
 | 
			
		||||
    import { addToast } from "$lib/stores";
 | 
			
		||||
 | 
			
		||||
    import { page } from '$app/stores';
 | 
			
		||||
    const sent = $page.url.searchParams.get('sent');
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,38 @@
 | 
			
		||||
<h1>Repos</h1>
 | 
			
		||||
<p>Stay tuned! This is still in development.</p>
 | 
			
		||||
<p>Come back later to find out what projects I'm currently working on!</p>
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    import { onMount } from "svelte";
 | 
			
		||||
    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",
 | 
			
		||||
      "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",
 | 
			
		||||
@@ -54,7 +59,7 @@
 | 
			
		||||
    {
 | 
			
		||||
      "duration" : "September 2015 - July 2020",
 | 
			
		||||
      "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 />"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user