Compare commits

...

90 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
rei
e46339c7a7 small change
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-28 20:46:53 +01:00
rei
2c88713ab6 logo nav mobile 2022-12-28 20:33:40 +01:00
rei
6c993511bf mobile navigation 2022-12-28 20:32:16 +01:00
rei
e3d98b4e32 logo 2022-12-28 20:24:15 +01:00
36 changed files with 10417 additions and 344 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>
);
};

102
components/Logo.tsx Normal file
View File

@@ -0,0 +1,102 @@
export const Logo = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
id="svg166"
version="1.1"
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"
>
<g id="167217677994600400">
<path
id="path119"
d="M108.79 15a1 1 0 0 0 .59 1.29c9.72 3.6 15.07 8.12 15.07 12.72a1 1 0 0 0 2 0c0-5.57-5.66-10.62-16.37-14.6a1 1 0 0 0-1.29.59Z"
/>
<path
id="path121"
d="M120.92 35.51a1 1 0 0 0-1.13 1.65c3.79 2.59 5.71 5.32 5.71 8.09a1 1 0 0 0 2 0c0-3.47-2.21-6.75-6.58-9.74z"
/>
<path
id="path123"
d="M112.9 48.45a1 1 0 1 0-.75 1.85c8.61 3.49 13.35 7.77 13.35 12.06a1 1 0 1 0 2 0c0-5.23-5.05-10.04-14.6-13.91z"
/>
<path
id="path125"
d="M125.45 80.52a1 1 0 0 0 1-1c0-6.42-7.62-12.2-21.46-16.28a1 1 0 1 0-.56 1.91c12.72 3.76 20 9 20 14.37a1 1 0 0 0 1.02 1z"
/>
<path
id="path127"
d="M32.89 98.39h.19a1 1 0 0 0 .37-.08h.08a.83.83 0 0 0 .22-.14l.09-.1a.76.76 0 0 0 .12-.19.84.84 0 0 0 .06-.14v-.12a.27.27 0 0 0 0-.09V62.47c3.92-.71 8.06-1.27 12.35-1.68v11.07a1 1 0 0 0 .22.63l8.2 10.09v10a93.19 93.19 0 0 0-23.09 11.2 101.78 101.78 0 0 0-18.31 15.17 1 1 0 0 0 .72 1.69 1 1 0 0 0 .73-.31 99.86 99.86 0 0 1 18-14.88 88.68 88.68 0 0 1 32-13.37 1.0179 1.0179 0 0 0-.38-2c-2.67.53-5.19 1.16-7.58 1.86v-9.71a1 1 0 0 0-.22-.63l-8.2-10.1V59.64a.83.83 0 0 0 0-.15.74.74 0 0 0 0-.14v-.08a.76.76 0 0 0-.08-.11l-.27-.16a.27.27 0 0 1-.08-.07l-2.93-2 3.27-7.05a.58.58 0 0 0 0-.19.71.71 0 0 0 0-.2V47a16.75 16.75 0 1 1 33.5 0v46.3a1 1 0 1 0 2 0v-3.65c11.28-.13 19.27 2.68 23.73 8.35a20 20 0 0 1 3.87 9.31v11.22H30.38a1 1 0 1 0 0 2h82.15a1 1 0 0 0 1-1v-12.29a.78.78 0 0 0 0-.16 21.86 21.86 0 0 0-4.28-10.32c-4.86-6.18-13.38-9.24-25.3-9.11v-26.5a136.18 136.18 0 0 1 15.95 2.78h.23a1 1 0 0 0 1-.76 1 1 0 0 0-.74-1.21c-1.84-.45-3.78-.85-5.74-1.23V45.44a106.09 106.09 0 0 1 11.71 2.81 1 1 0 0 0 .29 0 1 1 0 0 0 .3-1.95 108 108 0 0 0-12.3-2.94V28.33l1.73.32a80 80 0 0 1 19.57 6.24.93.93 0 0 0 .45.11 1 1 0 0 0 .89-.55 1 1 0 0 0-.44-1.34 81.26 81.26 0 0 0-20.08-6.42l-2.12-.4v-14c2.23.44 4.42.91 6.51 1.45a1.0017 1.0017 0 1 0 .5-1.94 157.17 157.17 0 0 0-38.19-4.33C28.16 7.47.5 16.92.5 29v50.52c0 8.03 12.11 15.08 32.39 18.87zM63.47 9.47a167.36 167.36 0 0 1 29.14 2.41v48.51c-2.79-.49-5.69-.91-8.68-1.25V46.83a18.7502 18.7502 0 0 0-37.5.17v2.14l-3.53 7.63a1 1 0 0 0 .34 1.23l1.38 1c-3.64.38-7.17.88-10.54 1.48V46.77a1.16 1.16 0 0 0 0-.18 1.08 1.08 0 0 0-.08-.19 1.16 1.16 0 0 0-.25-.29l-.19-.11a1.89 1.89 0 0 0-.21-.09h-.09C14.57 42.41 2.5 35.77 2.5 29c0-10.59 27.92-19.53 60.97-19.53Zm-61 25c4.14 5.57 14.55 10.29 29.58 13.2V96.2c-18-3.55-29.58-10-29.58-16.68Z"
/>
<path
id="path129"
d="M56.59 63.16a1.0098 1.0098 0 0 0 .28 2 1 1 0 0 0 .29 0 8.51 8.51 0 0 0 3.92-2.43c2.29-2.55 3.39-6.87 1.16-9.41a6.25 6.25 0 0 0-4.9-1.82 1 1 0 0 0 0 2 4.36 4.36 0 0 1 3.35 1.14c1.43 1.64.54 4.87-1.15 6.75a6.55 6.55 0 0 1-2.95 1.77z"
/>
<path
id="path131"
d="M40.93 30a1 1 0 0 0 .75-.33 1 1 0 0 0-.08-1.41L38 25.07a1 1 0 1 0-1.33 1.49l3.55 3.18a1 1 0 0 0 .71.26Z"
/>
<path
id="path133"
d="M43.86 30.27a1 1 0 1 0-1.33 1.49L45 33.92a1 1 0 0 0 .67.26 1 1 0 0 0 .75-.34 1 1 0 0 0-.08-1.41z"
/>
<path
id="path135"
d="M16.82 25.61 27 31a1 1 0 0 0 .46.12 1 1 0 0 0 .89-.53 1 1 0 0 0-.42-1.36l-8.13-4.28a98.46 98.46 0 0 1 11.66-3l3.15 2.8a1 1 0 0 0 1.33-1.49l-2-1.79c3.2-.58 6.54-1.07 10-1.45.92-.1 1.87-.18 2.8-.27l1.2 3.83a1 1 0 0 0 .95.7 1 1 0 0 0 .3 0 1 1 0 0 0 .66-1.26l-1.08-3.42c2.37-.2 4.79-.33 7.22-.42l.16 1.81a1 1 0 0 0 1 .91h.09a1 1 0 0 0 .9-1.09L58 19c1.82-.06 3.66-.09 5.5-.09a1 1 0 0 0 0-2c-2.22 0-4.42.05-6.61.13h-.12c-4.44.16-8.81.46-13 .93a115.63 115.63 0 0 0-26.76 5.84 1 1 0 0 0-.65.87 1 1 0 0 0 .46.93z"
/>
<path
id="path137"
d="M33.79 34.56a1.12 1.12 0 0 0 .47.11 1 1 0 0 0 .88-.53 1 1 0 0 0-.41-1.35l-3.66-1.93a1.002 1.002 0 0 0-.94 1.77z"
/>
<path
id="path139"
d="m44.28 37.82-6-3.18a1 1 0 1 0-.93 1.77l6 3.18a.92.92 0 0 0 .46.11 1 1 0 0 0 .47-1.88z"
/>
<path
id="path141"
d="m9 32.13 4.68 2a1.09 1.09 0 0 0 .39.08 1 1 0 0 0 .39-1.92l-4.68-2A1 1 0 0 0 9 32.13Z"
/>
<path
id="path143"
d="M43.08 44.33 20 34.6a1 1 0 1 0-.77 1.84l23.07 9.74a1 1 0 0 0 .38.08 1 1 0 0 0 .39-1.93z"
/>
<path
id="path145"
d="M51 26.68a1.001 1.001 0 0 0-1.91.6l.72 2.28a1 1 0 0 0 1 .71 1 1 0 0 0 .3-.05 1 1 0 0 0 .62-1.22z"
/>
<path
id="path147"
d="M57.32 22.93a1 1 0 0 0-.9 1.09l.28 3.05a1 1 0 0 0 1 .91h.09a1 1 0 0 0 .9-1.09l-.28-3.06a1 1 0 0 0-1.09-.9z"
/>
<path
id="path149"
d="M82.93 105.09a1 1 0 0 0 1-1l.13-4.31a1.0004 1.0004 0 0 0-2-.06l-.13 4.31a1 1 0 0 0 1 1z"
/>
<path
id="path151"
d="M25.12 55c0 .07.06.12.09.18l.13.15a1.21 1.21 0 0 0 .32.22 1 1 0 0 0 .39.07 1 1 0 0 0 .7-.29l.13-.15c0-.06.06-.11.09-.18l.06-.18a1.36 1.36 0 0 0 0-.2 1 1 0 0 0-.3-.7.87.87 0 0 0-.32-.22 1 1 0 0 0-.77 0 .87.87 0 0 0-.32.22 1 1 0 0 0-.29.7.68.68 0 0 0 0 .2 1.21 1.21 0 0 0 .09.18z"
/>
<path
id="path153"
d="M25.66 60.29a1 1 0 0 0 .39.07 1 1 0 1 0-.39-1.92 1 1 0 0 0-.32.21 1 1 0 0 0 0 1.42 1.21 1.21 0 0 0 .32.22z"
/>
<path
id="path155"
d="M25.66 65.06a1.09 1.09 0 0 0 .39.08 1 1 0 0 0 1-1 1 1 0 0 0-.08-.38.91.91 0 0 0-.22-.33 1 1 0 0 0-1.09-.21 1 1 0 0 0-.32.21 1.06 1.06 0 0 0-.22.33 1 1 0 0 0-.07.38 1 1 0 0 0 .29.71 1 1 0 0 0 .32.21z"
/>
<path
id="path157"
d="M78.41 53.24a1.51 1.51 0 0 0 .18.09.64.64 0 0 0 .18.06h.2a1 1 0 0 0 .71-.3 1 1 0 0 0 .29-.7 1 1 0 0 0-.29-.71 1.19 1.19 0 0 0-.33-.22 1 1 0 0 0-.58 0h-.18l-.18.1a.79.79 0 0 0-.15.12 1 1 0 0 0-.29.71 1 1 0 0 0 .29.7z"
/>
<path
id="path159"
d="m78.26 57.89.15.13.18.09.18.06h.2a1 1 0 0 0 .71-.3 1 1 0 0 0 .29-.7 1 1 0 0 0-.29-.71 1.19 1.19 0 0 0-.33-.22 1 1 0 0 0-.58 0h-.18l-.18.09-.15.13a1 1 0 0 0-.29.71 1 1 0 0 0 .29.72z"
/>
<path
id="path161"
d="M78 62.16a.7.7 0 0 0 .06.19.56.56 0 0 0 .09.17.88.88 0 0 0 .12.15l.15.13.18.09.18.06H79a1 1 0 0 0 .38-.07 1.19 1.19 0 0 0 .33-.22l.12-.15a.56.56 0 0 0 .09-.17.7.7 0 0 0 .06-.19A1.23 1.23 0 0 0 80 62a1 1 0 0 0-.08-.39 1 1 0 0 0-.21-.32 1.19 1.19 0 0 0-.33-.22 1 1 0 0 0-1.09.22 1 1 0 0 0-.21.32.88.88 0 0 0-.08.39 1.23 1.23 0 0 0 0 .16z"
/>
</g>
</svg>
);
};

