Upgrade to latest nodejs and completely rework website
This commit is contained in:
parent
07270c3aa6
commit
0372c4cd77
38 changed files with 4135 additions and 6933 deletions
34
src/app/components/AboutMe.tsx
Normal file
34
src/app/components/AboutMe.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import {Card} from "../../components/Skills";
|
||||
|
||||
export const AboutMe = () => {
|
||||
const age = Math.floor(
|
||||
((new Date() as any) - (new Date("1993-07-11") as any)) / 31557600000
|
||||
);
|
||||
|
||||
const work = Math.floor(
|
||||
((new Date() as any) - (new Date("2012-12-01") as any)) / 31557600000
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="leading-snug text-slate-500 dark:text-slate-400">
|
||||
<p>
|
||||
👋, my name is Roman Jaroš. I am {age}. {work} years working as software engineer.
|
||||
I have been programming since I was 15 years old and still love to learn new technologies.
|
||||
Outside of the programming world, I maintain servers with about 120 docker containers.
|
||||
Outside of the IT world, I enjoy reading self improvement books, meditating,
|
||||
alternative medicine and model painting or playing video games.
|
||||
</p>
|
||||
<br/>
|
||||
<p>
|
||||
<b>I am contractor and currently only for full remote jobs.</b>
|
||||
</p>
|
||||
<br />
|
||||
<div className="flex justify-center flex-col md:flex-row gap-2">
|
||||
<Card title="Web development" description="I offer my experience in web development." />
|
||||
<Card title="UI/UX Design" description="I offer design web application in figma or penpot." />
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
31
src/app/components/Contact.tsx
Normal file
31
src/app/components/Contact.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import {GithubIcon, InfoIcon, LinkedinIcon, MailIcon} from "lucide-react";
|
||||
|
||||
export const Contact = () => {
|
||||
return (
|
||||
<>
|
||||
<section className="leading-relaxed">
|
||||
<p className="flex justify-center">
|
||||
<a
|
||||
type="button"
|
||||
href="mailto:sales@romanjaros.dev"
|
||||
className="flex gap-2 focus:outline-none text-white bg-yellow-400 hover:bg-yellow-500 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg px-5 py-2.5 me-2 mb-2 dark:text-slate-600 dark:focus:ring-yellow-900">
|
||||
<MailIcon/> Send e-mail
|
||||
</a>
|
||||
</p>
|
||||
<p className="flex justify-center gap-4 my-8">
|
||||
<a href="mailto:info@romanjaros.dev"><InfoIcon/></a>
|
||||
<a
|
||||
target="_blank"
|
||||
href="http://linkedin.com/in/roman-jaroš-16a687139"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<LinkedinIcon/>
|
||||
</a>
|
||||
<a target="_blank" href="https://forgejo.romanjaros.dev" rel="noreferrer">
|
||||
<GithubIcon/>
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
20
src/app/components/Footer.tsx
Normal file
20
src/app/components/Footer.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
export const Footer = () => {
|
||||
return (
|
||||
<>
|
||||
<footer className="text-slate-800 p-2 my-2 leading-relaxed text-sm dark:text-slate-400">
|
||||
<p>
|
||||
IČO 08738734, DIČ CZ9307111946 |
|
||||
Bražec 50, Bochov 36471, Česká Republika
|
||||
</p>
|
||||
<p>
|
||||
<b>Jsem plátce DPH.</b> Fyzická osoba zapsaná v živnostenském
|
||||
rejstříku v Karlových Varech (CZ0412) od 02.12.2019.
|
||||
</p>
|
||||
<p className="mt-2">
|
||||
This website does not use cookies.
|
||||
The measurement of site traffic is completely anonymous.
|
||||
</p>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
};
|
62
src/app/components/Jobs.tsx
Normal file
62
src/app/components/Jobs.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
import {ArrowLeftIcon, ExternalLinkIcon, MapPinIcon, MoveRightIcon, SquareArrowOutUpRightIcon} from "lucide-react";
|
||||
import {notNil} from "../../utils";
|
||||
|
||||
type Job = {
|
||||
name: string,
|
||||
started: string,
|
||||
ended: string,
|
||||
description: string,
|
||||
tags: string[],
|
||||
link?: string
|
||||
}
|
||||
|
||||
export const Jobs = async () => {
|
||||
const res = await fetch("http://localhost:3000/jobs.json")
|
||||
const data: Job[] | undefined = await res?.json();
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="px-4">
|
||||
<ol className="relative border-s border-gray-200 dark:border-gray-700">
|
||||
{data?.filter(notNil).map(({name, started, ended, description, tags, link}, index) => (
|
||||
<li key={index} className="mb-10 ms-6">
|
||||
<span
|
||||
className="absolute flex items-center justify-center w-6 h-6 bg-white rounded-full -start-3 ring-8 ring-white dark:ring-slate-800 dark:bg-slate-800">
|
||||
<MapPinIcon className="text-black dark:text-white"/>
|
||||
</span>
|
||||
<h3 className="flex items-center gap-2 mb-1 text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{name}
|
||||
</h3>
|
||||
<time className="block mb-2 text-sm font-normal leading-none text-gray-400 dark:text-gray-500">
|
||||
{started} - {ended}
|
||||
</time>
|
||||
<p className="mb-4 text-base font-normal text-gray-500 dark:text-gray-400">
|
||||
{description}
|
||||
</p>
|
||||
{link != undefined &&
|
||||
<p>
|
||||
<a href={link}
|
||||
target="_blank"
|
||||
className="inline-flex gap-2 mb-4 items-center px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg hover:bg-gray-100 hover:text-blue-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700">
|
||||
Visit website
|
||||
<MoveRightIcon />
|
||||
</a>
|
||||
</p>
|
||||
}
|
||||
<p className="flex flex-wrap gap-2">
|
||||
{tags.sort().map((name) => (
|
||||
<span
|
||||
key={name}
|
||||
className="bg-purple-100 text-purple-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-purple-900 dark:text-purple-300"
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
))}
|
||||
</p>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
41
src/app/components/Skills.tsx
Normal file
41
src/app/components/Skills.tsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
import {notNil} from "../../utils";
|
||||
import {StarIcon} from "lucide-react";
|
||||
|
||||
type Job = {
|
||||
tags: string[]
|
||||
}
|
||||
|
||||
export const Skills = async () => {
|
||||
const res = await fetch("http://localhost:3000/jobs.json")
|
||||
const data: Job[] | undefined = await res?.json();
|
||||
|
||||
const skills = new Set(data?.filter(notNil).flatMap(({tags}) => tags).sort());
|
||||
|
||||
return (
|
||||
<>
|
||||
<section>
|
||||
<div className="flex items-center my-2">
|
||||
<p className="mr-2 w-12 ms-1 text-sm font-medium text-gray-500 dark:text-gray-400">Czech</p>
|
||||
<StarIcon fill="#fde047" className="w-4 h-4 ms-1 text-yellow-300"/>
|
||||
<StarIcon fill="#fde047" className="w-4 h-4 ms-1 text-yellow-300"/>
|
||||
<StarIcon fill="#fde047" className="w-4 h-4 ms-1 text-yellow-300"/>
|
||||
</div>
|
||||
<div className="flex items-center my-2">
|
||||
<p className="mr-2 w-12 ms-1 text-sm font-medium text-gray-500 dark:text-gray-400">English </p>
|
||||
<StarIcon fill="#fde047" className="w-4 h-4 ms-1 text-yellow-300"/>
|
||||
<StarIcon className="w-4 h-4 ms-1 text-gray-300 dark:text-gray-500"/>
|
||||
<StarIcon className="w-4 h-4 ms-1 text-gray-300 dark:text-gray-500"/>
|
||||
</div>
|
||||
</section>
|
||||
<section className="flex flex-wrap gap-2">
|
||||
{Array.from(skills)?.map((name) => (
|
||||
<span
|
||||
key={name}
|
||||
className="bg-indigo-100 text-indigo-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-indigo-900 dark:text-indigo-300">
|
||||
{name}
|
||||
</span>
|
||||
))}
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
12
src/app/components/Title.tsx
Normal file
12
src/app/components/Title.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
export const Title = () => {
|
||||
return (
|
||||
<div className="flex justify-center text-4xl sm:text-6xl my-8">
|
||||
<span className="text-gray-600 dark:text-white"><</span>
|
||||
<h1>
|
||||
<span className="text-gray-600 dark:text-white">Just</span>
|
||||
<span className="text-orange-800 dark:text-orange-400">Roman</span>
|
||||
</h1>
|
||||
<span className="text-orange-800 dark:text-orange-400"> /></span>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
@import '@treejs/styles/global.css';
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;700&display=swap');
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
@apply bg-white text-black text-sm;
|
||||
|
20
src/app/layout.tsx
Normal file
20
src/app/layout.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import {ReactNode} from "react";
|
||||
import "./globals.css"
|
||||
|
||||
export default function AppLayout({
|
||||
children,
|
||||
}: {
|
||||
children: ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</head>
|
||||
<body className="bg-white dark:bg-slate-800">
|
||||
<main>{children}</main>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
21
src/app/page.tsx
Normal file
21
src/app/page.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import {Title} from "./components/Title";
|
||||
import {AboutMe} from "./components/AboutMe";
|
||||
import {Contact} from "./components/Contact";
|
||||
import {Footer} from "./components/Footer";
|
||||
import {Jobs} from "./components/Jobs";
|
||||
import {Skills} from "./components/Skills";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-y-16 md:w-3/4 lg:w-2/3 mx-auto p-4 mb-20">
|
||||
<Title />
|
||||
<AboutMe />
|
||||
<Contact />
|
||||
<Skills />
|
||||
<Jobs />
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
import { FC } from "react";
|
||||
import MyTitle from "../components/MyTitle";
|
||||
import MySection from "./MySection";
|
||||
|
||||
const AboutMe: FC = () => {
|
||||
const age = Math.floor(
|
||||
((new Date() as any) - (new Date("1993-07-11") as any)) / 31557600000
|
||||
);
|
||||
|
||||
const work = Math.floor(
|
||||
((new Date() as any) - (new Date("2012-12-01") as any)) / 31557600000
|
||||
);
|
||||
|
||||
return (
|
||||
<MySection iconName="me">
|
||||
<MyTitle left="Dobrý" right="Den" />
|
||||
<div className="mt-10">
|
||||
Jmenuji se <b>Roman Jaroš</b>.
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<p>
|
||||
Je mi <b>{age} let</b> a již <b>{work} let</b> se profesionálně věnuji
|
||||
vývoji a správě webových aplikací.
|
||||
</p>
|
||||
<p className="mt-3">
|
||||
Programování se věnuji od svých 15 let. Mé dosažené vzdělání je
|
||||
Střední lesnická škola zakončené s maturitou. Fakt, že mám vystudováný
|
||||
zcela jiný obor, jen podtrhuje mé nabité znalosti a zkušenosti. Osobně
|
||||
si i myslím, že na vzdělání tolik nezáleží, pokud je práce i zábavou.
|
||||
Stále se rád učím novým technologiím a snažím se je aplikovat ve svém
|
||||
FW nebo na nových projektech.
|
||||
</p>
|
||||
<p className="mt-3">
|
||||
Rád se vzdělávám i mimo svět programování. Doma mám dva Intel NUC
|
||||
počítače, na kterých mi běží plno aplikací. Na těchto serverech se
|
||||
učím pracovat s aplikacemi pro CI/CD, monitorování různých aktivit a
|
||||
zapracování bezpečnostním prvků.
|
||||
</p>
|
||||
<p className="mt-3">
|
||||
Mimo svět IT se rád zabívám čtením knih o osobním rozvoji, meditacím a
|
||||
alternativní medicíně.
|
||||
</p>
|
||||
<p className="mt-3">
|
||||
<b>Aktuálně spolupracuji pouze na IČO.</b>
|
||||
</p>
|
||||
</div>
|
||||
</MySection>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutMe;
|
|
@ -1,47 +0,0 @@
|
|||
import { FC } from "react";
|
||||
import MySection from "./MySection";
|
||||
import MyTitle from "./MyTitle";
|
||||
|
||||
const Contact: FC = () => {
|
||||
return (
|
||||
<MySection iconName="contact">
|
||||
<MyTitle left="Můj" right="Kontakt" />
|
||||
<div className="mt-10">
|
||||
<p className="mb-2">
|
||||
Obchodní nabídky prosím zasílejte
|
||||
<a href="mailto:sales@romanjaros.dev">sem</a>.
|
||||
</p>
|
||||
<p className="mb-2">
|
||||
Jiné dotazy prosím <a href="mailto:info@romanjaros.dev">sem</a>.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
<a
|
||||
target="_blank"
|
||||
href="http://linkedin.com/in/roman-jaroš-16a687139"
|
||||
rel="noreferrer"
|
||||
>
|
||||
LinkedIn
|
||||
</a>
|
||||
</p>
|
||||
<p className="mt-2">
|
||||
<a target="_blank" href="https://git.romanjaros.dev" rel="noreferrer">
|
||||
Gitea (Git)
|
||||
</a>
|
||||
</p>
|
||||
<p className="mt-10">
|
||||
Pokud potřebujete zadat tiket na podporu, použijte prosím
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://helpdesk.romanjaros.dev/index.php?a=add"
|
||||
rel="noreferrer"
|
||||
>
|
||||
tento formulář
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</MySection>
|
||||
);
|
||||
};
|
||||
|
||||
export default Contact;
|
|
@ -1,36 +0,0 @@
|
|||
import { Grid, GridCol } from "@treejs/components/Grid";
|
||||
import { FC } from "react";
|
||||
|
||||
const Footer: FC = () => {
|
||||
return (
|
||||
<footer className="bg-slate-300 p-2">
|
||||
<Grid cols={2} className="mx-auto w-full lg:w-3/5 md:w-4/5">
|
||||
<GridCol>
|
||||
<p>IČO 08738734</p>
|
||||
<p>DIČ CZ9307111946</p>
|
||||
</GridCol>
|
||||
<GridCol>
|
||||
<p>
|
||||
Bražec 50
|
||||
<br />
|
||||
Bochov 36471
|
||||
<br />
|
||||
Česká Republika
|
||||
</p>
|
||||
</GridCol>
|
||||
<GridCol colSpan={2}>
|
||||
<p>
|
||||
<b>Jsem plátce DPH.</b> Fyzická osoba zapsaná v živnostenském
|
||||
rejstříku v Karlových Varech (CZ0412) od 02.12.2019.
|
||||
</p>
|
||||
<p className="mt-2">
|
||||
Tento web nepoužívá cookies. Měření návšťěvnosti webu je zcela
|
||||
anonymní a probíhá pouze na službě vlastníka webu.
|
||||
</p>
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
|
@ -1,54 +0,0 @@
|
|||
import { isNil, map } from "ramda";
|
||||
import { FC, Fragment, useMemo } from "react";
|
||||
import { projects } from "../constants/projects";
|
||||
import MySection from "./MySection";
|
||||
import MyTitle from "./MyTitle";
|
||||
|
||||
const FullStory: FC = () => {
|
||||
const projectsRender = useMemo(() => {
|
||||
let i = 0;
|
||||
return map((project) => {
|
||||
i++;
|
||||
return (
|
||||
<Fragment key={i}>
|
||||
<div className="border-timeline border-dotted border-l-4 pl-4 my-2">
|
||||
<p className="mb-2 font-bold">{project.name}</p>
|
||||
<p className="mb-2 font-thin">
|
||||
{project.dateFrom} - {project.dateTo}
|
||||
</p>
|
||||
<p>
|
||||
{project.desciption}
|
||||
{!isNil(project.link) ? (
|
||||
<>
|
||||
<a
|
||||
href={project.link}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="ml-1"
|
||||
>
|
||||
Odkaz na projekt
|
||||
</a>
|
||||
.
|
||||
</>
|
||||
) : null}
|
||||
</p>
|
||||
</div>
|
||||
{i === projects.length ? null : (
|
||||
<svg height="20" width="20" className="-ml-2">
|
||||
<circle cx="10" cy="10" r="9" fill="#B25068" />
|
||||
</svg>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}, projects);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MySection iconName="story">
|
||||
<MyTitle left="Na" right="Projektech" />
|
||||
<div className="mt-10">{projectsRender}</div>
|
||||
</MySection>
|
||||
);
|
||||
};
|
||||
|
||||
export default FullStory;
|
|
@ -1,38 +0,0 @@
|
|||
import React, { FC, ReactElement } from "react";
|
||||
import { Grid, GridCol } from "@treejs/components/Grid";
|
||||
import Image from "next/image";
|
||||
import { GRID_SIZE } from "@treejs/components/Grid/types";
|
||||
|
||||
type IProps = {
|
||||
iconName: string;
|
||||
children: ReactElement | ReactElement[];
|
||||
};
|
||||
|
||||
const MySection: FC<IProps> = ({ iconName, children }) => {
|
||||
return (
|
||||
<section>
|
||||
<Grid
|
||||
cols={{ [GRID_SIZE.SM]: 1, [GRID_SIZE.LG]: 6 }}
|
||||
className="mb-28 mx-4"
|
||||
>
|
||||
<GridCol colSpan={1} className="text-center">
|
||||
<Image
|
||||
src={`/${iconName}.svg`}
|
||||
alt={iconName}
|
||||
width={200}
|
||||
height={200}
|
||||
objectFit="contain"
|
||||
/>
|
||||
</GridCol>
|
||||
<GridCol
|
||||
colSpan={{ [GRID_SIZE.SM]: 1, [GRID_SIZE.LG]: 5 }}
|
||||
className="lg:ml-10"
|
||||
>
|
||||
{children}
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default MySection;
|
|
@ -1,23 +0,0 @@
|
|||
import React, { FC } from "react";
|
||||
import cx from "classnames";
|
||||
|
||||
type IProps = {
|
||||
left: string;
|
||||
right: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const MyTitle: FC<IProps> = ({ left, right, className }) => {
|
||||
return (
|
||||
<div className={cx("mytitle", className)}>
|
||||
<span className="mytitle-left"><</span>
|
||||
<h2>
|
||||
<span className="mytitle-left">{left}</span>
|
||||
<span className="mytitle-right">{right}</span>
|
||||
</h2>
|
||||
<span className="mytitle-left"> /></span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyTitle;
|
|
@ -1,81 +1,17 @@
|
|||
import { Grid, GridCol } from "@treejs/components/Grid";
|
||||
import { FC, useMemo } from "react";
|
||||
import { skills } from "../constants/skills";
|
||||
import MyTitle from "./MyTitle";
|
||||
import { map } from "ramda";
|
||||
import { ISkill } from "../types/skills";
|
||||
import MySection from "./MySection";
|
||||
import { GRID_SIZE } from "@treejs/components/Grid/types";
|
||||
import {FC} from "react";
|
||||
|
||||
const Skills: FC = () => {
|
||||
const renderSkills = useMemo(() => {
|
||||
let i = 0;
|
||||
return map((skillList: ISkill[]) => {
|
||||
let z = 0;
|
||||
const skills = map((skill: ISkill) => {
|
||||
z++;
|
||||
return (
|
||||
<li className="flex mb-1" key={z}>
|
||||
<svg height="10" width="10" className="mt-1.5 mr-2">
|
||||
<circle
|
||||
cx="5"
|
||||
cy="5"
|
||||
r="4"
|
||||
fill={skill.level === "full" ? "#90C8AC" : "#FFE7BF"}
|
||||
/>
|
||||
</svg>
|
||||
{skill.name}
|
||||
</li>
|
||||
);
|
||||
})(skillList);
|
||||
i++;
|
||||
return (
|
||||
<ol className="mt-2" key={i}>
|
||||
{skills}
|
||||
</ol>
|
||||
);
|
||||
})(skills);
|
||||
}, []);
|
||||
type CardProps = {
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const Card: FC<CardProps> = ({title, description}) => {
|
||||
return (
|
||||
<MySection iconName="skills">
|
||||
<MyTitle left="Umím" right="Ovládat" />
|
||||
<Grid cols={{ [GRID_SIZE.SM]: 4 }} className="mt-10 grid-cols-2">
|
||||
<GridCol>
|
||||
<b>Vývoj FE</b>
|
||||
{renderSkills[0]}
|
||||
</GridCol>
|
||||
<GridCol>
|
||||
<b>Vývoj BE</b>
|
||||
{renderSkills[1]}
|
||||
</GridCol>
|
||||
<GridCol>
|
||||
<b>Další</b>
|
||||
{renderSkills[2]}
|
||||
</GridCol>
|
||||
<GridCol>
|
||||
<b>Správa serveru</b>
|
||||
{renderSkills[3]}
|
||||
</GridCol>
|
||||
</Grid>
|
||||
|
||||
<div className="flex mt-6 text-sm">
|
||||
<div className="flex">
|
||||
<svg height="10" width="10" className="mt-1.5 mr-2">
|
||||
<circle cx="5" cy="5" r="4" fill="#90C8AC" />
|
||||
</svg>
|
||||
používám na projektech
|
||||
</div>
|
||||
|
||||
<div className="flex ml-5">
|
||||
<svg height="10" width="10" className="mt-1.5 mr-2">
|
||||
<circle cx="5" cy="5" r="4" fill="#FFE7BF" />
|
||||
</svg>
|
||||
hraju si a učím se
|
||||
</div>
|
||||
</div>
|
||||
</MySection>
|
||||
);
|
||||
};
|
||||
|
||||
export default Skills;
|
||||
<div
|
||||
className="w-full md:w-80 block p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700"
|
||||
>
|
||||
<h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">{title}</h5>
|
||||
<p className="font-normal text-gray-700 dark:text-gray-400">{description}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import "../styles/globals.css";
|
||||
|
||||
import type { AppProps } from "next/app";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import Skeleton from "@treejs/components/Skeleton";
|
||||
import store from "../redux/store";
|
||||
import { Provider } from "react-redux";
|
||||
import Footer from "../components/Footer";
|
||||
|
||||
function PortolioApp({ Component, pageProps }: AppProps) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Skeleton
|
||||
history={router}
|
||||
menuItems={{}}
|
||||
enabledMenu={{
|
||||
sidebar: false,
|
||||
user: false,
|
||||
}}
|
||||
components={{
|
||||
footer: <Footer />,
|
||||
}}
|
||||
>
|
||||
<Component {...pageProps} />
|
||||
</Skeleton>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default PortolioApp;
|
|
@ -1,83 +0,0 @@
|
|||
import type { NextPage } from "next";
|
||||
|
||||
import AboutMe from "../components/AboutMe";
|
||||
import Skills from "../components/Skills";
|
||||
import Contact from "../components/Contact";
|
||||
import FullStory from "../components/FullStory";
|
||||
import { NextSeo, WebPageJsonLd } from "next-seo";
|
||||
import Head from "next/head";
|
||||
import Script from "next/script";
|
||||
|
||||
const date = new Date().toISOString();
|
||||
|
||||
const Home: NextPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
defer
|
||||
type="text/javascript"
|
||||
data-website-id="27410757-9ce4-4dad-a0ad-a1e2a0303495"
|
||||
src="https://wa.romanjaros.dev/script.js"
|
||||
/>
|
||||
<Head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</Head>
|
||||
<WebPageJsonLd
|
||||
description="Roman Developer"
|
||||
id="https://www.romanjaros.cz"
|
||||
lastReviewed={date}
|
||||
reviewedBy={{
|
||||
type: "Person",
|
||||
name: "Roman",
|
||||
}}
|
||||
/>
|
||||
<NextSeo
|
||||
title="Roman - Frontend developer"
|
||||
description="Primárně se zaměřuji na vývoj frontendů webových aplikací. Jsem schopný dělat vývoj backedů webových aplikací a učím se udržovat vlastní server pro dev stack."
|
||||
canonical="https://www.romanjaros.cz"
|
||||
openGraph={{
|
||||
url: "https://www.romanjaros.cz",
|
||||
type: "websites",
|
||||
title: "Roman Jaroš, Developer",
|
||||
description:
|
||||
"Portfolio web frontent and backend vývojáře Roman Jaroš",
|
||||
site_name: "Roman Developer",
|
||||
locale: "Czech Republic",
|
||||
images: [
|
||||
{
|
||||
url: "https://www.romanjaros.cz/icon.svg",
|
||||
alt: "Roman Developer",
|
||||
},
|
||||
],
|
||||
}}
|
||||
additionalLinkTags={[
|
||||
{
|
||||
rel: "icon",
|
||||
href: "https://www.romanjaros.cz/favicon.ico",
|
||||
},
|
||||
{
|
||||
rel: "apple-touch-icon",
|
||||
href: "https://www.romanjaros.cz/icon.svg",
|
||||
sizes: "76x76",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div className="mx-auto w-full md:w-4/5">
|
||||
<header className="mytitle text-3xl lg:text-6xl justify-center text-center mb-20">
|
||||
<span className="mytitle-left"><</span>
|
||||
<h1>
|
||||
<span className="mytitle-left">Roman</span>
|
||||
<span className="mytitle-right">Developer</span>
|
||||
</h1>
|
||||
<span className="mytitle-left"> /></span>
|
||||
</header>
|
||||
<AboutMe />
|
||||
<Skills />
|
||||
<Contact />
|
||||
<FullStory />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
|
@ -1,25 +0,0 @@
|
|||
import { combineReducers } from "redux";
|
||||
|
||||
import { MODAL_REDUCER_NAME } from "@treejs/components/Modal/constants";
|
||||
import modalReducer from "@treejs/components/Modal/reducer";
|
||||
import { TOASTER_REDUCER_NAME } from "@treejs/components/Toaster/constants";
|
||||
import toasterReducer from "@treejs/components/Toaster/reducer";
|
||||
import { ROOT_REDUCER_NAME } from "@treejs/constants/redux";
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
|
||||
type ITreejsReducer = {
|
||||
[MODAL_REDUCER_NAME]: typeof modalReducer;
|
||||
[TOASTER_REDUCER_NAME]: typeof toasterReducer;
|
||||
};
|
||||
|
||||
const store = configureStore({
|
||||
reducer: combineReducers({
|
||||
[ROOT_REDUCER_NAME]: combineReducers<ITreejsReducer>({
|
||||
[MODAL_REDUCER_NAME]: modalReducer,
|
||||
[TOASTER_REDUCER_NAME]: toasterReducer,
|
||||
}),
|
||||
}),
|
||||
devTools: process.env.NEXT_PUBLIC__IS_DEV === "true",
|
||||
});
|
||||
|
||||
export default store;
|
|
@ -1,22 +0,0 @@
|
|||
const title = (theme) => ({
|
||||
".mytitle": {
|
||||
"font-size": "30px",
|
||||
"font-weight": "bold",
|
||||
"padding-top": "40px",
|
||||
display: "flex",
|
||||
|
||||
"&-left": {
|
||||
color: theme("colors.black"),
|
||||
},
|
||||
|
||||
"&-right": {
|
||||
color: theme("colors.primary.DEFAULT"),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = ({ addComponents, theme }) => {
|
||||
addComponents(title(theme));
|
||||
};
|
||||
|
||||
module.exports.title = title;
|
|
@ -1,14 +0,0 @@
|
|||
const title = () => ({
|
||||
".page-main": {
|
||||
".content": {
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = ({ addComponents, theme }) => {
|
||||
addComponents(title(theme));
|
||||
};
|
||||
|
||||
module.exports.title = title;
|
|
@ -1,27 +0,0 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
const path = require("path");
|
||||
|
||||
const plugin = require("tailwindcss/plugin");
|
||||
|
||||
module.exports = {
|
||||
presets: [require("@treejs/styles/tailwind.config")],
|
||||
content: [
|
||||
...require("@treejs/styles/tailwind.config").content,
|
||||
path.resolve(""), // path to place, where are used tailwind styles
|
||||
],
|
||||
safelist: require("@treejs/styles/tailwind.config").safelist,
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
timeline: "var(--color-timeline)",
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
plugin(require("./plugins/mytitle")),
|
||||
plugin(require("./plugins/sketeton")),
|
||||
],
|
||||
};
|
5
src/utils.ts
Normal file
5
src/utils.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export function notNil<TValue>(
|
||||
value: TValue | null | undefined,
|
||||
): value is TValue {
|
||||
return value !== null && value !== undefined;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue