Reorganise views/ directory structure to match routes
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 16s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 16s
Move shrines and bookmarks under home/, landing and 404 into own subdirectories, and retire Notes.vue (served by external service). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import DefaultLayout from "@/layouts/DefaultLayout.vue";
|
||||
import CVLayout from "@/layouts/CVLayout.vue";
|
||||
import Landing from "@/views/Landing.vue";
|
||||
import Landing from "@/views/landing/Landing.vue";
|
||||
import { useHomeDataStore } from "@/stores/homeData";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
@@ -30,42 +30,37 @@ const router = createRouter({
|
||||
{
|
||||
path: "bookmarks",
|
||||
name: "bookmarks",
|
||||
component: () => import("@/views/Bookmarks.vue"),
|
||||
},
|
||||
{
|
||||
path: "notes/:path(.*)*",
|
||||
name: "notes",
|
||||
component: () => import("@/views/Notes.vue"),
|
||||
component: () => import("@/views/home/bookmarks/Bookmarks.vue"),
|
||||
},
|
||||
{
|
||||
path: "shrines",
|
||||
name: "shrine links",
|
||||
component: () => import("@/views/Shrines.vue"),
|
||||
component: () => import("@/views/home/shrines/Shrines.vue"),
|
||||
},
|
||||
{
|
||||
path: "shrines/gto",
|
||||
name: "gto shrine",
|
||||
component: () => import("@/views/shrines/GTO.vue"),
|
||||
component: () => import("@/views/home/shrines/GTO.vue"),
|
||||
},
|
||||
{
|
||||
path: "shrines/skipskipbenben",
|
||||
name: "skipskipbenben shrine",
|
||||
component: () => import("@/views/shrines/Skipskipbenben.vue"),
|
||||
component: () => import("@/views/home/shrines/Skipskipbenben.vue"),
|
||||
},
|
||||
{
|
||||
path: "shrines/evangelion",
|
||||
name: "evangelion shrine",
|
||||
component: () => import("@/views/shrines/Evangelion.vue"),
|
||||
component: () => import("@/views/home/shrines/Evangelion.vue"),
|
||||
},
|
||||
{
|
||||
path: "shrines/demoman",
|
||||
name: "demoman shrine",
|
||||
component: () => import("@/views/shrines/Demoman.vue"),
|
||||
component: () => import("@/views/home/shrines/Demoman.vue"),
|
||||
},
|
||||
{
|
||||
path: ":pathMatch(.*)*",
|
||||
name: "404",
|
||||
component: () => import("@/views/404.vue"),
|
||||
component: () => import("@/views/404/404.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
13
vue/src/views/404/404.vue
Normal file
13
vue/src/views/404/404.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<main class="flex flex-col items-center">
|
||||
<div
|
||||
class="a4page-portrait items-center bdr-1 flex flex-col relative overflow-scroll"
|
||||
>
|
||||
<h1>404</h1>
|
||||
<RouterLink to="/" class="bdr-2">
|
||||
<img src="/img/memes/epic.jpeg" loading="lazy" />
|
||||
</RouterLink>
|
||||
<h1>Click her, she will take you home</h1>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
@@ -6,8 +6,8 @@ import Header from "@/components/text/Header.vue";
|
||||
const site_links = [
|
||||
{ name: "CV", link: "/cv" },
|
||||
{ name: "Bookmarks", link: "/bookmarks" },
|
||||
{ name: "Shrines", link: "/shrines" },
|
||||
{ name: "Admin", link: "/admin" },
|
||||
// { name: "Shrines", link: "/shrines" },
|
||||
];
|
||||
|
||||
const social_links = [
|
||||
|
||||
255
vue/src/views/home/bookmarks/Bookmarks.vue
Normal file
255
vue/src/views/home/bookmarks/Bookmarks.vue
Normal file
@@ -0,0 +1,255 @@
|
||||
<script setup>
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
|
||||
const links = [
|
||||
[
|
||||
"Reading Links",
|
||||
[
|
||||
{
|
||||
name: "Substack",
|
||||
link: "https://substack.com/",
|
||||
},
|
||||
{
|
||||
name: "Medium",
|
||||
link: "https://medium.com/",
|
||||
},
|
||||
{
|
||||
name: "4Chan",
|
||||
link: "https://www.4chan.org/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Job Links",
|
||||
[
|
||||
{
|
||||
name: "LinkedIn",
|
||||
link: "https://www.linkedin.com/",
|
||||
},
|
||||
{
|
||||
name: "Jack and Jill",
|
||||
link: "https://app.jackandjill.ai",
|
||||
},
|
||||
{
|
||||
name: "LinkedIn",
|
||||
link: "https://www.linkedin.com/",
|
||||
},
|
||||
{
|
||||
name: "Prospects",
|
||||
link: "https://www.prospects.ac.uk/",
|
||||
},
|
||||
{
|
||||
name: "GOV",
|
||||
link: "https://findajob.dwp.gov.uk",
|
||||
},
|
||||
{
|
||||
name: "Glassdoor",
|
||||
link: "https://www.glassdoor.co.uk/",
|
||||
},
|
||||
{
|
||||
name: "Indeed",
|
||||
link: "https://www.indeed.co.uk/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Learning Links",
|
||||
[
|
||||
{
|
||||
name: "Leetcode",
|
||||
link: "https://leetcode.com/",
|
||||
},
|
||||
{
|
||||
name: "ISLP",
|
||||
link: "https://hastie.su.domains/ISLP/ISLP_website.pdf.download.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Social Links",
|
||||
[
|
||||
{
|
||||
name: "Outlook",
|
||||
link: "https://outlook.live.com/",
|
||||
},
|
||||
{
|
||||
name: "Gmail",
|
||||
link: "https://mail.google.com/",
|
||||
},
|
||||
{
|
||||
name: "Whatsapp",
|
||||
link: "https://web.whatsapp.com/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Radio links",
|
||||
[
|
||||
{
|
||||
name: "Radio Helsinki",
|
||||
link: "https://www.radiohelsinki.fi/",
|
||||
},
|
||||
{
|
||||
name: "Palanga Street Radio",
|
||||
link: "https://palanga.live/",
|
||||
},
|
||||
{
|
||||
name: "IDA Radio",
|
||||
link: "https://idaidaida.net/",
|
||||
},
|
||||
{
|
||||
name: "Tīrkultūra",
|
||||
link: "https://www.tirkultura.lv/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Hacking Links",
|
||||
[
|
||||
{
|
||||
name: "pwn.college",
|
||||
link: "https://pwn.college/",
|
||||
},
|
||||
{
|
||||
name: "OSINT Framework",
|
||||
link: "https://osintframework.com/",
|
||||
},
|
||||
{
|
||||
name: "OverTheWire",
|
||||
link: "https://overthewire.org/",
|
||||
},
|
||||
{
|
||||
name: "TryHackMe",
|
||||
link: "https://tryhackme.com/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Chinese Links",
|
||||
[
|
||||
{
|
||||
name: "MDBG Chinese Dictionary",
|
||||
link: "https://www.mdbg.net/chinese/dictionary",
|
||||
},
|
||||
{
|
||||
name: "Stroke Order",
|
||||
link: "https://www.strokeorder.com/",
|
||||
},
|
||||
{
|
||||
name: "HSK 1 Peking University",
|
||||
link: "https://youtube.com/playlist?list=PLVWfp7qXLmKVfSUkucXErLncKn-JqgBbK&si=2ytO3inS8-iOAOx2",
|
||||
},
|
||||
{
|
||||
name: "Stroke Order",
|
||||
link: "https://www.strokeorder.com/",
|
||||
},
|
||||
{
|
||||
name: "Offbeat Mandarin",
|
||||
link: "https://www.youtube.com/@OffbeatMandarin",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Art links",
|
||||
[
|
||||
{
|
||||
name: "Frida Kahlo",
|
||||
link: "https://www.fridakahlo.org/",
|
||||
},
|
||||
{
|
||||
name: "Cameron's World",
|
||||
link: "https://www.cameronsworld.net/",
|
||||
},
|
||||
{
|
||||
name: "Neocities",
|
||||
link: "https://neocities.org/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Vue links",
|
||||
[
|
||||
{
|
||||
name: "Vue",
|
||||
link: "https://vuejs.org/guide/introduction.html",
|
||||
},
|
||||
{
|
||||
name: "Vue Router",
|
||||
link: "https://router.vuejs.org/introduction.html",
|
||||
},
|
||||
{
|
||||
name: "Pinia",
|
||||
link: "https://pinia.vuejs.org/introduction.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Go links",
|
||||
[
|
||||
{
|
||||
name: "Golang",
|
||||
link: "https://golang.org/doc/",
|
||||
},
|
||||
{
|
||||
name: "Gin Gonic",
|
||||
link: "https://gin-gonic.com/en/docs/introduction/",
|
||||
},
|
||||
{
|
||||
name: "GORM",
|
||||
link: "https://gorm.io/gen/index.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Doc links",
|
||||
[
|
||||
{
|
||||
name: "Rust",
|
||||
link: "https://doc.rust-lang.org/stable/book/index.html",
|
||||
},
|
||||
{
|
||||
name: "Javascript",
|
||||
link: "https://developer.mozilla.org/en-US/docs/Web/JavaScript",
|
||||
},
|
||||
{
|
||||
name: "Python",
|
||||
link: "https://docs.python.org/3/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Article links",
|
||||
[
|
||||
{
|
||||
name: "Go and GORM",
|
||||
link: "https://medium.com/@chaewonkong/learn-go-understanding-and-implementing-foreign-keys-with-gorm-6d7608e1dbf6",
|
||||
},
|
||||
{
|
||||
name: "JWT Auth in GO",
|
||||
link: "https://medium.com/monstar-lab-bangladesh-engineering/jwt-auth-in-go-dde432440924",
|
||||
},
|
||||
{
|
||||
name: "Websockets in GO",
|
||||
link: "https://medium.com/@tanngontn/golang-gin-framework-with-normal-websocket-and-websocket-with-producer-is-rabbitmq-guide-93cad7d290f7",
|
||||
},
|
||||
],
|
||||
],
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="items-center flex flex-col">
|
||||
<div
|
||||
class="a4page-portrait bdr-1 flex flex-row flex-wrap overflow-x-auto gap-1"
|
||||
>
|
||||
<div class="w-full h-fit">
|
||||
<LinkTable
|
||||
class="flex flex-col flex-wrap"
|
||||
v-for="link in links"
|
||||
:title="link[0]"
|
||||
:items="link[1]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
29
vue/src/views/home/shrines/Demoman.vue
Normal file
29
vue/src/views/home/shrines/Demoman.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup>
|
||||
import VideoTable from "@/components/util/VideoTable.vue";
|
||||
import Link from "@/components/text/Link.vue";
|
||||
|
||||
const videoSources = [
|
||||
{ name: "demoman", link: "/img/demoman/1760582395316219.webm" },
|
||||
{ name: "demoman", link: "/img/demoman/1761052136609718.webm" },
|
||||
{ name: "demoman", link: "/img/demoman/1761088452011210.mp4" },
|
||||
{ name: "demoman", link: "/img/demoman/1761570214170465.webm" },
|
||||
{ name: "demoman", link: "/img/demoman/1761828457509465.webm" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="items-center flex flex-col">
|
||||
<div
|
||||
class="a4page-portrait bdr-1 flex flex-row relative overflow-scroll items-center"
|
||||
>
|
||||
<p>
|
||||
<Link href="https://wiki.teamfortress.com/wiki/Demoman"
|
||||
>The goat</Link
|
||||
>
|
||||
</p>
|
||||
<div>
|
||||
<VideoTable :sourceArr="videoSources" />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
13
vue/src/views/home/shrines/Evangelion.vue
Normal file
13
vue/src/views/home/shrines/Evangelion.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<script setup>
|
||||
import Wip from "@/components/util/Wip.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="items-center flex flex-col">
|
||||
<div
|
||||
class="a4page-portrait items-center bdr-1 flex flex-col relative overflow-scroll"
|
||||
>
|
||||
<Wip />
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
11
vue/src/views/home/shrines/GTO.vue
Normal file
11
vue/src/views/home/shrines/GTO.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup>
|
||||
import Wip from "@/components/util/Wip.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="items-center flex flex-col">
|
||||
<div class="a4page-portrait items-center bdr-1 flex flex-col relative overflow-scroll">
|
||||
<Wip />
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
20
vue/src/views/home/shrines/Shrines.vue
Normal file
20
vue/src/views/home/shrines/Shrines.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<script setup>
|
||||
import RouterTable from "@/components/util/RouterTable.vue";
|
||||
const shrine_links = [
|
||||
{ name: "Demoman", link: "/shrines/demoman" },
|
||||
{ name: "Evangelion", link: "/shrines/evangelion" },
|
||||
{ name: "GTO", link: "/shrines/gto" },
|
||||
{ name: "Skipskipbenben", link: "/shrines/skipskipbenben" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="items-center flex flex-col">
|
||||
<div class="background" />
|
||||
<div
|
||||
class="a4page-portrait bdr-1 flex flex-col relative overflow-scroll gap-1"
|
||||
>
|
||||
<RouterTable :linkArr="shrine_links" />
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
13
vue/src/views/home/shrines/Skipskipbenben.vue
Normal file
13
vue/src/views/home/shrines/Skipskipbenben.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<script setup>
|
||||
import Wip from "@/components/util/Wip.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="items-center flex flex-col">
|
||||
<div
|
||||
class="a4page-portrait items-center bdr-1 flex flex-col relative overflow-scroll"
|
||||
>
|
||||
<Wip />
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
56
vue/src/views/landing/Landing.vue
Normal file
56
vue/src/views/landing/Landing.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<script setup>
|
||||
import Link from "@/components/text/Link.vue";
|
||||
import InlineLink from "@/components/text/InlineLink.vue";
|
||||
import Header from "@/components/text/Header.vue";
|
||||
import Paragraph from "@/components/text/Paragraph.vue";
|
||||
|
||||
const links = [
|
||||
{ name: "GitHub", href: "https://github.com/SteveThePug" },
|
||||
{ name: "Gitea", href: "/gitea/explore/repos" },
|
||||
{ name: "Spotify", href: "https://open.spotify.com/user/stevethepug" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="flex justify-center px-4 py-16">
|
||||
<div class="max-w-xl w-full flex flex-col gap-12">
|
||||
<section>
|
||||
<Header>Adam French</Header>
|
||||
<Paragraph>
|
||||
Junior software engineer focused on full-stack development,
|
||||
systems programming, and infrastructure. First Class Honours
|
||||
in Computer Science with Mathematics from Leeds and
|
||||
Waterloo.
|
||||
</Paragraph>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Header>About</Header>
|
||||
<Paragraph>
|
||||
This website is self-hosted and has a lot more on it than it
|
||||
needs to. Please have a look at my
|
||||
<InlineLink to="/cv">CV</InlineLink> for a full breakdown of
|
||||
my experience, projects, and skills. Please visit
|
||||
<InlineLink to="/stp">STP</InlineLink> for the prefered but
|
||||
less professional experience.
|
||||
</Paragraph>
|
||||
</section>
|
||||
|
||||
<nav class="navRow flex flex-row flex-wrap gap-4 justify-around">
|
||||
<Link to="/cv"> CV </Link>
|
||||
<Link to="/stp"> STP </Link>
|
||||
<Link href="mailto:adam.a.french@outlook.com"> Email </Link>
|
||||
<Link v-for="link in links" :key="link.name" :href="link.href">
|
||||
{{ link.name }}
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.navRow > a {
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid currentColor;
|
||||
}
|
||||
</style>
|
||||
75
vue/src/views/unused/Notes.vue
Normal file
75
vue/src/views/unused/Notes.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<script setup>
|
||||
import Markdown from "@/components/util/Markdown.vue";
|
||||
import { ref, onMounted } from "vue";
|
||||
import axios from "axios";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const file = ref(null);
|
||||
const filename = ref("");
|
||||
const last_edited = ref(null);
|
||||
|
||||
// if the address is https://www.adam-french.co.uk/notes/PATH
|
||||
// request from https://www.adam-french.co.uk/api/notes/PATH
|
||||
const route = useRoute();
|
||||
const pathArray = route.params.path;
|
||||
const path = Array.isArray(pathArray) ? pathArray.join("/") : pathArray;
|
||||
const url = `/api/notes/${path}`;
|
||||
|
||||
function getFilename(headers) {
|
||||
const disposition = headers["content-disposition"];
|
||||
if (!disposition) return null;
|
||||
|
||||
const match = disposition.match(/filename="?([^"]+)"?/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
async function fetchFile() {
|
||||
const response = await axios.get(url, { responseType: "blob" });
|
||||
filename.value = getFilename(response.headers);
|
||||
|
||||
const lastModified = response.headers["last-modified"];
|
||||
last_edited.value = lastModified ? new Date(lastModified) : null;
|
||||
|
||||
if (filename.value.toLowerCase().endsWith(".md")) {
|
||||
const text = await response.data.text();
|
||||
file.value = fixLinks(text);
|
||||
} else {
|
||||
file.value = response.data;
|
||||
}
|
||||
}
|
||||
|
||||
function fixLinks(filedata) {
|
||||
return filedata.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => {
|
||||
if (
|
||||
url.startsWith("http://") ||
|
||||
url.startsWith("https://") ||
|
||||
url.startsWith("#") ||
|
||||
url.startsWith("./") ||
|
||||
url.startsWith("../") ||
|
||||
url.startsWith("//")
|
||||
) {
|
||||
return match;
|
||||
}
|
||||
|
||||
return `[${text}](/notes/${url})`;
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(fetchFile);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="items-center flex flex-col">
|
||||
<div class="background" />
|
||||
<div
|
||||
v-if="file"
|
||||
class="a4page-portrait border-primary-1 flex flex-col relative overflow-scroll gap-1 bg-bg_primary"
|
||||
>
|
||||
<h1>{{ filename }}</h1>
|
||||
<small>{{ last_edited }}</small>
|
||||
<Markdown class="flex-1 border-box text-wrap" :source="file" />
|
||||
</div>
|
||||
|
||||
<div v-else>Loading…</div>
|
||||
</main>
|
||||
</template>
|
||||
Reference in New Issue
Block a user