View File

@@ -2,69 +2,74 @@ import Link from "next/link";
import { IoMenu as MenuIcon, IoClose as CloseIcon } from "react-icons/io5"; import { IoMenu as MenuIcon, IoClose as CloseIcon } from "react-icons/io5";
import { useState } from "react"; import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
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://github.com/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-end transition-all ease-in duration-100 text-action hover:text-secondary" className="flex flex-row gap-2 items-center group"
> >
<div className="font-bold text-4xl font-mono">peroxy</div> <Logo />
<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
<span className="xl:text-sm text-xs">.dev</span>
</div>
</Link> </Link>
<div className="hidden lg: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>
))} ))}
</div> </div>
<div className="lg:hidden flex"> <div className="xl:hidden flex">
<button onClick={() => setShowMenu(true)} className="text-2xl"> <button onClick={() => setShowMenu(true)} className="text-2xl">
<MenuIcon /> <MenuIcon />
</button> </button>
<AnimatePresence>
{showMenu && (
<>
<motion.div
className="absolute left-0 top-0 h-screen w-screen bg-black/70 z-10"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
/>
<motion.div
className={`z-40 absolute w-1/2 bg-blue-900
right-0 top-0 px-10 py-6 h-screen`}
initial={{ x: 100 }}
animate={{ x: 0 }}
exit={{ x: 100 }}
transition={{ duration: 0.3 }}
>
<button onClick={() => setShowMenu(false)} className="text-2xl">
<CloseIcon />
</button>
<div className="flex flex-col gap-10 mt-10 font-bold font-mono">
{links.map(({ name, href }) => (
<Link href={href} key={name}>
<button>{name}</button>
</Link>
))}
</div>
</motion.div>
</>
)}
</AnimatePresence>
</div> </div>
<AnimatePresence>
{showMenu && (
<div className="fixed h-screen w-screen top-0 left-0">
<motion.div
className="absolute left-0 top-0 h-full w-full bg-black/70 z-10"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
/>
<motion.div
className={`z-40 absolute w-1/2 bg-blue-900 text-primary-text
right-0 top-0 px-10 py-6 h-full`}
initial={{ x: "100%" }}
animate={{ x: 0 }}
exit={{ x: "100%" }}
transition={{ ease: "easeInOut", duration: 0.4 }}
>
<button onClick={() => setShowMenu(false)} className="text-2xl">
<CloseIcon />
</button>
<div className="flex flex-col gap-10 mt-10 font-bold font-mono">
{links.map(({ name, href }) => (
<Link href={href} key={name}>
<button>{name}</button>
</Link>
))}
</div>
</motion.div>
</div>
)}
</AnimatePresence>
</nav> </nav>
); );
}; };

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

