remove text based componets, add blog, minor theming changes

This commit is contained in:
2026-01-30 17:58:52 -05:00
parent 24b8a6c4ec
commit d5d0fb904a
18 changed files with 1510 additions and 322 deletions

View File

@@ -1,23 +1,126 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<pre class="text-terminal font-mono whitespace-pre-wrap">{{ aboutTxt }}</pre>
<div class="h-full overflow-auto p-6">
<h1 class="text-3xl font-bold mb-6 text-[#000080] border-b-2 border-[#808080] pb-3">About Me</h1>
<!-- Profile Card -->
<div class="bg-white border-2 border-[#808080] p-6 shadow-md mb-6">
<div class="flex items-start gap-6 mb-6">
<div class="profile-avatar w-32 h-32 bg-[#000080] border-2 border-[#808080] flex items-center justify-center">
<User :size="64" color="#ffffff" />
</div>
<div class="flex-1">
<h2 class="text-3xl font-bold text-[#000080] mb-2">SticksDev</h2>
<p class="text-xl text-gray-700 mb-3">Tanner Sommers</p>
<div class="space-y-2 text-gray-700">
<div class="flex items-center gap-2">
<span class="font-semibold min-w-25">Age:</span>
<span>22</span>
</div>
<div class="flex items-center gap-2">
<span class="font-semibold min-w-25">Location:</span>
<span>United States (UTC-5)</span>
</div>
<div class="flex items-center gap-2">
<span class="font-semibold min-w-25">Occupation:</span>
<span>Software Engineer / Freelancer</span>
</div>
</div>
</div>
</div>
<div class="border-t-2 border-[#808080] pt-4">
<p class="text-gray-700 leading-relaxed">
Hi! I'm Tanner, a software engineer and freelancer from the US. I love coding, gaming, and learning new things.
I'm always looking for opportunities to grow and expand my skillset. Feel free to reach out to me if you have any
questions or just want to chat!
</p>
</div>
</div>
<!-- Skills Section -->
<div class="bg-white border-2 border-[#808080] p-6 shadow-md mb-6">
<h3 class="text-xl font-bold mb-4 flex items-center gap-2">
<Code :size="20" />
Technical Skills
</h3>
<div class="flex flex-wrap gap-2">
<span
v-for="skill in skills"
:key="skill"
class="skill-badge"
>
{{ skill }}
</span>
</div>
</div>
<!-- Interests & Hobbies -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="bg-white border-2 border-[#808080] p-5 shadow-md">
<h3 class="text-lg font-bold mb-3 flex items-center gap-2">
<Target :size="18" />
Interests
</h3>
<ul class="space-y-2">
<li
v-for="interest in interests"
:key="interest"
class="flex items-center gap-2 text-gray-700"
>
<ChevronRight :size="14" class="text-[#000080]" />
{{ interest }}
</li>
</ul>
</div>
<div class="bg-white border-2 border-[#808080] p-5 shadow-md">
<h3 class="text-lg font-bold mb-3 flex items-center gap-2">
<Gamepad2 :size="18" />
Hobbies
</h3>
<ul class="space-y-2">
<li
v-for="hobby in hobbies"
:key="hobby"
class="flex items-center gap-2 text-gray-700"
>
<ChevronRight :size="14" class="text-[#000080]" />
{{ hobby }}
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const aboutTxt = `
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ---- Reading file about_me.inf ----
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ---- File read successful ----
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Name: SticksDev (Tanner Sommers)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Age: 21
@@@@@@@@@@@****+++=@@@@@@@@@ Location: United States (UTC-5)
@@@@@@@@@=-@@@@@@@@@@@@@@@@@ Occupation: Software Engineer/Freelancer
@@@@@@@@@.:@@@@@@@@@@@@@@@@@ Skills: JavaScript, TypeScript, React, Svelte, Node.js, Python, C#, Java
@@@@@@@@@@@------@@@@@@@@@@@ Interests: Web Development, Game Development, Cybersecurity
@@@@@@@@@@@@@@@@@--@@@@@@@@@ Hobbies: Coding, Gaming, Chess, Music
@@@@@@@@@==+++***@@@@@@@@@@@ Bio:
@@@@@@@@@%%%%@@%@@@@@@@@@@@@ Hi! I'm Tanner, a software engineer and freelancer from the United States.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ I love coding, gaming, and learning new things. I'm always looking for new
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ opportunities to grow and expand my skillset. Feel free to reach out to me
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if you have any questions or just want to chat!
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ---- End of file ----
`
import { User, Code, Target, Gamepad2, ChevronRight } from 'lucide-vue-next'
const skills = ['JavaScript', 'TypeScript', 'Vue.js', 'React', 'Node.js', 'Python', 'C#', 'Java']
const interests = ['Web Development', 'Game Development', 'Cybersecurity']
const hobbies = ['Coding', 'Gaming', 'Chess', 'Music']
</script>
<style scoped>
.profile-avatar {
box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1);
}
.skill-badge {
color: #ffffff;
padding: 0.375rem 0.75rem;
border: 2px solid #808080;
font-size: 0.875rem;
font-weight: 600;
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.2);
transition: transform 0.2s, box-shadow 0.2s, background-color 0.2s;
}
.skill-badge:hover {
background-color: #1084d0;
transform: translateY(-1px);
box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.2);
}
</style>

