Compare commits

...

86 Commits

Author SHA1 Message Date
dcfad5fcd6 Merge branch 'dev'
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-24 13:17:16 +01:00
9b8b59d4e6 add Blur
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-24 13:16:50 +01:00
Rei
dc7e82b143 kollors
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 18:46:29 +01:00
Rei
703b611dfd sorted
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 18:29:52 +01:00
Rei
dd4f848071 divider
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 17:57:47 +01:00
Rei
46097b8390 style changes 2023-02-15 16:43:14 +01:00
e78bc12c49 merge
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-11 21:03:17 +01:00
aa3bb66d5e add custom directives 2023-02-11 21:00:28 +01:00
c9f5dfcba7 Update 'content/projects/RE-Chess.md'
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-11 20:10:11 +01:00
4902006130 revert
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-10 17:50:07 +01:00
71f679c3ca yt vid
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-10 17:33:08 +01:00
f7c6d3ae16 some changes
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-10 17:06:51 +01:00
f884ac1d1d new content
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-10 17:03:55 +01:00
9b58851c42 remove markdown test from main
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-09 21:41:01 +01:00
6142b6c9cc merge to main 2023-02-09 21:39:50 +01:00
3e5bb19970 remove trash shader
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-09 21:37:46 +01:00
22755e66e5 better design with selfmade shader
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-09 21:34:25 +01:00
ff8536f8c6 fix
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-08 17:58:06 +01:00
ad99601407 remove unwanted pckg
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-08 17:49:47 +01:00
2d88365a69 relative path
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-08 17:44:03 +01:00
3140f9b666 change docker volumes
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-08 17:42:15 +01:00
9d98b3ac69 fix?
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-08 17:23:28 +01:00
9a48d20a16 add gradient BG
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-08 17:17:40 +01:00
Rei
50358c43b9 remark plugins and width
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-06 17:10:36 +01:00
rei
cfdecde769 under construction
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-20 21:01:02 +01:00
Rei
839defdd06 margin in code and pre tags
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-18 17:27:12 +01:00
Rei
b4e6631f07 layout fix
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-18 17:02:46 +01:00
Rei
b0a87b5592 headings and scroll fix
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-18 16:56:45 +01:00
957ff33555 remove retry count
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-03 01:18:12 +01:00
8ce6560482 add restart policy
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-03 01:15:40 +01:00
rei
c5018b3bb9 small fix
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-30 15:14:30 +01:00
rei
f76edaec72 fixes 2022-12-30 15:05:00 +01:00
rei
4d9092ae3d dark mode and light mode support 2022-12-30 15:01:25 +01:00
rei
d397503c66 markdown features
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-30 14:14:05 +01:00
rei
e545a596ec added projects
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-29 13:42:04 +01:00
rei
446c4a4241 padding fix
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-29 01:56:00 +01:00
rei
ba2edb6c38 Merge branch 'main' of ssh://git.peroxy.dev:222/renttrent/peroxy_site
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-29 01:09:04 +01:00
rei
437a79877e testing peroxy 2022-12-29 01:08:46 +01:00
94ca95821d all done
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-29 00:00:17 +01:00
ceee45409d test changes
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 23:58:45 +01:00
7eed2ee59a test changes
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 23:56:47 +01:00
9a7e9048f2 test changes
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 23:54:38 +01:00
de224373ed test changes
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 23:51:51 +01:00
a1a0e15f6d test changes
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 23:51:06 +01:00
b200528007 test changes
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 23:44:42 +01:00
083fb3fd48 test changes
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 23:42:56 +01:00
75e24a6a08 package.json
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 23:38:09 +01:00
5a9e65396c fix trigger
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 23:36:35 +01:00
406183536e fix pipeline
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-12-28 23:35:26 +01:00
4be09b8100 fix pipeline
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 23:33:38 +01:00
d71f599f0d fix pipeline name
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 23:31:19 +01:00
be1b6268e7 add dev support
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-12-28 23:30:20 +01:00
d229d639fd add dev support
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-12-28 23:29:50 +01:00
74aa0ab925 Update 'package.json'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:56:36 +01:00
281e0f4170 Delete 'docker-compose.start.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:56:21 +01:00
e37f2f0212 Update 'docker-compose.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:55:02 +01:00
144020b6d1 Update 'docker-compose.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:51:43 +01:00
1c165a68cb Update 'docker-compose.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:50:45 +01:00
bbe50c4790 Update 'docker-compose.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:49:43 +01:00
4c4e762a4a Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:48:40 +01:00
d19966baba Update 'docker-compose.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:47:04 +01:00
c3f3a4914a Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:45:36 +01:00
c714281330 Update 'docker-compose.start.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:43:25 +01:00
bf0e8e2c02 Update 'docker-compose.start.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:41:43 +01:00
a83e68ea73 Update 'docker-compose.start.yml'
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-12-28 22:40:08 +01:00
49fc655de9 Update 'docker-compose.start.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:37:43 +01:00
2a6198aa1f Update 'docker-compose.start.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:31:20 +01:00
e1e9a41d59 Update 'docker-compose.start.yml'
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-12-28 22:27:26 +01:00
2abb8a1bfc Update 'docker-compose.start.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:26:34 +01:00
da4c565cb3 Update 'docker-compose.yml'
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-12-28 22:25:01 +01:00
31c7e8ea27 Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:22:39 +01:00
25cd9c75ab Update 'package.json'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:20:34 +01:00
2913688e63 Update 'package.json'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:15:21 +01:00
77ae0a746b Update 'package.json'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:13:50 +01:00
9ee61716d4 Update 'Dockerfile'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 22:10:55 +01:00
2ff40d856a Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:09:24 +01:00
f1f84aec3d Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:05:59 +01:00
a609afcefc Update 'package.json'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:05:05 +01:00
c77371b0a4 Update 'docker-compose.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:04:41 +01:00
5f2853083f Add 'docker-compose.start.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:04:21 +01:00
2cfcc3c892 Update 'docker-compose.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:02:34 +01:00
611fe5f12b Update 'docker-compose.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 22:00:54 +01:00
8f6b36eca1 Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 21:59:56 +01:00
a833d2666a Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-28 21:59:09 +01:00
0e18750370 test docker-compose
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 21:54:20 +01:00
d97e329f4c test docker-compose
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 21:53:35 +01:00
37 changed files with 10275 additions and 321 deletions

View File

@@ -1,15 +1,41 @@
--- ---
kind: pipeline kind: pipeline
name: default name: prod-pipe
steps: steps:
- name: now - name: prod
image: one000mph/drone-now # Use one000mph's version as lucaperret's is outdated image: docker/compose
environment: volumes:
NOW_TOKEN: - name: docker_socket
from_secret: now_token # Refers to a secret in your drone repo titled "NOW_TOKEN" path: /var/run/docker.sock
settings: commands:
secret: [now_token] # Refers to the above environment variable - docker-compose -f docker-compose.yml up --build --force-recreate -d
deploy_name: peroxy-dev # The name of your vercel project trigger:
prod: true # Leave this if you want to deploy to production, remove to disable production branch:
# directory: public # Only if you've pre-rendered the page. Normally you let vercel handle this - main
volumes:
- name: docker_socket
host:
path: /var/run/docker.sock
---
kind: pipeline
name: dev-pipe
steps:
- name: dev
image: docker/compose
volumes:
- name: docker_socket
path: /var/run/docker.sock
commands:
- docker-compose -f docker-compose.dev.yml up --build --force-recreate -d
trigger:
branch:
- dev
volumes:
- name: docker_socket
host:
path: /var/run/docker.sock

