Adding project to github

This commit is contained in:
Max
2023-11-22 11:23:48 -07:00
commit 80d2c52e27
27 changed files with 18759 additions and 0 deletions

67
pages/blog/[post].vue Normal file
View File

@@ -0,0 +1,67 @@
<template>
<div>
<div class="sticky top-0 py-2 px-4 bg-white opacity-90 shadow-md">
<div
class="m-auto w-full max-w-3xl flex items-center justify-between"
>
<NuxtLink class="text-2xl text-zinc-600" to="/blog"
>Project Overview</NuxtLink
>
<NuxtLink to="/">Back to Resume</NuxtLink>
</div>
</div>
<div class="pt-4"></div>
<div class="mx-auto max-w-3xl px-4 blog">
<h1>{{ page.title }}</h1>
<h2 class="text-zinc-500 pb-3">Posted on: {{ page.date }}</h2>
<!-- <ContentDoc /> -->
<ContentRenderer :key="page._id" :value="page" />
</div>
<div class="w-full h-2 bg-blue-400 my-4"></div>
<div v-if="data && page" class="mx-auto max-w-3xl px-4">
<p>Other Projects</p>
<a
v-for="post in data"
:href="post._path"
class="text-blue-700 w-full px-2"
>
<h3 class="text-xl">{{ post.title }}</h3>
<p class="text-zinc-500">{{ post.description }}</p>
<!-- <p>{{ post }}</p> -->
</a>
</div>
</div>
</template>
<script setup>
// Find other pages and list them
const { data } = await useAsyncData("blog", () => queryContent("/").find());
// Find current page content
const { page } = useContent();
// console.log(page.value);
// console.log(data.value);
</script>
<style>
.blog {
@apply leading-9 text-base;
}
.blog a {
@apply text-blue-700;
}
.blog h1 {
@apply pt-5 text-3xl border-zinc-300;
}
.blog h3 {
@apply pt-5 mb-2 text-xl border-b border-zinc-300;
}
.blog img {
@apply my-3 shadow-sm;
}
.blog p + P {
@apply pt-4;
}
.blog ul {
@apply list-disc ml-10;
}
</style>

50
pages/blog/index.vue Normal file
View File

@@ -0,0 +1,50 @@
<template>
<div class="">
<div class="sticky top-0 py-2 bg-white opacity-90 shadow-md">
<div
class="m-auto w-full max-w-3xl flex items-center justify-between"
>
<NuxtLink class="text-xl" to="/blog">Max's Blog</NuxtLink>
<NuxtLink class="" to="/">Home</NuxtLink>
</div>
</div>
<div class="w-full h-2 bg-blue-400"></div>
<div v-if="data" class="mx-auto max-w-3xl">
<a
v-for="post in data"
:href="post._path"
class="text-blue-700 w-full px-2"
>
<h3>{{ post.title }}</h3>
<p class="text-zinc-500">{{ post.description }}</p>
<!-- <p>{{ post }}</p> -->
</a>
</div>
</div>
</template>
<script setup>
// Find other pages and list them
const { data } = await useAsyncData("blog", () => queryContent("/").find());
</script>
<style>
.blog {
@apply leading-9 text-base;
}
.blog a {
@apply text-blue-700;
}
.blog h1 {
@apply pt-5 text-3xl border-zinc-300;
}
.blog h3 {
@apply pt-5 mb-2 text-xl border-b border-zinc-300;
}
.blog img {
@apply my-3 shadow-sm;
}
.blog p + P {
@apply pt-4;
}
</style>

780
pages/homepage.html.vue Normal file
View File