View File

@@ -0,0 +1,148 @@
<template>
<Teleport to="body">
<div
v-if="isOpen"
id="aboutDiag"
class="fixed inset-0 flex items-center justify-center z-50"
@click.self="close"
>
<div
class="bg-[#c0c0c0] border-2 border-white border-r-[#808080] border-b-[#808080] shadow-lg"
style="width: 400px"
@mousedown="startDrag"
>
<!-- Title Bar -->
<div
ref="titleBar"
class="bg-linear-to-r from-[#0054E3] to-[#3C8CF7] px-2 py-1 flex justify-between items-center cursor-move"
>
<div class="flex items-center gap-1 text-white font-bold text-sm">
<span>About ShrimpOS</span>
</div>
<button
class="bg-[#c0c0c0] border-2 border-white border-r-[#808080] border-b-[#808080] w-6 h-6 flex items-center justify-center text-xs font-bold hover:bg-[#dfdfdf]"
@click="close"
>
<X :size="60" />
</button>
</div>
<!-- Content -->
<div class="p-6">
<div class="flex items-start gap-4 mb-4">
<div class="text-6xl">🦐</div>
<div class="flex-1">
<h2 class="text-2xl font-bold mb-2">ShrimpOS</h2>
<p class="text-sm mb-1">Version 1.0</p>
<p class="text-xs text-gray-600 mb-4">© 2026 ShrimpOS. All rights reserved.</p>
</div>
</div>
<div class="border-t-2 border-[#808080] border-b-2 pt-3 pb-3 mb-4">
<p class="text-sm mb-3">
<strong>ShrimpOS is activated.</strong>
</p>
<p class="text-xs text-gray-700 leading-relaxed">
If you encounter any issues or have questions, please contact us
at 1-800-SHRIMP-OS or visit our website at
<a href="https://teamhydra.dev" class="text-blue-600 underline" target="_blank">www.shrimpos.com/support</a>.
</p>
</div>
<div class="mb-4">
<p class="text-xs font-bold mb-2">ShrimpOS is proudly powered by:</p>
<div class="space-y-1 text-xs">
<div class="flex items-center gap-2">
<span class="text-[#42b883]"></span>
<span>Vue.js - Progressive JavaScript Framework</span>
</div>
<div class="flex items-center gap-2">
<span class="text-[#00DC82]"></span>
<span>Nuxt 3 - The Intuitive Vue Framework</span>
</div>
<div class="flex items-center gap-2">
<span class="text-[#F38020]"></span>
<span>Cloudflare Pages - Fast & Secure Hosting</span>
</div>
<div class="flex items-center gap-2">
<span class="text-[#F6821F]"></span>
<span>Cloudflare D1 - Serverless SQL Database</span>
</div>
</div>
</div>
<div class="flex justify-end">
<button
class="bg-[#c0c0c0] border-2 border-white border-r-[#808080] border-b-[#808080] px-6 py-1 text-sm hover:bg-[#dfdfdf] active:border-[#808080] active:border-r-white active:border-b-white"
@click="close"
>
OK
</button>
</div>
</div>
</div>
</div>
</Teleport>
</template>
<script setup lang="ts">
import { X } from 'lucide-vue-next'
import { ref } from 'vue'
defineProps<{
isOpen: boolean
}>()
defineOptions({
name: 'AboutShrimpOS'
})
const emit = defineEmits<{
close: []
}>()
const titleBar = ref<HTMLElement | null>(null)
const isDragging = ref(false)
const dragOffset = ref({ x: 0, y: 0 })
const close = () => {
emit('close')
}
const startDrag = (e: MouseEvent) => {
// Only start dragging if clicking on the title bar, not the close button
if ((e.target as HTMLElement).closest('.bg-gradient-to-r') && !(e.target as HTMLElement).closest('button')) {
isDragging.value = true
const dialog = (e.currentTarget as HTMLElement)
const rect = dialog.getBoundingClientRect()
dragOffset.value = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
}
document.addEventListener('mousemove', drag)
document.addEventListener('mouseup', stopDrag)
}
}
const drag = (e: MouseEvent) => {
if (!isDragging.value) return
const dialog = document.getElementById('aboutDiag')?.firstElementChild as HTMLElement
if (dialog) {
dialog.style.position = 'fixed'
dialog.style.left = `${e.clientX - dragOffset.value.x}px`
dialog.style.top = `${e.clientY - dragOffset.value.y}px`
}
}
const stopDrag = () => {
isDragging.value = false
document.removeEventListener('mousemove', drag)
document.removeEventListener('mouseup', stopDrag)
}
</script>
<style scoped>
.cursor-move {
cursor: move;
}
</style>