@@ -2,9 +2,20 @@
title: "My First Blog" title: "My First Blog"
date: 27.12.2022 date: 27.12.2022
author: kookroach author: kookroach
authorLink: https://git.peroxy.dev/kookroach
description: Short description 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="mx-10">{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,36 +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 { 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) => {
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>
{frontMatter.date} </Link>
<PostHeader frontMatter={frontMatter} estTime={readingTime(html)} />
<StyledMarkdown html={html} />
</div>
</div> </div>
<div className="lg:text-5xl font-bold">{frontMatter.title}</div>
<div className="mt-2 font-medium">
By: <span className="text-action">@{frontMatter.author}</span>
</div>
<div
className="mt-4 prose prose-headings:text-primary-text prose-p:text-gray-400"
dangerouslySetInnerHTML={{ __html: html }}
/>
</MainLayout> </MainLayout>
); );
}; };
@@ -52,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,33 +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";
interface BasicBlogProps extends FrontMatter { const BlogCard = ({
title: string; blog,
description: string; slug,
date: string; }: {
author: string; blog: BasicArticleProps;
} 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
@@ -37,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}
/> />
))} ))}
@@ -56,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

@@ -2,8 +2,8 @@ import { MainLayout } from "../layouts/MainLayout";
export default function Home() { export default function Home() {
return ( return (
<MainLayout> <MainLayout>
<div className="grid lg:grid-cols-2 grid-cols-1 mt-4 lg:mt-20 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 lg: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