1
0
Fork 0

refactor: split components to multiple subdirs

subdirs
- homepage
- trainingpage
- layout
This commit is contained in:
Vojtěch Mareš 2023-01-11 12:17:35 +01:00
parent 0f8f9ccb04
commit c170415fd0
15 changed files with 21 additions and 21 deletions

View file

@ -0,0 +1,32 @@
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">
Posuňte svoji aplikaci dnes
</h2>
<p className="mt-4 text-lg tracking-tight text-white">
Je na čase pozvednout Vaši infrastrukturu na dnešní standardy. Vaše
infrastruktura by měla nabídnout Vaši aplikaci světu, ne ji držet
zpátky.
</p>
<Button
href="https://calendly.com/vojtechmares/30min"
color="white"
size="large"
className="mt-10"
>
Domluvme si schůzku
</Button>
</div>
</Container>
</section>
);
}

View file

@ -0,0 +1,166 @@
import Image from "next/image";
import { Container } from "@/components/Container";
import logoKubernetes from "@/images/logos/tools/kubernetes.svg";
import logok3s from "@/images/logos/tools/k3s.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 logovmware from "@/images/logos/tools/vmware.svg";
const features = [
{
name: "Kubernetes",
summary:
"Open Source systém pro automatizaci deploymentů, škálování a správu kontejnerizovaných aplikací.",
description:
"Kubernetes je na platformě nezávislý systém, díky kterému může běžet Vaše aplikace u vás v datacentru, v public cloudu nebo třeba v okrajových lokalitách, a nebo třeba na všech najednou, bez problému.",
icon: logoKubernetes,
iconColor: "#326CE5",
},
{
name: "k3s & rke2",
summary:
"k3s: lehká distrubuce Kubernetes; rke2: Kubernetes do Vašeho datacentra.",
description:
"k3s i rke2 jsou velice snadno instalovatelné distribuce Kubernetes, které můžete nainstalovat úplně všude a přitom mít stále k dispozici celý Kubernetes ekosystém, bez kompromisů.",
icon: logok3s,
iconColor: "#FFC61C",
},
{
name: "Rancher",
summary: "Kubernetes jako služba, ve Vašem datacentru.",
description:
"Platforma, pro Vaše Kubernetes clustery. Komplexní řešení celého životního cyklu clusteru. Neřešte každodení problémy, nechte je řešit Rancher řešit za vás.",
icon: logoRancher,
iconColor: "#0075A8",
},
{
name: "AWS",
summary: "Největší veřejný cloud. Máte problém? AWS má na to službu.",
description:
"Amazon Web Services (AWS) je cloudový poskytovatel služeb, včetně ukládání obrovských objemů dat, výpočetního výkonu a sítí. To vše aby pomohli firmám i jednotlivcům růst. AWS je nejrozšířenější poskytovatel, který je cenově dostupný, flexibilní cesta, jak stavět a provozovat aplikace a služby.",
icon: logoAWS,
iconColor: "#232F3E",
},
// {
// name: 'Google Cloud Platform',
// summary:
// 'Organize all of your contacts, service providers, and invoices in one place.',
// description:
// 'This also isnt actually a feature, its just some friendly advice. We definitely recommend that you do this, youll feel really organized and professional.',
// icon: logoGCP,
// iconColor: '#4285F4',
// },
{
name: "DigitalOcean",
summary: "Jednoduchý cloudový poskytovatel, ve kterém se neztratíte.",
description:
"DigitalOcean patří k menším cloudovým poskytovatelům, avšak jejich portfolio vám pro Vaši aplikaci bohatě stačí a nebudete se ztrácet v komplexitě velkých poskytovatelů se spoustou služeb.",
icon: logoDigitalOcean,
iconColor: "#0080FF",
},
// {
// name: 'OpenStack',
// summary:
// 'Organize all of your contacts, service providers, and invoices in one place.',
// description:
// 'This also isnt actually a feature, its just some friendly advice. We definitely recommend that you do this, youll feel really organized and professional.',
// icon: logoOpenStack,
// iconColor: '#ED1944',
// },
{
name: "VMware",
summary:
"Populární řešení pro správu Vaše datacentra, od virtuálních serverů až po úložiště.",
description:
"VMware je virtualizační platforma, která umožňuje vytvářet a spravovat virtuální servery a jejich fyzickém hardwaru. Zároveň umožňuje vytvářet oddělená prostředí například pro vývoj a ostrý provoz, tak i pro zcela různé aplikace.",
icon: logovmware,
iconColor: "#607078",
},
];
type FeatureType = {
name: string;
summary: string;
description: string;
icon: any;
iconColor: string;
};
type FeatureProps = {
feature: FeatureType;
className?: string;
props?: any[];
};
function Feature({ feature, className, ...props }: FeatureProps) {
return (
<div className={className} {...props}>
<Image
src={feature.icon}
className="rounded-lg p-2"
width="128"
height="128"
color={feature.iconColor}
alt=""
/>
<h3 className="mt-6 text-lg font-medium text-amber-500">{feature.name}</h3>
<p className="font-display mt-2 text-xl text-black">
{feature.summary}
</p>
<p className="mt-4 text-slate-700">{feature.description}</p>
</div>
);
}
function FeaturesMobile() {
return (
<div className="-mx-4 mt-20 flex flex-col gap-y-10 overflow-hidden px-4 sm:-mx-6 sm:px-6 lg:hidden">
{features.map((feature) => (
<div key={feature.name}>
<Feature feature={feature} className="mx-auto max-w-2xl" />
</div>
))}
</div>
);
}
function FeaturesDesktop() {
return (
<div className="hidden lg:mt-20 lg:block">
<div className="grid grid-cols-3 gap-x-8 gap-y-4">
{features.map((feature) => (
<div key={feature.name}>
<Feature feature={feature} className="relative" />
</div>
))}
</div>
</div>
);
}
export function Environment() {
return (
<section
id="secondary-features"
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">
Jakákoliv platforma, kdekoliv
</h2>
<p className="mt-4 text-lg tracking-tight text-slate-700">
Od veřejného cloudu přes on-premise po serverless, se vším vám
poradím.
</p>
</div>
<FeaturesMobile />
<FeaturesDesktop />
</Container>
</section>
);
}

