diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..7c28b83
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": false
+}
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 f4bd77c..0000000
--- a/app/globals.css
+++ /dev/null
@@ -1,107 +0,0 @@
-:root {
- --max-width: 1100px;
- --border-radius: 12px;
- --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
- "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
- "Fira Mono", "Droid Sans Mono", "Courier New", monospace;
-
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-
- --primary-glow: conic-gradient(
- from 180deg at 50% 50%,
- #16abff33 0deg,
- #0885ff33 55deg,
- #54d6ff33 120deg,
- #0071ff33 160deg,
- transparent 360deg
- );
- --secondary-glow: radial-gradient(
- rgba(255, 255, 255, 1),
- rgba(255, 255, 255, 0)
- );
-
- --tile-start-rgb: 239, 245, 249;
- --tile-end-rgb: 228, 232, 233;
- --tile-border: conic-gradient(
- #00000080,
- #00000040,
- #00000030,
- #00000020,
- #00000010,
- #00000010,
- #00000080
- );
-
- --callout-rgb: 238, 240, 241;
- --callout-border-rgb: 172, 175, 176;
- --card-rgb: 180, 185, 188;
- --card-border-rgb: 131, 134, 135;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
-
- --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
- --secondary-glow: linear-gradient(
- to bottom right,
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0.3)
- );
-
- --tile-start-rgb: 2, 13, 46;
- --tile-end-rgb: 2, 5, 19;
- --tile-border: conic-gradient(
- #ffffff80,
- #ffffff40,
- #ffffff30,
- #ffffff20,
- #ffffff10,
- #ffffff10,
- #ffffff80
- );
-
- --callout-rgb: 20, 20, 20;
- --callout-border-rgb: 108, 108, 108;
- --card-rgb: 100, 100, 100;
- --card-border-rgb: 200, 200, 200;
- }
-}
-
-* {
- box-sizing: border-box;
- padding: 0;
- margin: 0;
-}
-
-html,
-body {
- max-width: 100vw;
- overflow-x: hidden;
-}
-
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
-}
-
-a {
- color: inherit;
- text-decoration: none;
-}
-
-@media (prefers-color-scheme: dark) {
- html {
- color-scheme: dark;
- }
-}
diff --git a/app/layout.tsx b/app/layout.tsx
index 3314e47..36405a5 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,22 +1,36 @@
-import type { Metadata } from "next";
-import { Inter } from "next/font/google";
-import "./globals.css";
-
-const inter = Inter({ subsets: ["latin"] });
+import type { Metadata } from "next"
+import { GlobalStyle } from "@/styles/globalStyle"
+import StyledComponentsRegistry from "@/lib/registry"
+import Navbar from "@/components/navbar"
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
-};
+ title: "HangerThem",
+ description: "Personal portfolio of HangerThem (Frank Borisjuk)",
+ authors: [
+ {
+ name: "Frank Borisjuk",
+ url: "https://hangerthem.com",
+ },
+ ],
+ creator: "Frank Borisjuk",
+ publisher: "Frank Borisjuk",
+ keywords: ["Portfolio", "Personal", "Frank Borisjuk", "HangerThem"],
+}
export default function RootLayout({
children,
}: Readonly<{
- children: React.ReactNode;
+ children: React.ReactNode
}>) {
return (
-
-
{children}
-
- );
+
+
+
+
+
+ {children}
+
+
+
+ )
}
diff --git a/app/page.module.css b/app/page.module.css
deleted file mode 100644
index 5c4b1e6..0000000
--- a/app/page.module.css
+++ /dev/null
@@ -1,230 +0,0 @@
-.main {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- align-items: center;
- padding: 6rem;
- min-height: 100vh;
-}
-
-.description {
- display: inherit;
- justify-content: inherit;
- align-items: inherit;
- font-size: 0.85rem;
- max-width: var(--max-width);
- width: 100%;
- z-index: 2;
- font-family: var(--font-mono);
-}
-
-.description a {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 0.5rem;
-}
-
-.description p {
- position: relative;
- margin: 0;
- padding: 1rem;
- background-color: rgba(var(--callout-rgb), 0.5);
- border: 1px solid rgba(var(--callout-border-rgb), 0.3);
- border-radius: var(--border-radius);
-}
-
-.code {
- font-weight: 700;
- font-family: var(--font-mono);
-}
-
-.grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(25%, auto));
- max-width: 100%;
- width: var(--max-width);
-}
-
-.card {
- padding: 1rem 1.2rem;
- border-radius: var(--border-radius);
- background: rgba(var(--card-rgb), 0);
- border: 1px solid rgba(var(--card-border-rgb), 0);
- transition: background 200ms, border 200ms;
-}
-
-.card span {
- display: inline-block;
- transition: transform 200ms;
-}
-
-.card h2 {
- font-weight: 600;
- margin-bottom: 0.7rem;
-}
-
-.card p {
- margin: 0;
- opacity: 0.6;
- font-size: 0.9rem;
- line-height: 1.5;
- max-width: 30ch;
- text-wrap: balance;
-}
-
-.center {
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- padding: 4rem 0;
-}
-
-.center::before {
- background: var(--secondary-glow);
- border-radius: 50%;
- width: 480px;
- height: 360px;
- margin-left: -400px;
-}
-
-.center::after {
- background: var(--primary-glow);
- width: 240px;
- height: 180px;
- z-index: -1;
-}
-
-.center::before,
-.center::after {
- content: "";
- left: 50%;
- position: absolute;
- filter: blur(45px);
- transform: translateZ(0);
-}
-
-.logo {
- position: relative;
-}
-/* Enable hover only on non-touch devices */
-@media (hover: hover) and (pointer: fine) {
- .card:hover {
- background: rgba(var(--card-rgb), 0.1);
- border: 1px solid rgba(var(--card-border-rgb), 0.15);
- }
-
- .card:hover span {
- transform: translateX(4px);
- }
-}
-
-@media (prefers-reduced-motion) {
- .card:hover span {
- transform: none;
- }
-}
-
-/* Mobile */
-@media (max-width: 700px) {
- .content {
- padding: 4rem;
- }
-
- .grid {
- grid-template-columns: 1fr;
- margin-bottom: 120px;
- max-width: 320px;
- text-align: center;
- }
-
- .card {
- padding: 1rem 2.5rem;
- }
-
- .card h2 {
- margin-bottom: 0.5rem;
- }
-
- .center {
- padding: 8rem 0 6rem;
- }
-
- .center::before {
- transform: none;
- height: 300px;
- }
-
- .description {
- font-size: 0.8rem;
- }
-
- .description a {
- padding: 1rem;
- }
-
- .description p,
- .description div {
- display: flex;
- justify-content: center;
- position: fixed;
- width: 100%;
- }
-
- .description p {
- align-items: center;
- inset: 0 0 auto;
- padding: 2rem 1rem 1.4rem;
- border-radius: 0;
- border: none;
- border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
- background: linear-gradient(
- to bottom,
- rgba(var(--background-start-rgb), 1),
- rgba(var(--callout-rgb), 0.5)
- );
- background-clip: padding-box;
- backdrop-filter: blur(24px);
- }
-
- .description div {
- align-items: flex-end;
- pointer-events: none;
- inset: auto 0 0;
- padding: 2rem;
- height: 200px;
- background: linear-gradient(
- to bottom,
- transparent 0%,
- rgb(var(--background-end-rgb)) 40%
- );
- z-index: 1;
- }
-}
-
-/* Tablet and Smaller Desktop */
-@media (min-width: 701px) and (max-width: 1120px) {
- .grid {
- grid-template-columns: repeat(2, 50%);
- }
-}
-
-@media (prefers-color-scheme: dark) {
- .vercelLogo {
- filter: invert(1);
- }
-
- .logo {
- filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
- }
-}
-
-@keyframes rotate {
- from {
- transform: rotate(360deg);
- }
- to {
- transform: rotate(0deg);
- }
-}
diff --git a/app/page.tsx b/app/page.tsx
index 8107090..a1ba88f 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,95 +1,19 @@
-import Image from "next/image";
-import styles from "./page.module.css";
+import HeroBanner from "@/components/heroBanner"
+import About from "@/components/about"
+import Divider from "@/components/divider"
+import Techstack from "@/components/techstack"
+import Projects from "@/components/projects"
export default function Home() {
return (
-
-
-
- Get started by editing
- app/page.tsx
-
-
-
-
-
-
-
-
-
-
- );
+ <>
+
+
+
+
+
+
+
+ >
+ )
}
diff --git a/components/about.tsx b/components/about.tsx
new file mode 100644
index 0000000..1d05f2e
--- /dev/null
+++ b/components/about.tsx
@@ -0,0 +1,81 @@
+"use client"
+
+import styled, { keyframes } from "styled-components"
+import Image from "next/image"
+
+const AboutContainer = styled.section`
+ width: 100%;
+ height: 100vh;
+ padding: 2rem 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 2rem;
+`
+
+const wave = keyframes`
+ 0% {
+ transform: rotate(-15deg);
+ }
+ 50% {
+ transform: rotate(15deg);
+ }
+ 100% {
+ transform: rotate(-15deg);
+ }
+`
+
+const AboutContent = styled.div`
+ width: 50%;
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+
+ h2 {
+ font-size: 3rem;
+ font-weight: 600;
+ position: relative;
+
+ &::before {
+ content: "👋";
+ position: absolute;
+ left: -4rem;
+ transform-origin: 70% 70%;
+ animation: ${wave} 1s ease-in-out infinite;
+ }
+ }
+
+ p {
+ font-size: 1.2rem;
+ font-weight: 400;
+ max-width: 600px;
+ }
+`
+
+const AboutImage = styled.div`
+ img {
+ object-fit: cover;
+ object-position: center;
+ border-radius: 1rem;
+ }
+`
+
+export default function About() {
+ return (
+
+
+ Hi! My name is Frank!
+
+ I am a passionate and innovative web developer based in Czech
+ Republic. Ever since I laid hands on my first line of code, I've been
+ captivated by the boundless possibilities of the web. With a curious
+ mind and a desire to stay on the cutting edge of technology, I
+ constantly seek new challenges that push my skills to the next level.
+
+
+
+
+
+
+ )
+}
diff --git a/components/divider.tsx b/components/divider.tsx
new file mode 100644
index 0000000..4a6d077
--- /dev/null
+++ b/components/divider.tsx
@@ -0,0 +1,36 @@
+"use client"
+
+import styled from "styled-components"
+
+const DividerLine = styled.div`
+ width: 45%;
+ height: 1px;
+ background-color: rgba(var(--white), 0.5);
+ border: none;
+`
+
+const DividerSquare = styled.div`
+ width: 1rem;
+ height: 1rem;
+ transform: rotate(45deg);
+ background-color: rgba(var(--white), 0.5);
+`
+
+const DividerContainer = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+`
+
+const Divider = () => {
+ return (
+
+
+
+
+
+ )
+}
+
+export default Divider
diff --git a/components/heroBanner.tsx b/components/heroBanner.tsx
new file mode 100644
index 0000000..90ec4e3
--- /dev/null
+++ b/components/heroBanner.tsx
@@ -0,0 +1,82 @@
+"use client"
+
+import Image from "next/image"
+import styled from "styled-components"
+
+const HeroContainer = styled.div`
+ position: relative;
+ width: 100%;
+ height: 100vh;
+ overflow: hidden;
+
+ img {
+ object-fit: cover;
+ object-position: center;
+ width: 100%;
+ height: 100%;
+ }
+
+ &::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(var(--black), 0.5);
+ }
+`
+
+const ScrollIndicator = styled.div`
+ position: absolute;
+ bottom: 5%;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 2rem;
+ height: 4rem;
+ border: 2px solid rgb(var(--white));
+ border-radius: 2rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-between;
+ z-index: 100;
+ cursor: pointer;
+
+ &::before {
+ content: "";
+ width: 0.5rem;
+ height: 0.5rem;
+ background-color: rgb(var(--white));
+ border-radius: 50%;
+ animation: scroll 2s infinite;
+ }
+
+ @keyframes scroll {
+ 0% {
+ transform: translateY(1rem);
+ }
+ 100% {
+ opacity: 0;
+ transform: translateY(3rem);
+ }
+ }
+`
+
+export default function HeroBanner() {
+ return (
+
+
+
+ window.scrollTo({ top: window.innerHeight, behavior: "smooth" })
+ }
+ />
+
+ )
+}
diff --git a/components/navbar.tsx b/components/navbar.tsx
new file mode 100644
index 0000000..25329ad
--- /dev/null
+++ b/components/navbar.tsx
@@ -0,0 +1,93 @@
+"use client"
+
+import styled, { keyframes } from "styled-components"
+import Logo from "@/icons/logo"
+import Link from "next/link"
+
+const NavbarContainer = styled.nav`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 1rem 2rem;
+ background-color: rgba(var(--background), 0.5);
+ backdrop-filter: blur(10px);
+ position: absolute;
+ width: calc(100% - 4rem);
+ margin: 2rem;
+ border-radius: 1rem;
+ z-index: 100;
+
+ ul {
+ display: flex;
+ gap: 2rem;
+ li {
+ list-style: none;
+ font-size: 1.5rem;
+ font-weight: 600;
+ cursor: pointer;
+
+ a {
+ text-decoration: none;
+ color: rgba(var(--black), 0.7);
+ transition: color 0.2s;
+ font-weight: 400;
+ &:hover {
+ color: rgba(var(--black), 1);
+ }
+
+ &.active {
+ color: rgba(var(--white), 1);
+ font-weight: 600;
+ text-shadow: 0 4px 5px rgba(var(--black), 0.5);
+ }
+ }
+ }
+ }
+
+ svg {
+ width: 4rem;
+ height: 4rem;
+ }
+`
+
+const LogoWrapper = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+
+ h1 {
+ font-size: 2.5rem;
+ font-weight: 600;
+ color: rgb(var(--white));
+ text-shadow: 0 4px 5px rgba(var(--black), 0.5);
+ }
+`
+
+const Navbar = () => {
+ return (
+
+
+
+ HangerThem
+
+
+
+
+ Home
+
+
+
+ About
+
+
+ Projects
+
+
+ Contact me
+
+
+
+ )
+}
+
+export default Navbar
diff --git a/components/projects.tsx b/components/projects.tsx
new file mode 100644
index 0000000..52c4405
--- /dev/null
+++ b/components/projects.tsx
@@ -0,0 +1,45 @@
+"use client"
+
+import styled from "styled-components"
+import UnderConstruction from "@/icons/underConstruction"
+
+const ProjectsContainer = styled.section`
+ width: 100%;
+ height: 100vh;
+ padding: 2rem 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 2rem;
+
+ svg {
+ width: 15rem;
+ height: 15rem;
+ }
+`
+
+const ProjectsContent = styled.div`
+ width: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2rem;
+
+ h2 {
+ font-size: 3rem;
+ font-weight: 600;
+ }
+`
+
+export default function Projects() {
+ return (
+
+
+ Projects
+
+
+
+ )
+}
diff --git a/components/techstack.tsx b/components/techstack.tsx
new file mode 100644
index 0000000..b426cd1
--- /dev/null
+++ b/components/techstack.tsx
@@ -0,0 +1,45 @@
+"use client"
+
+import styled from "styled-components"
+import UnderConstruction from "@/icons/underConstruction"
+
+const TechstackContainer = styled.section`
+ width: 100%;
+ height: 100vh;
+ padding: 2rem 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 2rem;
+
+ svg {
+ width: 15rem;
+ height: 15rem;
+ }
+`
+
+const TechstackContent = styled.div`
+ width: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2rem;
+
+ h2 {
+ font-size: 3rem;
+ font-weight: 600;
+ }
+`
+
+export default function Techstack() {
+ return (
+
+
+ Tech Stack
+
+
+
+ )
+}
diff --git a/icons/logo.tsx b/icons/logo.tsx
new file mode 100644
index 0000000..4fc18ff
--- /dev/null
+++ b/icons/logo.tsx
@@ -0,0 +1,100 @@
+const Logo = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+)
+
+export default Logo
diff --git a/icons/underConstruction.tsx b/icons/underConstruction.tsx
new file mode 100644
index 0000000..9fa7150
--- /dev/null
+++ b/icons/underConstruction.tsx
@@ -0,0 +1,22 @@
+const UnderConstruction = () => (
+
+
+
+
+)
+
+export default UnderConstruction
diff --git a/lib/registry.tsx b/lib/registry.tsx
new file mode 100644
index 0000000..31e0505
--- /dev/null
+++ b/lib/registry.tsx
@@ -0,0 +1,27 @@
+"use client"
+
+import React, { useState } from "react"
+import { useServerInsertedHTML } from "next/navigation"
+import { ServerStyleSheet, StyleSheetManager } from "styled-components"
+
+export default function StyledComponentsRegistry({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())
+
+ useServerInsertedHTML(() => {
+ const styles = styledComponentsStyleSheet.getStyleElement()
+ styledComponentsStyleSheet.instance.clearTag()
+ return <>{styles}>
+ })
+
+ if (typeof window !== "undefined") return <>{children}>
+
+ return (
+
+ {children}
+
+ )
+}
diff --git a/package-lock.json b/package-lock.json
index 2d153e5..ef495d4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,8 +9,10 @@
"version": "0.1.0",
"dependencies": {
"next": "14.1.0",
+ "nodemailer": "^6.9.9",
"react": "^18",
- "react-dom": "^18"
+ "react-dom": "^18",
+ "styled-components": "^6.1.8"
},
"devDependencies": {
"@types/node": "^20",
@@ -42,6 +44,24 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
+ "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==",
+ "dependencies": {
+ "@emotion/memoize": "^0.8.1"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
+ "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz",
+ "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw=="
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -430,6 +450,11 @@
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
"dev": true
},
+ "node_modules/@types/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw=="
+ },
"node_modules/@typescript-eslint/parser": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
@@ -903,6 +928,14 @@
"node": ">=6"
}
},
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001584",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001584.tgz",
@@ -981,6 +1014,24 @@
"node": ">= 8"
}
},
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -2800,6 +2851,14 @@
}
}
},
+ "node_modules/nodemailer": {
+ "version": "6.9.9",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.9.tgz",
+ "integrity": "sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -3089,6 +3148,11 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -3414,6 +3478,11 @@
"node": ">= 0.4"
}
},
+ "node_modules/shallowequal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -3662,6 +3731,43 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/styled-components": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz",
+ "integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==",
+ "dependencies": {
+ "@emotion/is-prop-valid": "1.2.1",
+ "@emotion/unitless": "0.8.0",
+ "@types/stylis": "4.2.0",
+ "css-to-react-native": "3.2.0",
+ "csstype": "3.1.2",
+ "postcss": "8.4.31",
+ "shallowequal": "1.1.0",
+ "stylis": "4.3.1",
+ "tslib": "2.5.0"
+ },
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/styled-components"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0",
+ "react-dom": ">= 16.8.0"
+ }
+ },
+ "node_modules/styled-components/node_modules/csstype": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+ },
+ "node_modules/styled-components/node_modules/tslib": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
+ },
"node_modules/styled-jsx": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
@@ -3684,6 +3790,11 @@
}
}
},
+ "node_modules/stylis": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz",
+ "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ=="
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
diff --git a/package.json b/package.json
index 5756c7c..aed35b6 100644
--- a/package.json
+++ b/package.json
@@ -9,16 +9,18 @@
"lint": "next lint"
},
"dependencies": {
+ "next": "14.1.0",
+ "nodemailer": "^6.9.9",
"react": "^18",
"react-dom": "^18",
- "next": "14.1.0"
+ "styled-components": "^6.1.8"
},
"devDependencies": {
- "typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
- "eslint-config-next": "14.1.0"
+ "eslint-config-next": "14.1.0",
+ "typescript": "^5"
}
}
diff --git a/public/borisjuk_01.png b/public/borisjuk_01.png
new file mode 100644
index 0000000..c26ee06
Binary files /dev/null and b/public/borisjuk_01.png differ
diff --git a/public/hero-banner.jpg b/public/hero-banner.jpg
new file mode 100644
index 0000000..5d00657
Binary files /dev/null and b/public/hero-banner.jpg differ
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/styles/globalStyle.ts b/styles/globalStyle.ts
new file mode 100644
index 0000000..7af4a1f
--- /dev/null
+++ b/styles/globalStyle.ts
@@ -0,0 +1,50 @@
+"use client"
+
+import { createGlobalStyle } from "styled-components"
+
+export const GlobalStyle = createGlobalStyle`
+ :root {
+ --primary: 201, 14, 14;
+ --white: 255, 255, 255;
+ --black: 0, 0, 0;
+ --background: 217, 217, 217;
+ --accent: 104, 104, 104;
+ }
+
+ ::selection {
+ background-color: rgba(var(--primary), 0.5);
+ }
+
+ *,
+ *::before,
+ *::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+
+ scrollbar-width: thin;
+ scrollbar-color: rgba(var(--primary), 0.5) rgba(var(--black), 0.5);
+
+ &::-moz-selection {
+ background-color: rgba(var(--primary), 0.5);
+ }
+
+ &::-webkit-scrollbar {
+ width: 0.5rem;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background-color: rgba(var(--primary), 0.5);
+ }
+
+ &::-webkit-scrollbar-track {
+ background-color: rgba(var(--black), 0.5);
+ }
+ }
+
+ body {
+ font-family: 'K2D', sans-serif;
+ background-color: rgb(var(--black));
+ color: rgb(var(--white));
+ }
+`