Website updates

This commit is contained in:
Zakary Timson 2024-01-04 19:56:46 -05:00
parent 4b3e89fa59
commit 6b28ed61bd
19 changed files with 187 additions and 112 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
APP_POSTMAIL_ACCESS_TOKEN=s7uhce84sx6fayy5xlq0nrtx

View File

@ -1,4 +1,4 @@
FROM node as build FROM node:20-alpine as build
# Variables # Variables
ARG NODE_ENV=prod ARG NODE_ENV=prod
@ -8,15 +8,24 @@ ENV NG_CLI_ANALYTICS=ci \
NODE_OPTIONS=${NODE_OPTIONS} NODE_OPTIONS=${NODE_OPTIONS}
# Setup # Setup
RUN mkdir /app
WORKDIR /app WORKDIR /app
COPY . . COPY . .
# Install & build # Build
RUN if [ ! -d "dist" ]; then npm ci && npm run build; fi RUN if [ ! -d "dist" ]; then npm install && npm run build; fi
# Use Nginx to serve # Use Nginx to serve
FROM nginx:1.20-alpine FROM nginx:1.23-alpine
COPY --from=build /app/dist/browser /usr/share/nginx/html COPY --from=build /app/dist /usr/share/nginx/html
# Copy aditional files
COPY package.json /usr/share/nginx/html
COPY docker/robots.txt /usr/share/nginx/html/robots.txt COPY docker/robots.txt /usr/share/nginx/html/robots.txt
COPY docker/nginx.conf /etc/nginx/nginx.conf COPY docker/nginx.conf /etc/nginx/nginx.conf
# Setup environment varible script
COPY docker/setup-environment.sh /docker-entrypoint.d/setup-environment.sh
RUN chmod +x /docker-entrypoint.d/setup-environment.sh
EXPOSE 80 EXPOSE 80

View File

@ -0,0 +1,7 @@
#!/usr/bin/env sh
JSON_STRING='window.env = { \
APP_POSTMAIL_ACCESS_TOKEN: "'"${APP_POSTMAIL_ACCESS_TOKEN}"'", \
}'
sed -i "s@<script id=\"environment\"></script>@<script>${JSON_STRING}</script>@" /usr/share/nginx/html/index.html
exec "$@"

View File

@ -1,22 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8">
<title>ZaksCode</title> <title>ZaksCode</title>
<link rel="icon" href="/logo.png"> <link rel="icon" href="/logo.png">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name=”robots” content=”index,nofollow” />
<meta property=”og:type” content=”website” /> <meta property=”og:type” content=”website” />
<meta property=”og:title” content=”Zakary Timson /> <meta property=”og:title” content=”Zakary Timson />
<!-- <meta name=”twitter:title” content=”Zakary Timson” />-->
<meta name="description" content="Devops & Software Engineer" />
<meta property=”og:description” content=”Devops & Software Engineer /> <meta property=”og:description” content=”Devops & Software Engineer />
<!-- <meta name=”twitter:description” content=”Devops & Software Engineer” />-->
<meta property=”og:image” content=”https://zakscode.com/cloud.gif” /> <meta property=”og:image” content=”https://zakscode.com/cloud.gif” />
<!-- <meta name=”twitter:image” content=”https://zakscode.com/cloud.gif” />-->
<meta property=”og:url” content=”https://zakscode.com” /> <meta property=”og:url” content=”https://zakscode.com” />
<meta property=”og:site_name” content=”ZaksCode” /> <meta property=”og:site_name” content=”ZaksCode” />
<!-- <meta name=”twitter:title” content=”Zakary Timson” />-->
<!-- <meta name=”twitter:description” content=”Devops & Software Engineer” />--> <script id="environment"></script>
<!-- <meta name=”twitter:image” content=”https://zakscode.com/cloud.gif” />-->
</head> </head>
<body> <body>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View File

@ -10,7 +10,7 @@ import Profile from '@/components/profile.vue';
<!-- Content --> <!-- Content -->
<div class="cap-width mb-3 bg-white"> <div class="cap-width mb-3 bg-white">
<!-- Header --> <!-- Header -->
<header class="p-3 mx-auto" style="background: #732222"> <header class="px-4 d-flex justify-content-center justify-content-sm-start" style="background: #732222">
<profile style="transform: translateY(-33%)" /> <profile style="transform: translateY(-33%)" />
</header> </header>

