diff --git a/src/app.d.ts b/src/app.d.ts
index 8f4d638..7564bf3 100644
--- a/src/app.d.ts
+++ b/src/app.d.ts
@@ -1,6 +1,7 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
+
declare namespace App {
// interface Locals {}
// interface PageData {}
diff --git a/src/app.postcss b/src/app.postcss
index 2b81492..e279a82 100644
--- a/src/app.postcss
+++ b/src/app.postcss
@@ -24,6 +24,12 @@ body {
src: url('/fonts/Quicksand.ttf');
font-display: swap;
}
+
+.prose {
+ font-family: 'Cooper Hewitt', sans-serif;
+ letter-spacing: 0.25px;
+}
+
/*
@font-face {
font-family: 'Magilio';
diff --git a/src/content/blog/Dockerizing apps.txt b/src/content/blog/Dockerizing apps.txt
new file mode 100644
index 0000000..c90ec11
--- /dev/null
+++ b/src/content/blog/Dockerizing apps.txt
@@ -0,0 +1,12 @@
+
+tldr:
+I started by containerizing my SvelteKit and Strapi apps, then Pushed these to Docker Hub and AWS ECR,
+leveraging 1 free private image on docker hub and free-tier 500mb limit on AWS ECR, thereby minimizing costs and exploring each option.
+
+1. Conteinerization
+ a. Sveltekit
+Keeping in mind that dev, build, test and lint, etc. scripts are handled by turborepo, we use these when containerizing.
+
+Step 1.
+
+ b. Strapi
diff --git a/src/content/blog/Setup.txt b/src/content/blog/Setup.txt
new file mode 100644
index 0000000..85eb3bb
--- /dev/null
+++ b/src/content/blog/Setup.txt
@@ -0,0 +1,7 @@
+choosing a package manager
+
+I tried to abstain from the community battles between pms and looked at the performance of the top 3 used - npm, yarn and pnpm. https://pnpm.io/benchmarks
+I've got experience with each and would like to use pnpm as it is the much faster than NPM,
+however Strapi doesn't officialy support it so I ended up choosing yarn as in most cases it is a bit faster than npm, has some better handling with monorepos and I personally like it.
+I used Turborepo with npm and there were some problems with setting dependencies in workspaces vs the root of monorepo and private packages, which required workarounds.
+In terms of CI performance can have significant consequences.
\ No newline at end of file
diff --git a/src/content/blog/aws iam.txt b/src/content/blog/aws iam.txt
new file mode 100644
index 0000000..8caba07
--- /dev/null
+++ b/src/content/blog/aws iam.txt
@@ -0,0 +1,15 @@
+AWS set up
+
+A thing I learned using linux is user management, specifically don't do everything as root :D.
+When using AWS first I didn't care about IAM roles, but I think I learned the same lesson...
+
+Anyways I used this process, when configuring accounts:
+
+When starting login as root user and access IAM dashboard,
+Set up Multi-factor Auth as root user (prefferably with Yubikey or some OTP in a secure device)
+Later on, like in linux, the root account access can be minimized for a better decentralized privilege system, even when being the only admin.
+
+Go to services then IAM Identity center
+Select identity source -> In my case stick with the default Identity Center directory, bigger organizations or ones using other sources can connect to external ones.
+In Multi-account permissions select permission sets and create a permission set.
+Then go to AWS accounts, select the account you wish and assign the permission set to them.
\ No newline at end of file
diff --git a/src/content/blog/ec2 & rds.txt b/src/content/blog/ec2 & rds.txt
new file mode 100644
index 0000000..d72f145
--- /dev/null
+++ b/src/content/blog/ec2 & rds.txt
@@ -0,0 +1,62 @@
+Namecheap
+Saw mattmor.in and just bought it, no questions asked.
+
+I immediately created a cloudflare account, because of their great certificate management, security checks, analytics and mostly DNS.
+
+
+
+
+Setting up AWS EC2 & RDS instances
+
+EC2 setup
+I've got a great opportunity to set up a "free-tier" instance, of course the limitations are quite interesting - 750 hrs/m and some compute limiting factors.
+Let's use this opportunity, it is a better deal than GCP with 300$/3mos and my experience with GCP while dealing with Auth API was pretty bad.
+
+Made SSH keys
+got an Elastic IP and connected it with my EC2 instance to be accessible publicly on a stable IP.
+added DNS records to cloudflare
+
+
+Log in via SSH, update, upgrade everything, restart.
+Then I configured fail2ban with some custom responses and enabled it, I also configured the seemingly redundant ufw and allowed ssh, https
+
+And with that I am ready to roll onto installing necessary software like nginx, jenkins, docker for now.
+
+RDS setup
+
+I've already configured Strapi for my backend, I selected PostgreSQL, because while theoretically the default SQLite db would be sufficient and very easy to manage.
+I know it's scalability is limited and is not suitable for multiple user access, which I might need in other projects with the same tech stack.
+The main reason for choosing PostgreSQL is I can showcase it and learn with it on a project using AWS.
+I've worked mainly with MariaDB before, and used PostgreSQL only on some ancient Wordpress projects back in the day.
+
+As I already set up a free-tier EC2 instance, I can also setup AWS RDS with Aurora(PostgreSQL compatible) or PostgreSQL also on free-tier, which is awesome!
+Let's choose PostgreSQL, because that's simpler and more than sufficient.
+
+The Free Tier is limited to the same time frame for RDS...
+If I really wanted to make this completely free I could use AWS Lambda, which is also free up to 1 million requests/month :D, to turn off both the EC2 and RDS instances at night. Gotta think when do recruiters go to sleep...
+
+
+Now seriously, to actualy set this up:
+
+Select:
+burstable class db.t4g.micro
+General Purpose SSD (gp3) 20GiB
+I disabled autoscaling as it's not possible I would use more than this in this use-case.
+
+Strapi recommends PostgreSQL v14.0 at the time of writing
+AWS offers 14.5 above, let's choose 14.9 R1, should be backwards compatible.
+Template -> Free tier
+
+Security:
+As my OpSec dictates I choose passwords with high entropy so you can't hack me.
+
+Backup & Maintenance:
+Setup Backup and Amazon auto-maintenance windows, I am not a maniac to not backup.
+
+Connectivity:
+I will not connect this to my EC2 instance, because I will be testing this on localhost.
+I need public access and in this case I do not think accessing by a private network is necessary.
+I will make a new VPC security group, then we can access it via an internet gateway.
+
+
+https://docs.aws.amazon.com/images/AmazonRDS/latest/UserGuide/images/GS-VPC-network.png
\ No newline at end of file
diff --git a/src/content/blog/first-post.md b/src/content/blog/first-post.md
index c8d07a2..6720740 100644
--- a/src/content/blog/first-post.md
+++ b/src/content/blog/first-post.md
@@ -1,18 +1,26 @@
---
title: First post
+type: blog
excerpt: First post
-date: 2021-01-01
tags:
- - first
- - post
-published: true
+ - Blog
+ - Linux
+ - Declarative
image: Feature.jpg
+postTitle: 'Best Medium Format Camera for Starting Out'
+focusKeyphrase: 'best medium format camera'
+datePublished: '2023-04-07T16:04:42.000+0100'
+lastUpdated: '2023-04-14T10:17:52.000+0100'
+seoMetaDescription: "Let's take a look."
+featuredImage: ''
+featuredImageAlt: 'Our own pcb'
+publicImageId: ''
---
## Svelte
Media inside the **Svelte** folder is served from the `static` folder.
-```python
+```python showLines
input_text = ''' "yahooapis.com",
"hotmail.com",
@@ -30,3 +38,112 @@ output_text = '\n'.join(formatted_lines)
print(output_text)
```
+
+## Turborepo [see 1st source]
+I will use turborepo as I have experience with it from previous projects, I prefer the centralized, more orderly handling of repositories.
+Because our CMS and webapp are workspaces that need to be configured differently, we need to extend the root config of Turborepo to each app individually by creating a turbo.json in each workspace.
+
+For Strapi this will be:
+$root/apps/cms/turbo.json
+
+``` json
+
+{
+ "extends": ["//"],
+ "pipeline": {
+ "build": {
+ // custom configuration for the build task in this workspace
+ },
+ // new tasks only available in this workspace
+ "special-task": {},
+ }
+}
+```
+
+For Sveltekit Webapp:
+$root/apps/web/turbo.json
+
+``` json
+{
+ "extends": ["//"],
+ "pipeline": {
+ "build": {
+ "outputs": [".svelte-kit/**"]
+ }
+ }
+}
+```
+
+Key notes about this setup:
+
+Docker:
+ Base Layer: Installs container dependencies and Turborepo globally.
+ Pruned Layer: Copies project files and runs turbo prune to exclude unnecessary dependencies.
+ Installer Layer: Copies pruned workspace and runs yarn to install dependencies.
+ Runner Layer: Starts the app.
+
+## Docker
+
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
+
+Learned
+
+Used sources:
+
+1. https://turbo.build/repo/docs
+2. https://dev.to/moofoo/creating-a-development-dockerfile-and-docker-composeyml-for-yarn-122-monorepos-using-turborepo-896
+
+
+## Docker
+
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
+## Docker
+
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
+## Docker
+
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
+## Docker
+
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
+## Docker
+
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
+## Docker
+
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
diff --git a/src/content/blog/monitoring.txt b/src/content/blog/monitoring.txt
new file mode 100644
index 0000000..abf90e1
--- /dev/null
+++ b/src/content/blog/monitoring.txt
@@ -0,0 +1,18 @@
+install Grafana, Prometheus, ELK Stack, and Jenkins on a single server and use them to monitor other EC2 instances or cloud resources. There are trade-offs:
+
+Pros:
+
+ Simplified Management: All tools in one place.
+ Lower Costs: Fewer servers to maintain.
+
+Cons:
+
+ Resource Contention: These tools can be resource-intensive.
+ Single Point of Failure: If the server goes down, all tools are affected.
+ Security Risks: Multiple services on one server can increase the attack surface.
+
+Recommendations:
+
+ Use containerization (Docker) for easier management and isolation.
+ Set up a robust backup and recovery strategy.
+ Ensure adequate resource allocation and scaling capabilities.
\ No newline at end of file
diff --git a/src/content/blog/postwa.md b/src/content/blog/postwa.md
index f9e4fa3..8ccdedc 100644
--- a/src/content/blog/postwa.md
+++ b/src/content/blog/postwa.md
@@ -1,12 +1,19 @@
---
-title: w post
-excerpt: w post
-date: 2021-01-01
+title: First post
+type: blog
+excerpt: First post
tags:
- - first
- - post
-published: true
+ - NixOS
+ - Linux
+ - Declarative
image: Feature.jpg
+postTitle: 'Best Medium Format Camera for Starting Out'
+focusKeyphrase: 'best medium format camera'
+datePublished: '2022-04-07T16:04:42.000+0100'
+lastUpdated: '2022-04-14T10:17:52.000+0100'
+seoMetaDescription: "Let's take a look."
+featuredImage: ''
+featuredImageAlt: 'Our own pcb'
+publicImageId: ''
---
-
-## Svelte
\ No newline at end of file
+## Svelte
diff --git a/src/content/blog/project description.txt b/src/content/blog/project description.txt
new file mode 100644
index 0000000..196e765
--- /dev/null
+++ b/src/content/blog/project description.txt
@@ -0,0 +1,76 @@
+The goal of this project is to showcase my skillset both as a portfolio site and showcase how I used devops and web development practices to build it.
+The tech stack and feature set is meant to:
+legitimize the goal of the portfolio site, which is mentioned above
+Use modern DevOps and web development practices that I know of so I can build it as fast as possible.
+minimize costs and be potentially scalable and feature-upgradeable.
+be secure and be build using my evolving OpSec and limited cybersecurity knowledge.
+show proficiency in using new tools.
+
+As such the current cloud stack is:
+1. AWS EC2 t3.micro
+ For: Jenkins
+ Why: CI/CD pipeline, free tier, 1GB RAM sufficient for Jenkins.
+2. AWS EC2 t3.micro
+ For: docker-compose SvelteKit app
+ Why: Frontend, free tier, 1GB RAM sufficient for SvelteKit.
+
+3. Amazon ECS Anywhere
+
+ For: docker-compose Strapi
+ Why: Container orchestration, 2200 free hours, scalable.
+
+4. AWS Lambda
+
+ For: Automated tasks
+ Why: 1 million free requests, event-driven architecture.
+
+5. Amazon RDS
+
+ For: Database
+ Why: 750 free hours, managed service, 20GB storage.
+
+6. Amazon S3
+
+ For: File storage, backups
+ Why: 5GB free storage, durable.
+
+7. Amazon CloudWatch
+
+ For: Monitoring
+ Why: 10 free custom metrics and alarms.
+
+8. AWS Secrets Manager
+
+ For: Secrets
+ Why: Secure, but consider alternatives due to cost.
+
+9. Amazon API Gateway
+
+ For: APIs
+ Why: 1 million free API calls, secure.
+
+10. Terraform and Ansible
+
+ For: IaC and Configuration
+ Why: Version control, automation.
+
+11. Documentation
+
+ For: READMEs
+ Why: Clarity, onboarding, and best practices.
+
+12. GitHub and AWS ECR
+
+ For: Code and container repositories
+ Why: Version control, Docker Hub limitations.
+
+Cost Analysis
+
+ EC2 t3.micro: Free tier
+ ECS Anywhere: Free tier (2200 hours)
+ Lambda: Free tier (1 million requests)
+ RDS: Free tier (750 hours)
+ S3: Free tier (5GB)
+ CloudWatch: Free tier (10 metrics)
+ Secrets Manager: $0.40/secret, consider alternatives
+ API Gateway: Free tier (1 million calls)
\ No newline at end of file
diff --git a/src/content/blog/second-post.md b/src/content/blog/second-post.md
index 930f194..f985f1e 100644
--- a/src/content/blog/second-post.md
+++ b/src/content/blog/second-post.md
@@ -1,13 +1,20 @@
---
-title: Second post
-excerpt: Second post
-date: 2023-01-01
+title: First post
+type: blog
+excerpt: First post
tags:
- - first
- - post
-published: true
+ - NixOS
+ - Linux
+ - Declarative
image: Feature.jpg
-
+postTitle: 'Best Medium Format Camera for Starting Out'
+focusKeyphrase: 'best medium format camera'
+datePublished: '2024-04-07T16:04:42.000+0100'
+lastUpdated: '2021-04-14T10:17:52.000+0100'
+seoMetaDescription: "Let's take a look."
+featuredImage: ''
+featuredImageAlt: 'Our own pcb'
+publicImageId: ''
---
@@ -23,5 +30,4 @@ Media inside the **Svelte** folder is server from the `static` folder.
I am ditching the societal value of having a contributions table on my profile, you should view it on git.mattmor.in
-
---- If my contributions in 3d do not work, Github made breaking changes to their frontend and I can't scrape it anymore.
\ No newline at end of file
+--- If my contributions in 3d do not work, Github made breaking changes to their frontend and I can't scrape it anymore.
diff --git a/src/content/blog/skillset.txt b/src/content/blog/skillset.txt
new file mode 100644
index 0000000..397823d
--- /dev/null
+++ b/src/content/blog/skillset.txt
@@ -0,0 +1,74 @@
+Hard skills in SW:
+HTML, CSS, JS, TS, Svelte, Sveltekit, Vite,
+
+WebDev (meta)frameworks: Svelte (and sveltekit), a theoretical knowledge of reactjs (and next.js) and vue (and nuxt)
+WebDev langs: HTML, CSS, tailwindcss, postcss (basics), JS, TS (basics), multiple ui libraries and billions of packages :D
+WebDev linting: eslint
+WebDev testing: Playwright
+
+Languages: JS, Python, Micropython, C and C++ (both basics with microcontrollers), I really want to code in OstraJava and Brainf*ck
+
+
+
+OS:
+Linux [Ubuntu, Debian (Rpi OS, Kali - basics), QubesOS, Arch (Manjaro)], WSL,
+Windows :D, advanced as a power user of XP,Vista,7,8,10,11 in my life, caused deep trauma. Haven't used win servers and don't plan to.
+
+Terminal:
+Process Monitoring
+Performance Monitoring
+Networking Tools
+Text Manipulation
+
+Scripting:
+Bash
+Power Shell (for user tasks)
+
+Editors:
+Nano, Emacs, VS Code, Notepad :D and Jupyter notebook
+
+
+
+Version control: Git
+
+
+VCS Hosting: Github, Gitlab
+CI/CD:
+Jenkins In progress
+Gitlab CI In progress
+
+Infrastructure Provisioning:
+Terraform: In progress
+
+Cloud Providers:
+AWS - Preffered
+DigitalOcean
+Google Cloud (I did auth, api, company set up and some bots with spreadsheet)
+
+CDN: Cloudinary
+
+Networking, Security and Protocols:
+FTP / SFTP
+SSL / TLS
+HTTP / HTTPS
+DNS
+SSH (putty and linux)
+
+Serverless: AWS Lambda (0), Cloudflare, Vercel
+
+Monorepo (with pipelines): all yarn, npm, pnpm with turborepo
+
+
+
+Containerization: docker (dockerfile, docker-compose, ran many apps with it), DockerHub, AWS RCD
+
+Container Orchestration: Docker swarm(basics)
+K8s/K3s: In progress...
+
+Orchestration: Terraform (0)
+
+GitOps: In progress ArgoCD
+
+Application monitoring: New Relic, Prometheus, Grafana, Elk stack
+
+Logs Management:
\ No newline at end of file
diff --git a/src/content/blog/turbo and docker.txt b/src/content/blog/turbo and docker.txt
new file mode 100644
index 0000000..db09887
--- /dev/null
+++ b/src/content/blog/turbo and docker.txt
@@ -0,0 +1,56 @@
+
+## Turborepo [see 1st source]
+I will use turborepo as I have experience with it from previous projects, I prefer the centralized, more orderly handling of repositories.
+Because our CMS and webapp are workspaces that need to be configured differently, we need to extend the root config of Turborepo to each app individually by creating a turbo.json in each workspace.
+
+For Strapi this will be:
+$root/apps/cms/turbo.json
+```
+{
+ "extends": ["//"],
+ "pipeline": {
+ "build": {
+ // custom configuration for the build task in this workspace
+ },
+ // new tasks only available in this workspace
+ "special-task": {},
+ }
+}
+```
+
+For Sveltekit Webapp:
+$root/apps/web/turbo.json
+```
+{
+ "extends": ["//"],
+ "pipeline": {
+ "build": {
+ "outputs": [".svelte-kit/**"]
+ }
+ }
+}
+```
+
+
+Key notes about this setup:
+
+Docker:
+ Base Layer: Installs container dependencies and Turborepo globally.
+ Pruned Layer: Copies project files and runs turbo prune to exclude unnecessary dependencies.
+ Installer Layer: Copies pruned workspace and runs yarn to install dependencies.
+ Runner Layer: Starts the app.
+
+## Docker
+Alpine is more lightweight than Ubuntu, I will stick to the inspiration blog post [see 2nd source], which has a similar setup.
+The blog post creates intermediate images 'base', 'pruned' etc. that can be used in subsequent stages.
+
+To push images to docker hub:
+
+```docker push mando42/portfolio:tagname```
+
+
+Learned
+
+Used sources:
+1. https://turbo.build/repo/docs
+2. https://dev.to/moofoo/creating-a-development-dockerfile-and-docker-composeyml-for-yarn-122-monorepos-using-turborepo-896
\ No newline at end of file
diff --git a/src/lib/assets/code.css b/src/lib/assets/code.css
new file mode 100644
index 0000000..8492174
--- /dev/null
+++ b/src/lib/assets/code.css
@@ -0,0 +1,40 @@
+.code-highlight {
+ position: relative;
+ font-family: 'Fira Mono', monospace;
+ overflow-x: hidden;
+ overflow-y: auto;
+ max-height: 60vh;
+ margin: 1rem auto;
+ box-shadow: var(--shadow);
+ border-radius: 0.5rem;
+ font-size: 1.5rem;
+ max-width: 90%;
+}
+
+.code-highlight > .code-language {
+ position: absolute;
+ top: 0;
+ right: 0;
+ border-top-right-radius: 0.5rem;
+ border-bottom-left-radius: 0.5rem;
+ background: rgba(127, 127, 127, 0.3);
+ padding: 0 0.25rem;
+}
+
+.code-highlight > code {
+ display: inline-block;
+ padding: 1rem;
+}
+
+.code-highlight > code.numbered {
+ margin-left: 2rem;
+ padding-left: 0.5rem;
+ border-left: 1px solid rgba(127, 127, 127, 0.5);
+ counter-reset: line;
+}
+
+.code-highlight > code > .line-of-code {
+ white-space: pre-wrap;
+ display: inline-block;
+ min-height: 1em;
+}
diff --git a/src/lib/assets/global.css b/src/lib/assets/global.css
new file mode 100644
index 0000000..62cd6b8
--- /dev/null
+++ b/src/lib/assets/global.css
@@ -0,0 +1,120 @@
+:root {
+ --light: #f1f4f8;
+ --dark: #2c2d2f;
+ --primary: #ff3e00;
+ --fg: var(--light);
+ --bg: var(--dark);
+ --color-scrollbar: rgba(0, 0, 0, 0.3);
+ --shadow: 0 0.5rem 0.5rem 0 rgba(0, 0, 0, 0.2), 0 0.25rem 1rem 0 rgba(0, 0, 0, 0.2),
+ 0 0.5rem 0.25rem -0.25rem rgba(0, 0, 0, 0.2);
+}
+
+@media only screen and (prefers-color-scheme: dark) {
+ :root {
+ --fg: var(--light);
+ --bg: var(--dark);
+ --color-scrollbar: rgba(255, 255, 255, 0.3);
+ }
+
+ body.light {
+ --fg: var(--dark);
+ --bg: var(--light);
+ --color-scrollbar: rgba(0, 0, 0, 0.3);
+ }
+}
+
+@media only screen and (prefers-color-scheme: light) {
+ :root {
+ --fg: var(--dark);
+ --bg: var(--light);
+ --color-scrollbar: rgba(0, 0, 0, 0.3);
+ }
+
+ body.dark {
+ --fg: var(--light);
+ --bg: var(--dark);
+ --color-scrollbar: rgba(255, 255, 255, 0.3);
+ }
+}
+
+body {
+ color: var(--fg);
+ background-color: var(--bg);
+ font-family: 'Fira Mono', monospace;
+ font-size: 1.5rem;
+ height: 1080px;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: 'Fira Mono', monospace;
+}
+
+p,
+.prose {
+ font-family: 'Cooper Hewitt', sans-serif;
+ letter-spacing: 0.25px;
+}
+
+.container {
+ margin: 0 auto;
+ padding: 0;
+ width: calc(100vw - 2rem);
+ max-width: 1920px;
+}
+
+a {
+ color: currentColor;
+ transition: color 200ms ease-in-out;
+}
+
+* {
+ scrollbar-width: thin;
+ scrollbar-color: var(--color-scrollbar) transparent;
+ -webkit-overflow-scrolling: touch;
+}
+
+*::-webkit-scrollbar {
+ width: 0.5rem;
+}
+
+*::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+*::-webkit-scrollbar-thumb {
+ background-color: var(--color-scrollbar);
+ border-radius: 0.25rem;
+}
+
+html {
+ height: 100%;
+}
+body {
+ height: 100%;
+}
+
+.shadow {
+ box-shadow: var(--shadow);
+}
+
+h1,
+h2,
+h3,
+h4 {
+ margin-top: 0;
+}
+
+h1 {
+ margin-bottom: 0.5rem;
+}
+h2 {
+ margin-bottom: 0.25rem;
+}
+h3 {
+ margin-bottom: 0.1rem;
+}
diff --git a/src/lib/cloudinary.ts b/src/lib/cloudinary.ts
new file mode 100644
index 0000000..001381a
--- /dev/null
+++ b/src/lib/cloudinary.ts
@@ -0,0 +1,12 @@
+// src/lib/cloudinary.ts
+import { v2 as cloudinary } from 'cloudinary';
+import { PUBLIC_CLOUDINARY_NAME } from '$env/static/public';
+import { CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET } from '$env/static/private';
+
+cloudinary.config({
+ cloud_name: PUBLIC_CLOUDINARY_NAME,
+ api_key: CLOUDINARY_API_KEY,
+ api_secret: CLOUDINARY_API_SECRET
+});
+
+export default cloudinary;
diff --git a/src/lib/components/home/QuickCards.svelte b/src/lib/components/home/QuickCards.svelte
index b8ee942..d59a98c 100644
--- a/src/lib/components/home/QuickCards.svelte
+++ b/src/lib/components/home/QuickCards.svelte
@@ -1,26 +1,26 @@
- I possess a wide range of skills that enable me to develop visually appealing and
- interactive user interfaces for web applications.
-
- Over the years, I have honed my ability to create visually appealing interfaces that
- are both user-friendly and intuitive.
-
- I understand the importance of creating a seamless UX for end-users. Which includes
- a solid understanding user behavior.
-
+ I hone my problem solving and coding skills all the time. I try to learn the underlying
+ mechanics and use abstractions where relevant.
+
+ I try to create better, novel ways to approach problems and give my best to present them
+ in a clear and concise manner.
+
+ From my experience with a wide range of roles I understand the how to communication with
+ stakeholders across an organization.
+ Development
- Design
- User Experience
- Development
+ Creativity & Presentation
+ Teamwork & Stakeholders
+
${lang}${lines.map(lineRenderer(options)).join('\n')}\n
`;
+}
+
+const lineRenderer = (options) => (line) => {
+ const output = line.map(tokenRenderer(options)).join('');
+ const { leadingWS, content, trailingWS } = splitLeadingAndTrailingWS(output);
+ return `${leadingWS || ''}${content || ''}${
+ trailingWS || ''
+ }`;
+};
+
+const tokenRenderer = (options) => (token) => {
+ if (!token.color || token.color.toLowerCase() === options.fg) {
+ return escape(token.content);
+ }
+ const { leadingWS, content, trailingWS } = splitLeadingAndTrailingWS(token.content);
+ if (!content) {
+ return leadingWS;
+ }
+
+ return `${leadingWS}${escape(content)}${trailingWS}`;
+};
+
+function splitLeadingAndTrailingWS(content) {
+ const len = content.length;
+ let start = 0;
+ let end = len;
+
+ while (start < end && isWS(content.charAt(start))) {
+ start++;
+ }
+
+ if (start === end) {
+ return {
+ leadingWS: content || ''
+ };
+ }
+
+ while (end > start && isWS(content.charAt(end - 1))) {
+ end--;
+ }
+
+ return {
+ leadingWS: content.slice(0, start),
+ content: content.slice(start, end),
+ trailingWS: end < content.length ? content.slice(end) : ''
+ };
+}
+
+function isWS(char) {
+ return char === ' ' || char === '\t';
+}
+
+function isPlaintext(lang) {
+ return !lang || ['plaintext', 'txt', 'text'].indexOf(lang) !== -1;
+}
+
+const defaultOpts = {
+ theme: 'nord',
+ fg: undefined,
+ bg: undefined,
+ showLineNumbers: (numberOfLines) => numberOfLines > 5
+};
+
+export default async function createHighlighter(opts) {
+ const options = { ...defaultOpts, ...opts };
+
+ if (options.theme.endsWith('.json')) {
+ options.theme = loadTheme(options.theme);
+ } else {
+ options.theme = getTheme(options.theme);
+ }
+ const baseSettings = (
+ (options.theme['tokenColors'] || []).find((x) => !x.scope) || { settings: {} }
+ ).settings;
+ const colors = options.theme.colors || {};
+ const getThemeColor = (name) => baseSettings[name] || colors[`editor.${name}`] || colors[name];
+ const fg = (options.fg || getThemeColor('foreground') || '#eeeeee').toLowerCase();
+ const bg = (options.bg || getThemeColor('background') || '#222222').toLowerCase();
+ return getHighlighter(options).then(
+ (highlighter) => (code, lang) =>
+ render(
+ isPlaintext(lang)
+ ? [[{ content: code }]]
+ : highlighter.codeToTokensBase(code, lang),
+ { ...options, fg, bg, lang }
+ )
+ );
+}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 58026c4..27226db 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,48 +1,26 @@