View 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 lets 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 cant 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 havent 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 its 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 cant find what youre looking for, email our support team
and if youre 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>
);
}

View file

@ -0,0 +1,99 @@
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 logoDigitoo from "@/images/logos/digitoo.svg";
type Company = {
name: string;
logo: StaticImageData;
}
type CompanyList = Company[][]; // rows, three items per row
const companies: CompanyList = [
[
{ name: 'GLAMI', logo: logoGLAMI },
{ name: 'Digitoo', logo: logoDigitoo },
],
// [], // columns for mobile view - 3 items per row
];
export function Hero() {
return (
<>
<Container className="pt-5 lg:pt-8">
<div className="md:flex md:justify-between md:items-center">
<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 md:flex-row md:justify-left md:gap-x-6">
<Button href="https://calendly.com/vojtechmares/30min" size="large">
Domluvme si schůzku
</Button>
<Button
href="mailto:iam@vojtechmares.com"
variant="outline"
size="large"
>
Napište mi email
</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 items-center justify-center gap-x-8 sm:justify-start sm:flex-col sm:gap-x-0 sm:gap-y-10 xl:flex-row xl:gap-x-12 xl:gap-y-0"
>
{companies.map((group, groupIndex) => (
<li key={groupIndex}>
<ul
role="list"
className="flex flex-col items-center justify-center gap-y-8 sm:justify-start sm:flex-row sm:gap-x-12 sm:gap-y-0"
>
{group.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}
/>
</li>
))}
</ul>
</li>
))}
</ul>
</div>
</div>
<Image className="pt-10 md:pt-0" width={400} height={800} src={avatarVojtechMares} alt="Vojtěch Mareš" />
</div>
</Container>
</>
);
}

