diff --git a/.dockerignore b/.dockerignore index 35b7e05..030b614 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,9 +2,12 @@ !.env !next.config.js +!tailwind.config.js +!postcss.config.js !tsconfig.json !package.json !yarn.lock !public !prisma -!src \ No newline at end of file +!src +!data \ No newline at end of file diff --git a/.drone.yml b/.drone.yml index 12a6088..7744e7e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -8,10 +8,10 @@ platform: steps: - name: Test the newest commit - image: node:16-alpine + image: node:lts-alpine volumes: - - name: cache - path: /drone/src/node_modules + - name: cache + path: /drone/src/node_modules commands: - yarn install - yarn run prisma:generate @@ -37,7 +37,7 @@ steps: image: plugins/docker settings: repo: guusvanmeerveld/portfolio - tags: + tags: - latest - latest-amd64 platforms: linux/amd64 @@ -71,4 +71,4 @@ steps: from_secret: docker_password depends_on: - - test \ No newline at end of file + - test diff --git a/.env b/.env index bcaa995..8d0830a 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ DATABASE_URL=postgresql://portfolio:portfolio@localhost:5432/portfolio?schema=public -LANDING_JSON_LOCATION=./landing.json \ No newline at end of file +DATA_DIR=./data \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index cf57695..dff6158 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,8 @@ RUN addgroup -g 1001 -S nodejs RUN adduser -S nextjs -u 1001 COPY --from=builder /app/next.config.js ./ +COPY --from=builder /app/postcss.config.js ./ +COPY --from=builder /app/tailwind.config.js ./ COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next COPY --from=builder /app/node_modules ./node_modules diff --git a/data/avatar.jpg b/data/avatar.jpg new file mode 100644 index 0000000..89ae870 Binary files /dev/null and b/data/avatar.jpg differ diff --git a/data/landing.json b/data/landing.json new file mode 100644 index 0000000..f7df63a --- /dev/null +++ b/data/landing.json @@ -0,0 +1,49 @@ +{ + "header": { + "fullName": "Guus van Meerveld", + "name": "guus", + "description": "AI student at Radboud University. Creating software as a hobby.", + "contact": { + "email": "contact@guusvanmeerveld.dev", + "git": "https://github.com/Guusvanmeerveld", + "linkedin": "https://linkedin.com/in/guus-van-meerveld-038357210" + } + }, + "projects": [ + { + "name": "Dust-Mail", + "avatarUrl": "https://avatars.githubusercontent.com/u/130915639?s=200&v=4", + "description": "Dust-Mail is a free and open source project that aims to replace all desktop and web email clients by providing a fast and simple experience.", + "url": "https://github.com/Dust-Mail/" + }, + { + "name": "Argo-Client", + "avatarUrl": "https://avatars.githubusercontent.com/u/71986232?s=200&v=4", + "description": "Argo is a modern client for Magister 6 that is available for Android and IOS.", + "url": "https://argo-magister.nl" + }, + { + "name": "MaterialTube", + "avatarUrl": "https://raw.githubusercontent.com/Guusvanmeerveld/MaterialTube/master/src/svg/logo.svg", + "description": "MaterialTube is a beautiful and elegant web client for Invidious servers, built using Next.js and MUI.", + "url": "https://github.com/Guusvanmeerveld/MaterialTube" + } + ], + "footer": { + "columns": [ + { + "title": "Built with", + "links": [ + { "url": "https://nextjs.org/", "text": "Next.js" }, + { "url": "https://nextui.org/", "text": "NextUI" } + ] + }, + { + "title": "Social", + "links": [ + { "url": "https://github.com/Guusvanmeerveld", "text": "Github" } + ] + } + ] + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 616a026..0d3327c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,15 @@ version: "3" services: - # app: - # build: . - # container_name: portfolio - # environment: - # NEXT_PUBLIC_GITEA_USERNAME: "Guusvanmeerveld" - # NEXT_PUBLIC_GITEA_SERVER: "git.guusvanmeerveld.dev" - # SESSION_PASSWORD: "jsdlakfjad;slkfjepoweaur3290r830-q998-039jaklfjdkl" - # NEXT_PUBLIC_ALLOW_REGISTRATION: true - # DATABASE_URL: "postgres://portfolio:portfolio@db:5432/portfolio" - # ports: - # - 3000:3000 + app: + build: . + container_name: portfolio + volumes: + - ./data:/app/data + environment: + DATABASE_URL: "postgres://portfolio:portfolio@db:5432/portfolio" + ports: + - 3000:3000 db: image: postgres:14 @@ -25,5 +23,5 @@ services: volumes: - db:/var/lib/postgresql/data -volumes: - db: \ No newline at end of file +volumes: + db: diff --git a/landing.json b/landing.json deleted file mode 100644 index 1561195..0000000 --- a/landing.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "owner": { - "fullName": "Guus van Meerveld", - "name": "guus", - "description": "AI student at Radboud University. Creating software as a hobby.", - "contact": { - "email": "contact@guusvanmeerveld.dev", - "git": "https://github.com/Guusvanmeerveld", - "linkedin": "https://linkedin.com/in/guus-van-meerveld-038357210" - } - } -} \ No newline at end of file diff --git a/package.json b/package.json index 749e308..8446bd8 100644 --- a/package.json +++ b/package.json @@ -16,22 +16,24 @@ "full-test": "yarn test-build && yarn lint && yarn stylelint" }, "dependencies": { - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.0", - "@mui/material": "^5.15.11", + "@nextui-org/react": "^2.2.10", "@prisma/client": "4.10.1", "@tanstack/react-query": "^4.24.9", "axios": "^1.1.2", "bcrypt": "^5.1.0", + "framer-motion": "^11.0.8", "fs-extra": "^11.2.0", "iron-session": "^6.3.1", - "next": "^12.1.0", - "next-seo": "^4.24.0", + "next": "^14.1.1", "next-themes": "^0.2.1", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-icons": "^5.0.1", "timeago.js": "^4.0.2", - "zod": "^3.20.6" + "zod": "^3.20.6", + "autoprefixer": "^10.4.18", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1" }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.0.0", diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..054c147 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {} + } +}; diff --git a/src/app/(landing)/Header.tsx b/src/app/(landing)/Header.tsx new file mode 100644 index 0000000..7740c86 --- /dev/null +++ b/src/app/(landing)/Header.tsx @@ -0,0 +1,82 @@ +"use client"; + +import { Button } from "@nextui-org/button"; +import { Image } from "@nextui-org/image"; +import { Spacer } from "@nextui-org/react"; +import { Tooltip } from "@nextui-org/tooltip"; +import { Component } from "@typings/component"; +import Link from "next/link"; + +import { useMemo } from "react"; +import { FiGithub, FiMail, FiLinkedin } from "react-icons/fi"; + +import HeaderProps from "@models/header"; + +export const Header: Component<{ data: HeaderProps; avatar: string }> = ({ + data, + avatar +}) => { + const socials = useMemo( + () => [ + { + link: `mailto:${data.contact.email}`, + name: "Email address", + icon: + }, + { + link: data.contact.git, + name: "Github", + icon: + }, + { + link: data.contact.linkedin, + name: "LinkedIn", + icon: + } + ], + [data.contact] + ); + + return ( +
+
+ {`A + + + +
+

{data.fullName}

+ + +

{data.description}

+ + + {socials.map((social) => ( + + + + ))} +
+
+
+ ); +}; diff --git a/src/app/(landing)/Projects.tsx b/src/app/(landing)/Projects.tsx new file mode 100644 index 0000000..86c49ba --- /dev/null +++ b/src/app/(landing)/Projects.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { Card, CardHeader, CardBody, CardFooter } from "@nextui-org/card"; +import { Divider } from "@nextui-org/divider"; +import { Image } from "@nextui-org/image"; +import { Link } from "@nextui-org/link"; +import { Spacer } from "@nextui-org/spacer"; +import { Component } from "@typings/component"; + +import ProjectProps from "@models/project"; + +export const Projects: Component<{ data: ProjectProps[] }> = ({ data }) => { + return ( + <> +
+

Projects

+ +
+ {data.map((project) => { + const url = new URL(project.url); + + return ( + + + {`${project.name} +
+

{project.name}

+

{url.host}

+
+
+ + +

{project.description}

+
+ + + + Visit the project. + + +
+ ); + })} +
+
+ + + ); +}; diff --git a/src/app/(landing)/page.tsx b/src/app/(landing)/page.tsx new file mode 100644 index 0000000..9d7dd0d --- /dev/null +++ b/src/app/(landing)/page.tsx @@ -0,0 +1,22 @@ +import { Footer } from "../Footer"; +import { Header } from "./Header"; +import { Projects } from "./Projects"; + +import { dataDirLocation } from "@utils/constants"; +import { readAvatarFile, readLandingJson } from "@utils/landing"; + +export default async function Page() { + // Any error will get handled by the `error.tsx` file. + const landing = await readLandingJson(dataDirLocation); + const avatar = await readAvatarFile(dataDirLocation); + + return ( + <> +
+ +