220
app/components/Blog.vue Normal file
View File

@@ -0,0 +1,220 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<div class="blog-container h-full overflow-auto">
<!-- Blog Header -->
<div class="mb-6 pb-4 border-b-2 border-[#808080]">
<h1 class="text-2xl font-bold mb-2 flex items-center gap-2">
<FileText :size="24" />
Blog Posts
</h1>
<p class="text-gray-600">The inner machinations of my mind are an enigma.</p>
</div>
<!-- Blog Posts List -->
<div v-if="pending" class="flex items-center justify-center py-12">
<div class="text-center">
<div class="flex justify-center mb-2">
<Loader2 :size="40" class="animate-spin text-gray-600" />
</div>
<p class="text-gray-600">Loading posts...</p>
</div>
</div>
<div v-else-if="error" class="bg-red-100 border-2 border-red-400 p-4">
<p class="text-red-700 font-bold flex items-center gap-2">
<AlertCircle :size="20" />
Error loading blog posts
</p>
<p class="text-red-600 text-sm mt-1">{{ error.message }}</p>
</div>
<div v-else-if="sortedPosts && sortedPosts.length > 0" class="space-y-4">
<article
v-for="post in sortedPosts"
:key="post.path"
class="blog-post bg-white border-2 border-[#808080] p-4 hover:border-[#000080] cursor-pointer transition-colors"
@click="openPost(post.path)"
>
<h2 class="text-xl font-bold text-[#000080] mb-2">{{ post.title }}</h2>
<div class="text-sm text-gray-500 mb-3 flex items-center gap-3">
<span class="flex items-center gap-1">
<Calendar :size="14" />
{{ formatDate(post.date) }}
</span>
<span v-if="post.tags && post.tags.length > 0" class="flex items-center gap-1">
<Tag :size="14" />
{{ post.tags.join(', ') }}
</span>
</div>
<p class="text-gray-700 mb-3">{{ post.description }}</p>
<button
class="px-3 py-1 bg-[#c0c0c0] border-2 border-white border-r-[#808080] border-b-[#808080] text-sm font-bold hover:bg-[#dfdfdf] flex items-center gap-1"
>
Read More
<ArrowRight :size="14" />
</button>
</article>
</div>
<div v-else class="bg-yellow-50 border-2 border-yellow-400 p-6 text-center">
<p class="text-yellow-700 text-lg font-bold mb-2 flex items-center justify-center gap-2">
<Inbox :size="24" />
No blog posts yet
</p>
<p class="text-yellow-600 text-sm">Check back later for updates!</p>
</div>
<!-- Blog Post Modal -->
<Teleport to="body">
<div v-if="selectedPost" ref="modalRef" class="fixed z-60" :style="modalStyle">
<div
class="bg-[#c0c0c0] border-2 border-white border-r-[#808080] border-b-[#808080] shadow-2xl max-w-4xl w-full max-h-[85vh] flex flex-col"
>
<!-- Modal Title Bar -->
<div
class="bg-linear-to-r from-[#000080] to-[#1084d0] px-2 py-1 flex items-center justify-between cursor-move select-none"
@mousedown="startDrag"
>
<span class="text-white font-bold text-sm">{{ selectedPost.title }}</span>
<button
class="w-5 h-5 bg-[#c0c0c0] border border-white border-b-[#808080] border-r-[#808080] flex items-center justify-center text-xs font-bold hover:bg-[#dfdfdf]"
@click="selectedPost = null"
>
<X :size="16" />
</button>
</div>
<!-- Modal Content -->
<div class="bg-white border-2 border-[#808080] border-t-white border-l-white overflow-auto flex-1">
<div class="max-w-3xl mx-auto px-8 py-8">
<div class="mb-6 pb-6 border-b-2 border-[#808080]">
<h1 class="text-4xl font-bold mb-4 text-[#000080]">{{ selectedPost.title }}</h1>
<div class="flex items-center gap-4 text-sm text-gray-600">
<span class="flex items-center gap-1.5 bg-[#f0f0f0] px-3 py-1.5 border border-[#808080]">
<Calendar :size="16" />
{{ formatDate(selectedPost.date) }}
</span>
<span
v-if="selectedPost.tags && selectedPost.tags.length > 0"
class="flex items-center gap-1.5 bg-[#f0f0f0] px-3 py-1.5 border border-[#808080]"
>
<Tag :size="16" />
{{ selectedPost.tags.join(', ') }}
</span>
</div>
</div>
<!-- key change: a single reusable class -->
<ContentRenderer :value="selectedPost" class="blog-prose">
<template #empty>
<p class="text-gray-500 text-center py-8">No content available.</p>
</template>
</ContentRenderer>
</div>
</div>
</div>
</div>
</Teleport>
</div>
</template>
<script setup lang="ts">
import { X, Calendar, Tag, ArrowRight, FileText, Loader2, AlertCircle, Inbox } from 'lucide-vue-next'
import type { BlogCollectionItem } from '@nuxt/content'
import { ref, computed, onMounted, onUnmounted } from 'vue'
const selectedPost = ref<BlogCollectionItem | null>(null)
const selectedPostPath = ref<string | null>(null)
const modalRef = ref<HTMLElement | null>(null)
const isDragging = ref(false)
const dragStartX = ref(0)
const dragStartY = ref(0)
const modalX = ref(0)
const modalY = ref(0)
const { data: posts, pending, error } = await useAsyncData('blog-posts', () => {
return queryCollection('blog').all()
})
const sortedPosts = computed(() => {
if (!posts.value) return []
return [...posts.value].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
})
const modalStyle = computed(() => {
if (modalX.value === 0 && modalY.value === 0) {
return {
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%)',
width: '100%',
maxWidth: '56rem',
padding: '1rem',
}
}
return {
left: `${modalX.value}px`,
top: `${modalY.value}px`,
width: '100%',
maxWidth: '56rem',
padding: '1rem',
}
})
const openPost = async (path: string) => {
selectedPostPath.value = path
selectedPost.value = await queryCollection('blog').path(path).first()
modalX.value = 0
modalY.value = 0
}
const startDrag = (e: MouseEvent) => {
isDragging.value = true
if (modalX.value === 0 && modalY.value === 0) {
const rect = modalRef.value?.getBoundingClientRect()
if (rect) {
modalX.value = rect.left
modalY.value = rect.top
}
}
dragStartX.value = e.clientX - modalX.value
dragStartY.value = e.clientY - modalY.value
}
const onDrag = (e: MouseEvent) => {
if (!isDragging.value) return
modalX.value = e.clientX - dragStartX.value
modalY.value = e.clientY - dragStartY.value
}
const stopDrag = () => {
isDragging.value = false
}
const formatDate = (dateString: string) => {
if (!dateString) return 'Unknown date'
const date = new Date(dateString)
return date.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })
}
onMounted(() => {
document.addEventListener('mousemove', onDrag)
document.addEventListener('mouseup', stopDrag)
})
onUnmounted(() => {
document.removeEventListener('mousemove', onDrag)
document.removeEventListener('mouseup', stopDrag)
})
</script>
<style scoped>
.blog-post {
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.2);
}
.blog-post:active {
transform: translateY(1px);
box-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
}
</style>

