Rework and finished the boot sequence.
This commit is contained in:
parent
80ad010cfd
commit
bb8c83bb9b
21
index.html
21
index.html
@ -1,6 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
@ -9,15 +10,15 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
||||||
rel="stylesheet"
|
rel="stylesheet" />
|
||||||
/>
|
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap" rel="stylesheet" />
|
||||||
<link
|
<link rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
||||||
rel="stylesheet"
|
</head>
|
||||||
/>
|
|
||||||
</head>
|
<body>
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
54
package-lock.json
generated
54
package-lock.json
generated
@ -8,7 +8,9 @@
|
|||||||
"name": "temppersonal",
|
"name": "temppersonal",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": "^18.15.7",
|
||||||
"@types/three": "^0.149.0",
|
"@types/three": "^0.149.0",
|
||||||
|
"p5-svelte": "^3.1.2",
|
||||||
"svelte-cubed": "^0.2.1",
|
"svelte-cubed": "^0.2.1",
|
||||||
"three": "^0.150.1"
|
"three": "^0.150.1"
|
||||||
},
|
},
|
||||||
@ -472,6 +474,17 @@
|
|||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "18.15.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.7.tgz",
|
||||||
|
"integrity": "sha512-LFmUbFunqmBn26wJZgZPYZPrDR1RwGOu2v79Mgcka1ndO6V0/cwjivPTc4yoK6n9kmw4/ls1r8cLrvh2iMibFA=="
|
||||||
|
},
|
||||||
|
"node_modules/@types/p5": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/p5/-/p5-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-EhaRGjqGcv5lKWvBUfC4Oxi2J5T1C1HuoQnJCdxJJMrRf+HTVdh7hCgBo88nHe6LbUXxkrxVj9tc1zOuemefFA==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@types/pug": {
|
"node_modules/@types/pug": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
||||||
@ -1273,6 +1286,23 @@
|
|||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p5": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p5/-/p5-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-RowF+RxfVUhJm/YKXL5TCFzTqnwAIwK6W1VGs9LAqSf3PCmLz9Igbxzlf0Ry5IMV71L42wipCdH/bDiNsqAstA=="
|
||||||
|
},
|
||||||
|
"node_modules/p5-svelte": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/p5-svelte/-/p5-svelte-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-lcfWh+cJ1/wRdIXHnjpYmDgj2h3TCy1QJVQnf/cBcFWS8CSkvyAN5F8u8H2U8qBUtZ4XaD3nd+1NoYUMHaMExQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"p5": "^1.4.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/p5": "^1.4.2",
|
||||||
|
"p5": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@ -2302,6 +2332,17 @@
|
|||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"version": "18.15.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.7.tgz",
|
||||||
|
"integrity": "sha512-LFmUbFunqmBn26wJZgZPYZPrDR1RwGOu2v79Mgcka1ndO6V0/cwjivPTc4yoK6n9kmw4/ls1r8cLrvh2iMibFA=="
|
||||||
|
},
|
||||||
|
"@types/p5": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/p5/-/p5-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-EhaRGjqGcv5lKWvBUfC4Oxi2J5T1C1HuoQnJCdxJJMrRf+HTVdh7hCgBo88nHe6LbUXxkrxVj9tc1zOuemefFA==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"@types/pug": {
|
"@types/pug": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
||||||
@ -2878,6 +2919,19 @@
|
|||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"p5": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p5/-/p5-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-RowF+RxfVUhJm/YKXL5TCFzTqnwAIwK6W1VGs9LAqSf3PCmLz9Igbxzlf0Ry5IMV71L42wipCdH/bDiNsqAstA=="
|
||||||
|
},
|
||||||
|
"p5-svelte": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/p5-svelte/-/p5-svelte-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-lcfWh+cJ1/wRdIXHnjpYmDgj2h3TCy1QJVQnf/cBcFWS8CSkvyAN5F8u8H2U8qBUtZ4XaD3nd+1NoYUMHaMExQ==",
|
||||||
|
"requires": {
|
||||||
|
"p5": "^1.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"parent-module": {
|
"parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
"vite": "^4.2.0"
|
"vite": "^4.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": "^18.15.7",
|
||||||
"@types/three": "^0.149.0",
|
"@types/three": "^0.149.0",
|
||||||
|
"p5-svelte": "^3.1.2",
|
||||||
"svelte-cubed": "^0.2.1",
|
"svelte-cubed": "^0.2.1",
|
||||||
"three": "^0.150.1"
|
"three": "^0.150.1"
|
||||||
}
|
}
|
||||||
|
@ -1,60 +1,44 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import GlitchText from "./lib/GlitchText.svelte";
|
import { onMount } from "svelte";
|
||||||
import ThreeScene from "./lib/ThreeScene.svelte";
|
import Background from "./components/Background.svelte";
|
||||||
|
import Bootup from "./components/Bootup.svelte";
|
||||||
|
import Footer from "./components/Footer.svelte";
|
||||||
|
import NameSplash from "./components/NameSplash.svelte";
|
||||||
|
import About from "./components/About.svelte";
|
||||||
|
import Projects from "./components/Projects.svelte";
|
||||||
|
import Modal from "./utils/Modal.svelte";
|
||||||
|
|
||||||
|
let bootDone = false;
|
||||||
|
let mainContent;
|
||||||
|
|
||||||
|
async function finishBoot() {
|
||||||
|
bootDone = true;
|
||||||
|
await new Promise((r) => setTimeout(r, 300));
|
||||||
|
mainContent.classList.add("opacity-100");
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if ("skip_boot" in localStorage) {
|
||||||
|
console.log("Skipping boot sequence");
|
||||||
|
finishBoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ThreeScene/>
|
<Background />
|
||||||
|
<section class="h-screen relative p-4" class:hidden={bootDone}>
|
||||||
<div class="fixed w-full h-full bg-green-700/20 rounded-3xl border-solid border-2 border-green-300/50">
|
<Bootup on:boot_done={finishBoot} />
|
||||||
<div class="absolute screendim"></div>
|
|
||||||
<div class="absolute scanlines"></div>
|
|
||||||
</div>
|
|
||||||
<section class="h-screen relative">
|
|
||||||
<div class="relative top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
|
||||||
<img class="w-1/4 mx-auto rounded-full aspect-square object-cover mb-6" src="/profile.jpg" alt="">
|
|
||||||
<h1 class="text-center font-mono text-6xl text-white drop-shadow-screen ">Thomas Cole</h1>
|
|
||||||
<GlitchText strings={["system administrator", "Linux Enthusiast", "Web Developer", "Network Engineer"]} classVars="text-neutral-50 drop-shadow-screen text-center text-xl font-mono w-fit mx-auto capitalize"/>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="h-screen"></section>
|
<div
|
||||||
|
bind:this={mainContent}
|
||||||
<style>
|
class="trasnition-all ease-in duration-300 opacity-0"
|
||||||
.scanlines{
|
class:hidden={!bootDone}
|
||||||
background: linear-gradient(
|
>
|
||||||
rgb(134,239,172,.15),
|
<NameSplash />
|
||||||
rgb(134,239,172,.15) 3px,
|
<div class="py-6" />
|
||||||
transparent 3px,
|
<About />
|
||||||
transparent 9px
|
<div class="py-6" />
|
||||||
|
<Projects />
|
||||||
);
|
<Footer />
|
||||||
background-size: 100% 9px;
|
</div>
|
||||||
border-radius: 1.5rem;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
animation: scan 120s infinite linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
.screendim{
|
|
||||||
background: radial-gradient(
|
|
||||||
circle,
|
|
||||||
rgba(0,0,0,0) 0%,
|
|
||||||
rgba(0,0,0,0) 50%,
|
|
||||||
rgba(0,0,0,1) 100%
|
|
||||||
);
|
|
||||||
border-radius: 1.5rem;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes scan{
|
|
||||||
from{
|
|
||||||
background-position: 0% 0%;
|
|
||||||
}
|
|
||||||
|
|
||||||
to{
|
|
||||||
background-position: 0% -100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -10,4 +10,5 @@ body {
|
|||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
17
src/components/About.svelte
Normal file
17
src/components/About.svelte
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section
|
||||||
|
id="projects"
|
||||||
|
class="w-5/6 lg:xl:w-4/5 mx-auto font-mono text-neutral-50 rounded-xl drop-shadow-screen p-4 border-2 border-solid border-green-700"
|
||||||
|
>
|
||||||
|
<p class="font-bold text-2xl pb-6 ">> About Me</p>
|
||||||
|
<p>
|
||||||
|
Detail oriented IT professional with 5+ years in systems and network
|
||||||
|
administration. Excellent problem-solving skills and ability to perform
|
||||||
|
well in a team. Responsible for operation and maintenance of a
|
||||||
|
multicampus enterprise network with 500+ average daily users.
|
||||||
|
Demonstrated experience in reducing operating expenses by implementing
|
||||||
|
open-source solutions and services.
|
||||||
|
</p>
|
||||||
|
</section>
|
46
src/components/Background.svelte
Normal file
46
src/components/Background.svelte
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<div
|
||||||
|
class="fixed w-full h-screen top-0 left-0 bg-green-700/20 rounded-3xl border-solid border-2 border-green-300/50 -z-10 "
|
||||||
|
>
|
||||||
|
<div class="absolute screendim" />
|
||||||
|
<div class="absolute scanlines" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.scanlines {
|
||||||
|
background: linear-gradient(
|
||||||
|
rgb(134, 239, 172, 0.15),
|
||||||
|
rgb(134, 239, 172, 0.15) 3px,
|
||||||
|
transparent 3px,
|
||||||
|
transparent 9px
|
||||||
|
);
|
||||||
|
background-size: 100% 9px;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
animation: scan 120s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screendim {
|
||||||
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
rgba(0, 0, 0, 0) 0%,
|
||||||
|
rgba(0, 0, 0, 0) 70%,
|
||||||
|
rgba(0, 0, 0, 1) 100%
|
||||||
|
);
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scan {
|
||||||
|
from {
|
||||||
|
background-position: 0% 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
background-position: 0% -100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
82
src/components/Bootup.svelte
Normal file
82
src/components/Bootup.svelte
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount, createEventDispatcher } from "svelte";
|
||||||
|
import Progress from "../utils/Progress.svelte";
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
let bootStage1;
|
||||||
|
let bootStage2;
|
||||||
|
let hexDumpContainer;
|
||||||
|
let percentage = 0;
|
||||||
|
|
||||||
|
onMount(async ()=>{
|
||||||
|
await bootPart1();
|
||||||
|
await bootPart2();
|
||||||
|
})
|
||||||
|
|
||||||
|
function makeConsoleString(text:string){
|
||||||
|
const e = document.createElement('p');
|
||||||
|
e.className = baseTextClass;
|
||||||
|
e.innerText = text;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateHexString(){
|
||||||
|
return "0x" + (Math.random()*4096).toString(16).replace('.','').slice(0,8).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function bootPart1() {
|
||||||
|
bootStage1.insertBefore(makeConsoleString("> System Boot Start..."), hexDumpContainer);
|
||||||
|
await sleep(100);
|
||||||
|
for (let i = 0; i <4 ; i++) {
|
||||||
|
var hexCol = document.createElement('div');
|
||||||
|
hexCol.className = "flex flex-col mr-4"
|
||||||
|
hexDumpContainer.appendChild(hexCol);
|
||||||
|
for (let j = 0; j<16; j++){
|
||||||
|
hexCol.appendChild(makeConsoleString(generateHexString()));
|
||||||
|
await sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await sleep(500);
|
||||||
|
bootStage1.appendChild(makeConsoleString("> Boot ROM Initialized"));
|
||||||
|
await sleep(750);
|
||||||
|
bootStage1.appendChild(makeConsoleString("> Checking Integrity"));
|
||||||
|
await sleep(750);
|
||||||
|
bootStage1.appendChild(makeConsoleString("> Checksums OK"));
|
||||||
|
await sleep(750);
|
||||||
|
bootStage1.appendChild(makeConsoleString("> Starting DisplayOS"));
|
||||||
|
await sleep(2000);
|
||||||
|
bootStage1.classList.add("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function bootPart2(){
|
||||||
|
bootStage2.classList.remove("hidden");
|
||||||
|
await sleep(500)
|
||||||
|
while(percentage < 100){
|
||||||
|
percentage += 10;
|
||||||
|
await sleep(Math.random()*500);
|
||||||
|
}
|
||||||
|
bootStage2.classList.add("opacity-0");
|
||||||
|
await sleep(300);
|
||||||
|
dispatch("boot_done");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sleep(delay:number){
|
||||||
|
await new Promise(r => setTimeout(r, delay));
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseTextClass = "text-neutral-50 drop-shadow-screen text-xl font-mono";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={bootStage1}>
|
||||||
|
<div bind:this={hexDumpContainer} class="flex flex-row"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div bind:this={bootStage2} class="hidden w-full h-full transition-all duration-300 ease-out">
|
||||||
|
<div class="relative top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-center">
|
||||||
|
<img class="w-1/5 mx-auto" src="/vite.svg" alt="" draggable="false">
|
||||||
|
<div class="h-2 w-4/5 mx-auto mt-8 relative drop-shadow-screen bg-green-700 rounded-md">
|
||||||
|
<Progress color="#fafafa" percentage={percentage}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
12
src/components/Footer.svelte
Normal file
12
src/components/Footer.svelte
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<footer
|
||||||
|
class="w-5/6 xl:lg:w-4/5 mx-auto text-neutral-50 drop-shadow-screen font-mono font-light m-2 p-4"
|
||||||
|
>
|
||||||
|
<div class="flex gap-4 place-content-center underline">
|
||||||
|
<a href="mailto:thomas.patrick.cole@gmail.com">Contact</a>
|
||||||
|
<a href="https://github.com/thomaspcole">Github</a>
|
||||||
|
<a href="https://git.thomaspcole.com/thomascole">Gitea</a>
|
||||||
|
<a href="https://www.linkedin.com/in/thomaspcole/">Linkedin</a>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<p class="text-sm text-center font-sans">© 2023 Thomas Cole</p>
|
||||||
|
</footer>
|
30
src/components/NameSplash.svelte
Normal file
30
src/components/NameSplash.svelte
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<script>
|
||||||
|
import GlitchText from "../utils/GlitchText.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section id="top" class="h-screen">
|
||||||
|
<div class="relative top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||||
|
<img
|
||||||
|
class="w-1/2 lg:xl:w-1/4 mx-auto rounded-full aspect-square object-cover mb-6"
|
||||||
|
src="/profile.jpg"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<h1
|
||||||
|
class="text-center font-mono text-4xl lg:xl:text-6xl text-neutral-50 drop-shadow-screen "
|
||||||
|
>
|
||||||
|
Thomas Cole
|
||||||
|
</h1>
|
||||||
|
<GlitchText
|
||||||
|
strings={[
|
||||||
|
"system administrator",
|
||||||
|
"linux enthusiast",
|
||||||
|
"web developer",
|
||||||
|
"network engineer",
|
||||||
|
]}
|
||||||
|
classVars="text-neutral-50 drop-shadow-screen text-center text-xl lg:xl:text-2xl font-mono w-fit mx-auto capitalize"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="material-symbols-outlined absolute bottom-[10px] left-1/2 -translate-x-1/2 text-neutral-50 drop-shadow-screen text-4xl lg:xl:text-6xl animate-[pulse_4s_cubic-bezier(0.4,0,0.6,1)_infinite]">
|
||||||
|
expand_more
|
||||||
|
</span>
|
||||||
|
</section>
|
10
src/components/Nav.svelte
Normal file
10
src/components/Nav.svelte
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="h-[10vh] w-5/6 lg:xl:w-4/5 mx-auto text-neutral-50 drop-shadow-screen font-mono">
|
||||||
|
<div class="flex flex-col text-2xl">
|
||||||
|
<p>> <a href="#projects" class="underline">Latest Projects</a></p>
|
||||||
|
<p>> <a href="#about" class="underline">About Me</a></p>
|
||||||
|
</div>
|
||||||
|
</section>
|
14
src/components/Projects.svelte
Normal file
14
src/components/Projects.svelte
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import ProjectCard from "../utils/ProjectCard.svelte";
|
||||||
|
import LocalDemo from "../utils/LocalDemo.svelte";
|
||||||
|
import Quicksort from "../demos/quicksort.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section
|
||||||
|
id="projects"
|
||||||
|
class="w-5/6 lg:xl:w-4/5 mx-auto font-mono text-neutral-50 rounded-xl drop-shadow-screen p-4 border-2 border-solid border-green-700"
|
||||||
|
>
|
||||||
|
<p class="font-bold text-2xl pb-6 ">> Projects and Demos</p>
|
||||||
|
<ProjectCard title="Pedal-pi" subtitle="A custom effects processor using MODEP" image="https://images.unsplash.com/photo-1511203438670-49f8ea8441c6?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80" link="#" callback={undefined}/>
|
||||||
|
<LocalDemo title="Quicksort Demo" subtitle="A simple visualization of the quicksort algorithm using p5.js" modalComponent="" image="https://images.unsplash.com/photo-1669399213378-2853e748f217?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1632&q=80"/>
|
||||||
|
</section>
|
119
src/components/Resume.svelte
Normal file
119
src/components/Resume.svelte
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import ResumeItem from "../utils/ResumeItem.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section
|
||||||
|
id="about"
|
||||||
|
class="w-5/6 lg:xl:w-4/5 mx-auto font-mono text-neutral-50 rounded-xl drop-shadow-screen p-4 border-2 border-solid border-green-700"
|
||||||
|
>
|
||||||
|
<a href="#top" class="text-sm font-thin underline">Back to Top</a>
|
||||||
|
<!-- <a href="#top" class="text-sm font-thin underline">Download as PDF</a> -->
|
||||||
|
|
||||||
|
<p class="font-bold text-2xl py-6 ">> Work Experience</p>
|
||||||
|
<ResumeItem
|
||||||
|
title="Director Of Information Technology"
|
||||||
|
subtitle="Christ Lutheran Church | December 2020 - Present"
|
||||||
|
>
|
||||||
|
<ul class="mt-2 mb-4">
|
||||||
|
<li>
|
||||||
|
> Maintain and upgrade critical network infrastructure for a
|
||||||
|
multi-campus environment.
|
||||||
|
</li>
|
||||||
|
<li>> Facilitate backups and ensure their integrity.</li>
|
||||||
|
<li>
|
||||||
|
> Integrate with action teams to develop technology plans and
|
||||||
|
solutions.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Implement new software and hardware solutions with
|
||||||
|
increased functionality while reducing costs by $50,000/yr.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</ResumeItem>
|
||||||
|
<ResumeItem
|
||||||
|
title="Tech Associate"
|
||||||
|
subtitle="Christ Lutheran Church | August 2019 - December 2020 (Part Time)"
|
||||||
|
>
|
||||||
|
<ul class="mt-2 mb-4">
|
||||||
|
<li>
|
||||||
|
> Develop and implement new strategies in collaboration with
|
||||||
|
the Christ Providence Tech team to improve live stream services
|
||||||
|
and reach a broader audience.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Facilitated building and installation of new computer
|
||||||
|
systems to improve recording and streaming capabilities of
|
||||||
|
worship services.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Run graphics for in house worship and live stream services.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</ResumeItem>
|
||||||
|
<ResumeItem
|
||||||
|
title="Tier II Managed Services Technician"
|
||||||
|
subtitle="ScanOnline | June 2019 - December 2020"
|
||||||
|
>
|
||||||
|
<ul class="mt-2 mb-4">
|
||||||
|
<li>
|
||||||
|
> Administer Office 365 and Windows Active Directory
|
||||||
|
infrastructure.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Manage company VOIP phone system and extension listings.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Deploy and configure virtual machines to align with
|
||||||
|
business needs.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Develop new Android applications to suit the business needs
|
||||||
|
of customers operating in the logistics industry.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Maintain legacy Windows Mobile applications for existing
|
||||||
|
customers.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Preform configuration and maintenance of customer hardware
|
||||||
|
and software.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</ResumeItem>
|
||||||
|
<ResumeItem
|
||||||
|
title="Student Network Analyst"
|
||||||
|
subtitle="University of North Carolina at Greensboro | February 2018 - May 2019"
|
||||||
|
>
|
||||||
|
<ul class="mt-2 mb-4">
|
||||||
|
<li>
|
||||||
|
> Assisted in maintenance and troubleshooting of enterprise
|
||||||
|
network systems.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
> Preformed on-boarding of new network devices at the
|
||||||
|
physical level.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</ResumeItem>
|
||||||
|
|
||||||
|
<p class="font-bold text-2xl py-6 ">> Education</p>
|
||||||
|
<ResumeItem
|
||||||
|
title="The University of North Carolina at Greensboro"
|
||||||
|
subtitle=""
|
||||||
|
>
|
||||||
|
<ul class="mt-2 mb-4">
|
||||||
|
<li>
|
||||||
|
> Bachelor Of Science Information Systems and Supply Chain
|
||||||
|
Management
|
||||||
|
</li>
|
||||||
|
<li>> Minor in Computer Science</li>
|
||||||
|
</ul>
|
||||||
|
</ResumeItem>
|
||||||
|
|
||||||
|
<p class="font-bold text-2xl py-6 ">> Professional Certifications</p>
|
||||||
|
<ResumeItem title="Dante Level 3" subtitle="">
|
||||||
|
<ul class="mt-2 mb-4">
|
||||||
|
<li>> Audinate | Certificate earned March 2021</li>
|
||||||
|
</ul>
|
||||||
|
</ResumeItem>
|
||||||
|
</section>
|
195
src/demos/quicksort.svelte
Normal file
195
src/demos/quicksort.svelte
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import P5, { type Sketch } from "p5-svelte";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
|
// Demo modified from a very old p5js sketch written in college.
|
||||||
|
// The original was part of a the application process to work for the university IT department
|
||||||
|
// https://github.com/thomaspcole/p5QuicksortVisualization
|
||||||
|
|
||||||
|
let data = [];
|
||||||
|
let animArray = [];
|
||||||
|
let valuesToGenerate = 200;
|
||||||
|
let frame = 0;
|
||||||
|
|
||||||
|
let parentContainer;
|
||||||
|
let sketch:Sketch;
|
||||||
|
|
||||||
|
//Added controls for play/pause and stepping frame by frame.
|
||||||
|
let playpause = false;
|
||||||
|
|
||||||
|
onMount(()=>{
|
||||||
|
const sketchWidth = parentContainer.offsetWidth;
|
||||||
|
const barWidth = (sketchWidth-20)/valuesToGenerate;
|
||||||
|
sketch = (p5) => {
|
||||||
|
p5.setup = () => {
|
||||||
|
for (let i = 0; i < valuesToGenerate; i++) {
|
||||||
|
data[i]=(i%700);
|
||||||
|
}
|
||||||
|
|
||||||
|
p5.shuffle(data, true)
|
||||||
|
quicksort(data, 0, data.length-1);
|
||||||
|
animArray.push(new arrayFrame(data.toString(), null, null, null));
|
||||||
|
|
||||||
|
//setup the canvas
|
||||||
|
p5.createCanvas(sketchWidth,400);
|
||||||
|
p5.frameRate(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
p5.draw = () => {
|
||||||
|
if(playpause){
|
||||||
|
if(frame == animArray.length-1){
|
||||||
|
playpause = !playpause;
|
||||||
|
} else {
|
||||||
|
drawFrame(frame);
|
||||||
|
frame++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
drawFrame(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawFrame(index){
|
||||||
|
let dataFrame = animArray[index];
|
||||||
|
p5.background(28);
|
||||||
|
for (var i = 0; i < valuesToGenerate; i++){
|
||||||
|
p5.fill(255)
|
||||||
|
if(dataFrame.midIndex == i){
|
||||||
|
p5.fill(255,0,0);
|
||||||
|
}
|
||||||
|
if(dataFrame.lowVal == i || dataFrame.highVal == i){
|
||||||
|
p5.fill(0,255,0);
|
||||||
|
}
|
||||||
|
p5.rect(barWidth*i+10,350, barWidth,-dataFrame.getArray()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied directly from original code
|
||||||
|
* @param array the array of data being worked on
|
||||||
|
* @param low the low values
|
||||||
|
* @param high the high value
|
||||||
|
*/
|
||||||
|
function quicksort(array, low, high){
|
||||||
|
animArray.push(new arrayFrame(array.toString(), 0, array.length, 0));
|
||||||
|
//Do we need to sort?
|
||||||
|
if(low >= high){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Pick a pivot point in the middle of the passed array.
|
||||||
|
let mid = Math.floor(low + ((high-low) / 2));
|
||||||
|
let pivot = array[mid];
|
||||||
|
|
||||||
|
let l = low;
|
||||||
|
let h = high;
|
||||||
|
|
||||||
|
while(l <= h){
|
||||||
|
while(array[l] < pivot){
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(array[h] > pivot){
|
||||||
|
h--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(l <= h){
|
||||||
|
//console.log(array, l, h, mid);
|
||||||
|
//console.log("Switch: " + array[l] + ":" + array[h]);
|
||||||
|
animArray.push(new arrayFrame(array.toString(), l, h, mid));
|
||||||
|
|
||||||
|
let tmp = array[l];
|
||||||
|
array[l] = array[h];
|
||||||
|
array[h] = tmp;
|
||||||
|
l++;
|
||||||
|
h--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(low < h){
|
||||||
|
quicksort(array, low, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(high > l){
|
||||||
|
quicksort(array, l, high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a arrayFrame object
|
||||||
|
* @param arrayState the array of data at a current point in time
|
||||||
|
* @param lowVal the low index
|
||||||
|
* @param highVal the high midIndex
|
||||||
|
* @param midIndex the pivot index
|
||||||
|
* @param getArray Returns the array at the current time
|
||||||
|
*/
|
||||||
|
function arrayFrame(arrayState, lowVal, highVal, midIndex){
|
||||||
|
this.arrayState = arrayState;
|
||||||
|
this.lowVal = lowVal;
|
||||||
|
this.highVal = highVal;
|
||||||
|
this.midIndex = midIndex;
|
||||||
|
|
||||||
|
this.getArray = function(){
|
||||||
|
return this.arrayState.split(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevFrame(){
|
||||||
|
if(frame == 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frame--;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextFrame(){
|
||||||
|
if(frame == animArray.length-1){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frame++;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset(){
|
||||||
|
frame=0;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={parentContainer} class="w-full">
|
||||||
|
<P5 {sketch}/>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-evenly mt-6 mb-4">
|
||||||
|
<button on:click={prevFrame}>
|
||||||
|
<span class="material-symbols-outlined">
|
||||||
|
skip_previous
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button on:click={()=>{
|
||||||
|
if(frame==animArray.length-1){
|
||||||
|
reset();
|
||||||
|
} else {
|
||||||
|
playpause = !playpause;
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{#if playpause}
|
||||||
|
<span class="material-symbols-outlined">
|
||||||
|
pause
|
||||||
|
</span>
|
||||||
|
{:else if frame==animArray.length-1}
|
||||||
|
<span class="material-symbols-outlined">
|
||||||
|
restart_alt
|
||||||
|
</span>
|
||||||
|
{:else}
|
||||||
|
<span class="material-symbols-outlined">
|
||||||
|
play_arrow
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
<button on:click={nextFrame}>
|
||||||
|
<span class="material-symbols-outlined">
|
||||||
|
skip_next
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
@ -1,26 +0,0 @@
|
|||||||
<script>
|
|
||||||
import * as THREE from 'three';
|
|
||||||
import * as SC from 'svelte-cubed';
|
|
||||||
|
|
||||||
let y;
|
|
||||||
|
|
||||||
$: camZpos = (y*.1)+1;
|
|
||||||
|
|
||||||
//Animation callback
|
|
||||||
SC.onFrame(()=>{
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:window bind:scrollY={y}/>
|
|
||||||
|
|
||||||
<SC.Canvas>
|
|
||||||
<SC.Mesh
|
|
||||||
geometry={new THREE.BoxGeometry()}
|
|
||||||
material={new THREE.MeshStandardMaterial({
|
|
||||||
color: 0xff00ff
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<SC.PerspectiveCamera position={[0,0,camZpos]}/>
|
|
||||||
<SC.AmbientLight intensity={0.6} />
|
|
||||||
<SC.DirectionalLight intensity={0.6} position={[-2, 3, 2]} />
|
|
||||||
</SC.Canvas>
|
|
1
src/utils/Divider.svelte
Normal file
1
src/utils/Divider.svelte
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div class="my-6 h-0.5 mx-auto bg-neutral-50 drop-shadow-screen rounded"/>
|
@ -36,19 +36,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
itterations ++;
|
itterations ++;
|
||||||
}, 30);
|
}, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(()=>{
|
onMount(()=>{
|
||||||
stringIndex = Math.floor(Math.random()*strings.length)
|
stringIndex = Math.floor(Math.random()*strings.length)
|
||||||
pickNextWord();
|
pickNextWord();
|
||||||
|
|
||||||
|
setInterval(pickNextWord,5000);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||||
<p class={classVars} on:mouseover={pickNextWord}>
|
<!-- <p class={classVars} on:mouseover={pickNextWord}> -->
|
||||||
|
<p class={classVars}>
|
||||||
{text}
|
{text}
|
||||||
</p>
|
</p>
|
23
src/utils/LocalDemo.svelte
Normal file
23
src/utils/LocalDemo.svelte
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import ProjectCard from "./ProjectCard.svelte";
|
||||||
|
import Modal from "./Modal.svelte";
|
||||||
|
import type { SvelteComponent } from "svelte";
|
||||||
|
import Quicksort from "../demos/quicksort.svelte";
|
||||||
|
|
||||||
|
export let image:string;
|
||||||
|
export let title:string;
|
||||||
|
export let subtitle:string;
|
||||||
|
export let modalComponent:string;
|
||||||
|
let showModal = false;
|
||||||
|
|
||||||
|
function callback(){
|
||||||
|
showModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ProjectCard title={title} subtitle={subtitle} image={image} link={undefined} callback={callback}/>
|
||||||
|
<Modal bind:showModal>
|
||||||
|
<!-- <svelte:component this={modalComponent.component}/> -->
|
||||||
|
<Quicksort/>
|
||||||
|
</Modal>
|
64
src/utils/Modal.svelte
Normal file
64
src/utils/Modal.svelte
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<script>
|
||||||
|
//Modal from example on svelte website. https://svelte.dev/examples/modal
|
||||||
|
export let showModal;
|
||||||
|
let dialog;
|
||||||
|
$: if (dialog && showModal) dialog.showModal();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<dialog
|
||||||
|
bind:this={dialog}
|
||||||
|
on:close={() => (showModal = false)}
|
||||||
|
on:click|self={() => dialog.close()}
|
||||||
|
class="w-4/5"
|
||||||
|
>
|
||||||
|
<div on:click|stopPropagation>
|
||||||
|
<slot name="header"/>
|
||||||
|
<hr>
|
||||||
|
<slot />
|
||||||
|
<hr />
|
||||||
|
<!-- svelte-ignore a11y-autofocus -->
|
||||||
|
<button autofocus on:click={() => dialog.close()}>close modal</button>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
dialog {
|
||||||
|
max-width: 32em;
|
||||||
|
width: 80%;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
dialog::backdrop {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
dialog > div {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
dialog[open] {
|
||||||
|
animation: zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
}
|
||||||
|
@keyframes zoom {
|
||||||
|
from {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialog[open]::backdrop {
|
||||||
|
animation: fade 0.2s ease-out;
|
||||||
|
}
|
||||||
|
@keyframes fade {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
21
src/utils/Progress.svelte
Normal file
21
src/utils/Progress.svelte
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let percentage: number | 0;
|
||||||
|
export let color: string | "#FFFFFF";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="progress left rounded-md"
|
||||||
|
style="background-color: {color}; clip-path: polygon(0% 0%, 0% 100%, {percentage}% 100%, {percentage}% 0%);"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.progress {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transition: 0.4s clip-path;
|
||||||
|
clip-path: polygon(0% 0%, 0% 100%, 0% 100%, 0% 0%);
|
||||||
|
}
|
||||||
|
</style>
|
30
src/utils/ProjectCard.svelte
Normal file
30
src/utils/ProjectCard.svelte
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let link:string;
|
||||||
|
export let image:string;
|
||||||
|
export let title:string;
|
||||||
|
export let subtitle:string;
|
||||||
|
export let callback;
|
||||||
|
|
||||||
|
let url;
|
||||||
|
if(typeof link === undefined){
|
||||||
|
url = "javascript:void(0)"
|
||||||
|
} else {
|
||||||
|
url = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof callback === undefined){
|
||||||
|
callback = ()=>{};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="rounded-lg transition ease-in-out hover:scale-[101%]">
|
||||||
|
<a href={url} on:click={callback}>
|
||||||
|
<div class="ml-2 my-2 flex flex-col sm:flex-col md:flex-col lg:flex-row xl:flex-row 2xl:flex-row w-11/12 mx-auto">
|
||||||
|
<img class="h-28 my-2 aspect-video object-cover rounded-lg" src={image} alt="">
|
||||||
|
<div class="lg:ml-4 xl:ml-4 2xl:ml-4 grow">
|
||||||
|
<p class="mt-2 font-semibold text-2xl py-2 sm:text-2xl md:text-2xl lg:text-3xl xl:text-3xl 2xl:text-3xl">{title}</p>
|
||||||
|
<p>{subtitle}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
11
src/utils/ResumeItem.svelte
Normal file
11
src/utils/ResumeItem.svelte
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let title: string;
|
||||||
|
export let subtitle: string;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="px-5">
|
||||||
|
<p class="text-xl font-bold">{title}</p>
|
||||||
|
<p class="">{subtitle}</p>
|
||||||
|
<hr />
|
||||||
|
<slot />
|
||||||
|
</div>
|
@ -15,6 +15,6 @@
|
|||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
"isolatedModules": true
|
"isolatedModules": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
|
"include": ["./**/*.d.ts", "./**/*.ts", "./**/*.js", "./**/*.svelte"],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user