@@ -0,0 +1,780 @@
<template>
<div class="max-links">
<div class="text-box">
<input
type="text"
placeholder="Type some shit 😘🔎"
class="glass"
v-model="inputText"
v-on:keydown="filterKeydown"
v-on:keyup="filterLinks"
v-on:keyup.enter="webSearch"
ref="search"
/>
<div class="suggestions" v-if="suggestions.length > 0">
<div
class="suggestion"
v-for="(suggestion, index) in suggestions"
:class="{ active: suggestionIndex == index }"
>
{{ suggestion }}
</div>
</div>
</div>
<div v-for="column in columns" class="column">
<h2>{{ column }}</h2>
<div
v-for="link in sortedLinks(links, column)"
v-if="link?.title"
class="flex-child"
>
<a
:href="setupUrl(link.url)"
class="max-link"
target="_blank"
v-on:click="linkClick"
v-if="link.column == column"
>
<span class="visual-aid">
{{ link.emoji }}
</span>
{{ link?.title }}
</a>
</div>
</div>
<!-- <div class="lip one"></div> -->
<span
v-on:click="clicks++"
class="small message"
v-html="generateMessage(2)"
></span>
</div>
</template>
<script setup>
let seed = ref(0);
let clicks = ref(0);
let inputText = ref("");
let suggestions = ref([]);
let suggestionIndex = ref(0);
let autocomplete = ref(["google.com", "gmail.com", "graxday.com"]);
let columns = ref(["web", "apps", "local", "dumb"]);
let links = ref([
{
column: "local",
url: "192.168.1.6",
title: "Tower",
emoji: "🖥️",
},
{
column: "local",
url: "192.168.1.242/admin",
title: "Pi-Hole",
emoji: "🌌",
},
{
column: "local",
url: "192.168.1.6:8112",
title: "Deluge",
emoji: "💦",
},
{
column: "local",
url: "192.168.1.164",
title: "Marvin",
emoji: "🧪",
},
{
column: "local",
url: "https://192.168.1.1",
title: "Router",
emoji: "📶",
},
{
column: "apps",
url: "192.168.1.164:9999/admin",
title: "Blog Editing",
emoji: "✏️",
},
{
column: "apps",
url: "www.solidscribe.com",
title: "Solid Scribe",
emoji: "🔏",
},
{
column: "web",
url: "www.wunderground.com/weather/us/az/flagstaff/KAZFLAGS335",
title: "Weather",
emoji: "🌦️",
},
{
column: "web",
url: "https://mail.protonmail.com/u/0/inbox",
title: "Proton Mail",
emoji: "📧",
},
{
column: "web",
url: "www.amazon.com",
title: "Amazon",
emoji: "🛒",
},
{
column: "web",
url: "www.camelcamelcamel.com",
title: "Camel Camel Camel",
emoji: "🐫",
},
{
column: "apps",
url: "spotify.com",
title: "Spotify",
emoji: "🎶",
},
{
column: "web",
url: "butcherbox.com",
title: "Butcher Box",
emoji: "📦",
},
{ column: "web", url: "gmail.com", title: "Gmail", emoji: "✉" },
{
column: "apps",
url: "schwab.com",
title: "Schwab",
emoji: "🤑",
},
{
column: "local",
url: "graxday.com",
title: "Grax Day",
emoji: "😘",
},
{
column: "web",
url: "https://drive.google.com/drive/u/0/folders/10hsNBu0o8at687PLc5mcfDtJkhjDcwk9?ths=true",
title: "Grax Day Docs",
emoji: "📄",
},
// {'column':'apps','url':'x.maxg.cc/code/?folder=/home/mab/ss', 'title':'Code Server', 'emoji':'🦿'},
{
column: "apps",
url: "pix.maxg.cc/library/import",
title: "PhotoPrism Import",
emoji: "📷",
},
{
column: "apps",
url: "http://git.maxg.cc",
title: "Gitea",
emoji: "🍵",
},
{
column: "web",
url: "https://forum.xda-developers.com/t/rom-13-op7pro-crdroid-v9-0-18-12-2022.4511589/page-12",
title: "OnePlus7 ISO",
emoji: "📱",
},
{
column: "local",
url: "https://localhost:47990/",
title: "Sunshine",
emoji: "☀️",
},
// dumb
{
column: "dumb",
url: "www.youtube.com",
title: "Youtube",
emoji: "📺",
},
{
column: "dumb",
url: "arstechnica.com",
title: "ArsTechnica",
emoji: "📰",
},
{
column: "dumb",
url: "phoronix.com",
title: "Phoronix",
emoji: "📰",
},
{
column: "dumb",
url: "slashdot.org/",
title: "Slashdot",
emoji: "📃",
},
{
column: "dumb",
url: "imgur.com",
title: "Imgur",
emoji: "😺",
},
{
column: "dumb",
url: "hackaday.com",
title: "Hack a Day",
emoji: "☠",
},
{
column: "dumb",
url: "duckduckgo.com",
title: "Duck Duck Go",
emoji: "🦆",
},
{ column: "dumb", url: "bing.com", title: "Bing", emoji: "🦑" },
{
column: "dumb",
url: "google.com",
title: "Google",
emoji: "🐚",
},
{
column: "dumb",
url: "https://www.etsy.com/shop/PowerfulSpell",
title: "Powerful Spell",
emoji: "🧚🏻",
},
{
column: "dumb",
url: "https://kbd.news/",
title: "KBD",
emoji: "⌨️",
},
{
column: "web",
url: "https://store.epicgames.com/en-US/free-games",
title: "Free Game!",
emoji: "🎮",
},
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
{ url: "", title: "" },
]);
onMounted(() => {
// setup autocomplete
Object.keys(this.links).forEach((key) => {
const link = this.links[key].url;
if (link) {
this.autocomplete.push(link);
}
});
// remove duplicates
// this.autocomplete = [...new Set(this.autocomplete)]
this.$nextTick(() => {
this.$refs.search.focus();
});
});
function sortedLinks(inLinks, category) {
let sortList = [];
inLinks.forEach((link) => {
const lowText = this.inputText.toLowerCase();
const searchTitle = link.title.toLowerCase().includes(lowText);
const searchUrl = link.url.toLowerCase().includes(lowText);
const searchFilter =
this.inputText == "" || searchTitle || searchUrl;
if (link.column == category && searchFilter) {
sortList.push(link);
}
});
return sortList.sort((a, b) => {
return a.title.localeCompare(b.title);
});
}
function setupIcon(title) {
title = title.toLowerCase().trim();
return icons[finalRandomIndex];
}
function setupUrl(inUrl) {
if (inUrl.indexOf("http") === -1) {
inUrl = "http://" + inUrl;
}
return inUrl.trim();
}
function filterKeydown(e) {
if (e.code != "Tab") {
return;
}
if (e.code == "Tab") {
e.preventDefault();
this.suggestionIndex++;
if (this.suggestionIndex > this.suggestions.length - 1) {
this.suggestionIndex = 0;
}
}
return;
}
function filterLinks(e) {
// if(e.code == 'Escape'){
// e.preventDefault()
// this.suggestions = []
// this.inputText = ''
// return
// }
// if(e.code == 'ArrowUp'){
// e.preventDefault()
// this.suggestionIndex--
// if(this.suggestionIndex <= -1){
// this.suggestionIndex = this.suggestions.length -1
// }
// return
// }
// if(e.code == 'ArrowDown'){
// e.preventDefault()
// this.suggestionIndex++
// if(this.suggestionIndex > this.suggestions.length-1){
// this.suggestionIndex = 0
// }
// return
// }
if (e.code == "Tab" || e.code == "Enter") {
e.preventDefault();
return;
}
this.suggestionIndex = -1;
this.suggestions = [];
const searchString = String(e.target.value)
.trim()
.toLowerCase()
.replace("www.", "");
if (searchString.length < 2) {
return;
}
this.autocomplete.forEach((entry) => {
const test = entry.toLowerCase().indexOf(searchString);
if (test >= 0) {
this.suggestions.push(entry);
}
});
this.suggestions = this.suggestions.splice(0, 2);
}
function webSearch(e) {
// go to suggestion
if (this.suggestions.length >= 1) {
window.location.href = `https://${this.suggestions[0]}`;
return;
}
// go straight to URLs
const urlCheck = String(e.target.value).trim();
if (urlCheck.indexOf(".") > -1 && urlCheck.indexOf(" ") == -1) {
let goodUrl = urlCheck.replace("http://", "").replace("www.", "");
window.location.href = `https://www.${goodUrl}`;
return;
}
// Skip empty strings
if (e.target.value == "") {
return;
}
// duck duck go search
let webString = String(e.target.value).replaceAll(" ", "+");
window.location.href = `https://duckduckgo.com/?hps=1&q=${webString}`;
return;
}
function generateMessage(index) {
let message = "";
let m = [];
var now = new Date();
var days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
var months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
var day = days[now.getDay()];
var month = months[now.getMonth()];
this.seed =
parseInt(`${now.getMonth()}${now.getHours()}${now.getDay()}`) +
this.clicks;
let weekday =
day + ", " + month + " " + now.getDate() + "<sup>th</sup>";
if (index == 1) {
m = [
[
"Continue",
"Keep on",
"Don't stop",
"Persist",
"Never stop",
"Without falter keep",
],
[
"Slaying",
"Rocking",
"Fighting",
"murdering",
"betraying",
"stabbing",
"killing",
"dancing",
],
[weekday],
];
}
if (index == 2 && this.seed % 2 == 0) {
m = [
["You", "The world", "The universe", "Your life"],
[
"really",
"could be",
"might be",
"certainly",
"will turn out to be",
"will be",
],
[
"tough",
"strong",
"a champ",
"a bitch",
"stronger than a bull",
"another day",
"a fine one",
"sick nasty",
],
["."],
["\nAll your"],
[
"exploits",
"missions",
"endeavors",
"journeys",
"limbs",
"friendships",
"meetings",
"destinations",
"plants",
"thoughts",
"dreams",
"projects",
],
[
"will",
"could",
"may",
"certainly will",
"are going to",
"are about to",
"will",
"will",
],
[
"succeed",
"avail",
"pass",
"make good",
"grow famous",
"work",
"profit",
"reap success",
"conquer",
"avail",
"thrive",
"flourish",
"triumph",
],
["."],
];
}
if (index == 2 && this.seed % 2 == 1) {
m = [
["Things", "Stuff", "Its", "Everything"],
["are not", "ain't", "is not"],
["so", "that"],
["bad", "grim", "brutal", "hard", "stuffy", "saddening"],
[".", ".", ".", ".", ".", ".", ".", "?"],
["\nGet", "\nRun", "\nSprint", "\nShamble"],
["out there", "in there", "on over", "along now", "on over"],
["and"],
["seize", "grab", "embrace", "hug", "curb stomp", "smash"],
["the", "those", "thine"],
["tasty", "special", "spicy", "magical", "wicked", "powerful"],
[
"day",
"goals",
"missions",
"pants",
"trees",
"dreams",
"pants",
"goats",
"grundus",
],
["."],
];
}
m.forEach((part) => {
// const p = part[Math.floor(Math.random() * part.length)]
const p = part[this.seed % part.length];
let space = " ";
if (p == "." || p == "?") {
space = "";
}
message += space + p;
});
return "<span>" + message + "</span>";
}
function linkClick() {
setTimeout(() => {
console.log("Close a boy");
window.open("", "_self").close();
}, 250);
}
function onCluck() {
console.log("hi");
}
</script>
<style>
html {
font-family: Roboto, Helvetica Neue, Arial, Helvetica, sans-serif;
}
body {
background-image: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%239C92AC' fill-opacity='0.25' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"),
linear-gradient(
135deg,
rgba(0, 0, 0, 0) 1%,
rgba(0, 8, 70, 0.56) 60%
),
radial-gradient(
circle at left bottom,
rgb(179, 0, 193) 0%,
rgb(0, 0, 0) 50%
);
margin: 0;
padding: 0;
height: 100vh;
}
input {
width: calc(100% - 20px);
margin: 0 10px 15px;
font-size: 1.4em;
border-radius: 4px;
outline: none;
padding: 10px 15px;
border: none;
box-sizing: border-box;
}
.message {
display: inline-block;
width: 100%;
color: white;
font-size: 1.5em;
text-align: center;
border-bottom: 1px solid white;
padding: 0 0 5px 0;
white-space: pre-wrap;
}
.large.message {
padding: 0 0 5px 0;
font-size: 2em;
border-bottom: none;
}
.small.message {
padding: 5px 0 15px 0;
font-size: 1em;
border-bottom: none;
text-align: right;
}
.center-container {
display: flex;
justify-content: center;
align-items: center;
height: 80vh;
position: relative;
}
.column {
width: 25%;
display: inline-block;
}
h2 {
text-align: center;
color: white;
text-transform: capitalize;
}
.max-links {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: flex-start;
align-content: space-evenly;
width: 100%;
position: relative;
}
.flex-child {
width: calc(100% - 10px);
margin: 0 0 10px;
}
.glass {
background-color: rgba(255, 255, 255, 0.25);
border-radius: 4px;
backdrop-filter: blur(3px);
border: 2px solid rgba(255, 255, 255, 0.1);
color: white;
}
.max-link {
display: inline-block;
box-sizing: border-box;
cursor: pointer;
background-color: rgba(255, 255, 255, 0.25);
border-radius: 4px;
width: 100%;
font-size: 0.8em;
padding: 10px 10px;
text-decoration: none;
color: white;
word-break: break-word;
backdrop-filter: blur(2px);
/* border: 2px solid rgba(255,255,255,0.1);*/
font-size: 1.1em;
}
.max-link:hover {
transition: all 0.4s ease-out;
/* background-color: #35004d;*/
backdrop-filter: blur(7px);
}
.visual-aid {
display: inline-block;
box-sizing: border-box;
margin: 0 5px 0 0;
}
.text-box {
display: inline-block;
position: relative;
width: 100%;
}
.suggestions {
display: inline-block;
background-color: white;
position: absolute;
top: 49px;
left: 0px;
right: 0;
z-index: 2;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
margin: 0 10px 0;
box-sizing: border-box;
box-shadow: 0px 4px 3px 0px gray;
background-color: rgba(255, 255, 255, 0.25);
backdrop-filter: blur(4px);
}
.suggestion {
display: inline-block;
padding: 10px;
border-radius: 4px;
width: 100%;
box-sizing: border-box;
color: white;
}
.suggestion.active {
background-color: purple;
color: white;
}
.nose,
.lip,
.eye {
display: inline-block;
background-color: rgba(255, 255, 255, 0.18);
border-radius: 4px;
padding: 5px 10px;
backdrop-filter: blur(3px);
border: 2px solid rgba(255, 255, 255, 0.1);
}
.lip {
width: calc(100% - 35px);
}
.lip.one {
height: 10px;
}
@media only screen and (max-width: 600px) {
.max-links {
width: 100%;
}
}
@media only screen and (min-width: 992px) {
.max-links {
width: 70%;
}
}
</style>