View File

@@ -1,34 +1,95 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<div class="font-mono">
<h1 class="text-2xl font-bold mb-2">Contact</h1>
<p class="text-terminal-dim mb-2">
You can reach me at the following email address:
</p>
<a
href="mailto:tanner@teamhydra.dev"
class="text-terminal-dim hover:text-terminal hover:underline transition-colors"
>
tanner@teamhydra.dev
</a>
<br />
<span class="text-terminal-dim">-- or --</span>
<br />
<a
href="https://discord.gg/zira"
target="_blank"
class="text-terminal-dim hover:text-terminal hover:underline transition-colors"
>
Via Discord
</a>
<p class="text-terminal-dim mt-2">
Please use the #other-support channel to get in touch with me. My
username is sticksdev.
</p>
<p class="text-terminal-dim mt-2">
I look forward to hearing from you soon :)
<div class="h-full overflow-auto p-6">
<h1 class="text-3xl font-bold mb-6 text-[#000080] border-b-2 border-[#808080] pb-3">Contact Me</h1>
<p class="text-gray-700 mb-6 leading-relaxed">
I'd love to hear from you! Whether you have a question, want to collaborate, or just want to say hi,
feel free to reach out through any of the following channels.
</p>
<!-- Contact Cards -->
<div class="space-y-4">
<!-- Email Card -->
<a
href="mailto:tanner@teamhydra.dev"
class="contact-card bg-white border-2 border-[#808080] p-5 shadow-md flex items-start gap-4 hover:border-[#000080] transition-colors group"
>
<div class="contact-icon bg-[#000080] border-2 border-[#808080] w-16 h-16 flex items-center justify-center group-hover:bg-[#1084d0] transition-colors">
<Mail :size="32" color="#ffffff" />
</div>
<div class="flex-1">
<h3 class="text-xl font-bold text-[#000080] mb-1">Email</h3>
<p class="text-gray-600 text-sm mb-2">Best for professional inquiries and projects</p>
<p class="text-[#000080] font-mono text-lg">tanner@teamhydra.dev</p>
</div>
</a>
<!-- Discord Card -->
<a
href="https://discord.gg/zira"
target="_blank"
class="contact-card bg-white border-2 border-[#808080] p-5 shadow-md flex items-start gap-4 hover:border-[#000080] transition-colors group"
>
<div class="contact-icon bg-[#5865F2] border-2 border-[#808080] w-16 h-16 flex items-center justify-center group-hover:bg-[#4752C4] transition-colors">
<DiscordIcon :size="32" style="color: white" />
</div>
<div class="flex-1">
<h3 class="text-xl font-bold text-[#000080] mb-1">Discord</h3>
<p class="text-gray-600 text-sm mb-2">Join the Discord server for casual conversations</p>
<p class="text-gray-700 mb-1">
<span class="font-semibold">Username:</span> <span class="font-mono">sticksdev</span>
</p>
<p class="text-gray-700">
<span class="font-semibold">Channel:</span> #other-support
</p>
</div>
</a>
<!-- GitHub Card -->
<a
href="https://github.com/SticksDev"
target="_blank"
class="contact-card bg-white border-2 border-[#808080] p-5 shadow-md flex items-start gap-4 hover:border-[#000080] transition-colors group"
>
<div class="contact-icon bg-[#24292e] border-2 border-[#808080] w-16 h-16 flex items-center justify-center group-hover:bg-[#1a1e22] transition-colors text-white">
<GitHubIcon :size="32" style="color: white" />
</div>
<div class="flex-1">
<h3 class="text-xl font-bold text-[#000080] mb-1">GitHub</h3>
<p class="text-gray-600 text-sm mb-2">Check out my projects and contributions</p>
<p class="text-[#000080] font-mono">@SticksDev</p>
</div>
</a>
</div>
<!-- Response Time Note -->
<div class="mt-6 bg-[#ffffcc] border-2 border-[#808080] p-4">
<p class="text-sm text-gray-700">
<Lightbulb :size="16" class="inline mr-1 text-yellow-600" />
<span class="font-bold">Note:</span> I typically respond within 24-48 hours. Looking forward to connecting with you!
</p>
</div>
</div>
</template>
<script setup lang="ts">
import { Mail, Lightbulb } from 'lucide-vue-next'
import { GitHubIcon, DiscordIcon } from 'vue3-simple-icons'
</script>
<style scoped>
.contact-card {
box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1);
transition: transform 0.2s, box-shadow 0.2s;
}
.contact-card:hover {
transform: translateY(-2px);
box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.15);
}
.contact-icon {
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.2);
}
</style>

