diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8232be8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +** + +!next.config.js +!tsconfig.json +!package.json +!yarn.lock +!public +!src \ No newline at end of file diff --git a/.env b/.env index 50e1332..873ff8e 100644 --- a/.env +++ b/.env @@ -1,5 +1 @@ -VITE_GITHUB_USERNAME=Guusvanmeerveld -VITE_TWITTER_USERNAME=Guusvanmeerveld -VITE_KOFI_USERNAME=Guusvanmeerveld -VITE_YOUTUBE_CHANNEL_ID=UCYuqpoMay5SezCBrA_HKVWQ -VITE_MASTODON_URL=https://c.im/web/@guusvanmeerveld \ No newline at end of file +NEXT_PUBLIC_GITHUB_USERNAME=Guusvanmeerveld \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..33ff97e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,67 @@ +{ + "root": true, + "env": { + "node": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 8 + }, + "plugins": [ + "prettier", + "css-modules" + ], + "ignorePatterns": [ + "node_modules/*", + ".next/*", + ".out/*" + ], + "extends": [ + "eslint:recommended", + "plugin:css-modules/recommended" + ], + "overrides": [ + { + "files": [ + "**/*.ts", + "**/*.tsx" + ], + "parser": "@typescript-eslint/parser", + "settings": { + "react": { + "version": "detect" + } + }, + "env": { + "browser": true, + "node": true, + "es6": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:jsx-a11y/recommended" + ], + "rules": { + "prettier/prettier": "error", + "react/prop-types": "off", + "react/react-in-jsx-scope": "off", + "jsx-a11y/anchor-is-valid": "off", + "jsx-a11y/no-autofocus": "off", + "@typescript-eslint/no-unused-vars": [ + "error" + ], + "@typescript-eslint/explicit-function-return-type": [ + "warn", + { + "allowExpressions": true, + "allowConciseArrowFunctionExpressionsStartingWithVoid": true, + "allowTypedFunctionExpressions": true + } + ] + } + } + ] +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3a3cce5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml new file mode 100644 index 0000000..d10dbec --- /dev/null +++ b/.github/workflows/auto-merge.yml @@ -0,0 +1,20 @@ +name: Auto-merge dependabot + +on: + pull_request: + +permissions: + pull-requests: write + +jobs: + auto-merge: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + name: Checkout + + - uses: ahmadnassri/action-dependabot-auto-merge@v2 + name: Auto merge + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..63b66c3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,45 @@ +name: deploy + +on: + push: + branches: + - master + +jobs: + typescript: + runs-on: ubuntu-latest + steps: + - name: Setup checkout + uses: actions/checkout@v2 + - name: Setup NodeJS v12 + uses: actions/setup-node@v1 + with: + node-version: 16 + - name: Install Dependencies + run: yarn install + - name: Check for syntax errors + run: yarn test-build + - name: ESlint check + run: yarn lint + + docker: + runs-on: ubuntu-latest + needs: typescript + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build Dockerfile and push + id: docker_build + uses: docker/build-push-action@v2 + with: + push: true + tags: guusvanmeerveld/portfolio:latest + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 9707178..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: "Deploy website" - -on: - push: - branches: - - main - paths: - - src/** - - package.json - - yarn.lock - - tsconfig.* - - vite.config.ts - - .env - - index.html - - public - -jobs: - deploy_to_pages: - name: Build pages - runs-on: ubuntu-latest - steps: - - name: Setup - uses: actions/checkout@v2 - - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: "16.x" - cache: "yarn" - - - name: Install NPM dependencies - run: yarn install - - - name: Build client - run: yarn run build - - - name: Deploy to pages - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./dist - cname: guusvanmeerveld.dev diff --git a/.gitignore b/.gitignore index a547bf3..c81e972 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,4 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? +.env.local +.next +yarn-error.log \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index de0f127..0000000 --- a/.prettierrc +++ /dev/null @@ -1,27 +0,0 @@ -{ - "trailingComma": "none", - "useTabs": true, - "semi": true, - "printWidth": 80, - "arrowParens": "always", - "importOrderSeparation": true, - "importOrder": [ - "@rollup/.*", - "rollup-.*", - "^..?/.*", - "^use-local-storage-state$", - "^styled-components$", - "^react.*", - "^preact$", - "^preact.*", - "^axios.*", - "^@src/.*", - "^@models/.*", - "^@interfaces/.*", - "^@styles/.*", - "^@shared/.*", - "^@utils/.*", - "^@components/.*", - "^@svg/.*" - ] -} diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..e48ff09 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "trailingComma": "none", + "useTabs": true, + "semi": true, + "printWidth": 80, + "arrowParens": "always" +} \ No newline at end of file diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..c3137bf --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,9 @@ +{ + "extends": [ + "stylelint-config-standard", + "stylelint-config-idiomatic-order" + ], + "rules": { + "indentation": "tab" + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ff24a05..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "prettier.configPath": ".prettierrc" -} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3fe9a79 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +FROM node:alpine AS deps + +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile + +FROM node:alpine AS builder +WORKDIR /app +COPY . . +COPY --from=deps /app/node_modules ./node_modules +ENV NEXT_TELEMETRY_DISABLED 1; +RUN yarn build && yarn install --production --ignore-scripts --prefer-offline + +FROM node:alpine AS runner +WORKDIR /app + +ENV NODE_ENV production + +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +COPY --from=builder /app/next.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 +COPY --from=builder /app/package.json ./package.json + +USER nextjs + +EXPOSE 3000 + +CMD ["yarn", "start"] \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index fa6cf43..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Portfolio - -This is my portfolio website to show off all of my projects and provide my socials. - -It's build using Preact and Styled-Components and uses Vite as its build tool. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..49587d1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +version: "3" + +services: + app: + build: . + container_name: app + ports: + - 3000:3000 diff --git a/index.html b/index.html deleted file mode 100644 index b2597d9..0000000 --- a/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - Guus' Portfolio - - - -
- - - - diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..7549451 --- /dev/null +++ b/next.config.js @@ -0,0 +1,7 @@ +// @ts-check +/** + * @type {import('next/dist/next-server/server/config').NextConfig} + **/ +module.exports = { + reactStrictMode: true, +} \ No newline at end of file diff --git a/package.json b/package.json index 42033f4..e8a7ec3 100644 --- a/package.json +++ b/package.json @@ -1,39 +1,42 @@ { - "name": "portfolio", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "format": "prettier src --write", - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "@fontsource/montserrat": "^4.5.11", - "@fontsource/prompt": "^4.5.8", - "@tanstack/react-query": "^4.0.10", - "@tanstack/react-query-devtools": "^4.0.10", - "axios": "^0.27.2", - "bootstrap": "^5.2.0", - "preact": "^10.9.0", - "react-bootstrap": "^2.4.0", - "react-icons": "^4.4.0", - "react-router-dom": "6", - "react-spring": "^9.5.2", - "reset-css": "^5.0.1", - "styled-components": "^5.3.5", - "use-local-storage-state": "^18.1.0", - "vite-plugin-imagemin": "^0.6.1" - }, - "devDependencies": { - "@preact/preset-vite": "^2.3.0", - "@rollup/plugin-alias": "^3.1.9", - "@trivago/prettier-plugin-sort-imports": "^3.3.0", - "@types/styled-components": "^5.1.25", - "prettier": "^2.7.1", - "typescript": "^4.6.4", - "vite": "^3.0.0", - "vite-tsconfig-paths": "^3.5.0" - } + "license": "MIT", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "export": "next build && next export", + "test-build": "tsc", + "lint": "eslint src", + "stylelint": "npx stylelint **/*.scss", + "full-test": "yarn test-build && yarn lint && yarn stylelint" + }, + "dependencies": { + "axios": "^1.1.2", + "configcat-node": "^8.0.0", + "next": "^12.1.0", + "next-seo": "^4.24.0", + "next-themes": "^0.2.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "spectre.css": "^0.5.9" + }, + "devDependencies": { + "@types/node": "^15.12.1", + "@types/react": "^17.0.9", + "@types/react-dom": "^17.0.6", + "@typescript-eslint/eslint-plugin": "^4.26.0", + "@typescript-eslint/parser": "^4.26.0", + "eslint": "^7.28.0", + "eslint-plugin-css-modules": "^2.11.0", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-prettier": "^3.4.0", + "eslint-plugin-react": "^7.24.0", + "eslint-plugin-react-hooks": "^4.2.0", + "prettier": "^2.3.1", + "sass": "^1.34.1", + "stylelint": "^13.13.1", + "stylelint-config-idiomatic-order": "^8.1.0", + "stylelint-config-standard": "^22.0.0", + "typescript": "^4.3.2" + } } diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..5fae432 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/logo-dark.png b/public/logo-dark.png deleted file mode 100644 index 3d02b34..0000000 Binary files a/public/logo-dark.png and /dev/null differ diff --git a/public/logo-light.png b/public/logo-light.png deleted file mode 100644 index e185295..0000000 Binary files a/public/logo-light.png and /dev/null differ diff --git a/public/topography.svg b/public/topography.svg deleted file mode 100644 index dbaa571..0000000 --- a/public/topography.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/BestRepository.tsx b/src/components/BestRepository.tsx new file mode 100644 index 0000000..131e8b9 --- /dev/null +++ b/src/components/BestRepository.tsx @@ -0,0 +1,40 @@ +import Link from "next/link"; + +import { FC } from "react"; + +import { BestRepository } from "@interfaces/repository"; + +const BestRepository: FC<{ repository: BestRepository }> = ({ repository }) => { + return ( +
+
+
+
+