1
.gitignore vendored
View File

@@ -7,6 +7,7 @@
# testing # testing
/coverage /coverage
/content/projects/markdown-test.md
# next.js # next.js
/.next/ /.next/

2
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,2 @@
{
}

31
Dockerfile Normal file
View File

@@ -0,0 +1,31 @@
#Creates a layer from node:alpine image.
FROM node:alpine
#Creates directories
RUN mkdir -p /usr/src/app
#Sets an environment variable
ENV PORT 3000
#Sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD commands
WORKDIR /usr/src/app
#Copy new files or directories into the filesystem of the container
COPY package.json /usr/src/app
#COPY package-lock.json /usr/src/app
#Execute commands in a new layer on top of the current image and commit the results
RUN npm install
##Copy new files or directories into the filesystem of the container
COPY . /usr/src/app
#Execute commands in a new layer on top of the current image and commit the results
RUN npm run build
#Informs container runtime that the container listens on the specified network ports at runtime
EXPOSE 3000
#Allows you to configure a container that will run as an executable
ENTRYPOINT ["npm", "run"]

41
components/ImageSlide.tsx Normal file
View File

@@ -0,0 +1,41 @@
import React, { useState } from "react";
import { AiFillLeftCircle } from "react-icons/ai";
export const ImageSlide = ({ children }: any) => {
const [current, setCurrent] = useState(0);
const length = children.length;
const nextSlide = () => {
setCurrent(current === length - 1 ? 0 : current + 2);
};
const prevSlide = () => {
setCurrent(current === 0 ? length - 1 : current - 2);
};
if (children.length <= 0) {
return null;
}
return (
<section className="slider">
<AiFillLeftCircle className="left-arrow" onClick={prevSlide} />
<AiFillLeftCircle className="right-arrow" onClick={nextSlide} />
{children.map((slide: any, index: any) => {
return (
<div
className={index === current ? "slide active" : "slide"}
key={index}
>
{index === current && (
<img
src={slide.props.children[0]}
alt="travel image"
className="image"
/>
)}
</div>
);
})}
</section>
);
};

View File