View File

@@ -5,16 +5,22 @@
@click="$emit('click')"
@dblclick="$emit('dblclick')"
>
<div class="icon-image w-12 h-12 mb-1 flex items-center justify-center text-4xl">
{{ icon }}
<div class="icon-image w-12 h-12 mb-1 flex items-center justify-center">
<component
:is="icon"
:size="48"
color="white"
/>
</div>
<span class="text-white text-xs text-center drop-shadow-lg">{{ label }}</span>
</div>
</template>
<script setup lang="ts">
import type { Component } from 'vue'
defineProps<{
icon: string
icon: Component
label: string
isSelected?: boolean
}>()

View File

@@ -1,84 +1,116 @@
<template>
<div class="font-mono">
<h1 class="text-2xl font-bold mb-2">Experience</h1>
<p class="text-terminal-dim mb-4">
Use the buttons below to navigate through my experience.
</p>
<div class="flex justify-between mb-4">
<button
@click="handlePrev"
:disabled="index === 0"
class="text-terminal-dim hover:text-terminal transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
>
Previous
</button>
<button
@click="handleNext"
:disabled="index === experience.length - 1"
class="text-terminal-dim hover:text-terminal transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
>
Next
</button>
</div>
<div>
<pre class="whitespace-pre-wrap text-terminal">{{ experience[index] }}</pre>
<div class="h-full overflow-auto p-6">
<h1 class="text-3xl font-bold mb-6 text-[#000080] border-b-2 border-[#808080] pb-3">Work Experience</h1>
<div class="space-y-6">
<!-- Level.io -->
<div class="experience-card bg-white border-2 border-[#808080] p-5 shadow-md">
<div class="flex items-start gap-4 mb-4">
<div class="logo-container bg-white border border-gray-300 p-3 rounded flex items-center justify-center" style="min-width: 100px; height: 80px;">
<img
src="https://cdn.prod.website-files.com/65707faecd4cd453c0bb80ad/657087ef22ae05f257ad0b7b_Logo%20(1).svg"
alt="Level.io"
class="max-w-full max-h-full object-contain"
/>
</div>
<div class="flex-1">
<h2 class="text-2xl font-bold text-[#000080] mb-1">Support Specialist</h2>
<h3 class="text-lg font-semibold text-gray-700 mb-2">Level.io</h3>
<p class="text-sm text-gray-600">October 2024 - Present</p>
</div>
</div>
<div class="ml-0 md:ml-28">
<p class="text-gray-700 leading-relaxed">
Currently working as a Support Specialist at Level.io, helping customers solve technical issues and improve their experience with the platform.
Providing technical support, troubleshooting, and working closely with the engineering team to resolve complex problems.
</p>
</div>
</div>
<!-- Gordon Food Services -->
<div class="experience-card bg-white border-2 border-[#808080] p-5 shadow-md">
<div class="flex items-start gap-4 mb-4">
<div class="logo-container bg-white border border-gray-300 p-3 rounded flex items-center justify-center" style="min-width: 100px; height: 80px;">
<img
src="https://gfs.com/wp-content/uploads/2022/07/logo_gfs.png"
alt="Gordon Food Services"
class="max-w-full max-h-full object-contain"
/>
</div>
<div class="flex-1">
<h2 class="text-2xl font-bold text-[#000080] mb-1">Network Engineer / IT Specialist</h2>
<h3 class="text-lg font-semibold text-gray-700 mb-2">Gordon Food Services</h3>
<p class="text-sm text-gray-600">June 2022 - June 2024</p>
</div>
</div>
<div class="ml-0 md:ml-28">
<p class="text-gray-700 leading-relaxed mb-3">
Worked with Gordon Food Services to help maintain their network infrastructure and provide IT support to employees.
Responsible for troubleshooting network issues, setting up new network equipment, and providing support with IT issues.
</p>
<ul class="list-disc list-inside text-gray-700 space-y-1 text-sm">
<li>Maintained and troubleshot network infrastructure</li>
<li>Set up and configured network equipment</li>
<li>Provided technical support to employees</li>
<li>Managed IT helpdesk operations</li>
</ul>
</div>
</div>
<!-- Team Hydra -->
<div class="experience-card bg-white border-2 border-[#808080] p-5 shadow-md">
<div class="flex items-start gap-4 mb-4">
<div class="logo-container bg-white border border-gray-300 p-3 rounded flex items-center justify-center" style="min-width: 100px; height: 80px;">
<img
src="https://hep.gg/hydralogo"
alt="Team Hydra"
class="max-w-full max-h-full object-contain"
/>
</div>
<div class="flex-1">
<h2 class="text-2xl font-bold text-[#000080] mb-1">Software Developer</h2>
<h3 class="text-lg font-semibold text-gray-700 mb-2">Team Hydra</h3>
<p class="text-sm text-gray-600">September 2020 - Present</p>
</div>
</div>
<div class="ml-0 md:ml-28">
<p class="text-gray-700 leading-relaxed mb-3">
Working with Team Hydra on a variety of projects, including developing web applications, mobile apps, Discord bots, and APIs.
Great team environment with continuous learning opportunities.
</p>
<ul class="list-disc list-inside text-gray-700 space-y-1 text-sm">
<li>Developed web applications and APIs</li>
<li>Built Discord bots and integrations</li>
<li>Created mobile applications</li>
<li>Collaborated on various client projects</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const experience = [
`
@@@@@@@@@@
@@@@@*:@@@@@
@#*@+**-@:@@
@#@@@ @@@**@**@:*@@ @@@*@
@@+@@@:@@@@@*%*@**@*.%@@@@@:@@@+@@
@@@@@@@@@@@@@@*@*:#*@@@@@***:@#@@@**:*@*@@@@@@@@@@@%@@ Company Name: Team Hydra
@@@%%@@***********@@********@@**+*******+@@**@@@ Position: Software Developer
@@@#%@********+*@********@*************@@@ Start Date: 2020-09-01
@@@@%********.*@*%**@*@+.*********@@@@ End: Present
@@@@#**@*%**+@@*@@@@+@@+****@**+@@@@ About:
@@@@**@@*****@@*@@=@@*****@@%*@@@@ I've worked with team hydra on a variety of projects,
@ @@+*@@@*****@#@@*****@@@#*@@ @ including developing web applications, mobile apps, discord bots,
@@@ @@%%@@@@@***@@***@@@@@%@@@ @@@ and APIs. It's a great team to work with, and I've learned a lot.
@@@%@@@@*****+**@@@@%@@@ I highly recommend them to anyone looking for software development
@@@%%%***#@**@****%%%@@@ services and a career in software development.
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ @@
`,
`
*###########*
################*
######## *####
###### *
*####*
##### #########
##### ######### ordon food services
#####* ######### Position: Network Engineer/IT Specialist
###### *#### Start Date: 2022-06-01
#######* =###### End: 2024-06-01
################# About: I worked with Gordon food services to help maintain their network infrastructure
############* and provide IT support to their employees. I was responsible for troubleshooting network
####### issues, setting up new network equipment, and providing support to employees with IT issues.
#### I was laid off, but I enjoyed my time there and learned a lot about network engineering and
* IT support.
`,
]
const index = ref(0)
const handleNext = () => {
if (index.value < experience.length - 1) {
index.value++
}
}
const handlePrev = () => {
if (index.value > 0) {
index.value--
}
}
// No script needed for static content
</script>
<style scoped>
.experience-card {
box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1);
transition: transform 0.2s, box-shadow 0.2s;
}
.experience-card:hover {
transform: translateY(-2px);
box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.15);
}
.logo-container img {
filter: grayscale(0%);
transition: filter 0.2s;
}
.logo-container:hover img {
filter: grayscale(0%) brightness(1.1);
}
</style>