23
src/components/card.vue Normal file
View File

@ -0,0 +1,23 @@
<script setup lang="ts">
import Icon from '@/components/icon.vue';
defineProps({
color: {type: String, required: true},
icon: {type: String, required: true},
title: {type: String, required: true},
text: {type: String, required: true},
offset: {type: String, default: '0px'}
});
</script>
<template>
<div class="d-flex flex-column align-items-center border mb-3 p-3" style="width: 240px">
<div class="m-3 p-3 rounded-circle text-white d-flex align-items-middle justify-content-center" :style="'height: 50px; width: 50px; background:' + color">
<icon :name="icon" :style="'margin-top:' + offset"/>
</div>
<h4>{{title}}</h4>
<p class="text-center">
{{text}}
</p>
</div>
</template>

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import Icon from '@/components/icon.vue'; import Icon from '@/components/icon.vue';
import {environment} from '@/environments/environment';
import {ref} from 'vue'; import {ref} from 'vue';
const disable = ref(false); const disable = ref(false);
@ -10,7 +11,7 @@ const data = ref({
subject: '', subject: '',
message: '', message: '',
}); });
const errors = ref({ const errors = ref<any>({
banner: false, banner: false,
name: false, name: false,
email: false, email: false,
@ -29,6 +30,27 @@ function validateEmail(email: string) {
return /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(email); return /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(email);
} }
function send(name: string, email: string, subject: string, message: string) {
function formEncode(data: any): string {
return Object.entries(data).map(([key, value]) =>
encodeURIComponent(key) + '=' + encodeURIComponent(<any>value)
).join('&');
}
return fetch('https://postmail.invotes.com/send', {
method: 'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: formEncode({
access_token: environment.postMailKey,
subject: `ZaksCode: ${subject}`,
text: `App: ZaksCode\nFrom: ${name} <${email}>\nSubject: ${subject}\n\nMessage:\n${message}`
})
}).then(async resp => {
if(!resp.ok) throw new Error(resp.statusText);
return await resp.text();
});
}
function submit() { function submit() {
disable.value = true; disable.value = true;
const d = data.value; const d = data.value;
@ -42,39 +64,51 @@ function submit() {
}; };
if(errors.value.name || errors.value.email || errors.value.subject || errors.value.message) return disable.value = false; if(errors.value.name || errors.value.email || errors.value.subject || errors.value.message) return disable.value = false;
// Email.send(d.name, d.email, d.subject, d.message).then(() => { send(d.name, d.email, d.subject, d.message).then(() => {
// done.value = true; done.value = true;
// }).catch(err => { }).catch(err => {
// console.error(err); console.error(err);
// errors.value.banner = err?.message || err.toString(); errors.value.banner = err?.message || err.toString();
// disable.value = false; disable.value = false;
// }); });
} }
</script> </script>
<template> <template>
<!-- Success Banner -->
<div v-if="done" class="alert alert-success"> <div v-if="done" class="alert alert-success">
<span>Success! We sent you a copy & we will be intouch shortly.</span> <span>Success! We will be intouch shortly.</span>
</div> </div>
<!-- Error Banner -->
<div v-if="errors?.banner" class="alert alert-danger"> <div v-if="errors?.banner" class="alert alert-danger">
{{ errors.banner }} Error: {{ (errors as any).banner }}
</div> </div>
<!-- Contact Form -->
<form> <form>
<div class="d-flex flex-wrap justify-content-between mb-2"> <div class="d-flex flex-column flex-md-row flex-wrap justify-content-between">
<div class="input-group mb-2 mb-sm-0" style="width: 49%; min-width: 250px"> <!-- Name -->
<span class="input-group-text"><icon name="user"/></span> <div class="mb-2 p-0 pe-md-1 p-md-0" style="flex: 1 0 0;">
<input class="form-control" type="text" placeholder="Name" v-model="data.name" v-bind:class="{'is-invalid': errors?.name}" :disabled="!!user || disable" required> <div class="input-group">
<span class="input-group-text"><icon name="user"/></span>
<input class="form-control" type="text" placeholder="Name" v-model="data.name" v-bind:class="{'is-invalid': errors?.name}" :disabled="disable" required>
</div>
</div> </div>
<div class="input-group" style="width: 49%; min-width: 250px"> <!-- Email -->
<span class="input-group-text"><icon name="envelope"/></span> <div class="mb-2 p-0 ps-md-1" style="flex: 1 0 0;">
<input class="form-control" type="email" placeholder="Email" v-model="data.email" v-bind:class="{'is-invalid': errors?.email}" :disabled="!!user || disable" required> <div class="input-group">
<span class="input-group-text"><icon name="envelope"/></span>
<input class="form-control" type="email" placeholder="Email" v-model="data.email" v-bind:class="{'is-invalid': errors?.email}" :disabled="disable" required>
</div>
</div> </div>
</div> </div>
<!-- Subject -->
<div class="input-group mb-2"> <div class="input-group mb-2">
<span class="input-group-text"><icon name="book"/></span> <span class="input-group-text"><icon name="book"/></span>
<input class="form-control" type="text" placeholder="Subject" v-model="data.subject" v-bind:class="{'is-invalid': errors?.subject}" :disabled="disable" required> <input class="form-control" type="text" placeholder="Subject" v-model="data.subject" v-bind:class="{'is-invalid': errors?.subject}" :disabled="disable" required>
</div> </div>
<!-- Message Body -->
<textarea class="form-control" placeholder="Message" rows="5" v-model="data.message" v-bind:class="{'is-invalid': errors?.message}" :disabled="disable" required></textarea> <textarea class="form-control" placeholder="Message" rows="5" v-model="data.message" v-bind:class="{'is-invalid': errors?.message}" :disabled="disable" required></textarea>
<!-- Buttons -->
<div class="text-end pt-3"> <div class="text-end pt-3">
<button type="button" class="btn rounded-pill ms-3" @click="reset()">Reset</button> <button type="button" class="btn rounded-pill ms-3" @click="reset()">Reset</button>
<button type="button" class="btn btn-primary rounded-pill ms-3" @click="submit" :disabled="disable">Send Message</button> <button type="button" class="btn btn-primary rounded-pill ms-3" @click="submit" :disabled="disable">Send Message</button>