My most popular project:

+

{repository.name}

+

+ {repository.stargazers_count} Star(s) +

+
{repository.description}
+

+ Written in {repository.language}, has{" "} + {repository.open_issues_count} issue(s) and{" "} + {repository.forks_count} fork(s). +

+ + + Github + + {repository.homepage && ( + + Website + + )} +
+
+
+
+ ); +}; + +export default BestRepository; diff --git a/src/components/CssBaseline.tsx b/src/components/CssBaseline.tsx deleted file mode 100644 index 9175c6c..0000000 --- a/src/components/CssBaseline.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createGlobalStyle } from "styled-components"; - -const Baseline = createGlobalStyle` - body { - color: ${({ theme }) => theme.palette.text.primary}; - background-color: ${({ theme }) => theme.palette.background.primary}; - font-family: "Montserrat", sans-serif; - - background-image: url("/topography.svg"); - background-repeat: repeat; - } - - a { - color: ${({ theme }) => theme.palette.text.primary}; - text-decoration: none; - :hover { - color: ${({ theme }) => theme.palette.text.secondary}; - } - } -`; - -const CssBaseline = Baseline as () => JSX.Element; - -export default CssBaseline; diff --git a/src/components/Dots.tsx b/src/components/Dots.tsx deleted file mode 100644 index b49129d..0000000 --- a/src/components/Dots.tsx +++ /dev/null @@ -1,290 +0,0 @@ -import styled, { useTheme } from "styled-components"; - -import { FunctionalComponent } from "preact"; - -const Container = styled.div` - width: 100%; - transform: ${(props) => (props.left ? "scale(-1, -1)" : "none")}; -`; - -const Dots: FunctionalComponent<{ - left?: boolean; -}> = ({ left }) => { - const theme = useTheme(); - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default Dots; diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index c067a9d..5bd8d68 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -1,61 +1,51 @@ -import styled, { DefaultTheme } from "styled-components"; +import { FC } from "react"; -import Col from "react-bootstrap/Col"; -import Container from "react-bootstrap/Container"; -import Row from "react-bootstrap/Row"; +import Link from "next/link"; -import { FunctionalComponent } from "preact"; +import multipleClassNames from "@utils/multipleClassNames"; -import socials from "@utils/socials"; +import styles from "./footer.module.scss"; -import Header from "@components/Header"; - -const Body = styled.div` - background-color: ${({ theme }: { theme: DefaultTheme }) => - theme.palette.background.secondary}; - - border-top: 2px solid - ${({ theme }: { theme: DefaultTheme }) => theme.palette.border}; - padding: 2rem; -`; - -const ListHeader = styled(Header)` - font-size: 2rem; -`; - -const ListItem = styled.li` - font-size: 1.25rem; - margin-top: 1rem; -`; - -const ListItemIcon = styled.span` - margin-right: 1rem; -`; - -const Footer: FunctionalComponent = () => { +const Footer: FC = () => { return ( - - - - -
Guus van Meerveld
- - - - -
-
- +
+
+
+

Guus van Meerveld

+
+
+ + Github + + · + + Twitter + + · + + Ko-fi + + · + + Youtube + +
+
+

+ Built with{" "} + + ❤️ + {" "} + by Guus van Meerveld, using{" "} + + Spectre.css + +

+
+
+
); }; diff --git a/src/components/Header.tsx b/src/components/Header.tsx deleted file mode 100644 index 7c800ab..0000000 --- a/src/components/Header.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import styled from "styled-components"; - -const Header = styled.h1` - font-family: "Prompt", sans-serif; - margin-bottom: 1rem; - font-size: 3rem; - margin-bottom: ${(props) => (props.gutter ? "1rem" : "0")}; -`; - -export default Header; diff --git a/src/components/Image.tsx b/src/components/Image.tsx deleted file mode 100644 index 5e20208..0000000 --- a/src/components/Image.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import styled from "styled-components"; - -const Image = styled.img.attrs(() => ({ draggable: false }))` - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; -`; - -export default Image; diff --git a/src/components/Intro.tsx b/src/components/Intro.tsx new file mode 100644 index 0000000..cd012cb --- /dev/null +++ b/src/components/Intro.tsx @@ -0,0 +1,46 @@ +import { FC } from "react"; + +import styles from "./intro.module.scss"; + +const Intro: FC<{ isAvailable: boolean }> = ({ isAvailable }) => { + return ( +
+
+
+
+

Guus van Meerveld

+ +

+ Open source web developer +

+ +

+ + Github + + + + Contact + +

+ +

+ Availibility: {isAvailable && "Available"} + {!isAvailable && "Not available"} +

+
+
+
+
+ ); +}; + +export default Intro; diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 931869e..ab2d0ae 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -1,10 +1,12 @@ -import { FunctionalComponent } from "preact"; +import { FC } from "react"; import Footer from "@components/Footer"; +import ThemeChanger from "@components/ThemeChanger"; -const Layout: FunctionalComponent = ({ children }) => { +const Layout: FC = ({ children }) => { return ( <> + {children}