View File

@@ -1,57 +1,128 @@
<template>
<div class="font-mono">
<h1 class="text-terminal text-md mb-4">
--- Reading database projects.db ---<br>
Found {{ projects.length }} projects in database. Displaying all projects:
</h1>
<div v-for="(project, index) in preparedProjects" :key="index" class="flex flex-row flex-wrap mb-1">
<p class="text-terminal">{{ project.title }}</p>
<span class="text-terminal">&nbsp;|&nbsp;</span>
<p class="text-terminal">{{ project.description }}</p>
<span class="text-terminal">|</span>
<a
:href="project.link"
class="text-terminal-dim hover:text-terminal transition-colors ml-1"
target="_blank"
<div class="h-full overflow-auto p-6">
<h1 class="text-3xl font-bold mb-6 text-black border-b-2 border-[#808080] pb-3">My Projects</h1>
<p class="text-gray-700 mb-6 leading-relaxed">
Here are some of my featured projects. Check them out on GitHub!
</p>
<!-- Projects Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div
v-for="(project, index) in projects"
:key="index"
class="project-card bg-white border-2 border-[#808080] p-5 shadow-md hover:border-[#000080] transition-all group"
>
{{ project.link }}
<div class="flex items-start justify-between mb-3">
<div class="project-icon">
<component
:is="project.icon"
:size="32"
:class="['transition-colors', 'group-hover:text-[#1084d0]']"
/>
</div>
<a
:href="project.link"
target="_blank"
class="px-3 py-1 bg-[#c0c0c0] border-2 border-white border-r-[#808080] border-b-[#808080] text-xs font-bold hover:bg-[#dfdfdf] flex items-center gap-1"
>
View on GitHub
</a>
</div>
<h3 class="text-xl font-bold text-black mb-2">{{ project.title }}</h3>
<p class="text-gray-700 text-sm mb-3 leading-relaxed">{{ project.description }}</p>
<div class="flex flex-wrap gap-2">
<span
v-for="(tech, techIndex) in project.technologies"
:key="techIndex"
class="tech-badge text-xs px-2 py-1 bg-[#f0f0f0] border border-[#808080] text-gray-700"
>
{{ tech }}
</span>
</div>
</div>
</div>
<!-- More Projects CTA -->
<div class="mt-6 bg-white border-2 border-[#808080] p-5 shadow-md text-center">
<p class="text-gray-700 mb-3">
Want to see more? Check out my GitHub profile for all my projects and contributions!
</p>
<a
href="https://github.com/SticksDev"
target="_blank"
class="inline-block px-6 py-2 bg-[#24292e] text-white border-2 border-[#808080] font-bold hover:bg-[#1a1e22] transition-colors"
>
Visit GitHub Profile
</a>
</div>
<h1 class="text-terminal text-md mt-4">
--- End of database ---
</h1>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { Component } from 'vue'
import { Printer, Globe, Sparkles } from 'lucide-vue-next'
const projects = [
type Project = {
title: string
description: string
link: string
icon: Component
technologies: string[]
}
const projects: Project[] = [
{
title: 'BambuConnect',
description: 'A simple 3rd party client for managing your 3D printer.',
description:
'A third-party client for managing your Bambu Lab 3D printer with an intuitive interface and real-time monitoring capabilities.',
link: 'https://github.com/SticksDev/BambuConnect',
icon: Printer,
technologies: ['TypeScript', 'Electron', '3D Printing'],
},
{
title: 'VRDCN_NetworkTest',
description: 'A simple network test for a VR Streaming service. Written in Go.',
description:
'A network testing tool designed for VR streaming services, built with Go for high performance and reliability.',
link: 'https://github.com/SticksDev/VRCDN_NetworkTest',
icon: Globe,
technologies: ['Go', 'Networking', 'VR'],
},
{
title: 'Runic Spells',
description: 'A simple spell system for Minecraft using Java and PaperMC APIs.',
description:
'A comprehensive spell system for Minecraft servers using Java and PaperMC APIs, featuring custom magical abilities.',
link: 'https://github.com/SticksDev/runic_spells',
icon: Sparkles,
technologies: ['Java', 'Minecraft', 'PaperMC'],
},
]
const preparedProjects = computed(() => {
const maxTitleLength = Math.max(...projects.map((project) => project.title.length))
const maxDescriptionLength = Math.max(...projects.map((project) => project.description.length))
return projects.map((project) => ({
...project,
title: project.title.padEnd(maxTitleLength, ' '),
description: project.description.padEnd(maxDescriptionLength, ' '),
}))
})
</script>
<style scoped>
.project-card {
box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1);
transition: transform 0.2s, box-shadow 0.2s;
}
.project-card:hover {
transform: translateY(-2px);
box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.15);
}
.project-icon {
transition: transform 0.2s, color 0.2s;
}
.project-card:hover .project-icon {
transform: scale(1.1);
}
.tech-badge {
font-family: 'Courier New', monospace;
font-weight: 600;
}
</style>

