Split admin login into its own route and add auth guard to /admin
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 28s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 28s
- Add /admin/login route for Login.vue as a standalone page - Add requiresAdmin guard to /admin route - Update auth guard redirect to /admin/login with redirect query param - Update nginx @auth_denied to redirect to /admin/login - Remove Login component from Admin.vue; drop v-if auth checks (guard handles access) - Remove stale view files from old views/ structure (moved in prior commit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -246,7 +246,7 @@ http {
|
|||||||
}
|
}
|
||||||
|
|
||||||
location @auth_denied {
|
location @auth_denied {
|
||||||
return 302 /admin;
|
return 302 /admin/login;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /searxng {
|
location /searxng {
|
||||||
|
|||||||
@@ -22,10 +22,16 @@ const router = createRouter({
|
|||||||
name: "home",
|
name: "home",
|
||||||
component: () => import("@/views/home/Home.vue"),
|
component: () => import("@/views/home/Home.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "admin/login",
|
||||||
|
name: "admin-login",
|
||||||
|
component: () => import("@/views/admin/Login.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "admin",
|
path: "admin",
|
||||||
name: "admin",
|
name: "admin",
|
||||||
component: () => import("@/views/admin/Admin.vue"),
|
component: () => import("@/views/admin/Admin.vue"),
|
||||||
|
meta: { requiresAdmin: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "bookmarks",
|
path: "bookmarks",
|
||||||
@@ -94,7 +100,7 @@ router.beforeEach(async (to) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!useAuthStore().user.admin) return "/admin";
|
if (!useAuthStore().user.admin) return { path: "/admin/login", query: { redirect: to.fullPath } };
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,255 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
|
||||||
import { useAuthStore } from "@/stores/auth";
|
|
||||||
|
|
||||||
import Login from "./Login.vue";
|
|
||||||
import CreateUser from "./CreateUser.vue";
|
import CreateUser from "./CreateUser.vue";
|
||||||
import CreatePost from "./CreatePost.vue";
|
import CreatePost from "./CreatePost.vue";
|
||||||
import CreateFavorite from "./CreateFavorite.vue";
|
import CreateFavorite from "./CreateFavorite.vue";
|
||||||
@@ -10,21 +6,18 @@ import CreateActivity from "./CreateActivity.vue";
|
|||||||
import CreateRowing from "./CreateRowing.vue";
|
import CreateRowing from "./CreateRowing.vue";
|
||||||
import ManageUsers from "./ManageUsers.vue";
|
import ManageUsers from "./ManageUsers.vue";
|
||||||
import ManageRadio from "./ManageRadio.vue";
|
import ManageRadio from "./ManageRadio.vue";
|
||||||
|
|
||||||
const auth = useAuthStore();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main class="justify-center flex flex-row w-full h-full">
|
<main class="justify-center flex flex-row w-full h-full">
|
||||||
<div class="bdr-1 flex flex-col">
|
<div class="bdr-1 flex flex-col">
|
||||||
<Login class="bdr-2 bg-bg_primary" />
|
<CreateUser class="bdr-2 bg-bg_primary" />
|
||||||
<CreateUser class="bdr-2 bg-bg_primary" v-if="auth.loggedIn" />
|
<CreatePost class="bdr-2 bg-bg_primary" />
|
||||||
<CreatePost class="bdr-2 bg-bg_primary" v-if="auth.loggedIn" />
|
<CreateFavorite class="bdr-2 bg-bg_primary" />
|
||||||
<CreateFavorite class="bdr-2 bg-bg_primary" v-if="auth.loggedIn" />
|
<CreateActivity class="bdr-2 bg-bg_primary" />
|
||||||
<CreateActivity class="bdr-2 bg-bg_primary" v-if="auth.loggedIn" />
|
<CreateRowing class="bdr-2 bg-bg_primary" />
|
||||||
<CreateRowing class="bdr-2 bg-bg_primary" v-if="auth.loggedIn" />
|
<ManageUsers class="bdr-2 bg-bg_primary" />
|
||||||
<ManageUsers class="bdr-2 bg-bg_primary" v-if="auth.loggedIn" />
|
<ManageRadio class="bdr-2 bg-bg_primary" />
|
||||||
<ManageRadio class="bdr-2 bg-bg_primary" v-if="auth.loggedIn" />
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<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>
|
|
||||||
Reference in New Issue
Block a user