View File

@ -4,7 +4,11 @@
<style scoped> <style scoped>
footer { footer {
background: #343a40; background: #343a40;
color: darkgrey; color: #A3A3A3;
a {
color: #75B8FF;
}
} }
</style> </style>

View File

@ -232,6 +232,20 @@ window.cli['whoami'] = {
} }
} }
.hidden-label {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
@keyframes blink-empty { @keyframes blink-empty {
0% {background-size: 1px 1.1em;} 0% {background-size: 1px 1.1em;}
50% {background-size: 1px 1.1em;} 50% {background-size: 1px 1.1em;}
@ -245,7 +259,8 @@ window.cli['whoami'] = {
<div class="console-output"></div> <div class="console-output"></div>
<div class="console-input" @click=" focus()"> <div class="console-input" @click=" focus()">
<div class="console-input-prompt">root@{{hostname}}:~ #</div> <div class="console-input-prompt">root@{{hostname}}:~ #</div>
<input class="console-input-field" type="text" @keydown="stdIn($event)"> <label for="console-input-field" class="hidden-label"><!-- Accessibility -->CLI Input</label>
<input id="console-input-field" class="console-input-field" type="text" @keydown="stdIn($event)">
</div> </div>
</div> </div>
</template> </template>

View File

@ -21,7 +21,7 @@ import Icon from '@/components/icon.vue';
</h2> </h2>
<ul class="m-0 p-0 text-start" style="list-style: none"> <ul class="m-0 p-0 text-start" style="list-style: none">
<li><icon name="map-marker-alt" class="me-1"/> Toronto Ontario, Canada</li> <li><icon name="map-marker-alt" class="me-1"/> Toronto Ontario, Canada</li>
<li><icon name="envelope" class="me-1"/> <a href="mailto:zaktimson@gmail.com">zaktimson@gmail.com</a></li> <li><icon name="envelope" class="me-1"/> <a href="mailto:zaktimson@gmail.com" target="_blank">zaktimson@gmail.com</a></li>
<li><icon name="github" class="fa-brands me-1"/> <a href="https://github.com/ztimson" target="_blank">github.com/ztimson</a></li> <li><icon name="github" class="fa-brands me-1"/> <a href="https://github.com/ztimson" target="_blank">github.com/ztimson</a></li>
<li><icon name="git-alt" class="fa-brands me-1"/> <a href="https://git.zakscode.com" target="_blank">git.zakscode.com</a></li> <li><icon name="git-alt" class="fa-brands me-1"/> <a href="https://git.zakscode.com" target="_blank">git.zakscode.com</a></li>
</ul> </ul>

View File

@ -15,8 +15,7 @@ defineProps({
<template> <template>
<div> <div>
<div v-for="(p, i) in projects"> <div v-for="(p, i) in projects">
<hr v-if="i != 0"> <div class="d-flex align-items-center border p-2" :class="i == 0 ? '' : 'border-top-0'">
<div class="d-flex align-items-center">
<div class="me-2"> <div class="me-2">
<img :src="p.icon || '/git.png'" alt="Logo" style="height: 40px; width: 40px;"> <img :src="p.icon || '/git.png'" alt="Logo" style="height: 40px; width: 40px;">
</div> </div>

View File

@ -1,33 +1,30 @@
<script setup lang="ts"> <script setup lang="ts">
</script>
<style scoped lang="scss"> const resume = 'https://drive.google.com/file/d/1N1L2SYvqY49OJAR97cjjHANj0ModmZSy/view?usp=drive_link';
.btn-outline-info:hover {
color: #ffffff; const refrences = [
} // ['Andre Mourinho', ''],
</style> ['CD Projekt Red', 'https://files.zakscode.com/share/N61Db3y0'],
['Chris Cartwright', 'https://files.zakscode.com/share/luyY49_N'],
['Garry Whyte', 'https://files.zakscode.com/share/zHjnHReT'],
['Linda Nicodemo', 'https://files.zakscode.com/share/1wKpkQzW'],
['Ray Power', 'https://files.zakscode.com/share/bTR2ab_P'],
]
</script>
<template> <template>
<div class="d-block d-md-none"> <div class="d-block d-md-none">
<div class="mb-3"> <div class="mb-3">
<a class="btn btn-outline-primary w-100">CSV / Resume</a> <a class="btn btn-outline-danger w-100" :href="resume" target="_blank">CSV / Resume</a>
</div> </div>
<div class="btn-group-vertical w-100" role="group"> <div class="btn-group-vertical w-100" role="group">
<a class="btn btn-outline-info">CD Projekt Red</a> <a v-for="ref in refrences" class="btn btn-outline-primary" :href="ref[1]" target="_blank">{{ref[0]}}</a>
<a class="btn btn-outline-info">Chris Cartwright</a>
<a class="btn btn-outline-info">Garry Whyte</a>
<a class="btn btn-outline-info">Ray Power</a>
<a class="btn btn-outline-info">Linda Nicodemo</a>
</div> </div>
</div> </div>
<div class="d-none d-md-block"> <div class="d-none d-md-block">
<a class="btn btn-outline-primary me-3">CSV / Resume</a> <a class="btn btn-outline-danger me-3" :href="resume" target="_blank">CSV / Resume</a>
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<a class="btn btn-outline-info">CD Projekt Red</a> <a v-for="ref in refrences" class="btn btn-outline-primary" :href="ref[1]" target="_blank">{{ref[0]}}</a>
<a class="btn btn-outline-info">Chris Cartwright</a>
<a class="btn btn-outline-info">Garry Whyte</a>
<a class="btn btn-outline-info">Ray Power</a>
<a class="btn btn-outline-info">Linda Nicodemo</a>
</div> </div>
</div> </div>
</template> </template>

View File

@ -0,0 +1,3 @@
export const environment = {
postMailKey: (<any>window)?.env?.APP_POSTMAIL_KEY || import.meta.env.APP_POSTMAIL_ACCESS_TOKEN,
}

View File

@ -4,7 +4,7 @@
::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: #333; } ::-webkit-scrollbar-track { background: #333; }
::-webkit-scrollbar-thumb { background: #555; border-radius: 5px } ::-webkit-scrollbar-thumb { background: #555; border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: #aaa; } ::-webkit-scrollbar-thumb:hover { background: #aaa; }
html, body { html, body {
@ -14,11 +14,11 @@ html, body {
padding: 0; padding: 0;
font-family: Roboto,sans-serif; font-family: Roboto,sans-serif;
background: #354B72 url(/cloud.gif) no-repeat fixed right 50% top -10vh; background: #354B72 url('/cloud.gif') no-repeat fixed right 50% top -10vh;
} }
a:not(.btn), a:not(.btn):visited { a:not(.btn), a:not(.btn):visited {
color: #007bff; color: #006FE6;
text-decoration: none; text-decoration: none;
&:hover { &:hover {

View File

@ -1,81 +1,59 @@
<script setup lang="ts"> <script setup lang="ts">
import Card from '@/components/card.vue';
import Contact from '@/components/contact.vue'; import Contact from '@/components/contact.vue';
import Icon from '@/components/icon.vue';
import Konsole from '@/components/konsole.vue'; import Konsole from '@/components/konsole.vue';
import Projects from '@/components/projects.vue'; import Projects from '@/components/projects.vue';
import Refrences from '@/components/refrences.vue'; import Refrences from '@/components/refrences.vue';
import {ref} from 'vue';
const services: Projects[] = [ const services: Projects[] = [
{name: 'Formula Manager', icon: 'https://git.zakscode.com/avatars/7ec6bfd66b2bf9bad5c43c75a33f9cb3f6609b05c33a31f5d1e524a567cd09c1?size=280', link: 'https://screenprintingsuppliescanada.com/formulation-manager', description: 'Screen Printing Supplies'}, {name: 'Formula Manager', icon: 'https://git.zakscode.com/avatars/7ec6bfd66b2bf9bad5c43c75a33f9cb3f6609b05c33a31f5d1e524a567cd09c1?size=280', link: 'https://screenprintingsuppliescanada.com/formulation-manager', description: 'A web & computer application used by FH&Sons to record chemical formulas & distribute them to clients'},
{name: 'Map Alliance', icon: 'https://maps.zakscode.com/assets/images/logo.png', link: 'https://maps.zakscode.com', description: 'Online GIS & map editing solution'}, {name: 'Map Alliance', icon: 'https://maps.zakscode.com/assets/images/logo.png', link: 'https://maps.zakscode.com', description: 'An online GIS tool which enables users to view, edit & share various "marked-up" maps'},
{name: 'Phone Reminders', icon: 'https://phone-reminders.com/phone-reminders.png', link: 'https://phone-reminders.com', description: 'Send SMS & Voice call reminders from Google Calendar'}, {name: 'Phone Reminders', icon: 'https://phone-reminders.com/phone-reminders.png', link: 'https://phone-reminders.com', description: 'Automatically call & send SMS reminders to clients for events using Google Calendar'},
]; ];
const openSource: Projects[] = [ const openSource: Projects[] = [
{name: 'Formula Manager', icon: 'https://git.zakscode.com/avatars/7ec6bfd66b2bf9bad5c43c75a33f9cb3f6609b05c33a31f5d1e524a567cd09c1?size=280', link: 'https://screenprintingsuppliescanada.com/formulation-manager', description: 'Screen Printing Supplies'}, {name: 'ETF Demo', icon: 'https://git.zakscode.com/repo-avatars/0709db0c51d295d2d29b709865bd95f26e351f72a5c993ca63cd9ec4b4a07f43', link: 'https://etf.zakscode.com', source: 'https://git.zakscode.com/ztimson/etf-demo', description: 'Compare CSV files containing "Electronically Traded Funds" data (Check source for CSV files)'},
{name: 'Map Alliance', icon: 'https://maps.zakscode.com/assets/images/logo.png', link: 'https://maps.zakscode.com', description: 'Online GIS & map editing solution', source: 'https://google.com'}, {name: 'Legio 30', icon: 'https://git.zakscode.com/repo-avatars/f66e3d6f5ff4646b45e859f6bf00c0e0de0621d8a45a47481d53d67b67700f2a', link: 'https://legio-30.org', source: 'https://git.zakscode.com/ztimson/legio-30', description: 'Website for a non-profit Roman re-enactment group from Southern Ontario'},
{name: 'Phone Reminders', icon: 'https://phone-reminders.com/phone-reminders.png', link: 'https://phone-reminders.com', description: 'Send SMS & Voice call reminders from Google Calendar'}, {name: 'Pelican Landing', icon: 'https://git.zakscode.com/ztimson/pelican-landing/raw/branch/develop/src/assets/logo.png', link: 'https://pelican-landing.zakscode.com', source: 'https://git.zakscode.com/ztimson/pelican-landing', description: 'Business website for a hunting & fishing lodge on the Lage of Woods in Northern Ontario '},
{name: 'Persist', icon: 'https://git.zakscode.com/repo-avatars/89f6c36caf75762ed9f7f98b69044b7db30da5230be7c5cea54f8a1158f1669a', link: 'https://www.npmjs.com/package/@ztimson/persist', source: 'https://git.zakscode.com/ztimson/persist', description: 'Typescript library to sync variables with LocalStorage & persist state through page reloads'},
{name: 'PyBar', icon: 'https://git.zakscode.com/repo-avatars/002f97340c2781ccfa5d09fde97403fd499c39a9ad5675dc0edf05a8396e9ac5', link: 'https://git.zakscode.com/ztimson/py-bar', source: 'https://git.zakscode.com/ztimson/py-bar', description: 'Python library to display ASCII progress bars using iterators'},
{name: 'Transmute', icon: 'https://git.zakscode.com/repo-avatars/b497daaf22a214fe6d6cc35b8ec217cd22401b668dff93dcfcc7557bd8a46d96', link: 'https://git.zakscode.com/ztimson/transmute', source: 'https://git.zakscode.com/ztimson/transmute', description: 'Distributed video conversion tool with built in WebUI'},
{name: 'ZaksCode', icon: 'https://git.zakscode.com/repo-avatars/590279cb4b176c6a7924364c7b0ef78afa80696703abe5bef8d9ce7e12477f3d', link: 'https://zakscode.com', source: 'https://git.zakscode.com/ztimson/zakscode', description: 'Source code for this website, ZaksCode.com'},
]; ];
// Get repository count
let remainder = ref(0);
fetch('https://git.zakscode.com/api/v1/repos/search', {
method: 'get',
headers: {"Content-Type": "application/json"}
}).then(async repos => {
const data = (await repos.json())?.data;
remainder.value = data.length - openSource.length;
});
</script> </script>
<template> <template>
<div class="p-3"> <div class="p-3">
<!-- Terminal -->
<konsole class="mb-5" style="max-height: 300px" /> <konsole class="mb-5" style="max-height: 300px" />
<!-- Steps -->
<div class="mb-5 pt-5"> <div class="mb-5 pt-5">
<h4 class="mb-0 text-center">Plan for Success</h4> <h3 class="mb-0 text-center">Plan for Success</h3>
<hr class="mb-4"> <hr class="mb-4">
<div class="text-center my-5"> <div class="text-center my-5">
<img src="/cycle.svg" alt="Development Cycle" style="width: 100%; max-width: 600px; height: auto;"> <img src="/cycle.svg" alt="Development Cycle" style="width: 100%; max-width: 600px; height: auto;">
</div> </div>
<div class="d-flex"> <div class="d-flex flex-wrap justify-content-around">
<div class="d-flex flex-column align-items-center border m-3 p-3 text-center" style="flex: 1 0 0;"> <card color="#6aa84f" icon="clipboard" offset="1px" title="Plan" text="Working with the client we will identify the goals of the project. This includes things like the target audience, use case, features, style, and delivery."/>
<div class="m-3 p-3 rounded-circle text-white d-flex align-items-middle justify-content-center" style="background: #6aa84f; height: 50px; width: 50px"> <card color="#6d9eeb" icon="code" offset="2px" title="Code" text="Goals are broken down into tasks and prioritized in our ticketing system. Using CI/CD, tasks are automatically deployed for testing as they are completed."/>
<icon name="clipboard"/> <card color="#e69138" icon="message" offset="3px" title="Feedback" text="Clients are notified with the release notes and can test at their convince. Any critiques can be communicated directly to us or through our ticketing system."/>
</div> <card color="#674ea7" icon="play" offset="2px" title="Release" text="Once all goals are complete we will work with you to deploy the product to any location. Once setup, future updates are automatically deployed to our clients."/>
<h5>Plan</h5>
<p class="text-center">
Working with the client we will identify the goals of the project. This includes things like the target audience, use case, features, style, and deployment strategy.
</p>
</div>
<div class="d-flex flex-column align-items-center border m-3 p-3" style="flex: 1 0 0;">
<div class="m-3 p-3 rounded-circle text-white d-flex align-items-middle justify-content-center" style="background: #6d9eeb; height: 50px; width: 50px">
<icon name="code"/>
</div>
<h5>Develop</h5>
<p class="text-center">
Goals are broken down into tasks and are prioritized. Using CI/CD, tasks are automatically deployed for testing as they are completed.
</p>
</div>
<div class="d-flex flex-column align-items-center border m-3 p-3" style="flex: 1 0 0;">
<div class="m-3 p-3 rounded-circle text-white d-flex align-items-middle justify-content-center" style="background: #e69138; height: 50px; width: 50px">
<icon name="message"/>
</div>
<h5>Feedback</h5>
<p class="text-center">
Clients are notified with the release notes and can test at their convince. Any critiques can be communicated directly to us or through our ticketing system.
</p>
</div>
<div class="d-flex flex-column align-items-center border m-3 p-3" style="flex: 1 0 0;">
<div class="m-3 p-3 rounded-circle text-white" style="background: #674ea7; height: 50px; width: 50px">
<h5 class="m-0">4</h5>
</div>
<h5>Release</h5>
<p class="text-center">
Once all goals are complete we will work with you to deploy the product to any location. Once setup, future updates are automatically rolled out.
</p>
</div>
</div>
<div class="d-flex align-items-center">
<div>
</div>
<div class="d-flex flex-column">
</div>
</div> </div>
</div> </div>
<!-- About Section -->
<div class="mb-5"> <div class="mb-5">
<h3 class="mb-0">About</h3> <h3 class="mb-0">About</h3>
<hr class="mb-4"> <hr class="mb-4">
@ -98,6 +76,7 @@ const openSource: Projects[] = [
</div> </div>
</div> </div>
<!-- Projects List -->
<div class="mb-5"> <div class="mb-5">
<h3 class="m-0">Projects</h3> <h3 class="m-0">Projects</h3>
<hr class="mb-4"> <hr class="mb-4">
@ -109,8 +88,10 @@ const openSource: Projects[] = [
<h4 class="mb-3 text-muted">Open Source</h4> <h4 class="mb-3 text-muted">Open Source</h4>
<projects :projects="openSource"/> <projects :projects="openSource"/>
</div> </div>
<a v-if="remainder" class="float-end m-2" href="https://git.zakscode.com/explore" target="_blank">See {{remainder}} More...</a>
</div> </div>
<!-- Contact Form -->
<div> <div>
<h3 class="m-0">Contact</h3> <h3 class="m-0">Contact</h3>
<hr class="mb-4"> <hr class="mb-4">

View File

@ -11,6 +11,7 @@
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"noEmit": true, "noEmit": true,
"moduleResolution": "Node",
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": [ "@/*": [

View File

@ -10,7 +10,6 @@
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"noEmit": true, "noEmit": true,
"module": "ESNext",
"moduleResolution": "Bundler", "moduleResolution": "Bundler",
"types": [ "types": [
"node" "node"

View File

@ -1,7 +1,6 @@
import vue from '@vitejs/plugin-vue';
import {fileURLToPath, URL} from 'node:url';
import {defineConfig} from 'vite'; import {defineConfig} from 'vite';
import {fileURLToPath, URL} from 'node:url';
import vue from '@vitejs/plugin-vue';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
@ -12,5 +11,6 @@ export default defineConfig({
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)) '@': fileURLToPath(new URL('./src', import.meta.url))
} }
} },
envPrefix: 'APP',
}); });