709
pages/index.vue Normal file
View File

@@ -0,0 +1,709 @@
<template>
<div>
<!-- resume box -->
<div
class="container mx-auto flex flex-row flex-wrap max-w-none md:max-w-5xl bg-white paper my-5"
>
<div
class="w-full md:w-7/12 flex flex-col items-center justify-center fade-in"
>
<div class="p-6 pb-1 md:text-center text-sm md:text-base">
<p class="text-5xl md:text-6xl">Max Gialanella</p>
<p class="py-3">
Full stack engineer with a decade of professional
experience.
<br />Passionate about web technologies & creative
problem solving.
</p>
</div>
</div>
<div
class="w-full md:w-5/12 flex flex-row justify-around items-center pt-6 fade-in"
>
<div class="pl-1 pr-3 bg-zinc-50 rounded-md shadow-sm">
<img
src="/maxhead.png"
alt="Max head photo"
class="object-cover h-auto w-[150px]"
/>
</div>
<div
class="flex flex-col justify-start gap-2 text-sm md:text-base"
>
<div>
<EnvelopeIcon class="h-4 w-4 inline subtle" />
<a target="_blank" href="mailto:maxjobhunt@pm.me">
MaxJobHunt@pm.me
</a>
</div>
<div>
<PhoneIcon class="h-4 w-4 inline subtle" />
<a target="_blank" href="tel:480-788-5217">
(480) 788-5217
</a>
</div>
<div>
<MapPinIcon class="h-4 w-4 inline subtle" />
<a
target="_blank"
href="https://goo.gl/maps/smMV1RZ3pZrS6C1y7"
>
Flagstaff, AZ
</a>
</div>
</div>
</div>
<div class="w-full md:w-7/12 fade-in d1">
<!-- astound -->
<div class="p-6 pb-1">
<div class="w-full flex justify-between border-b accent">
<div>Astound Commerce</div>
<div class="text-s text-zinc-600">2021-2023</div>
</div>
<p class="font-bold py-2">
Software Engineer - Salesforce Commerce Cloud
</p>
<p>
<ChevronRightIcon class="w-3 h-3 accent inline" />
Launched a new SFCC, online storefront for
<a href="https://www.rag-bone.com" target="_blank"
>Rag & Bone</a
>
using Typescript, Node.JS and other JS technologies.
Updated & streamlined, domestic and international
payments before a big sale which facilitated millions in
new revenue.
</p>
</div>
<!-- rws -->
<div class="p-6 pb-1">
<div class="w-full flex justify-between border-b accent">
<div>RWS - IP Services</div>
<div class="text-s text-zinc-600">2018 - 2021</div>
</div>
<p class="font-bold pt-2">Senior Software Engineer</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />Worked
with partners to build a suite of internal tools.
Including custom systems for time tracking, invoicing, a
live cardwall, dashboards, forms with intelligent
validation, extensive reporting and tools allowing for
mass data import and export.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Worked with managers to create a sophisticated, dynamic
form-building system that enabled clients to input
custom data with intelligent auto-complete rules per
client, removing the need for Marketing and
Administrative interaction.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Fully rebuilt nine legacy, Single Page Applications.
Worked directly with managers and QA to scope out all
existing functionality, then wrote scalable
replacements.
</p>
<p class="font-bold pt-2">Lead Software Engineer</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Lead a team of developers in system design and releases.
Pushed for improved standards in communication &
quality.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Leveraged Azure Pipelines and Bash to stand up a DevOps
suite that automated builds, package management, version
control, source compression and dev, stage & prod
releases.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Created a highly performant, browser-based PDF
annotation & highlighting system with Vue. Annotations
were converted to images and OCR'd for searching,
allowing for cataloging of highlighted data across
thousands of documents.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Created an email invite tool to orchestrate sending
thousands of emails, inviting specific users based on
various attributes, reporting stats, tracking user
engagement and managing email queues. Which resulted in
increased product engagement.
</p>
</div>
<!-- article one -->
<div class="p-6 pb-1">
<div class="w-full flex justify-between border-b accent">
<div>Article One Partners</div>
<div class="text-s text-zinc-600">2013 - 2018</div>
</div>
<p class="font-bold pt-2">Software Engineer</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Rewrote outdated jQuery UI font end in Vue.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Worked to migrate system from PHP 5 to 7.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Migrated legacy file system to Azure cloud. Integrated
new packages from PHP to Node.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Updated systems to be GDPR compliant with intelligent
data purging and greater respect for user privacy and
control.
</p>
<p class="font-bold pt-2">JR Software Engineer</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Update old system to use dynamic template engine and
Doctrine ORM.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Integrated system with external APIs.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Updated front-end with new CSS styles and libraries for
modern and responsive web.
</p>
<p class="py-2">
<ChevronRightIcon class="w-3 h-3 accent inline" />
Learned to apply GIT, Agile, bash, and modern web
standards.
</p>
</div>
</div>
<!-- skills column -->
<div class="w-full md:w-5/12 skills p-6 fade-in d2">
<p class="w-full border-b accent">Primary Skills</p>
<p>
Javascript ES6, Node.js, NPM
<span class="years">10</span>
</p>
<p>
Vue, UI, UX
<span class="years">14</span>
</p>
<p>
HTML5, CCS3
<span class="years">15</span>
</p>
<p>
Linux, Bash
<span class="years">10</span>
</p>
<p>
GIT, SVN
<span class="years">8</span>
</p>
<p>
MySQL
<span class="years">10</span>
</p>
<p>
Agile, SCRUM
<span class="years">8</span>
</p>
<p>
OO Design, Architecture, MVC
<span class="years">10</span>
</p>
<p>
RESTful, SOAP APIs, SaaS
<span class="years">8</span>
</p>
<p>
Azure DevOps, CI/CD
<span class="years">4</span>
</p>
<p>
PHP, Zend 2, Composer
<span class="years">6</span>
</p>
<p class="w-full border-b accent">Secondary Skills</p>
<p>
Python, Java
<span class="years">8</span>
</p>
<p>
React, Angular, jQuery
<span class="years">7</span>
</p>
<p>Salesforce Commerce Cloud</p>
<p class="w-full border-b accent">Certifications</p>
<p>Salesforce Javascript Developer</p>
<p>Salesforce B2C Commerce Developer</p>
<!-- <a href="https://trailblazer.me/id/mgialanella" target="_blank">View Certifications</a> -->
<p class="w-full border-b accent">Education</p>
<p>
BS - Computer Science<br />University of Massachusets
Amherset
</p>
<p class="w-full border-b accent">Passions</p>
<p>
Building
<a
href="http://blog.maxg.cc/2023/02/22/pc-builds/"
target="_blank"
>PCs</a
>
&
<a
href="http://blog.maxg.cc/2023/01/11/Build-a-Keyboard-Links/#My-Builds"
>Keyboards</a
>
</p>
<p>Cooking, Diet, Nutrition</p>
<p>Brazilian Jiu-Jitsu, Ultimate Frisbee</p>
<p>Coffee Snobbery</p>
</div>
</div>
<!-- pagebreak for pdf -->
<div class="pagebreak"></div>
<div class="w-fill p-4 pb-10 flex justify-center">
<a
href="/resume.pdf"
class="flex flex-row border border-zinc-200 shadow-lg rounded-md px-4 py-2 bg-white"
>
<div class="flex items-center pr-4">
<FolderArrowDownIcon class="w-8 h-8 accent inline" />
</div>
<div>
<p class="text-base">Download Resume</p>
<p class="text-zinc-500 text-xs">.PDF Format</p>
</div>
</a>
</div>
<div v-if="false">
TODO
<p>Change Resume Mode - General, Frontend, Backend</p>
<p>Finish Blog Articles</p>
<p>Optimize for mobile</p>
<p>Dark Mode</p>
</div>
<!-- headshot and overview -->
<div class="w-full bg-gradient-to-tr from-slate-100 to-teal-50">
<div class="w-full md:max-w-5xl m-auto flex flex-row flex-wrap">
<!-- info and downloads -->
<div class="w-6/12 flex flex-col justify-center">
<div class="border-l-4 border-l-zinc-400">
<h1 class="text-2xl md:text-4xl pl-5">
Software is a
<span class="text-blue-600">passion</span>.
</h1>
<h2 class="text-2xl md:text-3xl pl-5">
I'll never stop building cool things.
</h2>
</div>
<div class="p-4"></div>
<div class="pl-4">
<p>Dig Deeper</p>
<p>
Connect with me on Linkedin
<a
href="https://www.linkedin.com/in/max-g-856a2555"
>
<CursorArrowRippleIcon
class="w-8 h-8 accent inline"
/>
Linkedin
</a>
</p>
<!-- <p>Learn More about my Frontend work</p>
<p>Link to frontend</p>
<p>Learn More about my backed work</p>
<p>Link to backend</p> -->
</div>
</div>
<!-- headshot -->
<div class="w-6/12 flex justify-center">
<div class="imgcropper">
<img
src="/maxheadcolor.png"
alt="Max Gialanella"
class="object-cover max-w-[300px] h-auto"
/>
</div>
</div>
</div>
</div>
<!-- marketing box -->
<div class="w-full bg-slate-200">
<div class="p-4 w-full md:max-w-5xl m-auto pt-10">
<h1 class="text-3xl">Personal Projects</h1>
<p class="text-zinc-500">
Recent Examples of Professional software and passion
projects.
</p>
</div>
</div>
<div class="flex flex-row flex-wrap">
<div class="w-full bg-slate-200 pb-10">
<div
class="flex flex-row flex-wrap items-stretch justify-around max-w-none md:max-w-5xl m-auto"
>
<NuxtLink
v-for="(p, index) in projects"
class="w-full md:w-4/12 p-4 cursor-pointer"
:to="p[3]"
>
<div
class="border border-zinc-200 rounded-lg overflow-hidden shadow-md bg-slate-100"
>
<!-- {{ p[2] }} -->
<div
class="min-h-[80px] overflow-hidden flex justify-center items-center"
:class="`bg${index + 1}`"
>
<img
:src="p[2]"
alt="cover"
class="object-cover w-auto h-[150px] bigskew"
/>
</div>
<div class="p-4">
<p class="text-zinc-900 text-lg">{{ p[0] }}</p>
<p
class="pt-2 text-sm min-h-[80px] text-zinc-600"
>
<ChevronRightIcon
class="w-3 h-3 accent inline"
/>
{{ p[1] }}
</p>
<p
class="text-sm w-full text-right accent pt-2"
>
Explore
</p>
</div>
</div>
</NuxtLink>
</div>
</div>
</div>
<div class="w-full overflow-hidden relative bg-black">
<div
class="w-full md:max-w-5xl m-auto flex flex-row flex-wrap z-20"
>
<!-- info and downloads -->
<div
class="w-4/12 md:w-6/12 flex justify-center items-end overflow-hidden h-[280px]"
>
<img
src="/callme.png"
alt="Max head photo"
class="object-cover w-auto h-[340px] imgcropper-right"
/>
</div>
<!-- headshot -->
<div
class="w-8/12 md:w-6/12 flex flex-col justify-center items-start text-white pl-5"
>
<p class="text-xl md:text-3xl font-bold pb-5">
Lets Chat. Anytime. Anywhere.
</p>
<div class="border-l-4 border-l-zinc-600 pl-4">
<p>Call me</p>
<PhoneIcon class="h-4 w-4 inline" />
<a
target="_blank"
href="tel:480-788-5217"
class="text-white"
>
(480) 788-5217
</a>
</div>
<div class="p-4"></div>
<div class="border-l-4 border-l-zinc-600 pl-4">
<p>Email me and schedule a meeting</p>
<EnvelopeIcon class="h-4 w-4 inline" />
<a
target="_blank"
href="mailto:maxjobhunt@pm.me"
class="text-white"
>
MaxJobHunt@pm.me
</a>
</div>
</div>
</div>
<div class="space1"></div>
<div class="space2"></div>
</div>
</div>
</template>
<script setup>
import {
BeakerIcon,
MapPinIcon,
EnvelopeIcon,
PhoneIcon,
PaperClipIcon,
ChevronRightIcon,
FolderArrowDownIcon,
CursorArrowRippleIcon,
} from "@heroicons/vue/24/outline";
const projects = [
[
"Ravenwulf Consulting",
"Marketing site I built for a consulting firm. I designed the logo and identity. Built using Tailwind, Nuxt.js and hosted on Cloudflare.",
"/covers/ravenwulficon.png",
"/blog/creation-of-ravenwulf",
],
[
"Solid Scribe",
"Encrypted note taking application I designed and built. Uses applied cryptography and web-sockets for a convenient and secure experience.",
"/covers/solidscribeicon.svg",
"/blog/building-solid-scribe",
],
[
"Chat GPT Autocomplete",
"Scripts to access chatGPT for instantly generated code snippets. Allowing for rapid prototyping and development.",
"/covers/gpticon.png",
"https://git.maxg.cc/max/ChatGPTAutocomplete",
],
[
"Atreyu Custom Keyboard",
"Affordable and sleek ergonomic keyboard with custom firmware",
"/covers/atreyuicon.png",
"/blog/atreyu-keyboard",
],
[
"Personal Git Repo",
"Examine more of my work on my self hosted git repository.",
"/covers/giticon.png",
"https://git.maxg.cc/max",
],
[
"Personal Blog",
"Personal Blog where I post about tech topics.",
"/covers/blogicon.png",
"https://blog.maxg.cc/",
],
];
onMounted(() => {
// generate stars
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const STAR_COUNT = 180;
const shades = ["#e0e0e0", "#e0e0e0", "#bdbdbd", "#bdbdbd", "#484848"];
for (var j = 1; j < 3; j++) {
let result = "";
for (let i = 0; i < STAR_COUNT; i++) {
const shade = shades[Math.floor(Math.random() * shades.length)];
result += `${randomNumber(-50, 50)}vw ${randomNumber(
-50,
50
)}vh ${randomNumber(0, 1)}px ${randomNumber(0, 1)}px ${shade},`;
}
document.documentElement.style.setProperty(
"--random-stars" + j,
result.substring(0, result.length - 1)
);
}
});
</script>
<style>
:root {
--primary-color: #d0b24d;
--color-hint: #515151;
--border: #ccc;
--duration: 30;
--rp1: 20;
--rp2: 72;
--rp3: 1;
--rp4: 2;
--rp5: 3;
--rp6: 4;
--ray-rotate: 26deg;
--shift: 3;
--x: 0;
--y: 0;
--random-stars1: 0;
--random-stars2: 0;
}
a {
@apply text-blue-600 border-zinc-300;
}
.accent {
@apply text-blue-600 border-zinc-300;
}
.subtle {
@apply text-zinc-600;
}
.years {
display: none;
}
.skills p + p {
padding: 7px 0 0 0;
}
.space1,
.space2 {
/* position: fixed; */
position: absolute;
top: -1px;
left: -1px;
right: -1px;
bottom: -1px;
z-index: 1;
top: 50%;
left: 50%;
height: 1px;
width: 1px;
border-radius: 100%;
--shift: -2;
--shift-px: calc(var(--shift) * 1px);
transform: translateX(calc((100vw - var(--x) * var(--shift-px)) / 90))
translateY(calc((100vh - var(--y) * var(--shift-px)) / 90));
/* background: radial-gradient(circle, rgba(0,0,0,1) 20%, rgba(47,47,47,1) 100%);*/
box-shadow: var(--random-stars1);
}
.space2 {
box-shadow: var(--random-stars2);
animation: zoom 50s alternate infinite;
}
@keyframes zoom {
0% {
transform: scale(0.6);
}
100% {
transform: scale(1.2);
}
}
.bg1 {
@apply bg-gradient-to-tr from-slate-900 to-teal-500;
}
.bg2 {
@apply bg-gradient-to-tr from-slate-900 to-cyan-500;
}
.bg3 {
@apply bg-gradient-to-tr from-slate-900 to-blue-500;
}
.bg4 {
@apply bg-gradient-to-tr from-slate-900 to-violet-500;
}
.bg5 {
@apply bg-gradient-to-tr from-slate-900 to-fuchsia-500;
}
.bg6 {
@apply bg-gradient-to-tr from-slate-900 to-pink-500;
}
.bigskew {
transform: scale(0.85);
transition: all 1s ease;
filter: drop-shadow(1px 1px 0.2px rgba(255, 255, 255, 0.503))
drop-shadow(-1px 1px 0.2px rgba(255, 255, 255, 0.503))
drop-shadow(1px -1px 0.2px rgba(255, 255, 255, 0.503))
drop-shadow(-1px -1px 0.2px rgba(255, 255, 255, 0.503));
}
a:hover .bigskew {
transform: scale(1);
transition: all 1s ease;
}
.paper {
background: #fff;
box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.15), 0 -10px 0 -5px #eee,
0 -10px 1px -4px rgba(0, 0, 0, 0.15), 0 -20px 0 -10px #eee,
0 -20px 1px -9px rgba(0, 0, 0, 0.15);
padding-bottom: 30px;
border-bottom: 1px solid #e0e0e0;
}
.imgcropper {
overflow: hidden;
border-radius: 20px 0 100px;
}
.imgcropper-right {
overflow: hidden;
border-radius: 5px;
position: relative;
z-index: 10;
}
.fade-in {
animation-duration: 0.6s;
animation-name: fadeIn;
animation-timing-function: ease-in-out;
animation-fill-mode: forwards;
opacity: 0;
}
@keyframes fadeIn {
0% {
opacity: 0;
transform: translate3d(0, 20px, 0);
}
100% {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.d1 {
animation-delay: 0.4s;
}
.d2 {
animation-delay: 0.8s;
}
/* styles for printing as pdf */
@media print {
.pagebreak {
page-break-before: always;
}
.paper {
box-shadow: none;
border: none !important;
}
}
</style>