@@ -4,7 +4,7 @@ export const Logo = () => {
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
id="svg166" id="svg166"
version="1.1" version="1.1"
className="fill-action group-hover:fill-secondary transition-all ease-in duration-100 flex-no-shrink xl:w-12 xl:h-12 w-8 h-8" className="fill-action group-hover:fill-primary dark:group-hover:fill-secondary transition-all ease-in duration-100 flex-no-shrink xl:w-12 xl:h-12 w-8 h-8"
viewBox="0 0 100 100" viewBox="0 0 100 100"
> >
<g id="167217677994600400"> <g id="167217677994600400">

View File

@@ -5,22 +5,22 @@ import { motion, AnimatePresence } from "framer-motion";
import { Logo } from "./Logo"; import { Logo } from "./Logo";
const links = [ const links = [
{ name: "blog", href: "/blog" }, { name: "Blog", href: "/blog" },
{ name: "projects", href: "/projects" }, { name: "Projects", href: "/projects" },
{ name: "github", href: "https://git.peroxy.dev/kookroach" }, { name: "Gitea", href: "https://git.peroxy.dev/kookroach" },
]; ];
export const Navbar = () => { export const Navbar = () => {
const [showMenu, setShowMenu] = useState(false); const [showMenu, setShowMenu] = useState(false);
return ( return (
<nav className="lg:p-4 p-2 lg:py-10 mx-6 flex flex-row justify-between"> <nav className="py-4 xl:px-10 px-4 flex flex-row justify-between sticky top-0 z-50 bg-gradient-to-b from-black/50 to-black/30">
<Link <Link
href="/" href="/"
id="logo" id="logo"
className="flex flex-row gap-2 items-center group" className="flex flex-row gap-2 items-center group"
> >
<Logo /> <Logo />
<div className="font-bold xl:text-4xl text-xl font-mono transition-all ease-in duration-100 text-action group-hover:text-secondary"> <div className="font-bold xl:text-4xl text-xl font-mono transition-all ease-in duration-100 text-action group-hover:text-primary dark:group-hover:text-secondary">
peroxy peroxy
<span className="xl:text-sm text-xs">.dev</span> <span className="xl:text-sm text-xs">.dev</span>
</div> </div>
@@ -28,7 +28,7 @@ export const Navbar = () => {
<div className="hidden xl:flex flex-row gap-10 items-center font-medium font-mono"> <div className="hidden xl:flex flex-row gap-10 items-center font-medium font-mono">
{links.map(({ name, href }) => ( {links.map(({ name, href }) => (
<Link href={href} key={name}> <Link href={href} key={name}>
<button className="px-10 py-1 rounded-sm bg-primary hover:bg-primary/50 transition-all duration-150 ease-out"> <button className="px-10 py-1 rounded-sm bg-gradient-to-r from-indigo-500/30 to-fuchsia-500/20 hover:bg-primary/50 transition-all duration-150 ease-out text-white">
{name} {name}
</button> </button>
</Link> </Link>
@@ -49,7 +49,7 @@ export const Navbar = () => {
exit={{ opacity: 0 }} exit={{ opacity: 0 }}
/> />
<motion.div <motion.div
className={`z-40 absolute w-1/2 bg-blue-900 className={`z-40 absolute w-1/2 bg-blue-900 text-primary-text
right-0 top-0 px-10 py-6 h-full`} right-0 top-0 px-10 py-6 h-full`}
initial={{ x: "100%" }} initial={{ x: "100%" }}
animate={{ x: 0 }} animate={{ x: 0 }}

51
components/PostHeader.tsx Normal file
View File

@@ -0,0 +1,51 @@
import Link from "next/link";
import { FrontMatter } from "../types/types";
export interface BasicArticleProps extends FrontMatter {
title: string;
description: string;
date: string;
author: string;
authorLink: string;
thumbnail: string;
}
export const PostHeader = ({
frontMatter,
estTime,
}: {
frontMatter: FrontMatter;
estTime: number;
}) => {
const { title, author, date, description, authorLink } =
frontMatter as BasicArticleProps;
return (
<div className="flex items-start gap-2 flex-col">
<div className="lg:text-5xl text-3xl font-bold mt-2 text-gray-50">
{title}
</div>
<div className="mt-2 text-gray-600dark:text-gray-400 text-sm">{description}</div>
<div className="mt-2 mb-10 flex lg:flex-row flex-col gap-2 items-start">
{author && (
<div className="font-medium ">
By{" "}
{authorLink && (
<Link href={authorLink} className="dark:text-action text-primary">
@{author}
</Link>
)}
{!authorLink && (
<span className="dark:text-action text-primary">@{author}</span>
)}
</div>
)}
<div className="text-sm font-medium text-gray-500 lg:before:content-['•'] lg:after:content-['•'] lg:before:pr-2 lg:after:pl-2">
{date}
</div>
<div className="text-sm font-medium text-gray-500">
{estTime} min read
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,66 @@
import { useRef, useMemo } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { BufferGeometry, Material, MathUtils, Mesh } from "three";
import { vertexShader } from "./Shaders/Background/vertex";
import { fragmentShader } from "./Shaders/Background/fragment";
const Fragment = () => {
// This reference will give us direct access to the mesh
const meshRef = useRef<Mesh<BufferGeometry, Material | Material[]>>(null);
const uniforms = useMemo(
() => ({
u_intensity: {
value: 1.0,
},
u_time: {
value: 0.0,
},
}),
[]
);
useFrame((state) => {
if (!meshRef.current) {
return;
}
const { clock } = state;
//@ts-ignore
meshRef.current.material.uniforms.u_time.value =
(0.4 * clock.getElapsedTime()) / 5;
//@ts-ignore
meshRef.current.material.uniforms.u_intensity.value = MathUtils.lerp(
//@ts-ignore
meshRef.current.material.uniforms.u_intensity.value,
1.0,
0.02
);
});
return (
<mesh
ref={meshRef}
position={[0, 0, 0]}
rotation={[-Math.PI / 17, Math.PI / 20, 0]}
scale={1.5}
>
<planeGeometry args={[30, 30, 200, 200]} />
<shaderMaterial
fragmentShader={fragmentShader}
vertexShader={vertexShader}
uniforms={uniforms}
wireframe={false}
/>
</mesh>
);
};
export const R3Gradient = () => {
return (
<div className="-z-40 h-screen w-screen fixed bg-black opacity-60 top-0 left-0 blur">
<Canvas camera={{ position: [0.0, 0.0, 5.0] }}>
<Fragment />
</Canvas>
</div>
);
};

View File

@@ -0,0 +1,75 @@
export const fragmentShader = `
uniform float u_intensity;
uniform float u_time;
uniform int width;
uniform int height;
varying vec2 vUv;
varying float vDisplacement;
//from Hash Functions for GPU Rendering (Jarzynski et al.)
//http://www.jcgt.org/published/0009/03/02/
vec3 pcg3d(uvec3 v)
{
v = v * 1664525u + 1013904223u;
v.x += v.y*v.z; v.y += v.z*v.x; v.z += v.x*v.y;
v ^= v >> 16u;
v.x += v.y*v.z; v.y += v.z*v.x; v.z += v.x*v.y;
return vec3(v) * (1.0/float(0xffffffffu));
}
// convert texture coordinates to pixel
float t2p(float t, int noOfPixels){
return t * float(noOfPixels) - 0.5;
}
#define M_PI 3.1415926535897932384626433832795
vec2 randomGradient(uvec3 p){
vec3 _uv = pcg3d(p);
float r = sqrt(_uv[0]);
float phi = 2.0 * M_PI * _uv[1];
return vec2(r* cos(phi), r * sin(phi));
}
vec3 gradientNoise(vec2 pos, float gridSize){
vec2 gridPos = pos * gridSize;
uvec2 i = uvec2(gridPos);
vec2 f = fract(gridPos);
vec2 g11 = randomGradient(uvec3(i.x,i.y,1));
vec2 g12 = randomGradient(uvec3(i.x + 1u,i.y,1));
vec2 g21 = randomGradient(uvec3(i.x,i.y + 1u,1));
vec2 g22 = randomGradient(uvec3(i.x + 1u,i.y +1u,1));
float d11 = dot(g11, f);
float d12 = dot(g12, f - vec2(1.0, 0.0));
float d21 = dot(g21, f - vec2(0.0, 1.0));
float d22 = dot(g22, f - vec2(1.0, 1.0));
vec3 f11 = pcg3d(uvec3(i.x,i.y,0)) * (d11 + 1.0);
vec3 f12 = pcg3d(uvec3(i.x + 1u,i.y,0))* (d12 + 1.0);
vec3 f21 = pcg3d(uvec3(i.x,i.y + 1u,0))* (d21 + 1.0);
vec3 f22 = pcg3d(uvec3(i.x + 1u,i.y +1u,0))* (d22 + 1.0);
f = smoothstep(0.0, 1.0, f);
vec3 q1 = mix(f11, f12, vec3(f.x));
vec3 q2 = mix(f21, f22, vec3(f.x));
vec3 p = mix(q1, q2, vec3(f.y));
return p;
}
void main() {
float distort = 2.0 * vDisplacement + u_intensity;
vec2 pos = vec2(u_time) /5.0 + vUv;
vec3 texColor = gradientNoise(pos, 4.0);
texColor.y = 0.0;
gl_FragColor = vec4(texColor, 1.0);
}
`

View File

@@ -0,0 +1,108 @@
export const vertexShader = `
uniform float u_intensity;
uniform float u_time;
varying vec2 vUv;
varying float vDisplacement;
// Classic Perlin 3D Noise
// by Stefan Gustavson
//
vec4 permute(vec4 x) {
return mod(((x*34.0)+1.0)*x, 289.0);
}
vec4 taylorInvSqrt(vec4 r) {
return 1.79284291400159 - 0.85373472095314 * r;
}
vec3 fade(vec3 t) {
return t*t*t*(t*(t*6.0-15.0)+10.0);
}
float cnoise(vec3 P) {
vec3 Pi0 = floor(P); // Integer part for indexing
vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
Pi0 = mod(Pi0, 289.0);
Pi1 = mod(Pi1, 289.0);
vec3 Pf0 = fract(P); // Fractional part for interpolation
vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
vec4 iy = vec4(Pi0.yy, Pi1.yy);
vec4 iz0 = Pi0.zzzz;
vec4 iz1 = Pi1.zzzz;
vec4 ixy = permute(permute(ix) + iy);
vec4 ixy0 = permute(ixy + iz0);
vec4 ixy1 = permute(ixy + iz1);
vec4 gx0 = ixy0 / 7.0;
vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;
gx0 = fract(gx0);
vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
vec4 sz0 = step(gz0, vec4(0.0));
gx0 -= sz0 * (step(0.0, gx0) - 0.5);
gy0 -= sz0 * (step(0.0, gy0) - 0.5);
vec4 gx1 = ixy1 / 7.0;
vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;
gx1 = fract(gx1);
vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
vec4 sz1 = step(gz1, vec4(0.0));
gx1 -= sz1 * (step(0.0, gx1) - 0.5);
gy1 -= sz1 * (step(0.0, gy1) - 0.5);
vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
g000 *= norm0.x;
g010 *= norm0.y;
g100 *= norm0.z;
g110 *= norm0.w;
vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
g001 *= norm1.x;
g011 *= norm1.y;
g101 *= norm1.z;
g111 *= norm1.w;
float n000 = dot(g000, Pf0);
float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
float n111 = dot(g111, Pf1);
vec3 fade_xyz = fade(Pf0);
vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
return 2.2 * n_xyz;
}
// End of Perlin Noise Code
void main() {
vUv = uv;
vDisplacement = cnoise(position + vec3(2.0 * u_time));
vec3 newPosition = position + normal * (u_intensity * vDisplacement);
vec4 modelPosition = modelMatrix * vec4(newPosition, 1.0);
vec4 viewPosition = viewMatrix * modelPosition;
vec4 projectedPosition = projectionMatrix * viewPosition;
gl_Position = projectedPosition;
}
`

View File

@@ -0,0 +1,216 @@
import rangeParser from "parse-numeric-range";
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
import tsx from "react-syntax-highlighter/dist/cjs/languages/prism/tsx";
import typescript from "react-syntax-highlighter/dist/cjs/languages/prism/typescript";
import scss from "react-syntax-highlighter/dist/cjs/languages/prism/scss";
import bash from "react-syntax-highlighter/dist/cjs/languages/prism/bash";
import markdown from "react-syntax-highlighter/dist/cjs/languages/prism/markdown";
import json from "react-syntax-highlighter/dist/cjs/languages/prism/json";
import { coldarkDark as defaulttheme } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { BiCopy } from "react-icons/bi";
import { Components } from "react-markdown";
import { generateSlug } from "../utils/general";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkTypograf from "@mavrin/remark-typograf";
import smartypants from "remark-smartypants";
import rehypeRaw from "rehype-raw";
import emoji from "remark-emoji";
import oembed from "@agentofuser/remark-oembed";
import remarkDirective from "remark-directive";
import remarkDirectiveRehype from "remark-directive-rehype";
import { YouTubeVideo } from "./Youtube";
import { ImageSlide } from "./ImageSlide";
//import rehypeSanitize from "rehype-sanitize";
SyntaxHighlighter.registerLanguage("tsx", tsx);
SyntaxHighlighter.registerLanguage("typescript", typescript);
SyntaxHighlighter.registerLanguage("scss", scss);
SyntaxHighlighter.registerLanguage("bash", bash);
SyntaxHighlighter.registerLanguage("markdown", markdown);
SyntaxHighlighter.registerLanguage("json", json);
export const StyledMarkdown = ({ html }: { html: string }) => {
const MarkdownComponents: Components = {
h1: (props: any) => {
const arr = props.children;
let heading = "";
for (let i = 0; i < arr.length; i++) {
if (arr[i]?.type !== undefined) {
for (let j = 0; j < arr[i].props.children.length; j++) {
heading += arr[i]?.props?.children[0];
}
} else heading += arr[i];
}
const slug = generateSlug(heading);
return (
<h1 id={slug}>
<a href={`#${slug}`} {...props}></a>
</h1>
);
},
h2: (props: any) => {
const arr = props.children;
let heading = "";
for (let i = 0; i < arr.length; i++) {
if (arr[i]?.type !== undefined) {
for (let j = 0; j < arr[i].props.children.length; j++) {
heading += arr[i]?.props?.children[0];
}
} else heading += arr[i];
}
const slug = generateSlug(heading);
return (
<h2 id={slug}>
<a href={`#${slug}`} {...props}></a>
</h2>
);
},
h3: (props: any) => {
const arr = props.children;
let heading = "";
for (let i = 0; i < arr.length; i++) {
if (arr[i]?.type !== undefined) {
for (let j = 0; j < arr[i].props.children.length; j++) {
heading += arr[i]?.props?.children[0];
}
} else heading += arr[i];
}
const slug = generateSlug(heading);
return (
<h3 id={slug} className="text-red-500">
<a href={`#${slug}`} {...props}></a>
</h3>
);
},
h4: (props: any) => {
const arr = props.children;
let heading = "";
for (let i = 0; i < arr.length; i++) {
if (arr[i]?.type !== undefined) {
for (let j = 0; j < arr[i].props.children.length; j++) {
heading += arr[i]?.props?.children[0];
}
} else heading += arr[i];
}
const slug = generateSlug(heading);
return (
<h4 id={slug}>
<a href={`#${slug}`} {...props}></a>
</h4>
);
},
code({ node, inline, className, ...props }: any) {
const match = /language-(\w+)/.exec(className || "");
const hasMeta = node?.data?.meta;
const applyHighlights: object = (applyHighlights: number) => {
if (hasMeta) {
const RE = /{([\d,-]+)}/;
const metadata = node.data.meta?.replace(/\s/g, "");
const strlineNumbers = RE?.test(metadata)
? // @ts-ignore
RE?.exec(metadata)[1]
: "0";
const highlightLines = rangeParser(strlineNumbers);
const highlight = highlightLines;
const data = highlight.includes(applyHighlights) ? "highlight" : null;
return { data };
} else {
return {};
}
};
const applyStartingNumber = () => {
if (hasMeta) {
const metadata = node.data.meta?.replace(/\s/g, "");
const RE = /line=(\d+)/;
const start = RE?.test(metadata) && RE.exec(metadata);
return start ? +start[1] : 1;
} else {
return 1;
}
};
const getTitle = () => {
if (hasMeta) {
const metadata = node.data.meta;
const RE = /title=\"(.*)\"/;
const title = RE?.test(metadata) && RE.exec(metadata);
return title ? title[1] : "Code";
}
return "Code";
};
return match ? (
<div>
<div className="w-full flex flex-row items-center gap-4">
<button
className="w-fit ml-2 important"
onClick={() => navigator.clipboard.writeText(props.children)}
>
<BiCopy />
</button>
{<div>{getTitle()}</div>}
</div>
<SyntaxHighlighter
style={defaulttheme}
language={match[1]}
PreTag="div"
className="codeStyle"
showLineNumbers={true}
wrapLines={hasMeta ? true : false}
useInlineStyles={true}
lineProps={applyHighlights}
startingLineNumber={applyStartingNumber()}
{...props}
/>
</div>
) : (
<code className={className} {...props} />
);
},
//custom directives
//@ts-ignore
yt: YouTubeVideo,
"img-slide": ImageSlide,
};
return (
<div
className="
prose
prose-code:font-mono prose-code:text-gray-100 prose-code:bg-black/20 prose-code:p-1 prose-code:m-1 prose-code:rounded-md
prose-headings:text-gray-800 dark:prose-headings:text-gray-100 prose-p:text-gray-600 dark:prose-p:text-gray-300
prose-img:w-full prose-img:h-auto prose-img:object-cover
prose-li:text-gray-600 dark:prose-li:text-gray-200 prose-td:text-gray-600 dark:prose-td:text-gray-300
prose-a:text-primary prose-strong:text-gray-900 dark:prose-strong:text-gray-50
dark:prose-hr:bg-gray-200 prose-hr:bg-gray-400
"
>
<ReactMarkdown
components={MarkdownComponents}
rehypePlugins={[rehypeRaw]}
remarkPlugins={[
remarkDirective,
remarkDirectiveRehype,
oembed,
remarkGfm,
smartypants,
emoji,
remarkTypograf,
]}
children={html}
/>
</div>
);
};

9
components/Youtube.tsx Normal file
View File

@@ -0,0 +1,9 @@
export const YouTubeVideo = ({id, children} : any) => (
<iframe
src={'https://www.youtube.com/embed/' + id}
width="640"
height="360"
>
{children}
</iframe>
)

View File

@@ -8,4 +8,14 @@ description: Short description
# First blog # First blog
Insane Insane
test change
# Header 1 test
## Header 2 test
### Header 3 test
#### Header 4 test

View File

@@ -1,5 +1,5 @@
--- ---
title: "My Third Blog" title: "My Third Blog (TEST)"
date: 27.12.2022 date: 27.12.2022
author: kookroach author: kookroach
description: Short description description: Short description

View File

@@ -0,0 +1,27 @@
---
title: "Concept Art and Game Design"
date: 17.01.2022
author: kookroach
authorLink: https://git.peroxy.dev/kookroach
description: "Creative basics for professional game development. A Workshop by Dr.-Ing. Wolfgang Höhl."
thumbnail: https://docs.peroxy.dev/uploads/f001b7e2-4e85-4335-8302-40cbda9c3490.png
---
From concept drawing to modeling to game engine. A neo-noir Game Concept inspired from Games like Max Payne and Luke Cage Noir comics.
### Sketches
#### Character Concept
::img-slide[https://wiki.tum.de/download/attachments/1030785260/Character%20Design%201%20rework.png?version=1&modificationDate=1642430318357&api=v2 https://wiki.tum.de/download/attachments/1030785260/Character%20Design%202.png?version=1&modificationDate=1642430320190&api=v2]{}
#### Environment Concept
::img-slide[https://wiki.tum.de/download/attachments/1030785260/Env-Design%20Skizze.png?version=1&modificationDate=1642430334223&api=v2 https://wiki.tum.de/download/attachments/1030785260/Env-Design%20Final.png?version=1&modificationDate=1642430333137&api=v2]{}
### Models
::img-slide[https://docs.peroxy.dev/uploads/251bda2e-05e2-4fe4-828c-e3a747e5c9e8.png https://docs.peroxy.dev/uploads/7a9e94b3-cb00-43bb-85ad-7fdf25e047fd.png https://docs.peroxy.dev/uploads/b8c07d01-11d6-4771-af21-4f208e443216.png https://docs.peroxy.dev/uploads/99cec6be-6239-46f3-a350-9ef9bfb60932.png https://docs.peroxy.dev/uploads/a3f69410-3e32-41a0-9f9a-c87f35d4cbfa.png https://docs.peroxy.dev/uploads/8b4cf730-48e4-422c-8cf5-590efd3e79b7.png]{}
### Final Render
![](https://wiki.tum.de/download/attachments/1030785260/render_third.png?version=1&modificationDate=1642430351370&api=v2)
### Final Result in Unity Engine
![](https://docs.peroxy.dev/uploads/851605f4-a7e7-46dd-902b-88e95d367a0c.png)

View File

@@ -0,0 +1,8 @@
---
title: "MadTrax"
date: 11.12.2022
author: kookroach
authorLink: https://git.peroxy.dev/kookroach
description: "A game jam game made entirely from scratch in just 42 hours using the Godot 4 game engine."
thumbnail: https://docs.peroxy.dev/uploads/b968afc4-059c-41fd-b948-67c9b32c2cc2.png
---

View File

@@ -0,0 +1,8 @@
---
title: "RE:Chess"
date: 19.06.2022
author: kookroach
authorLink: https://git.peroxy.dev/kookroach
description: "A game jam game made in just 42 hours using the Unity engine. Redefine the rules of chess to solve the re:chess puzzles in this unique chess game."
thumbnail: https://docs.peroxy.dev/uploads/4806dc24-3fe7-4349-8121-f230e7a02359.png
---

View File

@@ -0,0 +1,45 @@
---
title: "Space Madness"
date: 06.06.2020
author: kookroach
authorLink: https://git.peroxy.dev/kookroach
description: "Navigate through an endless battlefield and destroy turrets while avoiding being killed. See if you can beat the current high score of 7471."
thumbnail: https://docs.peroxy.dev/uploads/cd22a289-ebe7-4d82-98e3-b639d1df2ea6.png
---
```
_____ ___ ___ _
/ ___| | \/ | | |
\ `--. _ __ __ _ ___ ___ | . . | __ _ __| | _ __ ___ ___ ___
`--. \| '_ \ / _` | / __| / _ \ | |\/| | / _` | / _` || '_ \ / _ \/ __|/ __|
/\__/ /| |_) || (_| || (__ | __/ | | | || (_| || (_| || | | || __/\__ \\__ \
\____/ | .__/ \__,_| \___| \___| \_| |_/ \__,_| \__,_||_| |_| \___||___/|___/
| |
|_|
```
> :warning: **Assets and Sounds of this game are not self made**
### About this Project
My introduction to game development began with the completion of my first project, "Space Madness", which I created using the Unity Engine. This experience sparked my passion for the field and led me to pursue a degree in Informatics: Games Engineering at the Technical University of Munich.
A Challenging mobile endless space shooter game.
### Technical Features
- Procedual Terrain generation
- Chunk rendering with LOD
- Endless Level generation
- Basic Boss Fight Logic
- Touch input support
### Gameplay Video
::yt[Video of a cat in a box]{#1qquNEJrA10}
## Links
Repository [here](https://gitlab.com/moungoslukas/stonks)
Download Windows Build [here](https://cloud.peroxy.dev/s/c5PzG37xtqyD8gZ) (playable by using the Mouse and Left Mouse Button)

1
desc.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module "@mavrin/remark-typograf";

25
docker-compose.dev.yml Normal file
View File

@@ -0,0 +1,25 @@
version: '3'
services:
peroxy_site_dev:
container_name: peroxy_site_dev
command: start
restart: unless-stopped
build:
context: .
labels:
- "traefik.enable=true"
- "traefik.http.routers.peroxy_site_dev.entrypoints=https"
- "traefik.http.routers.peroxy_site_dev.rule=Host(`test.peroxy.dev`)"
- "traefik.http.routers.peroxy_site_dev.tls=true"
- "traefik.http.routers.peroxy_site_dev.tls.certresolver=http"
- "traefik.http.routers.peroxy_site_dev.service=peroxy_site_dev-service"
- "traefik.http.services.peroxy_site_dev-service.loadbalancer.server.port=3000"
networks:
- proxy
volumes:
- ./dev_site:/var/lib/website/dev
networks:
proxy:
external: true

25
docker-compose.yml Normal file
View File

@@ -0,0 +1,25 @@
version: '3'
services:
peroxy_site:
container_name: peroxy_site
command: start
restart: unless-stopped
build:
context: .
labels:
- "traefik.enable=true"
- "traefik.http.routers.peroxy_site.entrypoints=https"
- "traefik.http.routers.peroxy_site.rule=Host(`peroxy.dev`, `www.peroxy.dev`)"
- "traefik.http.routers.peroxy_site.tls=true"
- "traefik.http.routers.peroxy_site.tls.certresolver=http"
- "traefik.http.routers.peroxy_site.service=peroxy_site-service"
- "traefik.http.services.peroxy_site-service.loadbalancer.server.port=3000"
networks:
- proxy
volumes:
- ./dev_site:/var/lib/website/prod
networks:
proxy:
external: true

View File

@@ -1,11 +1,13 @@
import { PropsWithChildren } from "react"; import { PropsWithChildren } from "react";
import { R3Gradient } from '../components/R3Background';
import { Navbar } from "../components/Navbar"; import { Navbar } from "../components/Navbar";
export const MainLayout = ({ children }: PropsWithChildren) => { export const MainLayout = ({ children }: PropsWithChildren) => {
return ( return (
<div className="w-11/12 lg:w-2/3 m-auto overflow-x-hidden"> <div className="w-full">
<Navbar /> <Navbar />
<main className="xl:p-10 p-6 xl:mt-10 mt-4">{children}</main> <R3Gradient />
<main className="xl:p-5 p-4 px-5 xl:mx-0">{children}</main>
</div> </div>
); );
}; };

7597
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,21 +9,39 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@agentofuser/remark-oembed": "^1.0.4",
"@mavrin/remark-typograf": "^2.2.0",
"@react-three/drei": "^9.56.19",
"@react-three/fiber": "^8.11.0",
"@tailwindcss/typography": "^0.5.8", "@tailwindcss/typography": "^0.5.8",
"@types/node": "18.11.11", "@types/node": "18.11.11",
"@types/react": "18.0.26", "@types/react": "18.0.26",
"@types/react-dom": "18.0.9", "@types/react-dom": "18.0.9",
"@types/three": "^0.149.0",
"framer-motion": "^8.0.2", "framer-motion": "^8.0.2",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"next": "13.0.6", "next": "13.0.6",
"parse-numeric-range": "^1.3.0",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-icons": "^4.7.1", "react-icons": "^4.7.1",
"react-markdown": "^8.0.4",
"react-syntax-highlighter": "^15.5.0",
"react-youtube": "^10.1.0",
"rehype-raw": "^6.1.1",
"rehype-sanitize": "^5.0.1",
"remark": "^14.0.2", "remark": "^14.0.2",
"remark-directive": "^2.0.1",
"remark-directive-rehype": "^0.4.2",
"remark-emoji": "^3.1.0",
"remark-gfm": "^3.0.1",
"remark-html": "^15.0.1", "remark-html": "^15.0.1",
"remark-smartypants": "^2.0.0",
"three": "^0.149.0",
"typescript": "4.9.3" "typescript": "4.9.3"
}, },
"devDependencies": { "devDependencies": {
"@types/react-syntax-highlighter": "^15.5.5",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"postcss": "^8.4.19", "postcss": "^8.4.19",
"tailwindcss": "^3.2.4" "tailwindcss": "^3.2.4"

View File

@@ -1,46 +1,30 @@
import { GetStaticPaths, GetStaticProps } from "next"; import { GetStaticPaths, GetStaticProps } from "next";
import fs from "fs"; import fs from "fs";
import { ParsedUrlQuery } from "querystring"; import { ParsedUrlQuery } from "querystring";
import { import { BLOGS_PATH, getBlogContentBySlug } from "../../utils/markdown";
BLOGS_PATH,
getFileContentBySlug,
renderMarkdown,
} from "../../utils/markdown";
import { MarkdownRenderingResult } from "../../types/types"; import { MarkdownRenderingResult } from "../../types/types";
import { MainLayout } from "../../layouts/MainLayout"; import { MainLayout } from "../../layouts/MainLayout";
import Link from "next/link"; import Link from "next/link";
import { IoMdArrowRoundBack as BackIcon } from "react-icons/io"; import { IoMdArrowRoundBack as BackIcon } from "react-icons/io";
import { BasicBlogProps } from "."; import { PostHeader } from "../../components/PostHeader";
import { readingTime } from "../../utils/general";
import { StyledMarkdown } from "../../components/StyledMarkdown";
export const BlogArticle = ({ frontMatter, html }: MarkdownRenderingResult) => { export const BlogArticle = ({ frontMatter, html }: MarkdownRenderingResult) => {
const { title, author, date, description, authorLink } =
frontMatter as BasicBlogProps;
return ( return (
<MainLayout> <MainLayout>
<Link href="/blog"> <div className="rounded-md border border-gray-200 shadow-md shadow-gray-200 dark:shadow-gray-900 dark:border-gray-700 gap-4 bg-black bg-opacity-30 round">
<button className="flex flex-row items-center gap-2 text-secondary hover:text-secondary/50 transition-all ease-in duration-75"> <div className="mx-10 mt-5 mb-10">
<BackIcon /> <Link href="/blog">
<span>Go Back</span> <button className="flex flex-row items-center gap-2 text-primary hover:text-primary-dark dark:text-secondary dark:hover:text-secondary/50 transition-all ease-in duration-75">
</button> <BackIcon />
</Link> <span>Go Back</span>
<div className="lg:mt-10 mt-4 mb-2 text-sm font-medium text-gray-500"> </button>
{date}
</div>
<div className="lg:text-5xl font-bold">{title}</div>
<div className="mt-2 font-medium">
By{" "}
{authorLink && (
<Link href={authorLink} className="text-action">
@{author}
</Link> </Link>
)} <PostHeader frontMatter={frontMatter} estTime={readingTime(html)} />
{!authorLink && <span className="text-action">@{author}</span>} <StyledMarkdown html={html} />
</div>
</div> </div>
<div className="mt-2">{description}</div>
<div
className="mt-4 prose prose-headings:text-primary-text prose-p:text-gray-400"
dangerouslySetInnerHTML={{ __html: html }}
/>
</MainLayout> </MainLayout>
); );
}; };
@@ -62,12 +46,11 @@ export const getStaticPaths: GetStaticPaths<BlogProps> = async () => {
export const getStaticProps: GetStaticProps<MarkdownRenderingResult> = async ({ export const getStaticProps: GetStaticProps<MarkdownRenderingResult> = async ({
params, params,
}) => { }) => {
const markdownContent = getFileContentBySlug(params?.slug as string); const markdownContent = getBlogContentBySlug(params?.slug as string);
const renderedHTML = await renderMarkdown(markdownContent.content);
return { return {
props: { props: {
frontMatter: markdownContent.frontMatter, frontMatter: markdownContent.frontMatter,
html: renderedHTML, html: markdownContent.content,
}, },
}; };
}; };

View File

@@ -1,34 +1,26 @@
import { GetServerSideProps } from "next"; import { GetServerSideProps } from "next";
import { MainLayout } from "../../layouts/MainLayout"; import { MainLayout } from "../../layouts/MainLayout";
import { BlogPost, getAllFilesFrontMatter } from "../../utils/markdown"; import { Post, getAllBlogsFrontMatter } from "../../utils/markdown";
import { FrontMatter } from "../../types/types";
import Link from "next/link"; import Link from "next/link";
import { formatDate } from "../../utils/general";
import { BasicArticleProps } from "../../components/PostHeader";
export interface BasicBlogProps extends FrontMatter { const BlogCard = ({
title: string; blog,
description: string; slug,
date: string; }: {
author: string; blog: BasicArticleProps;
authorLink: string; slug: string;
} }) => {
const BlogCard = ({ blog, slug }: { blog: BasicBlogProps; slug: string }) => {
const format = (date: string) => {
const [day, month, year] = date.split(".");
const d = new Date(`${year}-${month}-${day}`);
return d.toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
});
};
return ( return (
<div className="p-4 rounded-md border border-gray-700"> <div className="p-4 rounded-md border border-gray-200 shadow-md shadow-gray-200 dark:shadow-gray-900 dark:border-gray-700 bg-black bg-opacity-60">
<div className="text-sm font-medium text-gray-500"> <div className="text-sm font-medium text-gray-500">
{format(blog.date)} {formatDate(blog.date)}
</div> </div>
<h2 className="text-2xl font-bold">{blog.title}</h2> <h2 className="text-2xl font-bold">{blog.title}</h2>
<p className="text-gray-400 text-lg">{blog.description}</p> <p className="text-gray-600 dark:text-gray-400 text-sm">
{blog.description}
</p>
<Link href={`blog/${slug}`}> <Link href={`blog/${slug}`}>
<button className="bg-action px-2 py-1 rounded-md mt-4 hover:bg-action/60 transition-all ease-in duration-100 font-bold text-white"> <button className="bg-action px-2 py-1 rounded-md mt-4 hover:bg-action/60 transition-all ease-in duration-100 font-bold text-white">
Read more Read more
@@ -38,16 +30,18 @@ const BlogCard = ({ blog, slug }: { blog: BasicBlogProps; slug: string }) => {
); );
}; };
const Blog = ({ posts }: { posts: BlogPost[] }) => { const Blog = ({ posts }: { posts: Post[] }) => {
return ( return (
<MainLayout> <MainLayout>
<h1 className="text-3xl font-bold mt-10">Blog</h1> <h1 className="text-3xl font-bold text-gray-800 dark:text-gray-200">
<div className="w-full h-0.5 bg-white/50 my-4 rounded-full" /> Blog
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> </h1>
<div className="w-full h-0.5 bg-violet-200 dark:bg-white/20 my-4 rounded-full" />
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{posts.map((post, index) => ( {posts.map((post, index) => (
<BlogCard <BlogCard
key={index} key={index}
blog={post.frontMatter as BasicBlogProps} blog={post.frontMatter as BasicArticleProps}
slug={post.slug} slug={post.slug}
/> />
))} ))}
@@ -57,7 +51,7 @@ const Blog = ({ posts }: { posts: BlogPost[] }) => {
}; };
export const getServerSideProps: GetServerSideProps = async () => { export const getServerSideProps: GetServerSideProps = async () => {
const posts = getAllFilesFrontMatter(); const posts = getAllBlogsFrontMatter();
return { return {
props: { props: {
posts, posts,

View File

@@ -3,7 +3,7 @@ export default function Home() {
return ( return (
<MainLayout> <MainLayout>
<div className="grid lg:grid-cols-2 grid-cols-1 xl:mt-10 gap-10 items-center"> <div className="grid lg:grid-cols-2 grid-cols-1 xl:mt-10 gap-10 items-center">
<div className="bg-primary-dark p-10 rounded-lg flex flex-col gap-10 h-fit 3xl:w-2/3 w-full text-lg text-primary-text/90 shadow-lg shadow-gradient-dark/20"> <div className="bg-primary-dark/30 border-white/30 border p-10 rounded-lg flex flex-col gap-10 h-fit 3xl:w-2/3 w-full text-lg text-primary-text/90 shadow-lg shadow-gradient-dark/20">
<div> <div>
<span className="font-bold text-xl text-primary-text"> <span className="font-bold text-xl text-primary-text">
Lorem ipsum dolor{" "} Lorem ipsum dolor{" "}

62
pages/project/[slug].tsx Normal file
View File

@@ -0,0 +1,62 @@
import { GetStaticPaths, GetStaticProps } from "next";
import fs from "fs";
import { ParsedUrlQuery } from "querystring";
import { getProjectContentBySlug, PROJECTS_PATH } from "../../utils/markdown";
import { MarkdownRenderingResult } from "../../types/types";
import { MainLayout } from "../../layouts/MainLayout";
import Link from "next/link";
import { IoMdArrowRoundBack as BackIcon } from "react-icons/io";
import { readingTime } from "../../utils/general";
import { PostHeader } from "../../components/PostHeader";
import { StyledMarkdown } from "../../components/StyledMarkdown";
export const ProjectArticle = ({
frontMatter,
html,
}: MarkdownRenderingResult) => {
return (
<MainLayout>
<div className="rounded-md border border-gray-200 shadow-md shadow-gray-200 dark:shadow-gray-900 dark:border-gray-700 gap-4 bg-black bg-opacity-30 round">
<div className="mx-10 my-10">
<Link href="/projects">
<button className="flex flex-row items-center gap-2 text-primary hover:text-primary-dark dark:text-secondary dark:hover:text-secondary/50 transition-all ease-in duration-75">
<BackIcon />
<span>Go Back</span>
</button>
</Link>
<PostHeader frontMatter={frontMatter} estTime={readingTime(html)} />
<StyledMarkdown html={html} />
</div>
</div>
</MainLayout>
);
};
interface ProjectProps extends ParsedUrlQuery {
slug: string;
}
export const getStaticPaths: GetStaticPaths<ProjectProps> = async () => {
const paths = fs
.readdirSync(PROJECTS_PATH)
.map((path) => path.replace(/\.mdx?$/, ""))
.map((slug) => ({ params: { slug } }));
return {
paths,
fallback: false,
};
};
export const getStaticProps: GetStaticProps<MarkdownRenderingResult> = async ({
params,
}) => {
const markdownContent = getProjectContentBySlug(params?.slug as string);
return {
props: {
frontMatter: markdownContent.frontMatter,
html: markdownContent.content,
},
};
};
export default ProjectArticle;

71
pages/projects/index.tsx Normal file
View File

@@ -0,0 +1,71 @@
import { GetServerSideProps } from "next";
import { MainLayout } from "../../layouts/MainLayout";
import { Post, getAllProjectsFrontMatter } from "../../utils/markdown";
import Link from "next/link";
import { formatDate } from "../../utils/general";
import { BasicArticleProps } from "../../components/PostHeader";
const ProjectCard = ({
project,
slug,
}: {
project: BasicArticleProps;
slug: string;
}) => {
return (
<div className="p-4 rounded-md border border-gray-200 shadow-md shadow-gray-200 dark:shadow-gray-900 dark:border-gray-700 grid grid-cols-1 xl:grid-cols-2 items-center gap-4 bg-black bg-opacity-60">
<div className="order-last xl:order-1">
<div className="text-sm font-medium text-gray-500">
{formatDate(project.date)}
</div>
<h2 className="text-2xl font-bold">{project.title}</h2>
<p className="text-gray-600 dark:text-gray-400 text-sm">
{project.description}
</p>
<Link href={`project/${slug}`}>
<button className="bg-action px-2 py-1 rounded-md mt-4 hover:bg-action/60 transition-all ease-in duration-100 font-bold text-white">
Read more
</button>
</Link>
</div>
{project.thumbnail && (
<img
src={project.thumbnail}
alt={`${slug}-thumbnail`}
className="w-full xl:h-40 h-auto object-cover rounded-md order-1 xl:order-last"
/>
)}
</div>
);
};
const Projects = ({ posts }: { posts: Post[] }) => {
return (
<MainLayout>
<h1 className="text-3xl font-bold text-gray-800 dark:text-gray-100">
Projects
</h1>
<div className="w-full h-0.5 bg-violet-200 dark:bg-white/20 my-4 rounded-full" />
<div className="grid grid-cols-1 gap-4">
{posts.map((post, index) => (
<ProjectCard
key={index}
project={post.frontMatter as BasicArticleProps}
slug={post.slug}
/>
))}
</div>
</MainLayout>
);
};
export const getServerSideProps: GetServerSideProps = async () => {
const posts = getAllProjectsFrontMatter();
return {
props: {
posts,
},
};
};
export default Projects;

View File

@@ -2,6 +2,109 @@
@import "tailwindcss/components"; @import "tailwindcss/components";
@import "tailwindcss/utilities"; @import "tailwindcss/utilities";
html {
scroll-padding-top: 5rem;
scroll-behavior: smooth;
}
body { body {
@apply dark:bg-gradient-dark dark:text-primary-text bg-white text-gradient-dark; @apply dark:bg-gradient-dark dark:text-primary-text bg-slate-100 text-gradient-dark w-full mx-auto;
}
main {
max-width: 800px !important;
margin: auto !important;
}
.prose {
margin: 0;
min-width: 100%;
}
pre {
@apply dark:bg-black/30 bg-slate-200 text-slate-800 dark:text-slate-200 !important;
}
pre > code {
@apply bg-transparent text-gray-700 dark:text-slate-300 !important;
}
.codeStyle {
@apply bg-transparent !important
}
pre > div > div > button > svg:hover {
@apply hover:text-action transition-all ease-in-out duration-100 !important;
}
h1 > a, h2 > a, h3 > a, h4 > a {
@apply cursor-pointer relative text-gray-800 dark:text-gray-100 decoration-transparent font-bold !important;
}
h1 > a:hover::before,
h2 > a:hover::before,
h3 > a:hover::before,
h4 > a:hover::before {
@apply content-['#'] absolute -left-8 text-gray-300 dark:text-gray-400;
}
h2 > a:hover::before {
@apply -left-6;
}
h3 > a:hover::before {
@apply -left-5;
}
h4 > a:hover::before {
@apply -left-4;
}
div > code, pre > code {
@apply p-0 m-0 !important
}
.slider {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.image {
width: 1000px;
height: 600px;
border-radius: 10px;
}
.right-arrow {
position: absolute;
top: 50%;
right: 0%;
font-size: 2rem;
rotate: 180deg;
color: #bdbdbd;
z-index: 10;
cursor: pointer;
user-select: none;
}
.left-arrow {
position: absolute;
top: 50%;
left: -5%;
font-size: 2rem;
color: #bdbdbd;
z-index: 10;
cursor: pointer;
user-select: none;
}
.slide {
opacity: 0;
transition-duration: 0.5s ease;
}
.slide.active {
opacity: 1;
transition-duration: 0.5s;
transform: scale(0.8);
} }

View File

@@ -15,7 +15,7 @@ module.exports = {
secondary: "#FFE600", secondary: "#FFE600",
"primary-text": "#D9D9D9", "primary-text": "#D9D9D9",
}, },
} },
}, },
plugins: [require('@tailwindcss/typography')], plugins: [require("@tailwindcss/typography")],
}; };

View File

@@ -15,6 +15,11 @@
"jsx": "preserve", "jsx": "preserve",
"incremental": true "incremental": true
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"desc.d.ts"
],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }

35
utils/general.ts Normal file
View File

@@ -0,0 +1,35 @@
export const formatDate = (date: string) => {
if (!date) return null;
const [day, month, year] = date.split(".");
const d = new Date(`${year}-${month}-${day}`);
return d.toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
});
};
export const generateSlug = (str: string) => {
str = str?.replace(/^\s+|\s+$/g, "");
str = str?.toLowerCase();
const from = "àáãäâèéëêìíïîòóöôùúüûñç·/_,:;";
const to = "aaaaaeeeeiiiioooouuuunc------";
for (let i = 0, l = from.length; i < l; i++) {
str = str.replace(new RegExp(from.charAt(i), "g"), to.charAt(i));
}
str = str
?.replace(/[^a-z0-9 -]/g, "")
.replace(/\s+/g, "-")
.replace(/-+/g, "-");
return str;
};
export const readingTime = (content: string) => {
const wpm = 225;
const words = content.trim().split(/\s+/).length;
const time = Math.ceil(words / wpm);
return time;
};

View File

@@ -6,8 +6,21 @@ import { remark } from "remark";
import html from "remark-html"; import html from "remark-html";
export const BLOGS_PATH = join(process.cwd(), "content/blogs"); export const BLOGS_PATH = join(process.cwd(), "content/blogs");
export const PROJECTS_PATH = join(process.cwd(), "content/projects");
export interface Post {
frontMatter: FrontMatter;
slug: string;
}
export const getFileContentBySlug = (slug: string): MarkdownDocument => { const getDate = (date: string) => {
if (typeof date === "string") {
const d = date.split(".").map((v) => +v);
return new Date(d[2], d[1] - 1, d[0]);
}
return new Date();
};
export const getBlogContentBySlug = (slug: string): MarkdownDocument => {
const filepath = join(BLOGS_PATH, `${slug}.md` || `${slug}.mdx`); const filepath = join(BLOGS_PATH, `${slug}.md` || `${slug}.mdx`);
const filecontents = fs.readFileSync(filepath); const filecontents = fs.readFileSync(filepath);
@@ -18,21 +31,47 @@ export const getFileContentBySlug = (slug: string): MarkdownDocument => {
content: content, content: content,
}; };
}; };
export const getProjectContentBySlug = (slug: string): MarkdownDocument => {
const filepath = join(PROJECTS_PATH, `${slug}.md` || `${slug}.mdx`);
const filecontents = fs.readFileSync(filepath);
export interface BlogPost { const { data, content } = matter(filecontents);
frontMatter: FrontMatter;
slug: string;
}
export const getAllFilesFrontMatter = (): BlogPost[] => { return {
frontMatter: data,
content: content,
};
};
export const getAllBlogsFrontMatter = (): Post[] => {
const files = fs.readdirSync(BLOGS_PATH); const files = fs.readdirSync(BLOGS_PATH);
return files.reduce((allPosts: BlogPost[], postSlug: string) => { const blogs = files.reduce((allPosts: Post[], postSlug: string) => {
const slug = postSlug.replace(".md", ""); const slug = postSlug.replace(".md", "");
const post = getFileContentBySlug(slug); const post = getBlogContentBySlug(slug);
return [{ frontMatter: post.frontMatter, slug }, ...allPosts]; return [{ frontMatter: post.frontMatter, slug }, ...allPosts];
}, []); }, []);
return blogs.sort(
//@ts-ignore
(a, b) => getDate(b.frontMatter.date) - getDate(a.frontMatter.date)
);
};
export const getAllProjectsFrontMatter = (): Post[] => {
const files = fs.readdirSync(PROJECTS_PATH);
const projects = files.reduce((allPosts: Post[], postSlug: string) => {
const slug = postSlug.replace(".md", "");
const post = getProjectContentBySlug(slug);
return [{ frontMatter: post.frontMatter, slug }, ...allPosts];
}, []);
return projects.sort(
//@ts-ignore
(a, b) => getDate(b.frontMatter.date) - getDate(a.frontMatter.date)
);
}; };
export async function markdownToHtml(markdown: any) { export async function markdownToHtml(markdown: any) {

1716
yarn.lock

File diff suppressed because it is too large Load Diff