Compare commits
5 Commits
8627a7945e
...
570a823426
| Author | SHA1 | Date | |
|---|---|---|---|
| 570a823426 | |||
| 6dddcd4d7a | |||
| 69e158b871 | |||
| d857cce5dc | |||
| c2bbd7ad88 |
@@ -16,7 +16,7 @@ const parentPath = computed(() => {
|
||||
});
|
||||
|
||||
const inHome = computed(() => {
|
||||
return route.path == "/";
|
||||
return route.path == "/" || route.path == "/stp";
|
||||
});
|
||||
|
||||
const faces = [
|
||||
@@ -47,10 +47,10 @@ const faces_string = faces.join(" ");
|
||||
<template>
|
||||
<nav class="flex flex-row w-full h-fit border border-primary bg-bg_primary">
|
||||
<RouterLink class="bdr-2 bg-bg_primary" to="/" v-if="!inHome">
|
||||
<a>HOME</a>
|
||||
<span>HOME</span>
|
||||
</RouterLink>
|
||||
<RouterLink class="bdr-2 bg-bg_primary" v-if="parentPath" :to="parentPath">
|
||||
<a>UP</a>
|
||||
<span>UP</span>
|
||||
</RouterLink>
|
||||
<Headline class="border flex-1 max-w-full">
|
||||
<code class="whitespace-pre">{{ faces_string }}</code>
|
||||
|
||||
39
nginx/vue/src/components/text/InlineLink.vue
Normal file
39
nginx/vue/src/components/text/InlineLink.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
href: { type: String, default: "" },
|
||||
to: { type: String, default: "" },
|
||||
target: { type: String, default: undefined },
|
||||
rel: { type: String, default: undefined },
|
||||
});
|
||||
|
||||
const computedRel = computed(() => {
|
||||
if (props.rel !== undefined) return props.rel;
|
||||
if (props.target === "_blank") return "noopener noreferrer";
|
||||
return undefined;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterLink v-if="to" :to="to" class="inline-link">
|
||||
<slot />
|
||||
</RouterLink>
|
||||
<a v-else :href="href" :target="target" :rel="computedRel" class="inline-link">
|
||||
<slot />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.inline-link {
|
||||
color: var(--primary);
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
text-decoration: none;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.inline-link:hover {
|
||||
color: var(--tertiary);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,38 @@
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
href: { type: String, default: "" },
|
||||
to: { type: String, default: "" },
|
||||
target: { type: String, default: undefined },
|
||||
rel: { type: String, default: undefined },
|
||||
bare: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const computedRel = computed(() => {
|
||||
if (props.rel !== undefined) return props.rel;
|
||||
if (props.target === "_blank") return "noopener noreferrer";
|
||||
return undefined;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterLink v-if="to" :to="to" :class="{ link: !bare }">
|
||||
<slot />
|
||||
</RouterLink>
|
||||
<a v-else :href="href" :target="target" :rel="computedRel" :class="{ link: !bare }">
|
||||
<slot />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.link {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
color: var(--tertiary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,6 +4,7 @@ import Button from "@/components/input/Button.vue";
|
||||
import { useMessagesStore } from "@/stores/messages";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import Header from "@/components/text/Header.vue";
|
||||
import Link from "@/components/text/Link.vue";
|
||||
|
||||
const messagesStore = useMessagesStore();
|
||||
const authStore = useAuthStore();
|
||||
@@ -79,7 +80,7 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-col flex min-h-0">
|
||||
<div class="chat-root flex-col flex min-h-0">
|
||||
<Header>Chat</Header>
|
||||
<div ref="messagesContainer" class="flex flex-col flex-1 min-h-0 overflow-y-auto overflow-x-hidden p-2 min-w-0">
|
||||
<p v-for="message in messages" :key="message.id" class="break-words min-w-0 w-full">
|
||||
@@ -88,13 +89,13 @@ onUnmounted(() => {
|
||||
v-for="(part, i) in parseMessageParts(message.text || '')"
|
||||
:key="i"
|
||||
>
|
||||
<a
|
||||
<Link
|
||||
v-if="part.type === 'link'"
|
||||
bare
|
||||
:href="part.value"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-primary underline break-all"
|
||||
>{{ part.value }}</a
|
||||
>{{ part.value }}</Link
|
||||
>
|
||||
<span v-else>{{ part.value }}</span>
|
||||
</template>
|
||||
@@ -112,9 +113,9 @@ onUnmounted(() => {
|
||||
class="w-full max-w-full max-h-48 rounded block"
|
||||
@loadedmetadata="scrollToBottom"
|
||||
/>
|
||||
<a v-else :href="message.fileUrl" target="_blank" class="underline break-all">{{
|
||||
<Link v-else bare :href="message.fileUrl" target="_blank" class="underline break-all">{{
|
||||
message.fileUrl.split("/").pop()
|
||||
}}</a>
|
||||
}}</Link>
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
@@ -139,3 +140,11 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@media (max-width: 850px) {
|
||||
.chat-root {
|
||||
max-height: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useHomeDataStore } from "@/stores/homeData";
|
||||
import { storeToRefs } from "pinia";
|
||||
import Header from "@/components/text/Header.vue";
|
||||
import Link from "@/components/text/Link.vue";
|
||||
|
||||
const homeData = useHomeDataStore();
|
||||
const { gitFeed: feed, loaded } = storeToRefs(homeData);
|
||||
@@ -18,9 +19,9 @@ const { gitFeed: feed, loaded } = storeToRefs(homeData);
|
||||
<div v-else-if="feed" class="flex-1 flex flex-col overflow-y-auto">
|
||||
<h3>Last git activity</h3>
|
||||
<img :src="feed.avatarUrl" alt="User avatar" class="avatar" />
|
||||
<a :href="feed.repoUrl">
|
||||
<Link :href="feed.repoUrl">
|
||||
<h3>repo: {{ feed.repoName }}</h3>
|
||||
</a>
|
||||
</Link>
|
||||
<p>Action: {{ feed.opType }}</p>
|
||||
<p>Message: {{ feed.commitMessage }}</p>
|
||||
<small> {{ new Date(feed.createdAt).toLocaleString() }}</small>
|
||||
|
||||
@@ -1,20 +1,73 @@
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import { ref } from "vue";
|
||||
import Link from "@/components/text/Link.vue";
|
||||
import ToggleHeader from "@/components/text/ToggleHeader.vue";
|
||||
|
||||
const props = defineProps({
|
||||
linkArr: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
variant: {
|
||||
type: String,
|
||||
default: "list",
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const keys = ["name", "link"];
|
||||
const show = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a v-for="(row, rowIndex) in linkArr" :key="rowIndex" :href="row.link">
|
||||
<p class="bdr-2 bg-bg_tertiary">
|
||||
{{ row.name }}
|
||||
</p>
|
||||
</a>
|
||||
<div v-if="title" class="h-fit w-fit">
|
||||
<ToggleHeader v-model="show" class="justify-between flex">
|
||||
{{ title }}
|
||||
</ToggleHeader>
|
||||
<template v-if="show">
|
||||
<Link
|
||||
v-if="variant === 'list'"
|
||||
v-for="(item, i) in items"
|
||||
:key="i"
|
||||
:href="item.link"
|
||||
>
|
||||
<p class="bdr-2 bg-bg_tertiary">{{ item.name }}</p>
|
||||
</Link>
|
||||
<table v-else>
|
||||
<tbody>
|
||||
<tr v-for="item in items" :key="item.id">
|
||||
<th>{{ item.type }}</th>
|
||||
<td v-if="item.link">
|
||||
<Link :href="item.link">{{ item.name }}</Link>
|
||||
</td>
|
||||
<td v-else>{{ item.name }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
</div>
|
||||
<template v-else>
|
||||
<template v-if="variant === 'list'">
|
||||
<Link
|
||||
v-for="(item, i) in items"
|
||||
:key="i"
|
||||
:href="item.link"
|
||||
>
|
||||
<p class="bdr-2 bg-bg_tertiary">{{ item.name }}</p>
|
||||
</Link>
|
||||
</template>
|
||||
<table v-else>
|
||||
<tbody>
|
||||
<tr v-for="item in items" :key="item.id">
|
||||
<th>{{ item.type }}</th>
|
||||
<td v-if="item.link">
|
||||
<Link :href="item.link">{{ item.name }}</Link>
|
||||
</td>
|
||||
<td v-else>{{ item.name }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<script setup>
|
||||
// Array will have the form
|
||||
// [ {type: string, name: string, link?: string}]
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const keys = ["type", "name", "link"];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr v-for="item in data" :key="item.id">
|
||||
<th>{{ item.type }}</th>
|
||||
<td v-if="item.link">
|
||||
<a :href="item.link">{{ item.name }}</a>
|
||||
</td>
|
||||
<td v-else>{{ item.name }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
@@ -46,3 +46,11 @@ onMounted(() => {
|
||||
setInterval(checkStream, 120000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
img {
|
||||
width: 100%;
|
||||
max-height: 150px;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -29,3 +29,10 @@ setInterval(updateDateTime, 60000);
|
||||
<h1>{{ time }}</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
div {
|
||||
text-align: center;
|
||||
padding: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -65,7 +65,7 @@ function playFinishedSound() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-1 p-1 items-center">
|
||||
<div class="timer-root flex flex-col gap-1 p-1 items-center">
|
||||
<Header>Timer</Header>
|
||||
<div v-if="finished && paused" class="flex flex-col">
|
||||
<div class="flex flex-row p-2 place-content-around">
|
||||
@@ -113,3 +113,12 @@ function playFinishedSound() {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@media (max-width: 850px) {
|
||||
.timer-root {
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
<script setup>
|
||||
import ToggleHeader from "@/components/text/ToggleHeader.vue";
|
||||
|
||||
import { ref } from "vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
|
||||
const props = defineProps({
|
||||
linkArr: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const show_links = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-fit w-fit">
|
||||
<ToggleHeader v-model="show_links" class="justify-between flex"
|
||||
>{{ title }}
|
||||
</ToggleHeader>
|
||||
<LinkTable v-if="show_links" :linkArr="props.linkArr" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,13 +1,18 @@
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import Home from "@/views/home/Home.vue";
|
||||
import Landing from "@/views/Landing.vue";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
name: "landing",
|
||||
component: Landing,
|
||||
},
|
||||
{
|
||||
path: "/stp",
|
||||
name: "home",
|
||||
component: Home,
|
||||
component: () => import("@/views/home/Home.vue"),
|
||||
},
|
||||
{
|
||||
path: "/cv",
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
import ToggleLinkTable from "@/components/util/ToggleLinkTable.vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
|
||||
const links = [
|
||||
[
|
||||
@@ -245,11 +243,11 @@ const links = [
|
||||
class="a4page-portrait bdr-1 flex flex-row flex-wrap overflow-x-auto gap-1"
|
||||
>
|
||||
<div class="w-full h-fit">
|
||||
<ToggleLinkTable
|
||||
<LinkTable
|
||||
class="flex flex-col flex-wrap"
|
||||
v-for="link in links"
|
||||
:title="link[0]"
|
||||
:linkArr="link[1]"
|
||||
:items="link[1]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
56
nginx/vue/src/views/Landing.vue
Normal file
56
nginx/vue/src/views/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="halftone 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,6 +1,6 @@
|
||||
<script setup>
|
||||
import AutoScroll from "@/components/util/AutoScroll.vue";
|
||||
import OptionalLinkTable from "@/components/util/OptionalLinkTable.vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
import Header from "@/components/text/Header.vue";
|
||||
|
||||
import { useActivityStore } from "@/stores/activity";
|
||||
@@ -12,7 +12,7 @@ const activityStore = useActivityStore();
|
||||
<div class="flex flex-col items-center">
|
||||
<Header>Consumption</Header>
|
||||
<AutoScroll class="flex-1 w-full">
|
||||
<OptionalLinkTable class="w-full" :data="activityStore.activity" />
|
||||
<LinkTable variant="table" class="w-full" :items="activityStore.activity" />
|
||||
</AutoScroll>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import Header from "@/components/text/Header.vue";
|
||||
import OptionalLinkTable from "@/components/util/OptionalLinkTable.vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
import AutoScroll from "@/components/util/AutoScroll.vue";
|
||||
|
||||
import { useFavoritesStore } from "@/stores/favorites";
|
||||
@@ -12,9 +12,10 @@ const favoritesStore = useFavoritesStore();
|
||||
<div class="flex flex-col items-center">
|
||||
<Header>favs</Header>
|
||||
<AutoScroll class="w-full flex-1">
|
||||
<OptionalLinkTable
|
||||
<LinkTable
|
||||
variant="table"
|
||||
class="w-full"
|
||||
:data="favoritesStore.favorites"
|
||||
:items="favoritesStore.favorites"
|
||||
/>
|
||||
</AutoScroll>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import Header from "@/components/text/Header.vue";
|
||||
import OptionalLinkTable from "@/components/util/OptionalLinkTable.vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
const gym = [
|
||||
{ name: "Row", type: "30 min" },
|
||||
{ name: "Run", type: "5k" },
|
||||
@@ -14,7 +14,7 @@ const gym = [
|
||||
<p>I'm not a gym geek</p>
|
||||
<p>4/7 days I do:</p>
|
||||
<div class="overflow-scroll w-full border-box">
|
||||
<OptionalLinkTable class="w-full" :data="gym" />
|
||||
<LinkTable variant="table" class="w-full" :items="gym" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -31,7 +31,7 @@ import Consumption from "./Consumption.vue";
|
||||
>
|
||||
<Chat class="flex-1 min-h-0" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="sidebar-image">
|
||||
<Miku class="border-tertiary border bg-bg_secondary" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,7 +63,7 @@ import Consumption from "./Consumption.vue";
|
||||
<!-- <Elle class="flex-1" /> -->
|
||||
<!-- <MusicPlayer /> -->
|
||||
</div>
|
||||
<div>
|
||||
<div class="sidebar-image">
|
||||
<img
|
||||
src="/img/memes/fire-woman.gif"
|
||||
class="border-tertiary border"
|
||||
@@ -122,14 +122,24 @@ import Consumption from "./Consumption.vue";
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 8px;
|
||||
justify-items: stretch;
|
||||
}
|
||||
|
||||
.sidebar > * {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.sidebar-image {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.sidebar-image :deep(img) {
|
||||
max-height: 200px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ const social_links = [
|
||||
<RouterTable :linkArr="site_links" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<LinkTable :linkArr="social_links" />
|
||||
<LinkTable :items="social_links" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { ref } from "vue";
|
||||
|
||||
import Touchscreen from "@/components/util/Touchscreen.vue";
|
||||
import Link from "@/components/text/Link.vue";
|
||||
import { shuffleArray } from "@/js/utils.js";
|
||||
|
||||
let srcs = [
|
||||
@@ -23,15 +24,15 @@ shuffleArray(srcs);
|
||||
<template>
|
||||
<Touchscreen>
|
||||
<div class="flex flex-wrap tst">
|
||||
<a href="https://www.adam-french.co.uk">
|
||||
<Link bare href="https://www.adam-french.co.uk">
|
||||
<img src="https://www.adam-french.co.uk/img/stamps/mine.gif" />
|
||||
</a>
|
||||
<a href="https://jacobbarron.xyz">
|
||||
</Link>
|
||||
<Link bare href="https://jacobbarron.xyz">
|
||||
<img
|
||||
src="https://jacobbarron.xyz/Banneh.gif"
|
||||
alt="jacobbarron.xyz"
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
<img v-for="src in srcs" :src="src" />
|
||||
</div>
|
||||
</Touchscreen>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<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" },
|
||||
@@ -16,8 +17,8 @@ const videoSources = [
|
||||
class="a4page-portrait bdr-1 flex flex-row relative overflow-scroll items-center"
|
||||
>
|
||||
<p>
|
||||
<a href="https://wiki.teamfortress.com/wiki/Demoman"
|
||||
>The goat</a
|
||||
<Link href="https://wiki.teamfortress.com/wiki/Demoman"
|
||||
>The goat</Link
|
||||
>
|
||||
</p>
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user