1
0

Init Commit

This commit is contained in:
2025-02-26 15:40:10 -06:00
commit 8ca7e1ce91
95 changed files with 14713 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
<template>
<div class="flex bg-sky-400 min-w-[40%] min-h-[20%] rounded-xl p-4">
<div
class="flex flex-row justify-between gap-4 bg-zinc-900 grow p-4 rounded-xl"
>
<a href="mailto:me@kyleaustad.com" class="text-center">
<nuxt-img
class="rounded-xl transform transition-all duration-300 ease-out hover:scale-[1.2] max-w-[52px]"
src="/email.png"
></nuxt-img>
<p>Email</p>
</a>
<a href="https://www.linkedin.com/in/kyle-austad/" class="text-center">
<nuxt-img
class="rounded-xl transform transition-all duration-300 ease-out hover:scale-[1.2] max-w-[52px]"
src="/linkedin.png"
></nuxt-img>
<p>LinkedIn</p>
</a>
<a
href="https://github.com/kyaustad?tab=repositories"
class="text-center"
>
<nuxt-img
class="rounded-xl transform transition-all duration-300 ease-out hover:scale-[1.2] max-w-[52px]"
src="/github.png"
></nuxt-img>
<p>GitHub</p>
</a>
<a
href="https://git.crabinteractive.com/explore/repos"
class="text-center"
>
<nuxt-img
class="rounded-xl transform transition-all duration-300 ease-out hover:scale-[1.2] max-w-[52px]"
src="/gitea.webp"
></nuxt-img>
<p>Gitea</p>
</a>
</div>
</div>
<div
class="flex bg-sky-400 max-w-[60%] sm:max-w-[40%] min-h-[20%] rounded-xl p-2"
>
<div
class="flex flex-col justify-between gap-4 bg-zinc-900 text-center grow p-2 rounded-xl"
>
<h3 class="text-white font-base text-sm">
This website was made using Nuxt 3, PrimeVue, jsParticles, and
TailwindCSS.
</h3>
<h3 class="text-white font-base text-sm">
Thank you to the open source community!
</h3>
</div>
</div>
</template>
<script lang="ts" setup></script>
<style></style>

View File

@@ -0,0 +1,53 @@
<template>
<div class="card flex justify-center">
<Galleria
v-model:visible="displayBasic"
:fullScreen="true"
:showItemNavigators="false"
containerClass="bg-zinc-950 pt-6"
class="bg-zinc-900"
:value="images"
:responsiveOptions="responsiveOptions"
:showIndicators="true"
:showThumbnails="false"
:changeItemOnIndicatorHover="true"
>
<template #item="slotProps">
<nuxt-img
:src="slotProps.item.itemImageSrc"
class="max-w-[80%] max-h-[80%] block"
></nuxt-img>
</template>
</Galleria>
<div>
<Button
label="Images"
severity="info"
size="small"
icon="pi pi-eye"
@click="displayBasic = true"
/>
</div>
</div>
</template>
<script lang="ts" setup>
const displayBasic = ref(false);
const responsiveOptions = ref([
{
breakpoint: "1300px",
numVisible: 4,
},
{
breakpoint: "575px",
numVisible: 1,
},
]);
const props = defineProps<{
images: { itemImageSrc: string }[];
}>();
</script>
<style></style>

View File

@@ -0,0 +1,16 @@
<template>
<div class="flex flex-col mt-24">
<h1 class="text-white font-bold text-4xl sm:text-5xl">{{ props.title }}</h1>
<div
class="fixed rounded-sm bg-red-500 ml-6 -z-[30] mt-6 min-h-[20px] min-w-[100px] sm:mt-8 sm:ml-8"
></div>
</div>
</template>
<script lang="ts" setup>
const props = defineProps<{
title: string;
}>();
</script>
<style></style>

View File

