diff --git a/.depcheckrc b/.depcheckrc
new file mode 100644
index 0000000..9a0dcc8
--- /dev/null
+++ b/.depcheckrc
@@ -0,0 +1,2 @@
+ignores: ["@types/node", "@types/react-dom", "autoprefixer", "postcss", "@commitlint/config-conventional", "prettier"]
+skip-missing: false
diff --git a/.github/workflows/lint-deps-check.yaml b/.github/workflows/lint-deps-check.yaml
new file mode 100644
index 0000000..c214b94
--- /dev/null
+++ b/.github/workflows/lint-deps-check.yaml
@@ -0,0 +1,47 @@
+name: Linting and Dependency Check
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ checks: write
+ contents: write
+
+jobs:
+ run-checks:
+ name: Run checks
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [18, 20]
+ steps:
+ - name: Checkout Git repository
+ uses: actions/checkout@v3.5.3
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v2.2.4
+ with:
+ version: 8.6.2
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: pnpm
+
+ - name: Install Node.js dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Run linters
+ uses: wearerequired/lint-action@v2.3.0
+ with:
+ eslint: true
+ prettier: true
+
+ - name: Run dependency check
+ run: npx depcheck
diff --git a/README.md b/README.md
index aa76d43..85e7f23 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
diff --git a/app/(index)/layout.tsx b/app/(index)/layout.tsx
new file mode 100644
index 0000000..3968f6c
--- /dev/null
+++ b/app/(index)/layout.tsx
@@ -0,0 +1,33 @@
+import Link from "next/link";
+
+import { cn } from "@/lib/utils";
+import { buttonVariants } from "@/components/ui/button";
+
+interface MarketingLayoutProps {
+ children: React.ReactNode;
+}
+
+export default async function MarketingLayout({
+ children,
+}: MarketingLayoutProps) {
+ return (
+
+
+
+
+
+
+
{children}
+
+ );
+}
diff --git a/app/(index)/page.tsx b/app/(index)/page.tsx
new file mode 100644
index 0000000..bdf1a1d
--- /dev/null
+++ b/app/(index)/page.tsx
@@ -0,0 +1,43 @@
+import Link from "next/link";
+
+import { siteConfig } from "@/config/site";
+import { cn } from "@/lib/utils";
+import { buttonVariants } from "@/components/ui/button";
+
+export default function IndexPage() {
+ return (
+ <>
+
+
+
+ View my LinkedIn profile
+
+
+ hellob.art
+
+
+ In progress build of my portfolio using Next.js 13 server
+ components.
+
+
+
+ Get Started
+
+
+ GitHub
+
+
+
+
+ >
+ );
+}
diff --git a/app/favicon.ico b/app/favicon.ico
deleted file mode 100644
index 718d6fe..0000000
Binary files a/app/favicon.ico and /dev/null differ
diff --git a/app/globals.css b/app/globals.css
deleted file mode 100644
index fd81e88..0000000
--- a/app/globals.css
+++ /dev/null
@@ -1,27 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-:root {
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
- }
-}
-
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
-}
diff --git a/app/layout.tsx b/app/layout.tsx
index 71b3fbf..8636523 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,21 +1,79 @@
-import './globals.css'
-import { Inter } from 'next/font/google'
+import { Inter, Fjalla_One } from "next/font/google";
-const inter = Inter({ subsets: ['latin'] })
+import { ThemeProvider } from "@/components/theme-provider";
+import "tailwindcss/tailwind.css";
-export const metadata = {
- title: 'Create Next App',
- description: 'Generated by create next app',
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: {
+ default: "hellob.art",
+ template: "%s | hellob.art",
+ },
+ description: "a simple portfolio made by bart van der braak",
+ metadataBase: new URL("https://hellob.art"),
+ openGraph: {
+ title: "hellob.art",
+ description: "a simple portfolio made by bart van der braak",
+ url: "https://hellob.art",
+ siteName: "hellob.art",
+ locale: "en-US",
+ type: "website",
+ },
+ robots: {
+ index: true,
+ follow: true,
+ googleBot: {
+ index: true,
+ follow: true,
+ "max-video-preview": -1,
+ "max-image-preview": "large",
+ "max-snippet": -1,
+ },
+ },
+ twitter: {
+ title: "hellob.art",
+ card: "summary_large_image",
+ },
+ icons: {
+ shortcut: "/favicon.png",
+ },
+};
+
+interface RootLayoutProps {
+ children: React.ReactNode;
}
-export default function RootLayout({
- children,
-}: {
- children: React.ReactNode
-}) {
+const inter = Inter({
+ subsets: ["latin"],
+ variable: "--font-inter",
+});
+
+const fjallaOne = Fjalla_One({
+ subsets: ["latin"],
+ weight: "400",
+ variable: "--font-fjalla-one",
+});
+
+interface RootLayoutProps {
+ children: React.ReactNode;
+}
+
+export default async function RootLayout({ children }: RootLayoutProps) {
return (
-
- {children}
-
- )
+ <>
+
+
+
+ {children}
+
+
+
+ >
+ );
}
diff --git a/app/page.tsx b/app/page.tsx
deleted file mode 100644
index 745df65..0000000
--- a/app/page.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-import Image from 'next/image'
-
-export default function Home() {
- return (
-
-
-
- Get started by editing
- app/page.tsx
-
-
-
-
-
-
-
-
-
-
- )
-}
diff --git a/components/theme-provider.tsx b/components/theme-provider.tsx
new file mode 100644
index 0000000..b4e8e4f
--- /dev/null
+++ b/components/theme-provider.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import * as React from "react";
+import { ThemeProvider as NextThemesProvider } from "next-themes";
+import { ThemeProviderProps } from "next-themes/dist/types";
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+ return {children};
+}
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
new file mode 100644
index 0000000..0ec0799
--- /dev/null
+++ b/components/ui/button.tsx
@@ -0,0 +1,51 @@
+import * as React from "react";
+import { VariantProps, cva } from "class-variance-authority";
+
+import { cn } from "@/lib/utils";
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+ outline:
+ "border border-input hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "underline-offset-4 hover:underline text-primary",
+ },
+ size: {
+ default: "h-10 py-2 px-4",
+ sm: "h-9 px-3 rounded-md",
+ lg: "h-11 px-8 rounded-md",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+);
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+Button.displayName = "Button";
+
+export { Button, buttonVariants };
diff --git a/config/navigation.ts b/config/navigation.ts
new file mode 100644
index 0000000..f04becb
--- /dev/null
+++ b/config/navigation.ts
@@ -0,0 +1,8 @@
+export const navigationConfig = {
+ mainNav: [
+ {
+ title: "Projects",
+ href: "/#projects",
+ },
+ ],
+};
diff --git a/config/site.ts b/config/site.ts
new file mode 100644
index 0000000..21a25d7
--- /dev/null
+++ b/config/site.ts
@@ -0,0 +1,14 @@
+export const siteConfig = {
+ name: "Taxonomy",
+ description:
+ "An open source application built using the new router, server components and everything new in Next.js 13.",
+ url: "https://hellob.art",
+ ogImage: "https://hellob.art/og.jpg",
+ links: {
+ linkedIn: "https://linkedin.com/in/bartvdbraak",
+ github: {
+ project: "https://github.com/bartvdbraak/hellob.art",
+ profile: "https://github.com/bartvdbraak",
+ },
+ },
+};
diff --git a/lib/utils.ts b/lib/utils.ts
new file mode 100644
index 0000000..7927ae7
--- /dev/null
+++ b/lib/utils.ts
@@ -0,0 +1,15 @@
+import { ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
+
+export function formatDate(input: string | number): string {
+ const date = new Date(input);
+ return date.toLocaleDateString("en-US", {
+ month: "long",
+ day: "numeric",
+ year: "numeric",
+ });
+}
diff --git a/package.json b/package.json
index 981c525..58d2a18 100644
--- a/package.json
+++ b/package.json
@@ -2,24 +2,35 @@
"name": "hellob.art",
"version": "0.1.0",
"private": true,
+ "author": {
+ "name": "Bart van der Braak",
+ "url": "https://hellob.art"
+ },
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
- "prepare": "husky install"
+ "prepare": "husky install",
+ "typecheck": "tsc --noEmit",
+ "format:write": "prettier . --write --cache",
+ "format:check": "prettier . --check --cache"
},
"dependencies": {
"@types/node": "20.3.1",
"@types/react": "18.2.12",
"@types/react-dom": "18.2.5",
"autoprefixer": "10.4.14",
+ "class-variance-authority": "^0.6.0",
+ "clsx": "^1.2.1",
"eslint": "8.42.0",
"eslint-config-next": "13.4.5",
"next": "13.4.5",
+ "next-themes": "^0.2.1",
"postcss": "8.4.24",
"react": "18.2.0",
"react-dom": "18.2.0",
+ "tailwind-merge": "^1.13.1",
"tailwindcss": "3.3.2",
"typescript": "5.1.3"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1cdd707..313c3a8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,6 +13,12 @@ dependencies:
autoprefixer:
specifier: 10.4.14
version: 10.4.14(postcss@8.4.24)
+ class-variance-authority:
+ specifier: ^0.6.0
+ version: 0.6.0(typescript@5.1.3)
+ clsx:
+ specifier: ^1.2.1
+ version: 1.2.1
eslint:
specifier: 8.42.0
version: 8.42.0
@@ -22,6 +28,9 @@ dependencies:
next:
specifier: 13.4.5
version: 13.4.5(react-dom@18.2.0)(react@18.2.0)
+ next-themes:
+ specifier: ^0.2.1
+ version: 0.2.1(next@13.4.5)(react-dom@18.2.0)(react@18.2.0)
postcss:
specifier: 8.4.24
version: 8.4.24
@@ -31,6 +40,9 @@ dependencies:
react-dom:
specifier: 18.2.0
version: 18.2.0(react@18.2.0)
+ tailwind-merge:
+ specifier: ^1.13.1
+ version: 1.13.1
tailwindcss:
specifier: 3.3.2
version: 3.3.2
@@ -645,10 +657,27 @@ packages:
fsevents: 2.3.2
dev: false
+ /class-variance-authority@0.6.0(typescript@5.1.3):
+ resolution: {integrity: sha512-qdRDgfjx3GRb9fpwpSvn+YaidnT7IUJNe4wt5/SWwM+PmUwJUhQRk/8zAyNro0PmVfmen2635UboTjIBXXxy5A==}
+ peerDependencies:
+ typescript: '>= 4.5.5 < 6'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ clsx: 1.2.1
+ typescript: 5.1.3
+ dev: false
+
/client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
dev: false
+ /clsx@1.2.1:
+ resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
+ engines: {node: '>=6'}
+ dev: false
+
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -1857,6 +1886,18 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: false
+ /next-themes@0.2.1(next@13.4.5)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==}
+ peerDependencies:
+ next: '*'
+ react: '*'
+ react-dom: '*'
+ dependencies:
+ next: 13.4.5(react-dom@18.2.0)(react@18.2.0)
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
/next@13.4.5(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-pfNsRLVM9e5Y1/z02VakJRfD6hMQkr24FaN2xc9GbcZDBxoOgiNAViSg5cXwlWCoMhtm4U315D7XYhgOr96Q3Q==}
engines: {node: '>=16.8.0'}
@@ -2500,6 +2541,10 @@ packages:
tslib: 2.5.3
dev: false
+ /tailwind-merge@1.13.1:
+ resolution: {integrity: sha512-tRtRN22TDokGi2TuYSvuHQuuW6BJ/zlUEG+iYpAQ9i66msc/0eU/+HPccbPnNNH0mCPp0Ob8thaC8Uy9CxHitQ==}
+ dev: false
+
/tailwindcss@3.3.2:
resolution: {integrity: sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==}
engines: {node: '>=14.0.0'}
diff --git a/postcss.config.js b/postcss.config.js
index 33ad091..12a703d 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -3,4 +3,4 @@ module.exports = {
tailwindcss: {},
autoprefixer: {},
},
-}
+};
diff --git a/public/logo.svg b/public/logo.svg
new file mode 100644
index 0000000..0662165
--- /dev/null
+++ b/public/logo.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/next.svg b/public/next.svg
deleted file mode 100644
index 5174b28..0000000
--- a/public/next.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/vercel.svg b/public/vercel.svg
deleted file mode 100644
index d2f8422..0000000
--- a/public/vercel.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tailwind.config.js b/tailwind.config.js
index 9a3c190..8758409 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -28,6 +28,7 @@ module.exports = {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
+ filter: "brightness(120%) saturate(120%) blur(2px)",
},
},
},
diff --git a/types/index.d.ts b/types/index.d.ts
new file mode 100644
index 0000000..20eca17
--- /dev/null
+++ b/types/index.d.ts
@@ -0,0 +1,11 @@
+export type NavItem = {
+ title: string;
+ href: string;
+ disabled?: boolean;
+};
+
+export type MainNavItem = NavItem;
+
+export type NavigationConfig = {
+ mainNav: MainNavItem[];
+};