refactor: move to monorepo
This commit is contained in:
parent
f81e3e1dd6
commit
d891426a12
88 changed files with 403 additions and 160 deletions
75
apps/vojtechmares.com/components/Button.tsx
Normal file
75
apps/vojtechmares.com/components/Button.tsx
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import Link from "next/link";
|
||||
import clsx from "clsx";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
const baseStyles = {
|
||||
solid:
|
||||
"group inline-flex items-center justify-center rounded-full font-semibold focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2",
|
||||
outline:
|
||||
"group inline-flex ring-1 items-center justify-center rounded-full focus:outline-none",
|
||||
};
|
||||
|
||||
const variantStyles = {
|
||||
solid: {
|
||||
black:
|
||||
"bg-black text-white hover:bg-slate-700 active:bg-slate-800 focus-visible:outline-slate-900",
|
||||
amber:
|
||||
"bg-amber-500 text-white hover:bg-amber-600 active:bg-amber-800 focus-visible:outline-amber-500",
|
||||
white:
|
||||
"bg-white text-black hover:bg-amber-50 active:bg-amber-200 focus-visible:outline-white",
|
||||
},
|
||||
outline: {
|
||||
black:
|
||||
"ring-slate-200 text-black hover:ring-slate-300 active:bg-slate-100 focus-visible:outline-amber-500 focus-visible:ring-slate-300",
|
||||
white:
|
||||
"ring-slate-700 text-white hover:ring-slate-500 active:ring-slate-700 focus-visible:outline-white",
|
||||
amber: "", // Outline buttons cannot be amber
|
||||
},
|
||||
};
|
||||
|
||||
const transitionStyle = "transition duration-150 ease-in-out";
|
||||
|
||||
const sizeStyles = {
|
||||
medium: "px-4 py-2 text-sm",
|
||||
large: "px-8 py-4 text-base",
|
||||
};
|
||||
|
||||
type Props = {
|
||||
variant?: "solid" | "outline";
|
||||
color?: "black" | "white" | "amber";
|
||||
size?: "medium" | "large";
|
||||
className?: string;
|
||||
href?: string;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
export function Button({
|
||||
variant = "solid",
|
||||
color = "black",
|
||||
size = "medium",
|
||||
className,
|
||||
href,
|
||||
children,
|
||||
}: Props) {
|
||||
if (variant === "outline" && color === "amber") {
|
||||
throw new Error("Outline buttons cannot be amber");
|
||||
}
|
||||
|
||||
className = clsx(
|
||||
baseStyles[variant],
|
||||
variantStyles[variant][color],
|
||||
sizeStyles[size],
|
||||
transitionStyle,
|
||||
className
|
||||
);
|
||||
|
||||
if (href !== undefined) {
|
||||
return (
|
||||
<Link href={href} className={className}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
return <button className={className}>{children}</button>;
|
||||
}
|
||||
}
|
||||
15
apps/vojtechmares.com/components/Container.tsx
Normal file
15
apps/vojtechmares.com/components/Container.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import clsx from "clsx";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
export function Container({ className, children }: Props) {
|
||||
return (
|
||||
<div className={clsx("mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", className)}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
30
apps/vojtechmares.com/components/homepage/CallToAction.tsx
Normal file
30
apps/vojtechmares.com/components/homepage/CallToAction.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { Button } from "@/components/Button";
|
||||
import { Container } from "@/components/Container";
|
||||
|
||||
export function CallToAction() {
|
||||
return (
|
||||
<section
|
||||
id="get-started-today"
|
||||
className="relative overflow-hidden bg-amber-500 py-32"
|
||||
>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-xl text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
Pojďme do toho společně
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-white">
|
||||
Je na čase pozvednout Vaši infrastrukturu na dnešní standardy. Infrastruktura má ukázat Vaši aplikaci světu, ne ji držet při zemi.
|
||||
</p>
|
||||
<Button
|
||||
href="mailto:iam@vojtechmares.com"
|
||||
color="white"
|
||||
size="large"
|
||||
className="mt-10"
|
||||
>
|
||||
Napište mi
|
||||
</Button>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
110
apps/vojtechmares.com/components/homepage/Faqs.tsx
Normal file
110
apps/vojtechmares.com/components/homepage/Faqs.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import Image from "next/image";
|
||||
|
||||
import { Container } from "@/components/Container";
|
||||
import backgroundImage from "@/images/background-faqs.jpg";
|
||||
|
||||
const faqs = [
|
||||
[
|
||||
{
|
||||
question: "Does TaxPal handle VAT?",
|
||||
answer:
|
||||
"Well no, but if you move your company offshore you can probably ignore it.",
|
||||
},
|
||||
{
|
||||
question: "Can I pay for my subscription via purchase order?",
|
||||
answer: "Absolutely, we are happy to take your money in all forms.",
|
||||
},
|
||||
{
|
||||
question: "How do I apply for a job at TaxPal?",
|
||||
answer:
|
||||
"We only hire our customers, so subscribe for a minimum of 6 months and then let’s talk.",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
question: "What was that testimonial about tax fraud all about?",
|
||||
answer:
|
||||
"TaxPal is just a software application, ultimately your books are your responsibility.",
|
||||
},
|
||||
{
|
||||
question:
|
||||
"TaxPal sounds horrible but why do I still feel compelled to purchase?",
|
||||
answer:
|
||||
"This is the power of excellent visual design. You just can’t resist it, no matter how poorly it actually functions.",
|
||||
},
|
||||
{
|
||||
question:
|
||||
"I found other companies called TaxPal, are you sure you can use this name?",
|
||||
answer:
|
||||
"Honestly not sure at all. We haven’t actually incorporated or anything, we just thought it sounded cool and made this website.",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
question: "How do you generate reports?",
|
||||
answer:
|
||||
"You just tell us what data you need a report for, and we get our kids to create beautiful charts for you using only the finest crayons.",
|
||||
},
|
||||
{
|
||||
question: "Can we expect more inventory features?",
|
||||
answer: "In life it’s really better to never expect anything at all.",
|
||||
},
|
||||
{
|
||||
question: "I lost my password, how do I get into my account?",
|
||||
answer:
|
||||
"Send us an email and we will send you a copy of our latest password spreadsheet so you can find your information.",
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
export function Faqs() {
|
||||
return (
|
||||
<section
|
||||
id="faq"
|
||||
aria-labelledby="faq-title"
|
||||
className="relative overflow-hidden bg-slate-50 py-20 sm:py-32"
|
||||
>
|
||||
<Image
|
||||
className="absolute top-0 left-1/2 max-w-none translate-x-[-30%] -translate-y-1/4"
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
width={1558}
|
||||
height={946}
|
||||
unoptimized
|
||||
/>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-2xl lg:mx-0">
|
||||
<h2
|
||||
id="faq-title"
|
||||
className="font-display text-3xl tracking-tight text-black sm:text-4xl"
|
||||
>
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
If you can’t find what you’re looking for, email our support team
|
||||
and if you’re lucky someone will get back to you.
|
||||
</p>
|
||||
</div>
|
||||
<ul
|
||||
role="list"
|
||||
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-8 lg:max-w-none lg:grid-cols-3"
|
||||
>
|
||||
{faqs.map((column, columnIndex) => (
|
||||
<li key={columnIndex}>
|
||||
<ul role="list" className="flex flex-col gap-y-8">
|
||||
{column.map((faq, faqIndex) => (
|
||||
<li key={faqIndex}>
|
||||
<h3 className="font-display text-lg leading-7 text-black">
|
||||
{faq.question}
|
||||
</h3>
|
||||
<p className="mt-4 text-sm text-slate-700">{faq.answer}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
81
apps/vojtechmares.com/components/homepage/Hero.tsx
Normal file
81
apps/vojtechmares.com/components/homepage/Hero.tsx
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import Image, { type StaticImageData } from "next/image";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import { Container } from "@/components/Container";
|
||||
|
||||
import avatarVojtechMares from "@/images/avatars/vojtech-mares.png";
|
||||
import logoGLAMI from "@/images/logos/glami.svg";
|
||||
import logoFakturoid from "@/images/logos/fakturoid.svg";
|
||||
|
||||
type Company = {
|
||||
name: string;
|
||||
logo: StaticImageData;
|
||||
}
|
||||
|
||||
const companies: Company[] = [
|
||||
{ name: 'GLAMI', logo: logoGLAMI },
|
||||
{ name: 'Fakturoid', logo: logoFakturoid },
|
||||
];
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<>
|
||||
<Container className="pt-5 lg:pt-8">
|
||||
<div className="flex flex-col justify-center md:flex-row md:justify-between md:items-end">
|
||||
<div>
|
||||
<h1 className="font-display text-5xl font-medium tracking-tight text-black sm:text-7xl leading-10">
|
||||
Jsem{" "}
|
||||
<span className="relative whitespace-nowrap text-amber-500">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 418 42"
|
||||
className="absolute top-2/3 left-0 h-[0.58em] w-full fill-amber-300/70"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<path d="M203.371.916c-26.013-2.078-76.686 1.963-124.73 9.946L67.3 12.749C35.421 18.062 18.2 21.766 6.004 25.934 1.244 27.561.828 27.778.874 28.61c.07 1.214.828 1.121 9.595-1.176 9.072-2.377 17.15-3.92 39.246-7.496C123.565 7.986 157.869 4.492 195.942 5.046c7.461.108 19.25 1.696 19.17 2.582-.107 1.183-7.874 4.31-25.75 10.366-21.992 7.45-35.43 12.534-36.701 13.884-2.173 2.308-.202 4.407 4.442 4.734 2.654.187 3.263.157 15.593-.78 35.401-2.686 57.944-3.488 88.365-3.143 46.327.526 75.721 2.23 130.788 7.584 19.787 1.924 20.814 1.98 24.557 1.332l.066-.011c1.201-.203 1.53-1.825.399-2.335-2.911-1.31-4.893-1.604-22.048-3.261-57.509-5.556-87.871-7.36-132.059-7.842-23.239-.254-33.617-.116-50.627.674-11.629.54-42.371 2.494-46.696 2.967-2.359.259 8.133-3.625 26.504-9.81 23.239-7.825 27.934-10.149 28.304-14.005.417-4.348-3.529-6-16.878-7.066Z" />
|
||||
</svg>
|
||||
<span className="relative">Vojtěch Mareš</span>
|
||||
</span>{" "}
|
||||
a pomohu Vám s Vaší IT infrastrukturou.
|
||||
</h1>
|
||||
<p className="mt-6 max-w-xl text-lg tracking-tight text-slate-700">
|
||||
Společně snížíme Vaše náklady na infrasturkuturu, zbavíme se technického
|
||||
dluhu a připravíme Vaší IT infrastrukturu na rapidní škálování.
|
||||
</p>
|
||||
<div className="mt-10 flex flex-col gap-y-6 md:gap-y-0 sm:flex-row sm:justify-start sm:gap-x-6">
|
||||
<Button
|
||||
href="mailto:iam@vojtechmares.com"
|
||||
size="large"
|
||||
>
|
||||
Napište mi
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-10 "> {/* mt-36 lg:mt-44 */}
|
||||
<p className="font-display text-lg tracking-tight text-slate-700">
|
||||
Moji spokojení klienti, přidejte se k nim i Vy.
|
||||
</p>
|
||||
<ul
|
||||
role="list"
|
||||
className="mt-4 flex flex-wrap items-center justify-center gap-x-6 sm:justify-start"
|
||||
>
|
||||
{companies.map((company) => (
|
||||
<li key={company.name} className="flex">
|
||||
<Image
|
||||
className="h-16 object-scale-down"
|
||||
src={company.logo}
|
||||
alt={company.name}
|
||||
width={128}
|
||||
height={64}
|
||||
priority
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<Image className="pt-10 md:pt-0 mx-auto md:mx-0" priority width={400} height={800} src={avatarVojtechMares} alt="Vojtěch Mareš" />
|
||||
</div>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import Image, { StaticImageData } from "next/image";
|
||||
import clsx from "clsx";
|
||||
|
||||
import { Container } from "@/components/Container";
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
import logoKubernetes from "@/images/logos/tools/kubernetes.svg";
|
||||
import logoRancher from "@/images/logos/tools/rancher.svg";
|
||||
|
||||
import logoAWS from "@/images/logos/tools/amazonaws.svg";
|
||||
import logoDigitalOcean from "@/images/logos/tools/digitalocean.svg";
|
||||
import logoGCP from "@/images/logos/tools/googlecloud.svg";
|
||||
import logoAzure from "@/images/logos/tools/microsoftazure.svg";
|
||||
import logoLinode from "@/images/logos/tools/linode.svg";
|
||||
|
||||
import logoOpenStack from "@/images/logos/tools/openstack.svg";
|
||||
import logoProxmox from "@/images/logos/tools/proxmox.svg";
|
||||
import logovmware from "@/images/logos/tools/vmware.svg";
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: "Kubernetes",
|
||||
description: "Kubernetes je open-source platforma pro automatizaci a správu kontejnerizovaných aplikací. Je to jednotná standardizovaná platforma pro vývoj a provozování aplikací, která umožňuje rychle a efektivně nasazovat a spravovat aplikace v kontejnerech.",
|
||||
images: [
|
||||
{ src: logoKubernetes, alt: "Kubernetes"},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Veřejný cloud",
|
||||
description: "Veřejný cloud je sdílená fyzická infrastruktura, která je spravována třetí stranou, díky tomu se nestaráte o vlastní hardware a jeho údržbu. Veřejné cloudy jsou využívány společnostmi ať pro vývoj a testování, ale i pro produkční nasazení a dodávání jejich aplikace zákazníkům, kdekoliv na celém světě.",
|
||||
images: [
|
||||
{ src: logoAWS, alt: "Amazon Web Services"},
|
||||
{ src: logoGCP, alt: "Google Cloud Platform"},
|
||||
{ src: logoAzure, alt: "Microsoft Azure"},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "\"Malý\" veřejný cloud",
|
||||
description: "Ne všichni hráči na cloudovém trhu jsou velké firmy. Existují i menší poskytovatelé, kteří sice nenabízí jejich rešení pro každý Váš problém, ale jen virtuální stroje, spravované Kubernetes a databáze a objektové úložiště. Což je však pro většinu aplikací naprosto dostatečné.",
|
||||
images: [
|
||||
{ src: logoDigitalOcean, alt: "Digital Ocean"},
|
||||
{ src: logoLinode, alt: "Linode"},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Vlastní infrastruktura",
|
||||
description: "Ať máte vlastní datacentrum nebo jen pár virtuálních strojů, můžete využít Kubernetes a všechny jeho výhody. Využijte vlastní infrastrukturu a vytvořte si vlastní cloud. Pokud používáte například Proxmox, OpenStack nebo VMware vSphere, můžete využít jejich API a přímo je propojit s Vašimi Kubernetes, ať jeden cluster nebo víc.",
|
||||
images: [
|
||||
{ src: logoOpenStack, alt: "OpenStack"},
|
||||
{ src: logoProxmox, alt: "Proxmox"},
|
||||
{ src: logovmware, alt: "VMware"},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Hybridní řešení",
|
||||
description: "Pokud máte vlastní infrastrukturu, ale chcete využít i veřejný cloud, můžete využít například Rancher, který vám umožní propojit Vaši vlastní infrastrukturu s veřejným cloudem. Využijte výhody obou světů a vytvořte si hybridní řešení. Díky Rancheru získáte jednotnou ucelenou platformu pro všechny prostředí.",
|
||||
images: [
|
||||
{ src: logoRancher, alt: "Rancher"},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const SectionDesktop = ({title, description, images, reverse}: { title: string, description: string, images: { src: StaticImageData, alt: string }[], reverse: boolean}) => (
|
||||
<div className="grid grid-cols-2 gap-x-24 gap-y-32">
|
||||
<div>
|
||||
<h3 className="font-display text-xl font-medium">{title}</h3>
|
||||
<p className="mt-4 text-slate-700">{description}</p>
|
||||
</div>
|
||||
<div className={clsx(reverse ? "order-first" : "")}>
|
||||
<div className="flex flex-row justify-around">
|
||||
{images.map((image, index) => (
|
||||
<Image key={index} src={image.src} width={128} height={128} alt={image.alt} title={image.alt} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const SectionMobile = ({title, description, images}: { title: string, description: string, images: { src: StaticImageData, alt: string }[]}) => (
|
||||
<>
|
||||
<div className="flex flex-wrap gap-x-8 justify-around overflow-hidden mb-4">
|
||||
{images.map((image, index) => (
|
||||
<Image key={index} src={image.src} width={128} height={128} alt={image.alt} title={image.alt} />
|
||||
))}
|
||||
</div>
|
||||
<h3 className="font-display text-xl font-medium">{title}</h3>
|
||||
<p className="mt-4 text-slate-700">{description}</p>
|
||||
</>
|
||||
)
|
||||
|
||||
const Mobile = () => (
|
||||
<div className="lg:hidden mt-10">
|
||||
{sections.map((section, index) => (
|
||||
<div key={index} className={clsx(sections.length - 1 !== index ? "mb-10" : "")}>
|
||||
<SectionMobile {...section} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
const Desktop = () => (
|
||||
<div className="hidden lg:block mt-10 lg:mt-20">
|
||||
{sections.map((section, index) => (
|
||||
<div key={index} className={
|
||||
clsx(sections.length - 1 !== index ? "mb-32" : "")
|
||||
}>
|
||||
<SectionDesktop {...section} reverse={index % 2 === 1}/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
export function KubernetesEverywhere() {
|
||||
return (
|
||||
<section
|
||||
id="kubernetes-kdekoliv"
|
||||
aria-label="Features for simplifying everyday business tasks"
|
||||
className="pt-20 pb-14 sm:pb-20 sm:pt-32 lg:pb-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-black sm:text-4xl">
|
||||
Kubernetes, jedna platforma, kdekoliv
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
Se vším Vám poradím, od veřejného cloudu přes on-premise a serverless, až po edge.
|
||||
</p>
|
||||
</div>
|
||||
<Mobile />
|
||||
<Desktop />
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
122
apps/vojtechmares.com/components/homepage/Services.tsx
Normal file
122
apps/vojtechmares.com/components/homepage/Services.tsx
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import clsx from "clsx";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import { Container } from "@/components/Container";
|
||||
|
||||
type SwirlyDoodleProps = { className: string };
|
||||
|
||||
function SwirlyDoodle({ className }: SwirlyDoodleProps) {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 281 40"
|
||||
className={className}
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M240.172 22.994c-8.007 1.246-15.477 2.23-31.26 4.114-18.506 2.21-26.323 2.977-34.487 3.386-2.971.149-3.727.324-6.566 1.523-15.124 6.388-43.775 9.404-69.425 7.31-26.207-2.14-50.986-7.103-78-15.624C10.912 20.7.988 16.143.734 14.657c-.066-.381.043-.344 1.324.456 10.423 6.506 49.649 16.322 77.8 19.468 23.708 2.65 38.249 2.95 55.821 1.156 9.407-.962 24.451-3.773 25.101-4.692.074-.104.053-.155-.058-.135-1.062.195-13.863-.271-18.848-.687-16.681-1.389-28.722-4.345-38.142-9.364-15.294-8.15-7.298-19.232 14.802-20.514 16.095-.934 32.793 1.517 47.423 6.96 13.524 5.033 17.942 12.326 11.463 18.922l-.859.874.697-.006c2.681-.026 15.304-1.302 29.208-2.953 25.845-3.07 35.659-4.519 54.027-7.978 9.863-1.858 11.021-2.048 13.055-2.145a61.901 61.901 0 0 0 4.506-.417c1.891-.259 2.151-.267 1.543-.047-.402.145-2.33.913-4.285 1.707-4.635 1.882-5.202 2.07-8.736 2.903-3.414.805-19.773 3.797-26.404 4.829Zm40.321-9.93c.1-.066.231-.085.29-.041.059.043-.024.096-.183.119-.177.024-.219-.007-.107-.079ZM172.299 26.22c9.364-6.058 5.161-12.039-12.304-17.51-11.656-3.653-23.145-5.47-35.243-5.576-22.552-.198-33.577 7.462-21.321 14.814 12.012 7.205 32.994 10.557 61.531 9.831 4.563-.116 5.372-.288 7.337-1.559Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
type ServiceProps = {
|
||||
name: string;
|
||||
price: string;
|
||||
description: string;
|
||||
href: string;
|
||||
featured?: boolean;
|
||||
buttonText?: string;
|
||||
};
|
||||
|
||||
function Service({
|
||||
name,
|
||||
price,
|
||||
description,
|
||||
href,
|
||||
featured = false,
|
||||
buttonText = "Napište mi",
|
||||
}: ServiceProps) {
|
||||
return (
|
||||
<section
|
||||
className={clsx(
|
||||
"flex flex-col rounded-3xl px-6 sm:px-8 py-8",
|
||||
featured ? "order-first bg-amber-500 lg:order-none" : "",
|
||||
featured ? "hover:bg-amber-600" : "md:ring-1 md:hover:ring-slate-700 md:ring-transparent",
|
||||
"transition ease-in-out duration-300 md:hover:-translate-y-1 md:hover:scale-110"
|
||||
)}
|
||||
>
|
||||
<h3 className="font-display text-4xl text-white">{name}</h3>
|
||||
<p className="font-display mt-4 text-lg font-light tracking-tight text-white">
|
||||
{price}
|
||||
</p>
|
||||
<p
|
||||
className={clsx(
|
||||
"mt-2 text-base",
|
||||
featured ? "text-slate-100" : "text-slate-400"
|
||||
)}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
<Button
|
||||
href={href}
|
||||
variant={featured ? "solid" : "outline"}
|
||||
color="white"
|
||||
className="mt-16"
|
||||
aria-label={`Get started with the ${name} plan for ${price}`}
|
||||
>
|
||||
{buttonText}
|
||||
</Button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function Services() {
|
||||
return (
|
||||
<section
|
||||
id="services"
|
||||
aria-label="Services"
|
||||
className="bg-black py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
<span className="relative whitespace-nowrap">
|
||||
<SwirlyDoodle className="absolute top-1/2 left-0 h-[1em] w-full fill-amber-400" />
|
||||
<span className="relative">Co pro Vás,</span>
|
||||
</span>{" "}
|
||||
můžu udělat
|
||||
</h2>
|
||||
<p className="mt-4 text-lg text-slate-400">
|
||||
Nezáleží na velikosti Vaší firmy, ať jste startup, nebo korporát, dokážu pomoci každému.
|
||||
</p>
|
||||
</div>
|
||||
<div className="-mx-4 mt-16 grid max-w-2xl grid-cols-1 gap-y-10 sm:mx-auto lg:-mx-8 lg:max-w-none lg:grid-cols-3 xl:mx-0 xl:gap-x-8">
|
||||
<Service
|
||||
name="Konzultace"
|
||||
price="2 000 CZK za hodinu"
|
||||
description="Chcete se poradit nebo si nevíte rady? Projdeme Váš současný stav a najdeme kde je problém a navrhneme řešení."
|
||||
href="mailto:iam@vojtechmares.com"
|
||||
/>
|
||||
<Service
|
||||
featured
|
||||
name="Firemní školení"
|
||||
price="24 000 CZK za jednodenní školení"
|
||||
description="Jednoduše, s názornými příklady, které si každý vyzkouší. Naučím váš tým nové technologii nebo prohloubíme stávající znalosti."
|
||||
href="/#skoleni"
|
||||
buttonText="Seznam školení"
|
||||
/>
|
||||
<Service
|
||||
name="Implementace"
|
||||
price="Cena dohodou"
|
||||
description="Analyzujeme Vaši situaci, projdeme možnosti, vybereme nejlepší řešení a společně jej nasadíme."
|
||||
href="mailto:iam@vojtechmares.com"
|
||||
buttonText="Napište mi"
|
||||
/>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
100
apps/vojtechmares.com/components/homepage/Testimonials.tsx
Normal file
100
apps/vojtechmares.com/components/homepage/Testimonials.tsx
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import Image from "next/image";
|
||||
|
||||
import { Container } from "@/components/Container";
|
||||
import avatarAntoninHoskovec from "@/images/avatars/antonin-hoskovec.jpg";
|
||||
|
||||
const testimonials = [
|
||||
[
|
||||
{
|
||||
content:
|
||||
"Když jsme Vojtu poznali, byli jsme zrovna v procesu migrace existujících Kubernetes clusterů na nové, vylepšené (vlastní) infrastrukturní balíčky. Krásně jsme si sedli v automatizaci jak vytváření/strhávání infrastruktury, tak v automatizaci nasazování a použitých technologiích (AWS, Kubernetes, Terraform, Python, GitLab. Docker). Vojta pro nás navrhnul a vytvořil nové Terraform repozitáře, pomohl nám i se školením týmu a mladších kolegů a byl dlouhodobě k dispozici pro řešení ad-hoc problémů.",
|
||||
author: {
|
||||
name: "Antonín Hoškovec",
|
||||
role: "AI team lead, GLAMI",
|
||||
image: avatarAntoninHoskovec,
|
||||
},
|
||||
},
|
||||
],
|
||||
// [
|
||||
// {
|
||||
// content:
|
||||
// "The best part about TaxPal is every time I pay my employees, my bank balance doesn’t go down like it used to. Looking forward to spending this extra cash when I figure out why my card is being declined.",
|
||||
// author: {
|
||||
// name: "Leland Kiehn",
|
||||
// role: "Founder of Kiehn and Sons",
|
||||
// image: avatarImage5,
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
];
|
||||
|
||||
function QuoteIcon(props: any) {
|
||||
return (
|
||||
<svg aria-hidden="true" width={105} height={78} {...props}>
|
||||
<path d="M25.086 77.292c-4.821 0-9.115-1.205-12.882-3.616-3.767-2.561-6.78-6.102-9.04-10.622C1.054 58.534 0 53.411 0 47.686c0-5.273.904-10.396 2.712-15.368 1.959-4.972 4.746-9.567 8.362-13.786a59.042 59.042 0 0 1 12.43-11.3C28.325 3.917 33.599 1.507 39.324 0l11.074 13.786c-6.479 2.561-11.677 5.951-15.594 10.17-3.767 4.219-5.65 7.835-5.65 10.848 0 1.356.377 2.863 1.13 4.52.904 1.507 2.637 3.089 5.198 4.746 3.767 2.41 6.328 4.972 7.684 7.684 1.507 2.561 2.26 5.5 2.26 8.814 0 5.123-1.959 9.19-5.876 12.204-3.767 3.013-8.588 4.52-14.464 4.52Zm54.24 0c-4.821 0-9.115-1.205-12.882-3.616-3.767-2.561-6.78-6.102-9.04-10.622-2.11-4.52-3.164-9.643-3.164-15.368 0-5.273.904-10.396 2.712-15.368 1.959-4.972 4.746-9.567 8.362-13.786a59.042 59.042 0 0 1 12.43-11.3C82.565 3.917 87.839 1.507 93.564 0l11.074 13.786c-6.479 2.561-11.677 5.951-15.594 10.17-3.767 4.219-5.65 7.835-5.65 10.848 0 1.356.377 2.863 1.13 4.52.904 1.507 2.637 3.089 5.198 4.746 3.767 2.41 6.328 4.972 7.684 7.684 1.507 2.561 2.26 5.5 2.26 8.814 0 5.123-1.959 9.19-5.876 12.204-3.767 3.013-8.588 4.52-14.464 4.52Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function Testimonials() {
|
||||
return (
|
||||
<section
|
||||
id="testimonials"
|
||||
aria-label="What our customers are saying"
|
||||
className="bg-slate-50 py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-black sm:text-4xl">
|
||||
Napsali o mně
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
Zde jsou některé z mých referencí.
|
||||
</p>
|
||||
</div>
|
||||
<ul
|
||||
role="list"
|
||||
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-6 sm:gap-8 lg:mt-20 lg:max-w-4xl" // lg:grid-cols-2
|
||||
>
|
||||
{testimonials.map((column, columnIndex) => (
|
||||
<li key={columnIndex}>
|
||||
<ul role="list" className="flex flex-col gap-y-6 sm:gap-y-8">
|
||||
{column.map((testimonial, testimonialIndex) => (
|
||||
<li key={testimonialIndex}>
|
||||
<figure className="relative rounded-2xl bg-white p-6 shadow-xl shadow-slate-900/10">
|
||||
<QuoteIcon className="absolute top-6 left-6 fill-slate-100" />
|
||||
<blockquote className="relative">
|
||||
<p className="text-lg tracking-tight text-black">
|
||||
{testimonial.content}
|
||||
</p>
|
||||
</blockquote>
|
||||
<figcaption className="relative mt-6 flex items-center justify-between border-t border-slate-100 pt-6">
|
||||
<div>
|
||||
<div className="font-display text-base text-black">
|
||||
{testimonial.author.name}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-slate-700">
|
||||
{testimonial.author.role}
|
||||
</div>
|
||||
</div>
|
||||
<div className="overflow-hidden rounded-full bg-slate-50">
|
||||
<Image
|
||||
className="h-14 w-14 object-cover"
|
||||
src={testimonial.author.image}
|
||||
alt={testimonial.author.name}
|
||||
width={56}
|
||||
height={56}
|
||||
/>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
94
apps/vojtechmares.com/components/homepage/Training.tsx
Normal file
94
apps/vojtechmares.com/components/homepage/Training.tsx
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import Image, { StaticImageData } from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
import { Container } from "@/components/Container";
|
||||
|
||||
import logoKubernetes from "@/images/logos/tools/kubernetes.svg";
|
||||
import logoTerraform from "@/images/logos/tools/terraform.svg";
|
||||
import logoArgo from "@/images/logos/tools/argo.svg";
|
||||
import logoGit from "@/images/logos/tools/git.svg";
|
||||
|
||||
type TrainingType = {
|
||||
name: string;
|
||||
logo: StaticImageData;
|
||||
href: string;
|
||||
};
|
||||
|
||||
const trainingList: TrainingType[] = [
|
||||
{ name: 'Kubernetes', href: '/skoleni/kubernetes', logo: logoKubernetes },
|
||||
{ name: 'Terraform', href: '/skoleni/terraform', logo: logoTerraform },
|
||||
{ name: 'ArgoCD', href: '/skoleni/argocd', logo: logoArgo },
|
||||
{ name: 'Git', href: '/skoleni/git', logo: logoGit },
|
||||
];
|
||||
|
||||
type TrainingProps = {
|
||||
training: TrainingType;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Training = ({ training, className }: TrainingProps) => {
|
||||
return (
|
||||
<Link href={training.href} className={className}>
|
||||
<Image
|
||||
src={training.logo}
|
||||
className="rounded-lg p-2 invert mx-auto"
|
||||
width="128"
|
||||
height="128"
|
||||
alt={training.name}
|
||||
/>
|
||||
<h3 className="mt-4 text-lg font-medium text-amber-500 text-center">{training.name}</h3>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const TrainingGridMobile = () => {
|
||||
return (
|
||||
<div className="-mx-4 mt-20 grid grid-cols-2 gap-x-8 gap-y-4 overflow-hidden px-4 sm:-mx-6 sm:px-6 lg:hidden">
|
||||
{trainingList.map((training) => (
|
||||
<div key={training.name} >
|
||||
<Training training={training} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TrainingGridDesktop = () => {
|
||||
return (
|
||||
<div className="hidden lg:mt-20 lg:block">
|
||||
<div className="grid grid-cols-4 gap-x-8 gap-y-4">
|
||||
{trainingList.map((training) => (
|
||||
<div key={training.name} className="relative py-4 cursor-pointer rounded-3xl transition ease-in-out duration-300 md:hover:-translate-y-1 md:hover:scale-110 md:ring-1 md:hover:ring-slate-700 md:ring-transparent">
|
||||
<Training training={training} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TrainingList = () => {
|
||||
return (
|
||||
<section
|
||||
id="skoleni"
|
||||
aria-label="Training"
|
||||
className="pt-20 pb-14 sm:pb-20 sm:pt-32 lg:pb-32 bg-black"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
Moje školení
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-400">
|
||||
Od veřejného cloudu přes on-premise až po serverless, se vším vám
|
||||
poradím.
|
||||
</p>
|
||||
</div>
|
||||
<TrainingGridMobile />
|
||||
<TrainingGridDesktop />
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { TrainingList };
|
||||
85
apps/vojtechmares.com/components/homepage/WhatIDo.tsx
Normal file
85
apps/vojtechmares.com/components/homepage/WhatIDo.tsx
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import clsx from "clsx";
|
||||
|
||||
import { Container } from "@/components/Container";
|
||||
|
||||
const steps = [
|
||||
{
|
||||
name: "Analýza současného stavu",
|
||||
description:
|
||||
"Zjistíme kde jsou slabá místa Vaší infrastruktury nebo aplikace, a nebo obojího.",
|
||||
},
|
||||
{
|
||||
name: "Návrh řešení",
|
||||
description:
|
||||
"Navrhnu, jak tato slabá místa odstranit, na co si dát pozor a naplánujeme případné další kroky. ",
|
||||
},
|
||||
{
|
||||
name: "Implementace",
|
||||
description:
|
||||
"Přesunu Vaši aplikaci do Kubernetes, ať na Vašem vlastním hardware nebo v public cloudu. Celá infrastruktura bude jasně deklarovaná jako kód pomocí Terraformu.",
|
||||
},
|
||||
{
|
||||
name: "Proškolení Vašeho týmu",
|
||||
description:
|
||||
"Naučím váš tým používat moderní technologie, tak abyste mohli rozvíjet Vaší aplikaci a byznys a technologie byly nástrojem k rozvoji, ne břemenem, které s sebou táhnete.",
|
||||
},
|
||||
];
|
||||
|
||||
export function WhatIDo() {
|
||||
return (
|
||||
<section
|
||||
id="features"
|
||||
aria-label="Features for running your books"
|
||||
className="relative overflow-hidden bg-gradient-to-br to-amber-600 via-amber-500 from-amber-500 pt-20 pb-28 sm:py-32"
|
||||
>
|
||||
<Container className="relative">
|
||||
<div className="max-w-2xl md:mx-auto md:text-center xl:max-w-none">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl md:text-5xl">
|
||||
Z nuly do cloudu
|
||||
</h2>
|
||||
<p className="mt-6 text-lg tracking-tight text-slate-100">
|
||||
Vše co budete potřebovat, od začátku až do cíle.
|
||||
</p>
|
||||
</div>
|
||||
<nav aria-label="Progress">
|
||||
<ol
|
||||
role="list"
|
||||
className="mx-auto mt-20 max-w-3xl overflow-hidden pt-2"
|
||||
>
|
||||
{steps.map((step, stepIdx) => (
|
||||
<li
|
||||
key={step.name}
|
||||
className={clsx(
|
||||
stepIdx !== steps.length - 1 ? "pb-10" : "",
|
||||
"relative"
|
||||
)}
|
||||
>
|
||||
{stepIdx !== steps.length - 1 ? (
|
||||
<div
|
||||
className="absolute top-4 left-6 -ml-px mt-0.5 h-full w-0.5 bg-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : null}
|
||||
<div className="group relative flex items-start">
|
||||
<span className="flex h-9 items-center" aria-hidden="true">
|
||||
<span className="relative z-10 flex h-12 w-12 items-center justify-center rounded-full border-2 border-amber-500 bg-white">
|
||||
<span className="h-3 w-3 rounded-full bg-amber-500" />
|
||||
</span>
|
||||
</span>
|
||||
<span className="ml-4 flex min-w-0 flex-col">
|
||||
<span className="text-2xl font-normal text-white">
|
||||
{step.name}
|
||||
</span>
|
||||
<span className="text-lg text-slate-100">
|
||||
{step.description}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</nav>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
162
apps/vojtechmares.com/components/layout/Footer.tsx
Normal file
162
apps/vojtechmares.com/components/layout/Footer.tsx
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
import Link from "next/link";
|
||||
|
||||
import { Container } from "@/components/Container";
|
||||
// import { Logo } from '@/components/Logo'
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="bg-slate-50">
|
||||
<Container className="py-8">
|
||||
<div className="py-4">
|
||||
<div className="grid grid-cols-1 gap-y-6 lg:grid-cols-4 lg:gap-4">
|
||||
<div>
|
||||
<h4 className="text-lg font-medium">Vojtěch Mareš</h4>
|
||||
<ul className="mt-4 list-none">
|
||||
<li>
|
||||
<Link href="tel:+420732490651" className="underline">
|
||||
+420 732 490 651
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href="mailto:iam@vojtechmares.com"
|
||||
className="underline"
|
||||
>
|
||||
iam@vojtechmares.com
|
||||
</Link>
|
||||
</li>
|
||||
<li className="mt-4">
|
||||
Company ID
|
||||
<br />
|
||||
<code id="company-id">06999280</code>
|
||||
</li>
|
||||
<li className="mt-2">
|
||||
VAT ID
|
||||
<br />
|
||||
<code id="vat-id">CZ9709180063</code>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">Nejblíbenější školení</h3>
|
||||
<ul className="mt-4 list-disc pl-4">
|
||||
<li>
|
||||
<Link href="/skoleni/kubernetes" className="underline">
|
||||
Kubernetes
|
||||
</Link>
|
||||
</li>
|
||||
{/* <li>
|
||||
<Link href="/skoleni/gitlab-ci" className="underline">GitLab CI</Link>
|
||||
</li> */}
|
||||
<li>
|
||||
<Link href="/skoleni/terraform" className="underline">
|
||||
Terraform
|
||||
</Link>
|
||||
</li>
|
||||
{/* <li>
|
||||
<Link href="/skoleni/rancher" className="underline">Rancher</Link>
|
||||
</li> */}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">Důležité odkazy</h3>
|
||||
<ul className="mt-4 list-disc pl-4">
|
||||
{/* <li>
|
||||
<Link
|
||||
href="https://devops-skoelni.cz/?utm_source=vojtechmares&utm_medium=vojtechmares-com-website&utm_content=link"
|
||||
className="underline"
|
||||
target="_blank"
|
||||
>
|
||||
DevOps-Skoleni.cz
|
||||
</Link>
|
||||
</li> */}
|
||||
<li>
|
||||
<Link
|
||||
href="https://skoleni.io/?utm_source=vojtechmares&utm_medium=vojtechmares-com-website&utm_content=link"
|
||||
className="underline"
|
||||
target="_blank"
|
||||
>
|
||||
Skoleni.io
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href="https://devopsaci.cz/?utm_source=vojtechmares&utm_medium=vojtechmares-com-website&utm_content=link"
|
||||
className="underline"
|
||||
target="_blank"
|
||||
>
|
||||
DevOpsaci.cz
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">Zaujal jsem vás?</h3>
|
||||
<p className="mt-4">
|
||||
Zaujal jsem vás avšak nevíte, jak přesně bych vám mohl pomoci?
|
||||
Nebojte se zeptat a společně vymyslíme, jak vám mohu pomoci.
|
||||
</p>
|
||||
<Button
|
||||
href="mailto:iam@vojtechmares.com"
|
||||
className="mt-5"
|
||||
>
|
||||
Napište mi
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center border-t border-slate-400/10 py-10 sm:flex-row-reverse sm:justify-between">
|
||||
<div className="flex gap-x-6">
|
||||
<Link
|
||||
href="https://www.linkedin.com/in/vojtech-mares/"
|
||||
target="_blank"
|
||||
className="group"
|
||||
aria-label="Vojtěch Mareš na LinkedIn"
|
||||
>
|
||||
<svg
|
||||
// role="img"
|
||||
// viewBox="0 0 24 24"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 fill-black group-hover:fill-slate-700"
|
||||
>
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
|
||||
</svg>
|
||||
</Link>
|
||||
<Link
|
||||
href="https://twitter.com/vojtechmares_"
|
||||
target="_blank"
|
||||
className="group"
|
||||
aria-label="Vojtěch Mareš na Twitter"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 fill-black group-hover:fill-slate-700"
|
||||
>
|
||||
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0 0 22 5.92a8.19 8.19 0 0 1-2.357.646 4.118 4.118 0 0 0 1.804-2.27 8.224 8.224 0 0 1-2.605.996 4.107 4.107 0 0 0-6.993 3.743 11.65 11.65 0 0 1-8.457-4.287 4.106 4.106 0 0 0 1.27 5.477A4.073 4.073 0 0 1 2.8 9.713v.052a4.105 4.105 0 0 0 3.292 4.022 4.093 4.093 0 0 1-1.853.07 4.108 4.108 0 0 0 3.834 2.85A8.233 8.233 0 0 1 2 18.407a11.615 11.615 0 0 0 6.29 1.84" />
|
||||
</svg>
|
||||
</Link>
|
||||
<Link
|
||||
href="https://github.com/vojtechmares"
|
||||
target="_blank"
|
||||
className="group"
|
||||
aria-label="Vojtěch Mareš na GitHub"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 fill-black group-hover:fill-slate-700"
|
||||
>
|
||||
<path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2Z" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
<p className="mt-6 text-slate-700 sm:mt-0">
|
||||
Copyright © {new Date().getFullYear()} Vojtěch Mareš. Všechna
|
||||
práva vyhrazena.
|
||||
</p>
|
||||
</div>
|
||||
</Container>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
45
apps/vojtechmares.com/components/layout/Header.tsx
Normal file
45
apps/vojtechmares.com/components/layout/Header.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import Link from "next/link";
|
||||
|
||||
import { Container } from "@/components/Container";
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
export function Header() {
|
||||
return (
|
||||
<>
|
||||
<header className="py-10">
|
||||
<Container>
|
||||
<nav className="relative z-50 flex justify-between">
|
||||
<div className="flex items-center md:gap-x-12">
|
||||
<span className="text-2xl font-bold">
|
||||
<Link href="/" className="py-2 px-4 rounded-full focus-visible:outline-black">Vojtěch Mareš</Link>
|
||||
</span>
|
||||
<div className="hidden md:flex md:gap-x-6">
|
||||
<Link
|
||||
href="/#skoleni"
|
||||
className="inline-block rounded-full py-2 px-4 text-lg font-medium text-slate-700 hover:bg-slate-100 hover:text-black focus-visible:outline-black"
|
||||
>
|
||||
Školení
|
||||
</Link>
|
||||
{/* <Link href="/pripadove-studie" className="inline-block rounded-full py-2 px-4 text-lg font-medium text-slate-700 hover:bg-slate-100 hover:text-black focus-visible:outline-black">Případové studie</Link> */}
|
||||
<Link
|
||||
href="https://vojtechmares.blog/"
|
||||
className="inline-block rounded-full py-2 px-4 text-lg font-medium text-slate-700 hover:bg-slate-100 hover:text-black focus-visible:outline-black"
|
||||
>
|
||||
Blog
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-5 md:gap-x-8">
|
||||
<Button href="mailto:iam@vojtechmares.com" color="amber">
|
||||
<span className="text-lg">
|
||||
Napište mi{" "}
|
||||
<span className="hidden lg:inline">ještě dnes</span>
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
</Container>
|
||||
</header>
|
||||
</>
|
||||
);
|
||||
}
|
||||
140
apps/vojtechmares.com/components/trainingpage/TrainingLayout.tsx
Normal file
140
apps/vojtechmares.com/components/trainingpage/TrainingLayout.tsx
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import clsx from "clsx";
|
||||
|
||||
import { Header } from "@/components/layout/Header";
|
||||
import { Footer } from "@/components/layout/Footer";
|
||||
import { Container } from "@/components/Container";
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
type Props = {
|
||||
content: any;
|
||||
meta: any;
|
||||
}
|
||||
|
||||
export default function TrainingLayout({ content, meta }: Props) {
|
||||
const formatter = new Intl.NumberFormat("cs", {
|
||||
style: "currency",
|
||||
currency: "CZK",
|
||||
maximumFractionDigits: 0,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Školení {meta.name} | Vojtěch Mareš - DevOps konzultant, lektor,
|
||||
engineer
|
||||
</title>
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content={`Školení ${meta.name} | Vojtěch Mareš - DevOps konzultant, lektor, engineer`}
|
||||
/>
|
||||
</Head>
|
||||
<main>
|
||||
<Header />
|
||||
<div className="pb-14 sm:pb-20 lg:pb-32">
|
||||
<div className="bg-black pt-16 pb-16">
|
||||
<Container className="flex justify-around">
|
||||
<Image
|
||||
src={meta.logo}
|
||||
width="1500"
|
||||
height="1500"
|
||||
alt=""
|
||||
priority
|
||||
className={clsx(
|
||||
"h-32 w-32 rounded-full",
|
||||
meta.logo.src.endsWith(".svg") ? "invert" : ""
|
||||
)}
|
||||
/>
|
||||
<h2 className="ml-4 text-center font-display self-center text-4xl tracking-tight text-white sm:text-6xl">
|
||||
Školení {meta.name}
|
||||
</h2>
|
||||
</Container>
|
||||
</div>
|
||||
<Container>
|
||||
<div className="mt-12 md:grid md:grid-cols-5 md:gap-x-4 md:gap-y-4">
|
||||
<div className="md:col-span-3">
|
||||
<div className="prose prose:text-black prose-p:text-slate-700 prose-h1:text-2xl prose-h1:font-medium prose-h2:text-xl prose-h2:font-medium prose-h3:text-lg prose-h3:font-medium prose-li:my-0">
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 md:col-span-2 md:mt-0">
|
||||
{meta.days === 2 ? (
|
||||
<div className=" mb-8 rounded-lg bg-blue-50 p-4 shadow">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
{/* <ExclamationTriangleIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" /> */}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className="h-5 w-5 text-blue-400"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<p className="text-blue-600">
|
||||
Toto školení je{" "}
|
||||
<span className="font-medium">
|
||||
dvoudenní.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<div className="mt-8 overflow-hidden rounded-lg bg-slate-50 shadow md:mt-0">
|
||||
<div className="px-4 pt-5 sm:px-6">
|
||||
<h3 className="text-lg font-medium leading-6 text-black">
|
||||
Cena za školení
|
||||
</h3>
|
||||
</div>
|
||||
<div className=" px-4 pb-5 pt-2">
|
||||
<dl className="sm:divide-y sm:divide-slate-400">
|
||||
<div className="py-4 sm:grid sm:grid-cols-2 sm:gap-4 sm:py-5 sm:px-6">
|
||||
<dt className="font-medium text-slate-700">
|
||||
Veřejný termín
|
||||
</dt>
|
||||
<dd className="mt-1 text-black sm:mt-0">
|
||||
{formatter.format(meta.price.open)} bez DPH
|
||||
</dd>
|
||||
</div>
|
||||
<div className="py-4 sm:grid sm:grid-cols-2 sm:gap-4 sm:py-5 sm:px-6">
|
||||
<dt className="font-medium text-slate-700">
|
||||
Firemní školení
|
||||
</dt>
|
||||
<dd className="mt-1 text-black sm:mt-0">
|
||||
{formatter.format(meta.price.company)} bez DPH
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<Button
|
||||
variant="solid"
|
||||
color="amber"
|
||||
className="w-full text-lg font-medium"
|
||||
href="mailto:iam@vojtechmares.com"
|
||||
>
|
||||
Nezávazně poptat
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in a new issue