@@ -0,0 +1,55 @@
<template>
<div
class="p-[1px] max-w-[95px] items-center justify-center rounded-xl bg-gradient-to-br from-red-500 to-blue-500 transform transition-all duration-300 ease-out shadow-xl"
ref="avatar"
:style="{
transform: `scale(${scale}) rotateX(${tiltY}deg) rotateY(${tiltX}deg)`,
}"
@mousemove="handleMouseMove"
@mouseleave="resetRotation"
v-motion-fade-visible
>
<div
class="flex flex-col items-center justify-center gap-1 text-center p-4 rounded-xl bg-[#292626]"
>
<nuxt-img :src="props.img" class="max-w-[30px] md:max-w-[50px] rounded" />
<h3 class="mb-0 text-sm md:text-base">{{ props.name }}</h3>
</div>
</div>
</template>
<script lang="ts" setup>
const props = defineProps<{
img: string;
name: string;
}>();
const avatar = ref<HTMLElement | null>(null);
const scale = ref(1);
const tiltX = ref(0);
const tiltY = ref(0);
const handleMouseMove = (event: MouseEvent) => {
if (avatar.value) {
const rect = avatar.value.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const offsetX = (event.clientX - centerX) / rect.width;
const offsetY = (event.clientY - centerY) / rect.height;
tiltX.value = offsetX * 80;
tiltY.value = offsetY * 80 * -1;
scale.value = 1.15;
}
};
const resetRotation = () => {
tiltX.value = 0;
tiltY.value = 0;
scale.value = 1;
};
</script>
<style></style>

View File

@@ -0,0 +1,44 @@
<template>
<div class="flex flex-col m-2 text-center">
<h3 class="text-white font-base text-3xl sm:text-4xl mb-10">Skills</h3>
<p class="text-[7px] font-base md:text-[10px] mb-3">... hover me</p>
<div
class="grid grid-cols-1 justify-between md:grid-cols-4 gap-4 md:gap-x-8"
>
<!-- First Column -->
<div class="flex md:flex-col gap-4 items-center justify-around">
<SkillAvatar img="/js-logo.png" name="JavaScript" />
<SkillAvatar img="/node-logo.png" name="Node.js" />
<SkillAvatar img="/vue.png" name="Vue 3" />
<SkillAvatar img="/nuxt.png" name="Nuxt" />
</div>
<!-- Second Column -->
<div class="flex md:flex-col gap-4 items-center justify-between">
<SkillAvatar img="/html.png" name="HTML" />
<SkillAvatar img="/css.png" name="CSS" />
<SkillAvatar img="/tailwind.png" name="Tailwind CSS" />
<SkillAvatar img="/express.webp" name="express.js" />
</div>
<!-- Third Column -->
<div class="flex md:flex-col gap-4 items-center justify-around">
<SkillAvatar img="/docker.webp" name="Docker" />
<SkillAvatar img="/mongo.svg" name="MongoDB" />
<SkillAvatar img="/cpp.png" name="C++" />
<SkillAvatar img="/unreal.svg" name="Unreal Engine" />
</div>
<div class="flex w-full md:flex-col gap-4 items-center justify-between">
<SkillAvatar img="/blender.png" name="Blender" />
<SkillAvatar img="/git.png" name="Git" />
<SkillAvatar img="/substance.png" name="Substance Painter" />
<SkillAvatar img="/brain.png" name="A Brain" />
</div>
</div>
</div>
</template>
<script lang="ts" setup></script>
<style></style>

View File

@@ -0,0 +1,32 @@
<template>
<section id="about">
<div
class="snap-start gap-36 flex flex-col items-center mt-[25px] w-full min-h-[1800px]"
v-motion-fade-visible
>
<SectionHeader title="About" />
<img src="/headshot.png" class="max-w-[200px]" />
<div
class="text-center items-center flex max-w-[360px] border-red-500 border-2 p-7 rounded-xl"
>
<p class="text-white text-xl font-base">
Having a lifelong passion for learning and growth, I have been able to
develop skills through various verticals. I'm a passionate developer
for full-stack web applications using JavaScript, Vue, Nuxt, MongoDB,
or express.js. I believe technology should be used to empower
indivuduals and their creative visions, whether it is C++ and
Blueprints in Unreal Engine or the latest in Progressive Web Apps.
With a unique background in sales, I know how to be a self-starter,
and keep my excitement and passion for all things 'development'.
</p>
</div>
<SkillColumn />
</div>
</section>
</template>
<script lang="ts" setup></script>
<style></style>

View File

@@ -0,0 +1,15 @@
<template>
<section id="contact">
<div
class="snap-start gap-36 flex flex-col items-center mt-[25px] w-full min-h-[1000px]"
>
<SectionHeader title="Contact Me" />
<ContactElement />
</div>
</section>
</template>
<script lang="ts" setup></script>
<style></style>

View File