View File

@@ -0,0 +1,72 @@
<template>
<Transition name="taskbar-fade">
<button
v-if="isOpen"
class="taskbar-item px-3 py-1 border-2 text-sm"
:class="[
isActive
? 'bg-[#000080] text-white border-[#808080] border-r-white border-b-white active-button'
: 'bg-[#c0c0c0] border-white border-r-[#808080] border-b-[#808080]'
]"
@click="$emit('click')"
>
<div class="flex items-center gap-1 icon-wrapper">
<component
:is="icon"
:size="16"
/>
<span>{{ label }}</span>
</div>
</button>
</Transition>
</template>
<script setup lang="ts">
import type { Component } from 'vue'
defineProps<{
icon: Component
label: string
isOpen: boolean
isActive: boolean
}>()
defineEmits<{
click: []
}>()
</script>
<style scoped>
.taskbar-item {
transition: background-color 0.15s ease, color 0.15s ease;
}
/* Default inactive hover */
.taskbar-item:not(.active-button):hover {
background: #000080;
color: #fff;
}
/* Disable hover effects entirely on active */
.taskbar-item.active-button:hover {
background: #000080; /* same as active */
color: white;
cursor: default;
}
.taskbar-fade-enter-active,
.taskbar-fade-leave-active {
transition: all 0.3s ease;
}
.taskbar-fade-enter-from {
opacity: 0;
transform: translateY(10px);
}
.taskbar-fade-leave-to {
opacity: 0;
transform: translateY(10px);
}
</style>

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<div
ref="windowRef"
@@ -17,9 +18,7 @@
class="close-btn w-5 h-5 bg-[#c0c0c0] border border-white border-b-[#808080] border-r-[#808080] flex items-center justify-center text-xs font-bold hover:bg-[#dfdfdf]"
@click="$emit('close')"
>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-10">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
</svg>
<X :size="60" />
</button>
</div>
@@ -31,6 +30,7 @@
</template>
<script setup lang="ts">
import { X } from 'lucide-vue-next';
import { ref, computed, onMounted, onUnmounted } from 'vue'
const props = defineProps<{