View 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 PlanProps = {
name: string;
price: string;
description: string;
href: string;
featured?: boolean;
buttonText?: string;
};
function Plan({
name,
price,
description,
href,
featured = false,
buttonText = "Napište mi",
}: PlanProps) {
return (
<section
className={clsx(
"flex flex-col rounded-3xl px-6 sm:px-8",
featured ? "order-first bg-amber-500 py-8 lg:order-none" : "lg:py-8",
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 mt-5 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 Pricing() {
return (
<section
id="pricing"
aria-label="Pricing"
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, 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">
<Plan
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"
/>
<Plan
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í"
/>
<Plan
name="Implementace"
price="Cena dohodou"
description="Analyzujeme Vaši situaci, projdeme možnosti, vybereme nejlepší řešení a společně jej nasadíme."
href="https://calendly.com/vojtechmares/30min"
buttonText="Domluvme si schůzku"
/>
</div>
</Container>
</section>
);
}

View 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 PrimaryFeatures() {
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 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>
);
}

View file

@ -0,0 +1,229 @@
import { ReactNode } from "react";
import Image, { StaticImageData } from "next/image";
import { Tab } from "@headlessui/react";
import clsx from "clsx";
import { Container } from "@/components/Container";
import screenshotArgoCD from "@/images/screenshots/argocd.png";
import screenshotGitLab from "@/images/screenshots/gitlab.png";
import screenshotTerraform from "@/images/screenshots/terraform.png";
import screenshotKubernetes from "@/images/screenshots/kubernetes.png";
import screenshotGrafana from "@/images/screenshots/grafana.png";
import screenshotPrometheus from "@/images/screenshots/prometheus.png";
import logoTerraform from "@/images/logos/tools/terraform.svg";
import logoGit from "@/images/logos/tools/git.svg";
import logoKubernetes from "@/images/logos/tools/kubernetes.svg";
import logoPrometheus from "@/images/logos/tools/prometheus.svg";
import logoArgo from "@/images/logos/tools/argo.svg";
import logoGrafana from "@/images/logos/tools/grafana.svg";
const features = [
{
name: "Verzování",
summary: "Spravujte svůj kód pomocí verzovacího nástroje Git.",
description:
"Mějte historii změn v aplikaci od začátku až do dnes, můžete se kdykoliv vrátit do bodu v čase. Řešte konflikty včas, předtím než je nasadíte do produkce a umožněte Vaším programátorům spolupracovat na jednou, aniž by si překáželi.",
image: screenshotGitLab,
icon: logoGit,
},
{
name: "Infastruktura jako kód",
summary:
"Mějte Vaši infrastrukturu deklarativně definovanou a verzovanou, díky Terraformu.",
description:
"Vaši infrastrukturu můžete snadno přesunout k jinému poskytovateli, a nebo jen vytvořit nové prostředí pro zákazníka, aby si váš produkt vyzkoušel a to během minut.",
image: screenshotTerraform,
icon: logoTerraform,
},
{
name: "Orchestrace",
summary:
"Nechte Vaši aplikaci běžet napříč mnoha servery a škálovat dle potřeb.",
description:
"Kubernetes se stalo nejen standardem, ale i hlavní platformou pro vývoj aplikací ať SaaS nebo dodávaných třetím stranám. Jde o skvělou platformu pro provoz Vaší aplikace ať ve veřejném cloudu nebo na vlastním hardwaru popř. on edge blízko koncových uživatelů.",
image: screenshotKubernetes,
icon: logoKubernetes,
},
{
name: "Monitoring",
summary: "Sledujte Vaši aplikaci, jak se chová v čase.",
description:
"Prometheus je standard pro monitoring aplikací, ať v Kubernetes ale i mimo. Sbírejte telemetrická data v čase o Vaši aplikaci. Vyhodnoťte, kde má Vaše aplikace slabá místa. Zároveň můžete tvořit pravidla, dle kterých vás AlertManager upozorní, když se něco pokazí.",
image: screenshotPrometheus,
icon: logoPrometheus,
},
{
name: "Vizualizace",
summary:
"Od grafů zatížení procesoru po počet otevřených TCP spojení, vše jasně a přehledně.",
description:
"Grafana je skvělý nástroj pro vizualizaci dat z monitoringu, vytvořte si dashboardy pro jednotlivé části Vaší aplikace, mějte pohromadě infrastrukturu, provoz na síti, dostupnost a třeba počet neúspěšných pokusů o přihlášení, zda vůči Vaší aplikaci neprobíhá hackerský útok.",
image: screenshotGrafana,
icon: logoGrafana,
},
{
name: "GitOps",
summary:
"Spravujte stav Vašich prostředí deklarativně, ať vždy víte, jaký je aktuální stav.",
description:
"ArgoCD je spolehlivý nástroj pro práci s Kubernetes a nasazováním změn a přitom si udržovat přehled o právě nasazených aplikacích, verzím a konfiguraci, snadno, soplehlivě, verzovaně.",
image: screenshotArgoCD,
icon: logoArgo,
},
];
type FeatureType = {
name: string | ReactNode;
summary: string;
description: string;
image: StaticImageData;
icon: any;
};
type FeatureProps = {
feature: FeatureType;
isActive: boolean;
className?: string;
props?: any;
};
function Feature({ feature, isActive, className, ...props }: FeatureProps) {
return (
<div
className={clsx(className, !isActive && "opacity-75 hover:opacity-100")}
{...props}
>
<Image
src={feature.icon}
width="128"
height="128"
className={clsx(
// 'w-32',
"flex justify-center rounded-lg p-2"
// isActive ? 'fill-amber-500' : 'fill-slate-500'
)}
alt=""
/>
<h3
className={clsx(
"mt-6 text-lg font-medium",
isActive ? "text-amber-500" : "text-slate-700"
)}
>
{feature.name}
</h3>
<p className="font-display mt-2 text-xl text-black">
{feature.summary}
</p>
<p className="mt-4 text-slate-700">{feature.description}</p>
</div>
);
}
function FeaturesMobile() {
return (
<div className="-mx-4 mt-20 flex flex-col gap-y-10 overflow-hidden px-4 sm:-mx-6 sm:px-6 lg:hidden">
{features.map((feature) => (
<div key={feature.name}>
<Feature feature={feature} className="mx-auto max-w-2xl" isActive />
<div className="relative mt-10 pb-10">
<div className="absolute -inset-x-4 bottom-0 top-8 bg-slate-200 sm:-inset-x-6" />
<div className="relative mx-auto w-[52.75rem] overflow-hidden rounded-xl bg-white shadow-lg shadow-slate-900/5 ring-1 ring-slate-500/10">
<Image
className="w-full"
src={feature.image}
alt=""
// sizes="52.75rem"
width="800"
height="548"
/>
</div>
</div>
</div>
))}
</div>
);
}
function FeaturesDesktop() {
return (
<Tab.Group as="div" className="hidden lg:mt-20 lg:block">
{({ selectedIndex }) => (
<>
<Tab.List className="grid grid-cols-3 gap-x-8 gap-y-4">
{features.map((feature, featureIndex) => (
<Feature
key={feature.name}
feature={{
...feature,
name: (
<Tab className="[&:not(:focus-visible)]:focus:outline-none">
<span className="absolute inset-0" />
{feature.name}
</Tab>
),
}}
isActive={featureIndex === selectedIndex}
className="relative"
/>
))}
</Tab.List>
<Tab.Panels className="rounded-4xl relative mt-20 overflow-hidden bg-slate-200 px-14 py-16 xl:px-16">
<div className="-mx-5 flex">
{features.map((feature, featureIndex) => (
<Tab.Panel
static
key={feature.name}
className={clsx(
"px-5 transition duration-500 ease-in-out [&:not(:focus-visible)]:focus:outline-none",
featureIndex !== selectedIndex && "opacity-60"
)}
style={{ transform: `translateX(-${selectedIndex * 100}%)` }}
aria-hidden={featureIndex !== selectedIndex}
>
<div className="w-[52.75rem] overflow-hidden rounded-xl bg-white shadow-lg shadow-slate-900/5 ring-1 ring-slate-500/10">
<Image
className="w-full"
src={feature.image}
alt=""
// sizes="52.75rem"
width="800"
height="548"
/>
</div>
</Tab.Panel>
))}
</div>
<div className="rounded-4xl pointer-events-none absolute inset-0 ring-1 ring-inset ring-slate-900/10" />
</Tab.Panels>
</>
)}
</Tab.Group>
);
}
export function TechStack() {
return (
<section
id="tech-stack"
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">
Open Source DevOps stack
</h2>
<p className="mt-4 text-lg tracking-tight text-slate-700">
Věřím v Open Source technologie, prakticky všichni je denně
využíváme a jsou naší budoucností.
</p>
</div>
<FeaturesMobile />
<FeaturesDesktop />
</Container>
</section>
);
}

View 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 doesnt 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>
);
}