@@ -0,0 +1,64 @@
<template>
<div class="sticky z-[80] top-0 flex min-w-full">
<header
class="top-0 left-0 w-full h-[80px] bg-zinc-700 flex justify-center md:justify-end items-center px-4 shadow-lg"
>
<div class="inset-0 flex gap-10 justify-between items-center">
<Button
@click="scrollToSection('about')"
label="About"
:outlined="activeSection !== 'about'"
severity="info"
/>
<Button
@click="scrollToSection('work')"
label="My Work"
:outlined="activeSection !== 'work'"
severity="info"
/>
<Button
@click="scrollToSection('contact')"
label="Contact"
:outlined="activeSection !== 'contact'"
severity="info"
/>
</div>
</header>
</div>
</template>
<script lang="ts" setup>
const activeSection = ref<string | null>(null);
const scrollToSection = (sectionId: string) => {
const section = document.getElementById(sectionId);
if (section) {
section.scrollIntoView({ behavior: "smooth", block: "start" });
// window.scrollTo({ top: section.offsetTop, behavior: "smooth" });
}
};
const handleScroll = () => {
const sections = ["about", "work", "contact"];
for (const sectionId of sections) {
const section = document.getElementById(sectionId);
if (section) {
const rect = section.getBoundingClientRect();
if (rect.top <= 100 && rect.bottom >= 100) {
activeSection.value = sectionId;
break;
}
}
}
};
onMounted(() => {
window.addEventListener("scroll", handleScroll);
});
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
</script>
<style></style>

View File

@@ -0,0 +1,16 @@
<template>
<section id="work">
<div class="snap-start gap-36 flex flex-col items-center mt-[25px] w-full">
<SectionHeader title="My Work" />
<LazyWorkCard v-for="entry in workEntries" :entry="entry">
<ImageGallery :images="entry.gallery" />
</LazyWorkCard>
</div>
</section>
</template>
<script lang="ts" setup>
import { workEntries } from "~/assets/WorkEntries";
</script>
<style></style>

83
components/WorkCard.vue Normal file
View File

@@ -0,0 +1,83 @@
<template>
<div
class="w-[90%] h-[550px] md:h-[450px] md:w-[80%] lg:w-[60%] bg-gradient-to-tr from-red-500 to-red-400 flex flex-col sm:flex-row rounded-xl justify-between items-center"
>
<div
class="rounded-xl flex flex-col sm:max-w-[60%] align-middle items-center justify-between grow hover:scale-[0.98] m-2 p-2 bg-zinc-800 h-[95%] transform transition-all duration-300 ease-out shadow-xl text-center"
>
<h3 class="text-white text-wrap mb-1 mt-0 font-bold text-lg md:text-2xl">
{{ entry.title }}
</h3>
<div
class="max-h-[300px] flex justify-center hover:scale-[1.02] transform transition-all duration-300 ease-out"
>
<a :href="entry.coverImg">
<nuxt-img
:src="`${entry.coverImg}`"
class="aspect-auto max-h-[95%]"
/>
</a>
</div>
<div
class="max-h-[18px] sm:max-h-[26px] md:max-h-[32px] w-full md:mb-2 align-middle flex justify-around"
>
<!-- <h3 class="text-white font-base text-xs mt-0">Tech Stack:</h3> -->
<nuxt-img
:src="`${img}`"
class="aspect-auto"
v-for="img in entry.stack"
/>
</div>
</div>
<div
class="rounded-xl flex flex-col justify-around sm:max-w-[40%] hover:scale-[0.98] m-2 p-2 bg-zinc-800 h-[95%] transform transition-all duration-300 ease-out shadow-xl text-center"
>
<p class="text-white text-wrap m-2 font-base text-base">
{{ entry.desc }}
</p>
<div class="flex w-full justify-around">
<Button
severity="help"
icon="pi pi-link"
@click="showAlert = true"
size="small"
label="Links"
/>
<Dialog
v-model:visible="showAlert"
modal
:header="`${entry.title} Links`"
:style="{ width: '25rem' }"
>
<div
class="flex items-center justify-center gap-4 mb-8"
v-for="item in entry.links"
>
<a :href="item.link">
<Button
:severity="item.severity"
:label="item.label"
:icon="item.icon"
/></a>
</div>
</Dialog>
<slot />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { WorkEntry } from "~/types/WorkEntry";
const props = defineProps<{
entry: WorkEntry;
}>();
const showAlert = ref(false);
</script>
<style></style>