Adding project to github
75
README.md
Normal file
@ -0,0 +1,75 @@
|
||||
# Nuxt 3 Minimal Starter
|
||||
|
||||
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install the dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
|
||||
# bun
|
||||
bun install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm run dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
|
||||
# bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm run build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
|
||||
# bun
|
||||
bun run build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm run preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
|
||||
# bun
|
||||
bun run preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
7
app.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</div>
|
||||
</template>
|
35
content/blog/atreyu-keyboard.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "Atreyu keyboard Build"
|
||||
description: "Creating a working ergonomic keyboard. From files to physical."
|
||||
date: "2023-10-1"
|
||||
---
|
||||
|
||||
### It started with an existing keyboard
|
||||
|
||||
It all began with the [lily58](https://www.littlekeyboards.com/collections/lily58-pcb-kits/products/lily58-pro-pcb-kit). An ergonomic keyboard that has 58 keys. I loved the design and layout. But it wasn't portable. It required a large amount of desk space to function comfortably.
|
||||
|
||||
I began to browse around for other options. A portable, wireless, lily58 keyboard.
|
||||
|
||||
### Finding the right project
|
||||
|
||||
I found [this post](https://kbd.news/Atreyu-Rev2-MX-1911.html). Which lead me to the extremely well documented [github project](https://github.com/climent/atreyu/tree/main/pcb/v2-choc). But there was a huge problem. Where do I buy the keyboard? Where do I buy the parts?
|
||||
|
||||
**There are none!**
|
||||
|
||||
You need to fabricate and assemble this keyboard from the files on github.
|
||||
|
||||
### Exporting the cutter files and fabrication
|
||||
|
||||
Using KiCad (An open source cad program for linux) I opened, customized and finally, after much reading and tweaking, exported the cutter files. Cutter files are used by PCB manufacturers to produce PCBs. I uploaded the files to Elecrow, a manufacturer in China. Then waited patiently for the PCBs to arrive in the mail.
|
||||
|
||||
### Building and programming
|
||||
|
||||
Once the PCBs showed up, I began soldering. In short order everything was built and ready to go. Except the firmware. There were example firmwares in the source repository but I wanted some specific layers, macros and the Dvorak layout. To get all these features I had to build them using the ZMK firmware.
|
||||
|
||||
Understanding the ZMK firmware was a challenge. The way you program the keyboard is by building out header files in c. The documentation is decent but understanding what its doing and how its happening is challenging. One easy part of the project is the brilliant usage of Github Actions by the ZMK developers. Every time a commit is made and pushed to github, it builds the firmware for you automatically. This saves a lot of hassle and makes building keyboard firmware a lot more accessible.
|
||||
|
||||
[After much trial and error](https://github.com/stimularity/zmk-config/commits/main) the keyboard was ready for action.
|
||||
|
||||
### Blank Keycaps
|
||||
|
||||
At first the blank keycaps were a cost saving measure. Keycaps without legends are considerably cheaper. But after some time using them, I have come to love them. Despite being able to touch type people generally still look at the keys frequently for numbers and symbols. Without any reference, you learn to touch type them as well. Ultimately it has made me a faster typist.
|
45
content/blog/building-solid-scribe.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
title: "Creation of Solid Scribe"
|
||||
description: "How I created, encrypted note taking application, solid scribe."
|
||||
icon: "/solidscribe.png"
|
||||
date: "2023-10-1"
|
||||
---
|
||||
|
||||
Solid Scribe is an end-to-end encrypted note taking application I created for personal convenience and privacy.
|
||||
|
||||
### Application overview
|
||||
|
||||
Solid Scribe is an encrypted note taking application that respects users privacy.
|
||||
|
||||
### Why it was created
|
||||
|
||||
I created solid scribe because I was tired of all my data being scraped and put into a giant marketing profile. Daily notes contain a lot of private information, giving all that data to google or facebook made me uncomfortable.
|
||||
|
||||
### How it works
|
||||
|
||||
Solid Scribe is end to end encrypted with note text completely encrypted using a private key. Any time a note is created a new encrypted database entry is created. Note text can not be read without the correct decryption key.
|
||||
|
||||
### Tech Stack
|
||||
|
||||
Solid Scribe is hosted on linode, using nginx and express router.
|
||||
The backend is fully Node.js without an ORM and minimal frameworks.
|
||||
Frontend Vue.js using Vue-CLI, Socket.io and Semanic UI for the styles.
|
||||
|
||||
### Current Major Features
|
||||
|
||||
- User accounts/login - Two Factor Authentication
|
||||
- Revoking active sessions from other browsers
|
||||
- Color themes and Dark mode
|
||||
- Note tags, tag searching
|
||||
- Note Searching, using Encrypted search index
|
||||
- Encrypted Notes with text editing, formatting, color themes
|
||||
- Todo lists with sorting and removing completed tasks
|
||||
- Link scraping from notes, with image capture and search
|
||||
- Inserting of link metadata into note
|
||||
- Secure sharing of notes with other users using public-key encryption
|
||||
- Synchronous note editing across open note instances
|
||||
- Pushing links from web to your account using a bookmarklet
|
||||
|
||||
### Source Code
|
||||
|
||||
https://git.maxg.cc/max/SolidScribe
|
43
content/blog/creation-of-ravenwulf.md
Normal file
@ -0,0 +1,43 @@
|
||||
---
|
||||
title: "Creation of Ravenwulf Consulting"
|
||||
description: "Designing and building of Ravenwulfconsulting.com"
|
||||
date: "2023-11-5"
|
||||
---
|
||||
|
||||
My latest project is www.ravenwulfconsulting.com. (Its still a work in progress.) Everything from design, to hosting was my responsibility and I'm delighted at the results.
|
||||
|
||||
### Logo design and identity
|
||||
|
||||
The logo of Ravenwulf was challenging to design. The request was to create a unique identity without making it look like a Harry Potter house crest. After some iterations on the design, we finally landed on the right balance of interesting and corporate. I used Inkscape to build out the designs but exporting it was a bit of a chore. SVG specifications are all over the place and don't always render correctly across devices.
|
||||
|
||||
![uploaded!](http://blog.maxg.cc/images/pasted-19.png)
|
||||
|
||||
### Tech stack
|
||||
|
||||
![uploaded!](http://blog.maxg.cc/images/pasted-20.png)
|
||||
|
||||
Ravenwulf is powered by Nuxt.js with the front end built using TailwindCss. I have never used either of these technologies before but they are modern and well documented.
|
||||
|
||||
I chose to use nuxt.js because its of declarative routing, server side rendering, good SEO options and most importantly, it uses Vue.js. Im a big Vue fan. I dont own any Vue clothing but its only a matter of time.
|
||||
|
||||
Next, I chose TailwindCSS because of all the hype. Was it really all its cracked up to be? Why relearn 100's of CSS selectors all over again just to get some new shorthand options? After spending some time with it, the short answer is "Hell Yes! Its good!"
|
||||
|
||||
That's all I needed for this project. Almost all the configurations are the defaults. My goal was to minimize dependencies and keep the project maintainable should someone else ever end up working on it.
|
||||
|
||||
### Hosting and Email
|
||||
|
||||
I didn't want to spend much money on hosting. I actually didn't want to spend any money. This is where Cloudflare Pages enters the picture. They offer free hosting, for lower traffic projects, on their super robust edge network.
|
||||
|
||||
Cloudflare offers automatic builds. To trigger them, simply push to a Git Repo. Within minutes I had Ravenwulf in a git repo and connected to Cloudflare Pages. Just like that, the site was live.
|
||||
|
||||
Hooking up the "Contact Form" and Sending email from the ravenwulf was the only part of this project that was truly a headache. Mostly because the feature is new and the documentation is a mess. After much struggling, the contact form was setup and working. [I detailed a setup guide here.](https://blog.maxg.cc/2023/10/01/Sending-Emails-with-Cloudflare-Workers/)
|
||||
|
||||
### Thoughts on the Ravenwulf Tech Stack
|
||||
|
||||
I'm extremely happy with the tech that runs Ravenwulf.com.
|
||||
|
||||
**TailwindCSS** is a fantastic tool. It made prototyping and building the site a breeze. Its major advantage is how explicit all the CSS declarations become. No more checking the style of .btn then .main then .content then checking the inspector to see how they are being rendered. Its all made clear from a glance at the element. While this does lend itself to more bulky, confusing and cluttered HTML syntax,the benefits completely outweigh the cons. Tailwind provides easy access to flexbox, responsive elements and color pallets. Additionally, almost never checking the inspector in the Browser make tailwind an absolute delight. Despite its added dependencies it will be my go-to on future projects.
|
||||
|
||||
**Nuxt.js** is a great framework. I barley scratched the surface of what its capable of doing because it does so much out of the box. I set up some pages, a couple components and thats it. It automatically generates routes. It automatically manages component includes. Its dev server is setup with file watching and hot-reloading. One click here, a click there and an entire site is built. There are tons of additional tools and options in Nuxt should anything else arise in the project, im sure nuxt could handle it. It also has a pretty large repository of Plugins.
|
||||
|
||||
**Inkscape** is a great tool but its SVG export options are frustrating to say the least. It supports a large number of tools and options. While browsers only support a small subset of what Inkscape is capable of creating. The internet is riddled with support threads asking why gradients don't render, elements don't appear, layer masks don't work on export or why entire SVGs are empty after saving. If Inkscape had an "export to web" option, it would be a top quality piece of open source software. Without that, its tough to recommend. I guess you can use Adobe Illustrator but I ain't got the money for that.
|
46
layouts/default.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div class="flex flex-col min-h-screen bg-slate-100">
|
||||
<slot />
|
||||
|
||||
<footer class="mx-auto w-full text-white bg-zinc-900 p-2"></footer>
|
||||
<div
|
||||
class="w-full mx-auto bg-zinc-800 flex flex-col justify-center items-center py-9 text-white fade-in-children"
|
||||
>
|
||||
<span> Max Gialanella - {{ new Date().getFullYear() }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const route = useRoute();
|
||||
|
||||
const updateMeta = () => {
|
||||
const sitePrefix = "Resume";
|
||||
const pageName = route.name
|
||||
.toLowerCase()
|
||||
.replace(/(?<= )[^\s]|^./g, (a) => a.toUpperCase());
|
||||
|
||||
useSeoMeta({
|
||||
title: `${sitePrefix} | ${pageName}`,
|
||||
ogTitle: "Max Gialanella",
|
||||
description: "Max Gialanella",
|
||||
ogDescription: "Max Gialanella",
|
||||
// ogImage: 'https://example.com/image.png',
|
||||
// twitterCard: 'Ravenwulf Logo',
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
color: rgb(47, 49, 50);
|
||||
}
|
||||
.page-enter-active,
|
||||
.page-leave-active {
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
.page-enter-from,
|
||||
.page-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
8
nuxt.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxtjs/tailwindcss', "@nuxt/content"],
|
||||
devtools: { enabled: false },
|
||||
content: {
|
||||
documentDriven: true
|
||||
}
|
||||
})
|
16833
package-lock.json
generated
Normal file
23
package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/content": "^2.9.0",
|
||||
"@nuxt/devtools": "latest",
|
||||
"@nuxtjs/tailwindcss": "^6.9.4",
|
||||
"nuxt": "^3.8.1",
|
||||
"vue": "^3.3.8",
|
||||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/vue": "^2.0.18"
|
||||
}
|
||||
}
|
67
pages/blog/[post].vue
Normal 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
@ -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
@ -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
@ -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>
|
BIN
public/callme.png
Normal file
After Width: | Height: | Size: 263 KiB |
BIN
public/covers/atreyuicon.png
Normal file
After Width: | Height: | Size: 252 KiB |
BIN
public/covers/blogicon.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
public/covers/giticon.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
public/covers/gpticon.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
public/covers/ravenwulficon.png
Normal file
After Width: | Height: | Size: 19 KiB |
19
public/covers/solidscribeicon.svg
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" id="svg8" version="1.1" viewBox="0 0 132.29166 132.29167" height="500" width="500">
|
||||
<defs id="defs2"/>
|
||||
<metadata id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g style="display:inline" transform="translate(0,-164.70832)" id="layer1">
|
||||
<path id="path3813-4" d="m 56.22733,165.36641 -55.56249926,15.875 8e-7,63.5 47.62499846,11.90625 v 27.78125 l -47.76066333,-13.9757 0.13566407,10.00695 55.56249926,15.875 v -47.625 l -47.6249985,-11.90625 -8e-7,-47.625 47.7606633,-13.94121 c 0.135664,-2.30629 -0.135664,-9.87129 -0.135664,-9.87129 z" style="fill:#0f7425;fill-opacity:1;stroke:none;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;shape-rendering:crispedges"/>
|
||||
<path id="path4563" d="m 20.508581,220.92891 c 15.265814,-14.23899 27.809717,-7.68002 39.687499,3.96875 v -7.9375 C 51.75093,200.8366 37.512584,206.01499 20.508581,205.05391 Z" style="fill:#04cb03;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;shape-rendering:crispedges"/>
|
||||
<path id="path4563-6" d="m 111.78985,220.92891 c -15.265834,-14.23899 -27.809737,-7.68002 -39.68752,3.96875 v -7.9375 c 8.445151,-16.12356 22.683497,-10.94517 39.68752,-11.90625 z" style="display:inline;fill:#04cb03;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;shape-rendering:crispedges"/>
|
||||
<path id="path3813-4-2" d="m 76.07108,165.36641 55.5625,15.875 v 63.5 l -47.625,11.90625 v 27.78125 l 47.76067,-13.9757 -0.13567,10.00695 -55.5625,15.875 v -47.625 l 47.625,-11.90626 V 189.17891 L 75.93542,175.2377 c -0.13567,-2.30629 0.13566,-9.87129 0.13566,-9.87129 z" style="display:inline;fill:#04cb03;fill-opacity:1;stroke:none;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;shape-rendering:crispedges"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/maxhead.png
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
public/maxheadcolor.png
Normal file
After Width: | Height: | Size: 304 KiB |
BIN
public/resume.pdf
Normal file
3
server/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../.nuxt/tsconfig.server.json"
|
||||
}
|
12
tailwind.config.js
Normal file
@ -0,0 +1,12 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./pages/*.{vue,js,ts,jsx,tsx}",
|
||||
"./components/*.{vue,js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
4
tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|