From 6cf6660eedf9725d6c3eb03af5ad12e20b9fa8a5 Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 14:21:25 +0200
Subject: [PATCH 01/25] add react-hook-form and zod packages
---
package-lock.json | 36 +++++++++++++++++++++++++++++++++++-
package.json | 5 ++++-
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 5130b3c..fd98ee9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "portfolio-site",
"version": "0.1.0",
"dependencies": {
+ "@hookform/resolvers": "^3.3.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"gray-matter": "^4.0.3",
@@ -16,8 +17,10 @@
"next-themes": "^0.2.1",
"react": "^18",
"react-dom": "^18",
+ "react-hook-form": "^7.50.1",
"react-icons": "^5.0.1",
- "tailwind-merge": "^2.2.1"
+ "tailwind-merge": "^2.2.1",
+ "zod": "^3.22.4"
},
"devDependencies": {
"@types/node": "^20",
@@ -553,6 +556,14 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@hookform/resolvers": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.3.4.tgz",
+ "integrity": "sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==",
+ "peerDependencies": {
+ "react-hook-form": "^7.0.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -5644,6 +5655,21 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-hook-form": {
+ "version": "7.50.1",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.50.1.tgz",
+ "integrity": "sha512-3PCY82oE0WgeOgUtIr3nYNNtNvqtJ7BZjsbxh6TnYNbXButaD5WpjOmTjdxZfheuHKR68qfeFnEDVYoSSFPMTQ==",
+ "engines": {
+ "node": ">=12.22.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18"
+ }
+ },
"node_modules/react-icons": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
@@ -6984,6 +7010,14 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zod": {
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
+ "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
}
}
}
diff --git a/package.json b/package.json
index 7d08caf..5009030 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"prepare": "husky install"
},
"dependencies": {
+ "@hookform/resolvers": "^3.3.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"gray-matter": "^4.0.3",
@@ -23,8 +24,10 @@
"next-themes": "^0.2.1",
"react": "^18",
"react-dom": "^18",
+ "react-hook-form": "^7.50.1",
"react-icons": "^5.0.1",
- "tailwind-merge": "^2.2.1"
+ "tailwind-merge": "^2.2.1",
+ "zod": "^3.22.4"
},
"devDependencies": {
"@types/node": "^20",
From bfd87de067da1377f7609d46bc7f92a63284a284 Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:53:14 +0200
Subject: [PATCH 02/25] add contact form zod utilities
---
src/utils/index.ts | 1 +
src/utils/zod.ts | 9 +++++++++
2 files changed, 10 insertions(+)
create mode 100644 src/utils/zod.ts
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 12a0292..366ac67 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -1,2 +1,3 @@
export * from './misc'
export * from './constants'
+export * from './zod'
diff --git a/src/utils/zod.ts b/src/utils/zod.ts
new file mode 100644
index 0000000..325b971
--- /dev/null
+++ b/src/utils/zod.ts
@@ -0,0 +1,9 @@
+import { z } from 'zod'
+
+export const ContactFormSchema = z.object({
+ email: z.string().email('Email is invalid'),
+ message: z.string().min(5, 'Message is too short'),
+ name: z.string().min(2, 'Name is required'),
+})
+
+export type ContactFormInputs = z.infer
From 5f327702934bd85da24e2ea8a3decf833c0a2c0d Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:53:45 +0200
Subject: [PATCH 03/25] replace button with link
---
src/components/sections/hero/hero.tsx | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/components/sections/hero/hero.tsx b/src/components/sections/hero/hero.tsx
index 7ede32d..6479f7c 100644
--- a/src/components/sections/hero/hero.tsx
+++ b/src/components/sections/hero/hero.tsx
@@ -1,8 +1,9 @@
-import Button from '@/components/ui/button'
+import Button, { buttonVariants } from '@/components/ui/button'
import Content from '@/components/ui/content'
import Heading from '@/components/ui/heading'
import Socials from '@/components/ui/socials/socials'
import { cn } from '@/utils'
+import Link from 'next/link'
import { FC, HTMLAttributes } from 'react'
import styles from './hero.module.css'
@@ -29,9 +30,12 @@ const Hero: FC = ({ className, ...props }) => {
elegant and responsive user interfaces.
-
+
+ My Projects
+
Date: Wed, 7 Feb 2024 16:54:09 +0200
Subject: [PATCH 04/25] update styles
---
src/components/sections/projects/projects.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/sections/projects/projects.tsx b/src/components/sections/projects/projects.tsx
index c931403..c50a6b9 100644
--- a/src/components/sections/projects/projects.tsx
+++ b/src/components/sections/projects/projects.tsx
@@ -23,7 +23,7 @@ const Projects: FC = async ({ className, ...props }) => {
explore other sections of the site.
) : (
-
+
{projects.map((project) => (
Date: Wed, 7 Feb 2024 16:54:47 +0200
Subject: [PATCH 05/25] update technologies mapping
---
src/components/sections/projects/project-card.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/sections/projects/project-card.tsx b/src/components/sections/projects/project-card.tsx
index 27c1563..85ae45d 100644
--- a/src/components/sections/projects/project-card.tsx
+++ b/src/components/sections/projects/project-card.tsx
@@ -39,10 +39,10 @@ const ProjectCard: FC = ({
/>
{technologies && (
- {technologies.map((technology, index) => (
+ {technologies.map((technology) => (
{technology}
From 0d285c5898872d1dac8474a98d04f8ac2c51bfcd Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:55:24 +0200
Subject: [PATCH 06/25] add Input component
---
src/components/ui/input.tsx | 76 +++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 src/components/ui/input.tsx
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 0000000..f27caa1
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,76 @@
+import { ContactFormInputs, cn } from '@/utils'
+import { VariantProps, cva } from 'class-variance-authority'
+import { FC, InputHTMLAttributes } from 'react'
+import { Path, UseFormRegister } from 'react-hook-form'
+
+export const inputVariants = cva(
+ 'w-full transition-colors outline-none md:text-xl',
+ {
+ defaultVariants: {
+ customSize: 'default',
+ variant: 'default',
+ },
+ variants: {
+ customSize: {
+ default: 'rounded-2xl px-4 py-3.5',
+ placeholder: 'rounded-2xl px-4 pb-2 pt-5',
+ },
+ variant: {
+ default:
+ 'border border-neutral-400 bg-light dark:border-neutral-600 dark:bg-dark',
+ placeholder:
+ 'border border-neutral-400 bg-light dark:border-neutral-600 dark:bg-dark peer relative placeholder:opacity-0',
+ },
+ },
+ }
+)
+
+export interface InputProps
+ extends InputHTMLAttributes,
+ VariantProps {
+ name: Path
+ register: UseFormRegister
+}
+
+const Input: FC = ({
+ className,
+ customSize,
+ name,
+ placeholder,
+ register,
+ required,
+ variant,
+ ...props
+}) => {
+ return (
+ <>
+ {placeholder ? (
+
+
+
+ {placeholder}
+
+
+ ) : (
+
+ )}
+ >
+ )
+}
+
+export default Input
From ed37705d1e574721afe2013370d96eb09de73d10 Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:55:45 +0200
Subject: [PATCH 07/25] add Textarea component
---
src/components/ui/textarea.tsx | 56 ++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 src/components/ui/textarea.tsx
diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx
new file mode 100644
index 0000000..7051c02
--- /dev/null
+++ b/src/components/ui/textarea.tsx
@@ -0,0 +1,56 @@
+import { inputVariants } from '@/components/ui/input'
+import { ContactFormInputs, cn } from '@/utils'
+import { VariantProps } from 'class-variance-authority'
+import { FC, TextareaHTMLAttributes } from 'react'
+import { Path, UseFormRegister } from 'react-hook-form'
+
+export interface TextareaProps
+ extends TextareaHTMLAttributes,
+ VariantProps {
+ name: Path
+ register: UseFormRegister
+}
+
+const Textarea: FC = ({
+ className,
+ customSize,
+ name,
+ placeholder,
+ register,
+ required,
+ variant,
+ ...props
+}) => {
+ return (
+ <>
+ {placeholder ? (
+
+
+
+ {placeholder}
+
+
+ ) : (
+
+ )}
+ >
+ )
+}
+
+export default Textarea
From aa63b546b855f6cfa8aa1d66f15f392e946440aa Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:56:06 +0200
Subject: [PATCH 08/25] add Label component
---
src/components/ui/label.tsx | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 src/components/ui/label.tsx
diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx
new file mode 100644
index 0000000..f6f3a2a
--- /dev/null
+++ b/src/components/ui/label.tsx
@@ -0,0 +1,14 @@
+import { cn } from '@/utils'
+import { FC, LabelHTMLAttributes } from 'react'
+
+interface LabelProps extends LabelHTMLAttributes {}
+
+const Label: FC = ({ children, className, ...props }) => {
+ return (
+
+ )
+}
+
+export default Label
From 15af2b0850d363efe555f672da451c5564b5369f Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:56:27 +0200
Subject: [PATCH 09/25] add FormItem component
---
src/components/ui/form-item.tsx | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 src/components/ui/form-item.tsx
diff --git a/src/components/ui/form-item.tsx b/src/components/ui/form-item.tsx
new file mode 100644
index 0000000..b62f7c9
--- /dev/null
+++ b/src/components/ui/form-item.tsx
@@ -0,0 +1,26 @@
+import { cn } from '@/utils'
+import { FC, HTMLAttributes } from 'react'
+
+interface FormItemProps extends HTMLAttributes {
+ error?: string
+}
+
+const FormItem: FC = ({
+ children,
+ className,
+ error,
+ ...props
+}) => {
+ return (
+
+ {children}
+ {error && (
+
+ {error}
+
+ )}
+
+ )
+}
+
+export default FormItem
From 523e760725544acb79b9122fbb228dae496c4a78 Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:58:51 +0200
Subject: [PATCH 10/25] add ContactForm component
---
.../sections/contact/contact-form.tsx | 74 +++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 src/components/sections/contact/contact-form.tsx
diff --git a/src/components/sections/contact/contact-form.tsx b/src/components/sections/contact/contact-form.tsx
new file mode 100644
index 0000000..cc07c96
--- /dev/null
+++ b/src/components/sections/contact/contact-form.tsx
@@ -0,0 +1,74 @@
+'use client'
+
+import Button from '@/components/ui/button'
+import FormItem from '@/components/ui/form-item'
+import Input from '@/components/ui/input'
+import Label from '@/components/ui/label'
+import Textarea from '@/components/ui/textarea'
+import { ContactFormInputs, ContactFormSchema, cn } from '@/utils'
+import { zodResolver } from '@hookform/resolvers/zod'
+import { FC, FormHTMLAttributes } from 'react'
+import { SubmitHandler, useForm } from 'react-hook-form'
+
+interface ContactFormProps extends FormHTMLAttributes {}
+
+const ContactForm: FC = ({ className, ...props }) => {
+ const {
+ formState: { errors },
+ handleSubmit,
+ register,
+ reset,
+ } = useForm({
+ resolver: zodResolver(ContactFormSchema),
+ })
+
+ const onSubmit: SubmitHandler = (data) => {
+ alert(JSON.stringify(data))
+ reset()
+ }
+
+ return (
+
+ )
+}
+
+export default ContactForm
From ac61b42e0bb89b5a884c8dbccb406d2696cd43b7 Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:59:34 +0200
Subject: [PATCH 11/25] add Contact component
---
src/components/sections/contact/contact.tsx | 32 +++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 src/components/sections/contact/contact.tsx
diff --git a/src/components/sections/contact/contact.tsx b/src/components/sections/contact/contact.tsx
new file mode 100644
index 0000000..f18a2ee
--- /dev/null
+++ b/src/components/sections/contact/contact.tsx
@@ -0,0 +1,32 @@
+import ContactForm from '@/components/sections/contact/contact-form'
+import Content from '@/components/ui/content'
+import Heading from '@/components/ui/heading'
+import { cn } from '@/utils'
+import { FC, HTMLAttributes } from 'react'
+
+interface ContactProps extends HTMLAttributes {}
+
+const Contact: FC = ({ className, ...props }) => {
+ return (
+
+ )
+}
+
+export default Contact
From 0a3e3e2ca0f27df806e308cac9ed958906559b51 Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 16:59:55 +0200
Subject: [PATCH 12/25] utilize Contact component
---
src/app/page.tsx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/app/page.tsx b/src/app/page.tsx
index ac6e9e0..fe745eb 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,4 +1,5 @@
import About from '@/components/sections/about'
+import Contact from '@/components/sections/contact/contact'
import Hero from '@/components/sections/hero/hero'
import Projects from '@/components/sections/projects/projects'
@@ -8,6 +9,7 @@ export default function Home() {
+
>
)
}
From 798b4a169e628e65cdd761a3cbd36888564b23ca Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 17:00:13 +0200
Subject: [PATCH 13/25] add new word
---
project-words.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/project-words.txt b/project-words.txt
index 844bf3d..bbff8cc 100644
--- a/project-words.txt
+++ b/project-words.txt
@@ -3,4 +3,5 @@ Bochkovskyi
clsx
Nextdotjs
Tailwindcss
-Skauna
\ No newline at end of file
+Skauna
+hookform
\ No newline at end of file
From a76f5896f827c581c6e5831d8c5510e4b0ff94ce Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 21:37:32 +0200
Subject: [PATCH 14/25] add sonner package
---
package-lock.json | 10 ++++++++++
package.json | 1 +
2 files changed, 11 insertions(+)
diff --git a/package-lock.json b/package-lock.json
index fd98ee9..f254e0c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"react-dom": "^18",
"react-hook-form": "^7.50.1",
"react-icons": "^5.0.1",
+ "sonner": "^1.4.0",
"tailwind-merge": "^2.2.1",
"zod": "^3.22.4"
},
@@ -6087,6 +6088,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/sonner": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.4.0.tgz",
+ "integrity": "sha512-nvkTsIuOmi9e5Wz5If8ldasJjZNVfwiXYijBi2dbijvTQnQppvMcXTFNxL/NUFWlI2yJ1JX7TREDsg+gYm9WyA==",
+ "peerDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
diff --git a/package.json b/package.json
index 5009030..5336f59 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"react-dom": "^18",
"react-hook-form": "^7.50.1",
"react-icons": "^5.0.1",
+ "sonner": "^1.4.0",
"tailwind-merge": "^2.2.1",
"zod": "^3.22.4"
},
From 4d84a5d3df386ced51668629da5bb9fa85535554 Mon Sep 17 00:00:00 2001
From: Bochkovskyi
Date: Wed, 7 Feb 2024 21:37:58 +0200
Subject: [PATCH 15/25] utilize Toaster component
---
src/app/layout.tsx | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 7bed936..5ae9165 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -3,6 +3,7 @@ import type { Metadata } from 'next'
import Header from '@/components/header/header'
import Providers from '@/store/providers'
import { cn } from '@/utils'
+import { Toaster } from 'sonner'
import { raleway } from './fonts'
import './globals.css'
@@ -25,6 +26,12 @@ export default function RootLayout({
{children}
11111
+