DEV;Update mobile view and add Jenkinsfile

This commit is contained in:
Roman Jaroš 2022-07-06 16:19:59 +02:00
parent 01d9d0d4a3
commit 906691bf15
22 changed files with 305 additions and 212 deletions

View file

@ -1,3 +1,6 @@
{
"extends": "next/core-web-vitals"
"extends": [
"next/core-web-vitals",
"eslint:recommended"
]
}

9
Jenkinsfile vendored Normal file
View file

@ -0,0 +1,9 @@
@Library('jenkins-lib')
import FrontendBuild
FrontendBuild({
name = 'portfolio'
port = "92:3000"
runSonar = true
appType = "nextjs"
})

View file

@ -1,34 +1,7 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
```

31
docker/Dockerfile Normal file
View file

@ -0,0 +1,31 @@
# Install dependencies only when needed
FROM node:16-alpine
RUN apk add --no-cache libc6-compat
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN ls -a
COPY .next/ .next/
COPY public/ public/
COPY node_modules/ node_modules/
COPY package.json package.json
RUN ls -a
RUN ls -a .next
RUN chown -R nextjs:nodejs .next
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]

View file

@ -1,6 +1,11 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
reactStrictMode: true,
i18n: {
locales: ["cs"],
defaultLocale: "cs",
},
output: "standalone",
};
module.exports = nextConfig
module.exports = nextConfig;

21
package-lock.json generated
View file

@ -1,18 +1,19 @@
{
"name": "portfolio",
"version": "0.1.0",
"version": "0.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "portfolio",
"version": "0.1.0",
"version": "0.1.1",
"dependencies": {
"@reduxjs/toolkit": "1.8.0",
"@treejs/components": "0.17.0",
"@treejs/constants": "0.17.0",
"@treejs/styles": "0.17.0",
"next": "12.2.0",
"next-seo": "^5.4.0",
"ramda": "^0.27.0",
"react": "17.0.2",
"react-dom": "17.0.2",
@ -2589,6 +2590,16 @@
}
}
},
"node_modules/next-seo": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/next-seo/-/next-seo-5.4.0.tgz",
"integrity": "sha512-R9DhajPwJnR/lsF2hZ8cN8uqr5CVITsRrCG1AF5+ufcaybKYOvnH8sH9MaH4/hpkps3PQ9H71S7J7SPYixAYzQ==",
"peerDependencies": {
"next": "^8.1.1-canary.54 || >=9.0.0",
"react": ">=16.0.0",
"react-dom": ">=16.0.0"
}
},
"node_modules/next/node_modules/postcss": {
"version": "8.4.5",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
@ -5560,6 +5571,12 @@
}
}
},
"next-seo": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/next-seo/-/next-seo-5.4.0.tgz",
"integrity": "sha512-R9DhajPwJnR/lsF2hZ8cN8uqr5CVITsRrCG1AF5+ufcaybKYOvnH8sH9MaH4/hpkps3PQ9H71S7J7SPYixAYzQ==",
"requires": {}
},
"node-releases": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",

View file

@ -1,8 +1,13 @@
{
"name": "portfolio",
"version": "0.1.0",
"version": "0.1.1",
"private": true,
"scripts": {
"ci:lint": "eslint .",
"ci:build": "npm run build",
"ci:test": "echo 1",
"ci:test-e2e": "echo 1",
"ci:increase-version": "npm version --git-tag-version=false",
"dev": "next dev",
"build": "next build",
"start": "next start",
@ -14,6 +19,7 @@
"@treejs/constants": "0.17.0",
"@treejs/styles": "0.17.0",
"next": "12.2.0",
"next-seo": "^5.4.0",
"ramda": "^0.27.0",
"react": "17.0.2",
"react-dom": "17.0.2",

2
public/robots.txt Normal file
View file

@ -0,0 +1,2 @@
User-agent: *
Allow: /

5
public/sitemap.xml Normal file
View file

@ -0,0 +1,5 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://romanjaros.cz</loc>
</url>
</urlset>

5
sonar-project.properties Normal file
View file

@ -0,0 +1,5 @@
sonar.projectKey=PORTFOLIO
sonar.projectName=portfolio
sonar.inclusions=src/**
sonar.coverage.exclusions=**/__tests__/**
sonar.javascript.lcov.reportPaths=temp/jest/lcov.info

View file

@ -1,7 +1,6 @@
import { Grid, GridCol } from "@treejs/components/Grid";
import Image from "next/image";
import { FC } from "react";
import MyTitle from "../components/MyTitle";
import MySection from "./MySection";
const AboutMe: FC = () => {
const age = Math.floor(
@ -13,30 +12,18 @@ const AboutMe: FC = () => {
);
return (
<Grid cols={6} className="mt-28">
<GridCol colSpan={1} className="text-center">
<Image
src="/me.svg"
alt="me"
width={200}
height={200}
objectFit="contain"
/>
</GridCol>
<GridCol colSpan={5} className="ml-10">
<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>Od roku 2020 pracuji pouze na IČO.</p>
</div>
</GridCol>
</Grid>
<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í. Aktuálně pracuji pouze na IČO.
</p>
</div>
</MySection>
);
};

View file

@ -1,73 +1,45 @@
import { Grid, GridCol } from "@treejs/components/Grid";
import Image from "next/image";
import { FC } from "react";
import MySection from "./MySection";
import MyTitle from "./MyTitle";
const Contact: 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 (
<Grid cols={6} className="mt-28">
<GridCol colSpan={1} className="text-center">
<Image
src="/contact.svg"
alt="contact"
width={200}
height={200}
objectFit="contain"
/>
</GridCol>
<GridCol colSpan={5} className="ml-10">
<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">
<p>
<a
target="_blank"
href="http://linkedin.com/in/roman-jaroš-16a687139"
rel="noreferrer"
>
LinkedIn
</a>
</p>
<p>
<a
target="_blank"
href="https://git.romanjaros.dev"
rel="noreferrer"
>
Gitea (Git)
</a>
</p>
</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>
</GridCol>
</Grid>
<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>
<br />
<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>
);
};

33
src/components/Footer.tsx Normal file
View file

@ -0,0 +1,33 @@
import { Grid, GridCol } from "@treejs/components/Grid";
import { FC } from "react";
const Footer: FC = () => {
return (
<div 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.</p>
</GridCol>
</Grid>
</div>
);
};
export default Footer;

View file

@ -1,8 +1,7 @@
import { Grid, GridCol } from "@treejs/components/Grid";
import Image from "next/image";
import { isEmpty, isNil, map } from "ramda";
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 = () => {
@ -45,21 +44,10 @@ const FullStory: FC = () => {
}, []);
return (
<Grid cols={6} className="mt-28">
<GridCol colSpan={1} className="text-center">
<Image
src="/story.svg"
alt="story"
width={200}
height={200}
objectFit="contain"
/>
</GridCol>
<GridCol colSpan={5} className="ml-10">
<MyTitle left="Na" right="Projektech" />
<div className="mt-10">{projectsRender}</div>
</GridCol>
</Grid>
<MySection iconName="story">
<MyTitle left="Na" right="Projektech" />
<div className="mt-10">{projectsRender}</div>
</MySection>
);
};

View file

@ -0,0 +1,36 @@
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 (
<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>
);
};
export default MySection;

View file

@ -10,14 +10,10 @@ type IProps = {
const MyTitle: FC<IProps> = ({ left, right, className }) => {
return (
<div className={cx("mytitle", className)}>
<span className="mytitle-left">
{"<"}
{left}
</span>
<span className="mytitle-right">
{right}
{" />"}
</span>
<span className="mytitle-left">{"<"}</span>
<h2 className="mytitle-left">{left}</h2>
<h2 className="mytitle-right">{right}</h2>
<span className="mytitle-left">&nbsp;{"/>"}</span>
</div>
);
};

View file

@ -1,10 +1,11 @@
import { Grid, GridCol } from "@treejs/components/Grid";
import Image from "next/image";
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";
const Services: FC = () => {
const renderSkills = useMemo(() => {
@ -37,54 +38,43 @@ const Services: FC = () => {
}, []);
return (
<Grid cols={6} className="mt-28">
<GridCol colSpan={1} className="text-center">
<Image
src="/services.svg"
alt="services"
width={200}
height={200}
objectFit="contain"
/>
</GridCol>
<GridCol colSpan={5} className="ml-10">
<MyTitle left="Umím" right="Ovládat" />
<Grid cols={4} className="mt-10">
<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 aplikací</b>
{renderSkills[3]}
</GridCol>
</Grid>
<MySection iconName="services">
<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 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>
</GridCol>
</Grid>
<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>
);
};

View file

@ -3,11 +3,11 @@ import { IProject } from "../types/projects";
export const projects: IProject[] = [
{
name: "doservislu.online",
dateFrom: "březen 2020",
dateFrom: "prosinec 2021",
dateTo: "současnost",
link: "http://doservisu.online",
desciption:
"Tvorba frontendu veřejné aplikace pro možnost jednoduchého obsloužení zákazníka autoservisu. Z pohledu FE se jedná o sólo vývoj.",
"Tvorba frontendu aplikace pro možnost jednoduchého obsloužení zákazníka autoservisu. Z pohledu FE se jedná o sólo vývoj.",
},
{
name: "Vývojář FE",

View file

@ -8,7 +8,7 @@ export const skills: ISkill[][] = [
level: "full",
},
{
name: "Redux (i tookit)",
name: "Redux (i toolkit)",
level: "full",
},
{
@ -63,17 +63,29 @@ export const skills: ISkill[][] = [
name: "NPM / Yarn",
level: "full",
},
{
name: "NightwatchJS",
level: "full",
},
{
name: "Jenkins (CI, CD)",
level: "full",
},
{
name: "SonarQube",
level: "full",
},
{
name: "Designování",
level: "part",
},
{
name: "UML",
level: "part",
},
],
// App maitenence
// server maitenence
[
{
name: "Docker",
@ -87,5 +99,9 @@ export const skills: ISkill[][] = [
name: "Portainer",
level: "part",
},
{
name: "Monitoring",
level: "part",
},
],
];

View file

@ -6,6 +6,7 @@ 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();
@ -20,13 +21,7 @@ function PortolioApp({ Component, pageProps }: AppProps) {
user: false,
}}
components={{
footer: (
<div className="bg-slate-300 p-2 text-center">
IČO 08738734 | DIČ CZ9307111946 | Jsem plátce DPH. Fyzická osoba
zapsaná v živnostenském rejstříku v Karlových Varech (CZ0412) od
02.12.2019. Tento web nepoužívá cookies.
</div>
),
footer: <Footer />,
}}
>
<Component {...pageProps} />

View file

@ -5,13 +5,36 @@ import AboutMe from "../components/AboutMe";
import Services from "../components/Services";
import Contact from "../components/Contact";
import FullStory from "../components/FullStory";
import { NextSeo } from "next-seo";
const Home: NextPage = () => {
return (
<>
<div className="mx-auto w-3/5">
<NextSeo
title="Roman Developer"
description="Primárně se zaměřuji na vývoj frontendů webových aplikací. Ale jsem schopný dělat vývoj i backedovžch částí webových aplikací."
openGraph={{
url: "https://romanjaros.cz",
type: "websites",
title: "Roman Jaroš Developer Portfolio",
description: "Portfolio web vývojáře Roman Jaroš",
site_name: "Roman Developer",
locale: "Czech Republic",
images: [
{
url: "http://romanjaros.cz/me.svg",
alt: "me",
},
],
}}
/>
<div className="mx-auto w-full md:w-4/5">
<div className="text-center mb-20">
<MyTitle left="Roman" right="Developer" className="text-6xl" />
<MyTitle
left="Roman"
right="Developer"
className="text-5xl lg:text-6xl justify-center"
/>
</div>
<AboutMe />
<Services />

View file

@ -3,6 +3,7 @@ const title = (theme) => ({
"font-size": "30px",
"font-weight": "bold",
"padding-top": "40px",
display: "flex",
"&-left": {
color: theme("colors.black"),