Compare commits

..

98 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
Rei
bc51e625b4 dynamic markdown
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-27 17:33:00 +01:00
16a53e169a Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-27 00:32:13 +01:00
4a963d1a73 Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-27 00:17:04 +01:00
15b4ae915f Add '.drone.yml'
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build is failing
2022-12-27 00:01:31 +01:00
Rei
1a29c39741 organized asf 2022-12-26 14:24:16 +01:00
rei
93dc624378 initial page 2022-12-23 00:39:52 +01:00
Rei
fa6921abe2 tailwind init 2022-12-07 18:28:34 +01:00
Rei
575f65be91 init project 2022-12-07 18:26:26 +01:00
45 changed files with 12063 additions and 1 deletions

41
.drone.yml Normal file
View File

@@ -0,0 +1,41 @@
---
kind: pipeline
name: prod-pipe
steps:
- name: prod
image: docker/compose
volumes:
- name: docker_socket
path: /var/run/docker.sock
commands:
- docker-compose -f docker-compose.yml up --build --force-recreate -d
trigger:
branch:
- 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

37
.gitignore vendored Normal file
View File

@@ -0,0 +1,37 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
/content/projects/markdown-test.md
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

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"]

View File

@@ -1 +1,34 @@
Hey
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

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>
);
};

75
components/Navbar.tsx Normal file
View File

@@ -0,0 +1,75 @@
import Link from "next/link";
import { IoMenu as MenuIcon, IoClose as CloseIcon } from "react-icons/io5";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Logo } from "./Logo";
const links = [
{ name: "Blog", href: "/blog" },
{ name: "Projects", href: "/projects" },
{ name: "Gitea", href: "https://git.peroxy.dev/kookroach" },
];
export const Navbar = () => {
const [showMenu, setShowMenu] = useState(false);
return (
<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
href="/"
id="logo"
className="flex flex-row gap-2 items-center group"
>
<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>
<div className="hidden xl:flex flex-row gap-10 items-center font-medium font-mono">
{links.map(({ name, href }) => (
<Link href={href} key={name}>
<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}
</button>
</Link>
))}
</div>
<div className="xl:hidden flex">
<button onClick={() => setShowMenu(true)} className="text-2xl">
<MenuIcon />
</button>
</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>
);
};

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

@@ -0,0 +1,21 @@
---
title: "My First Blog"
date: 27.12.2022
author: kookroach
authorLink: https://git.peroxy.dev/kookroach
description: Short description
---
# First blog
Insane
test change
# Header 1 test
## Header 2 test
### Header 3 test
#### Header 4 test

View File

@@ -0,0 +1,10 @@
---
title: "My Second Blog"
date: 27.12.2022
author: kookroach
description: Short description
---
# Secoond blog
Insane

View File

@@ -0,0 +1,10 @@
---
title: "My Third Blog (TEST)"
date: 27.12.2022
author: kookroach
description: Short description
---
# Third blog
Insane

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

13
layouts/MainLayout.tsx Normal file
View File

@@ -0,0 +1,13 @@
import { PropsWithChildren } from "react";
import { R3Gradient } from '../components/R3Background';
import { Navbar } from "../components/Navbar";
export const MainLayout = ({ children }: PropsWithChildren) => {
return (
<div className="w-full">
<Navbar />
<R3Gradient />
<main className="xl:p-5 p-4 px-5 xl:mx-0">{children}</main>
</div>
);
};

7
next.config.js Normal file
View File

@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
}
module.exports = nextConfig

7597
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

49
package.json Normal file
View File

@@ -0,0 +1,49 @@
{
"name": "peroxy_site",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"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",
"@types/node": "18.11.11",
"@types/react": "18.0.26",
"@types/react-dom": "18.0.9",
"@types/three": "^0.149.0",
"framer-motion": "^8.0.2",
"gray-matter": "^4.0.3",
"next": "13.0.6",
"parse-numeric-range": "^1.3.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"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-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-smartypants": "^2.0.0",
"three": "^0.149.0",
"typescript": "4.9.3"
},
"devDependencies": {
"@types/react-syntax-highlighter": "^15.5.5",
"autoprefixer": "^10.4.13",
"postcss": "^8.4.19",
"tailwindcss": "^3.2.4"
}
}

6
pages/_app.tsx Normal file
View File

@@ -0,0 +1,6 @@
import '../styles/globals.css'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

13
pages/api/hello.ts Normal file
View File

@@ -0,0 +1,13 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

57
pages/blog/[slug].tsx Normal file
View File

@@ -0,0 +1,57 @@
import { GetStaticPaths, GetStaticProps } from "next";
import fs from "fs";
import { ParsedUrlQuery } from "querystring";
import { BLOGS_PATH, getBlogContentBySlug } 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 { PostHeader } from "../../components/PostHeader";
import { readingTime } from "../../utils/general";
import { StyledMarkdown } from "../../components/StyledMarkdown";
export const BlogArticle = ({ 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 mt-5 mb-10">
<Link href="/blog">
<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 BlogProps extends ParsedUrlQuery {
slug: string;
}
export const getStaticPaths: GetStaticPaths<BlogProps> = async () => {
const paths = fs
.readdirSync(BLOGS_PATH)
.map((path) => path.replace(/\.mdx?$/, ""))
.map((slug) => ({ params: { slug } }));
return {
paths,
fallback: false,
};
};
export const getStaticProps: GetStaticProps<MarkdownRenderingResult> = async ({
params,
}) => {
const markdownContent = getBlogContentBySlug(params?.slug as string);
return {
props: {
frontMatter: markdownContent.frontMatter,
html: markdownContent.content,
},
};
};
export default BlogArticle;

62
pages/blog/index.tsx Normal file
View File

@@ -0,0 +1,62 @@
import { GetServerSideProps } from "next";
import { MainLayout } from "../../layouts/MainLayout";
import { Post, getAllBlogsFrontMatter } from "../../utils/markdown";
import Link from "next/link";
import { formatDate } from "../../utils/general";
import { BasicArticleProps } from "../../components/PostHeader";
const BlogCard = ({
blog,
slug,
}: {
blog: 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 bg-black bg-opacity-60">
<div className="text-sm font-medium text-gray-500">
{formatDate(blog.date)}
</div>
<h2 className="text-2xl font-bold">{blog.title}</h2>
<p className="text-gray-600 dark:text-gray-400 text-sm">
{blog.description}
</p>
<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">
Read more
</button>
</Link>
</div>
);
};
const Blog = ({ posts }: { posts: Post[] }) => {
return (
<MainLayout>
<h1 className="text-3xl font-bold text-gray-800 dark:text-gray-200">
Blog
</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) => (
<BlogCard
key={index}
blog={post.frontMatter as BasicArticleProps}
slug={post.slug}
/>
))}
</div>
</MainLayout>
);
};
export const getServerSideProps: GetServerSideProps = async () => {
const posts = getAllBlogsFrontMatter();
return {
props: {
posts,
},
};
};
export default Blog;

26
pages/index.tsx Normal file
View File

@@ -0,0 +1,26 @@
import { MainLayout } from "../layouts/MainLayout";
export default function Home() {
return (
<MainLayout>
<div className="grid lg:grid-cols-2 grid-cols-1 xl:mt-10 gap-10 items-center">
<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>
<span className="font-bold text-xl text-primary-text">
Lorem ipsum dolor{" "}
</span>{" "}
sit amet consectetur adipisicing elit. Laboriosam ab quia quae
reiciendis. Nostrum corrupti laboriosam quae vero repudiandae
dolorem quos dolores laborum recusandae atque itaque illo autem
neque odit, in soluta sit alias necessitatibus fugit veniam sunt at.
</div>
<button className="px-4 py-2 rounded-lg bg-primary hover:bg-primary/50 transition-all ease-out duration-150 font-bold w-fit text-white">
Action
</button>
</div>
<div id="showcase" className="w-full h-96 bg-primary-text">
<div className="text-primary-dark m-auto w-fit">showcase</div>
</div>
</div>
</MainLayout>
);
}

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;

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

4
public/vercel.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

110
styles/globals.css Normal file
View File

@@ -0,0 +1,110 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
html {
scroll-padding-top: 5rem;
scroll-behavior: smooth;
}
body {
@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);
}

21
tailwind.config.js Normal file
View File

@@ -0,0 +1,21 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
"gradient-dark": "#161926",
"gradient-light": "#1b2034",
primary: "#1E96FC",
"primary-dark": "#1B264F",
action: "#FF3366",
secondary: "#FFE600",
"primary-text": "#D9D9D9",
},
},
},
plugins: [require("@tailwindcss/typography")],
};

25
tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"desc.d.ts"
],
"exclude": ["node_modules"]
}

13
types/types.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
export interface FrontMatter {
[prop: string]: string;
}
export interface MarkdownDocument {
frontMatter: FrontMatter;
content: string;
}
export interface MarkdownRenderingResult {
frontMatter: FrontMatter;
html: string;
}

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;
};

86
utils/markdown.ts Normal file
View File

@@ -0,0 +1,86 @@
import matter from "gray-matter";
import { join } from "path";
import fs from "fs";
import { FrontMatter, MarkdownDocument } from "../types/types";
import { remark } from "remark";
import html from "remark-html";
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;
}
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 filecontents = fs.readFileSync(filepath);
const { data, content } = matter(filecontents);
return {
frontMatter: data,
content: content,
};
};
export const getProjectContentBySlug = (slug: string): MarkdownDocument => {
const filepath = join(PROJECTS_PATH, `${slug}.md` || `${slug}.mdx`);
const filecontents = fs.readFileSync(filepath);
const { data, content } = matter(filecontents);
return {
frontMatter: data,
content: content,
};
};
export const getAllBlogsFrontMatter = (): Post[] => {
const files = fs.readdirSync(BLOGS_PATH);
const blogs = files.reduce((allPosts: Post[], postSlug: string) => {
const slug = postSlug.replace(".md", "");
const post = getBlogContentBySlug(slug);
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) {
const result = await remark().use(html).process(markdown);
return result.toString();
}
export const renderMarkdown = async (
markdownContent: string
): Promise<string> => {
return await markdownToHtml(markdownContent || "");
};

2732
yarn.lock Normal file

File diff suppressed because it is too large Load Diff