@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
export let title: string = "";
|
||||
export let image: string = "";
|
||||
export let date: string = "";
|
||||
</script>
|
||||
|
||||
<article class="flex flex-col gap-5 lg:gap-10 text-base text-gray-900 dark:text-gray-100">
|
||||
<img src={image} class="rounded-xl w-full aspect-[2/1] lg:aspect-[4/1] object-cover" />
|
||||
|
||||
<div class="flex flex-col gap-2 lg:gap-5">
|
||||
<h1 class="text-2xl lg:text-6xl font-bold lg:tracking-wide">{title}</h1>
|
||||
<div class="flex gap-5 text-sm opacity-50">Posted {date} by Pascal</div>
|
||||
</div>
|
||||
|
||||
<hr class="opacity-10 w-1/2 lg:w-1/4"/>
|
||||
|
||||
<div class="prose dark:prose-invert max-w-[1000px]">
|
||||
<slot/>
|
||||
</div>
|
||||
|
||||
<hr class="opacity-10 w-1/2 lg:w-1/4"/>
|
||||
|
||||
<div class="flex gap-5">Posted {date} by Pascal</div>
|
||||
</article>
|
@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
export let url = "";
|
||||
export let title = "";
|
||||
export let preview = "";
|
||||
export let date = "";
|
||||
export let image = "";
|
||||
export let featured: boolean = false;
|
||||
export let isNew: boolean = false;
|
||||
</script>
|
||||
|
||||
{#if featured}
|
||||
<a href={url} class="flex flex-col gap-2 w-full lg:w-[600px] flex-none p-3 hover:bg-opacity-50 bg-opacity-0 dark:bg-opacity-0 relative hover:dark:bg-opacity-50 dark:bg-black bg-white duration-200 rounded-xl">
|
||||
{#if image.length > 0}
|
||||
<img src={image} class="rounded-lg w-full aspect-[2/1] object-cover" alt={title} />
|
||||
{/if}
|
||||
{#if isNew}
|
||||
<div class="absolute top-0 right-0 text-xl bg-blue-500 text-white font-bold px-5 rounded-full blob">New!</div>
|
||||
{/if}
|
||||
<h4 class="font-bold text-lg w-full text-justify">{title}</h4>
|
||||
<p class="text-xs lg:text-sm">
|
||||
{preview}
|
||||
</p>
|
||||
<sub class="text-xs">{date}</sub>
|
||||
</a>
|
||||
{:else}
|
||||
<a href={url} class="flex flex-col gap-2 w-[300px] relative flex-none p-3 hover:bg-opacity-50 bg-opacity-0 dark:bg-opacity-0 hover:dark:bg-opacity-50 dark:bg-black bg-white duration-200 rounded-xl">
|
||||
{#if image.length > 0}
|
||||
<img src={image} class="rounded-lg w-full aspect-[2/1] object-cover" alt={title} />
|
||||
{/if}
|
||||
{#if isNew}
|
||||
<div class="absolute top-2 right-0 bg-blue-500 text-white font-bold px-5 rounded-full blob">New!</div>
|
||||
{/if}
|
||||
<h4 class="font-bold text-lg w-full text-justify">{title}</h4>
|
||||
<sub class="text-xs">{date}</sub>
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.blob {
|
||||
animation-name: blob;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
@keyframes blob {
|
||||
0% {
|
||||
transform: scale(1) rotate(10deg);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1) rotate(10deg);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1) rotate(10deg);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,8 @@
|
||||
interface BlogPost {
|
||||
title: string;
|
||||
url: string;
|
||||
image: string;
|
||||
date: string;
|
||||
content: string;
|
||||
isNew: boolean;
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
<script lang="ts">
|
||||
import { browser } from "$app/env";
|
||||
import Preview from "$lib/blog/Preview.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let posts: BlogPost[] = [
|
||||
// {
|
||||
// image: "/blog/releasingpuppypride.png",
|
||||
// title: "Releasing Puppy Pride",
|
||||
// content: "It has taken me a while to develop, actually over 2.5 years of solo fullstack development with zero experience, but I finally managed to release and deploy the new Puppy Pride social network. There have definitely been ups an downs, and in this post I'd like to touch a little on what it took to get here and the lessons I learned along the way.",
|
||||
// url: "/blog/releasing-puppy-pride",
|
||||
// date: "August 1st 2023",
|
||||
// isNew: true,
|
||||
// },
|
||||
// {
|
||||
// image: "/blog/thepowerofvr.png",
|
||||
// title: "The power of VR",
|
||||
// content: "This website is a testament to my love of VR, I have a whole section dedicated to it after all. But in this post I'd like to touch a little more on why that is, on why I've created such a deep bond with a world that isn't even real to most, or at best a failed dream of out of touch billionares.",
|
||||
// url: "/blog/the-power-of-vr",
|
||||
// date: "August 1st 2023",
|
||||
// isNew: true,
|
||||
// },
|
||||
// {
|
||||
// image: "/blog/myinternshipatagroit.png",
|
||||
// title: "My internship at Agro IT",
|
||||
// content: "My year 3 internship as part of my study at Saxion University, I chose to work for Agro IT, a small company that creates software solutions for several types of businesses. At the end of it, I was asked to launch what I made and was offered a job. In this post I'd like to touch a little more on what went right or wrong, and what the lessons were I learned while working there.",
|
||||
// url: "/blog/my-internship-at-agro-it",
|
||||
// date: "August 1st 2023",
|
||||
// isNew: true,
|
||||
// },
|
||||
// {
|
||||
// image: "/blog/centeringadiv.png",
|
||||
// title: "Centering a div",
|
||||
// content: "On the web...",
|
||||
// url: "/blog/centering-a-div",
|
||||
// date: "August 1st 2023",
|
||||
// isNew: true,
|
||||
// }
|
||||
];
|
||||
|
||||
onMount(() => {
|
||||
if(browser) {
|
||||
const slider: HTMLElement = document.querySelector('.items');
|
||||
let isDown = false;
|
||||
let startX;
|
||||
let scrollLeft;
|
||||
|
||||
slider.addEventListener('mousedown', (e) => {
|
||||
isDown = true;
|
||||
slider.classList.add('active');
|
||||
startX = e.pageX - slider.offsetLeft;
|
||||
scrollLeft = slider.scrollLeft;
|
||||
});
|
||||
slider.addEventListener('mouseleave', () => {
|
||||
isDown = false;
|
||||
slider.classList.remove('active');
|
||||
});
|
||||
slider.addEventListener('mouseup', () => {
|
||||
isDown = false;
|
||||
slider.classList.remove('active');
|
||||
});
|
||||
slider.addEventListener('mousemove', (e) => {
|
||||
if(!isDown) return;
|
||||
e.preventDefault();
|
||||
const x = e.pageX - slider.offsetLeft;
|
||||
const walk = (x - startX) * 1; //scroll-fast
|
||||
slider.scrollLeft = scrollLeft - walk;
|
||||
console.log(walk);
|
||||
});
|
||||
slider.addEventListener('wheel', (evt) => {
|
||||
evt.preventDefault();
|
||||
slider.scrollLeft += evt.deltaY;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if posts.length > 0}
|
||||
<section class="relative container flex flex-col gap-5 lg:gap-20">
|
||||
<div class="absolute top-0 -mt-40" id="blog"></div>
|
||||
|
||||
<h2 class="text-center w-full text-4xl lg:text-6xl tracking-[0.2em] lg:tracking-[1em] font-bold"><-- BLOG --></h2>
|
||||
|
||||
<div class="flex flex-col lg:flex-row gap-5 overflow-visible">
|
||||
|
||||
<span>
|
||||
<Preview url={posts[0].url} title={posts[0].title} preview={posts[0].content.substring(0, 255) + ( posts[0].content.length > 255 ? "..." : "")} date={posts[0].date} image={posts[0].image} featured={true} isNew={posts[0].isNew} />
|
||||
</span>
|
||||
|
||||
{#if posts.length == 1}
|
||||
<p class="p-10 text-sm opacity-50">No more posts to show...</p>
|
||||
{:else}
|
||||
<div class="grid grid-flow-col grid-rows-2 grid-cols-[repeat(12, 400px)] w-full gap-5 overflow-x-scroll pb-5 scrollbar scrollbar-thumb-white dark:scrollbar-thumb-black scrollbar-h-3 scrollbar-track-transparent scrollbar-thumb-rounded-full items">
|
||||
{#each posts as post, key}
|
||||
{#if key != 0}
|
||||
<Preview url={post.url} title={post.title} date={post.date} image={post.image} featured={false} isNew={post.isNew} />
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
</section>
|
||||
{:else}
|
||||
<section class="relative container flex flex-col gap-5 lg:gap-20">
|
||||
<div class="absolute top-0 -mt-40" id="blog"></div>
|
||||
|
||||
<h2 class="text-center w-full text-4xl lg:text-6xl tracking-[0.2em] lg:tracking-[1em] font-bold"><-- BLOG --></h2>
|
||||
|
||||
<p class="p-10 text-sm opacity-50 text-center w-full">No posts to show...</p>
|
||||
</section>
|
||||
{/if}
|
@ -1,3 +1,3 @@
|
||||
<main class="container py-20">
|
||||
<main class="container pt-10 pb-20 min-h-screen">
|
||||
<slot/>
|
||||
</main>
|
@ -1,15 +0,0 @@
|
||||
# Uses
|
||||
|
||||
**Here's some stuff I use**
|
||||
|
||||
- SvelteKit
|
||||
- VS Code
|
||||
- Emojis 😎
|
||||
|
||||
```js
|
||||
// JavaScript goes here,
|
||||
// And will be syntax-highlighted!
|
||||
function main() {
|
||||
lol
|
||||
}
|
||||
```
|
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import Post from "$lib/blog/Post.svelte";
|
||||
</script>
|
||||
|
||||
<Post date="August 1st 2023" title="Centering a div" image="/blog/myinternshipatagroit.png">
|
||||
<b class="text-lg">
|
||||
My year 3 internship as part of my study at Saxion University, I chose to work for Agro IT, a small company that creates software solutions for several types of businesses. At the end of it, I was asked to launch what I made and was offered a job. In this post I'd like to touch a little more on what went right or wrong, and what the lessons were I learned while working there.
|
||||
</b>
|
||||
</Post>
|
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import Post from "$lib/blog/Post.svelte";
|
||||
</script>
|
||||
|
||||
<Post date="August 1st 2023" title="My internship at Agro IT: a retrospective" image="/blog/myinternshipatagroit.png">
|
||||
<b class="text-lg">
|
||||
My year 3 internship as part of my study at Saxion University, I chose to work for Agro IT, a small company that creates software solutions for several types of businesses. At the end of it, I was asked to launch what I made and was offered a job. In this post I'd like to touch a little more on what went right or wrong, and what the lessons were I learned while working there.
|
||||
</b>
|
||||
</Post>
|
@ -0,0 +1,42 @@
|
||||
<script>
|
||||
import Post from "$lib/blog/Post.svelte";
|
||||
</script>
|
||||
|
||||
<Post date="August 1st 2023" title="Releasing Puppy Pride: lessons about experience, Laravel, and deadlines" image="/blog/releasingpuppypride.png">
|
||||
<b class="text-lg">
|
||||
It has taken me a while to develop, actually over 2.5 years of solo fullstack development with zero experience, but I finally managed to release and deploy the new Puppy Pride social network. There have definitely been ups an downs, and in this post I'd like to touch a little on what it took to get here and the lessons I learned along the way.
|
||||
</b>
|
||||
|
||||
<p>
|
||||
That first bit wasn't a lie, I really did develop this site from scratch with zero experience, and it worked. Now the result is not a perfect system in hindsight, but I have gotten the mindset that all software can improve over time lately, so I'm sure the bits I wrote when I was starting out will be deprecated just as much as the ones I write today.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Before I get to my journey though, if you want to see the end result you can view it at <a class="href" href="https://puppypride.social/">https://puppypride.social/</a>. I am still in active development, and will likely remain like that for a long time. I do want to stress that Puppy Pride is an adult community of people who are into pet-play kinks. The website is 18+ restricted and most of the features can only be seen and used when logged in.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Back in December of 2020 my friend said he had someone who needed a website made. A remake for his aging and broken social website called Puppy Pride. Being the enthusiastic 19 year old freshman student I was, I thought my years of Wordpress tinkering and easy introduction to Java at University were quite something and offered to help. Turns out making websites is harder than I could ever think. I was asked to program a social site in Laravel, something I had vaguely heard of when I did a short internship during high school. I heard the word and went "Yeah, I know that!" and in January of 2021 were off to the races. Truth be told is my employer had nobody better, so I was his only choice.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The first 2 weeks were spent looking at beginner tutorials on the web about writing PHP and Laravel. I started off with a course on how to write a Twitter clone, and immediately came into contact with Laravel's huge ecosystem of tools to make the job easier. If it wasn't for tools like Breeze I would've never managed to get started the way I did, writing back-end logic and interactive forms within weeks of starting. I have to reiterate I wasn't a back-end or front-end engineer at all, and had no knowledge of things like MVC, REST APIs, Templaters, Multithreading, etc. But I was about to write a social system for 12000 users that was intended to be finished after 6-8 months of development time.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Wherever I could I harnessed the power of Laravel's rich ecosystem. Things like Spatie's Medialibrary and Laravel's Breeze helped me through difficult systems that I didn't know how to make myself. Little did I know I'd replace or rewrite most of them in the future, because as it turns while they're great starters they are too inflexible for very large systems like a social network. On top of that, my employer had a whole bunch of specific and weird requests to retain compatibility with the old website. For example, everything had to be stored in albums, even a thumbnail for a blog would get a complete image album. That led to needing to make many types of albums and differentiate between them, which is just an outright mess when combined with Spatie's more rigid system.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Speaking of requirements, the system didn't only have to be rewritten into a modern system within months by a junior, it also needed to be better and faster, naturally. How does a junior optimize a large system when not knowing what he's doing? He tries, and tries, and tries until it works, for 8 months long. The 2.5 years of development were mostly occupied by solving a few key problems:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Migrating old data to the new database: 6 months</li>
|
||||
<li>Deploying securely (Docker, NGINX): 4 months</li>
|
||||
<li>Load balancing and load time improvements: 8 months</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Right before launch I developed Pride Unbound*London's website using Laravel as well.....
|
||||
</p>
|
||||
</Post>
|
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import Post from "$lib/blog/Post.svelte";
|
||||
</script>
|
||||
|
||||
<Post date="August 1st 2023" title="The power of VR, and why it's probably not what you think" image="/blog/thepowerofvr.png">
|
||||
<b class="text-lg">
|
||||
This website is a testament to my love of VR, I have a whole section dedicated to it after all. But in this post I'd like to touch a little more on why that is, on why I've created such a deep bond with a world that isn't even real to most, or at best a failed dream of out of touch billionares.
|
||||
</b>
|
||||
</Post>
|
@ -1,13 +0,0 @@
|
||||
<script>
|
||||
import Footer from "$lib/footer/Footer.svelte";
|
||||
|
||||
import "../../app.css";
|
||||
</script>
|
||||
|
||||
<div class="bg-gray-100 dark:bg-gray-900 text-black dark:text-white">
|
||||
<div class="min-h-screen">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
@ -1,43 +0,0 @@
|
||||
<script>
|
||||
import Card from "$lib/home/Card.svelte";
|
||||
|
||||
import Socials from "$lib/Socials.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Home</title>
|
||||
</svelte:head>
|
||||
|
||||
<main>
|
||||
|
||||
<div class="relative h-screen" style="background-image: url('/esu/banner.jpg')">
|
||||
<!-- <img class="absolute inset-0" src="/esu/banner.jpg" /> -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-white dark:to-black"></div>
|
||||
|
||||
<div class="absolute h-96 inset-0 flex flex-col justify-center items-center mt-20">
|
||||
<h1 class="baron text-white text-9xl drop-shadow-xl">easter system <br/> <h2 class="baron text-white text-7xl ml-1">UNIVERSE</h2></h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="-mt-40 h-screen relative">
|
||||
<section class="mt-40 absolute inset-0 bg-white dark:bg-black">
|
||||
</section>
|
||||
<section class="absolute inset-0 triangle h-full w-2/3 mx-auto bg-gradient-to-t from-amber-500 to-red-600 z-0">
|
||||
</section>
|
||||
|
||||
<div class="absolute inset-0 h-96 mt-60 flex flex-col gap-20 justify-start items-center w-1/2 mx-auto">
|
||||
<div>
|
||||
<h1 class="baron-light text-black dark:text-white text-4xl">ACT 1</h1>
|
||||
<hr class="w-1/2 my-2" />
|
||||
<h1 class="baron text-black dark:text-white text-8xl">luther's throne</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.triangle {
|
||||
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
|
||||
}
|
||||
</style>
|
@ -1,9 +0,0 @@
|
||||
<script>
|
||||
import Socials from "$lib/Socials.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Home</title>
|
||||
</svelte:head>
|
||||
|
||||
<main />
|
@ -1,11 +0,0 @@
|
||||
<script>
|
||||
import Sona from "$lib/home/Sona.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Home</title>
|
||||
</svelte:head>
|
||||
|
||||
<main class="">
|
||||
<Sona/>
|
||||
</main>
|
@ -1,61 +0,0 @@
|
||||
<script>
|
||||
import Card from "$lib/home/Card.svelte";
|
||||
import Socials from "$lib/Socials.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Home</title>
|
||||
</svelte:head>
|
||||
|
||||
<main>
|
||||
<section class="bg-opacity-50 relative h-80">
|
||||
<div class="absolute left-0 h-full w-full bg-blue-600 opacity-50"></div>
|
||||
|
||||
<div class="container absolute inset-0 pt-20">
|
||||
<h1 class="text-8xl font-bold baron-light">portfolio</h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
<section class="py-20 flex gap-10 flex-col items-between">
|
||||
<section class="w-1/3 flex flex-col gap-5">
|
||||
<h2 class="font-bold text-4xl">Puppy Pride</h2>
|
||||
|
||||
<Card
|
||||
buttonHref="https://puppypride.social"
|
||||
buttonText="🌐 Visit Puppy Pride"
|
||||
>
|
||||
<p class="text-sm text-gray-800 dark:text-gray-100">
|
||||
I was the developer of the new Puppy Pride social
|
||||
network over the course of 2021, and continue to support and expand
|
||||
it to this day. The site was built from the ground up
|
||||
using the TALL stack in PHP.
|
||||
<br /><br />
|
||||
The site sports a whole array of social features including
|
||||
blogging, picture albums, statuses, user profiles, forums,
|
||||
events, groups with roles and custom pages, location data,
|
||||
instant messaging, various networking tools like friending
|
||||
and blocking, notifications through channels like push and
|
||||
mail, live feed, subscriptions and viewcounts, comment
|
||||
sections, likes and followers, and much more.
|
||||
<br /><br />
|
||||
The project is nearing completion and will be released soon.
|
||||
You may find a beta release public at <a target="_blank" class="a" href="https://beta.puppypride.social">beta.puppypride.social</a>.
|
||||
</p>
|
||||
</Card>
|
||||
</section>
|
||||
|
||||
<section class="w-1/2 h-96">
|
||||
<h2 class="font-bold text-4xl">The Moonlit Den</h2>
|
||||
</section>
|
||||
|
||||
<section class="w-1/2 h-96">
|
||||
<h2 class="font-bold text-4xl">The Moonlit Den</h2>
|
||||
</section>
|
||||
|
||||
<section class="w-1/2 h-96">
|
||||
<h2 class="font-bold text-4xl">The Moonlit Den</h2>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
After Width: | Height: | Size: 168 KiB |
After Width: | Height: | Size: 433 KiB |
After Width: | Height: | Size: 2.2 MiB |
After Width: | Height: | Size: 3.9 MiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 2.6 MiB |
After Width: | Height: | Size: 1.4 MiB |
After Width: | Height: | Size: 1.2 MiB |