Rebrand na WorkNuke: zelena znacka a prestavene hero

Prevzeti vizualniho smeru z predlohy. Web i portal stoji na tychz tokenech,
takze zmena hodnot v index.css se projevila naraz na obojim - portal je
zeleny, aniz by se sahlo na jedinou jeho komponentu.

Znacka a tokeny:
- akcent z cyanove na zelenou #B7FF3C, podklad z modrocerne na zelenocernou
  #0F1411. Seda dostala zelenou prichut, aby vedle podkladu nepusobila spinave.
- druhy akcent a text-gradient se nemazaly, jen presmerovaly do zelene rady.
  Pouziva je 341 mist a prepsat je vsechna kvuli barve by byla zbytecne velka
  zmena; fialova z nich zmizela tak jako tak.
- stav "v poradku" je nove modrozeleny. Akcent je zeleny a dve zelene na jedne
  obrazovce, kazda o necem jinem, nikdo nerozlisi.
- pismo Archivo na nadpisy, IBM Plex Sans na text, IBM Plex Mono na cisla a ID.
  Nadpisy maji tesny proklad, ktery Inter neumel bez trikareni.
- znak je plocha bomba misto pismene v gradientnim ctverci. LogoMark je
  samostatny export, aby sel pouzit i uvnitr snimku v heru. Novy favicon.
- primarni tlacitko je plna zelena misto prechodu ze dvou barev.

Hero a navigace:
- prokladany nadtitulek misto odznaku, dvouslovne radky nadpisu, jedno
  primarni tlacitko plus textovy odkaz, ctyri slovesa misto tri odrazek
  a snimek portalu vybihajici z prave hrany.
- navigace je pri levem okraji a bez pilulky za aktivni polozkou. Jedina
  pilulka na liste je primarni akce.

Opraveno u toho:
- zare v heru je pozadi sekce, ne vrstva pod ni. Prekryv se zapornym
  z-indexem se schoval za podklad stranky a nebyl videt vubec.
- presah snimku se pocita ze sirky kontejneru. Pevna hodnota ve vw stacila
  na notebooku, ale nad 1600 px se snimek vesel do postranni mezery
  a prestal byt oriznuty.

Zamerne nezmeneno: klice v prohlizeci (automia.token, automia.tenant), ID
firmy tnt_automia, ID aplikace csbot-prototype a prihlasovaci e-maily
v ukazkovych datech. Vypadaji jako jmeno, ale jsou to identifikatory.

Popis, jak znacka funguje v kodu, je v documentation/22-znacka-a-design.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
JiriUhlir
2026-08-26 09:56:23 +02:00
co-authored by Claude Opus 5
parent 2e863c1f8b
commit 73e0ecca4f
11 changed files with 640 additions and 174 deletions
+129
View File
@@ -0,0 +1,129 @@
# 22 - Znacka a design
Naprogramovano. Navrh, ze ktereho to vzniklo, je artefakt "WorkNuke Rebrand".
Tenhle dokument popisuje, **jak znacka funguje v kodu** - kde se meni barvy,
pismo a znak, a co se pri prejmenovani menit nesmi.
## Kde se meni vzhled
| Co | Kde |
| ----------------------- | ------------------------------------ |
| Barvy, pismo, utility | `web/src/index.css` |
| Znak a slovni znacka | `web/src/components/layout/Logo.tsx` |
| Nazev, kontakty, claim | `web/src/config/brand.ts` |
| Titulek a fonty stranky | `web/index.html` |
Zmena barevnosti celeho webu i portalu je zmena hodnot v `index.css`. Web
i portal stoji na tychz tokenech, takze se projevi naraz na obojim.
## Barvy
| Token | Hodnota | K cemu |
| ------------ | --------- | -------------------------------------------- |
| `brand-400` | `#B7FF3C` | Akcent. **Jedina hlasita barva na strance.** |
| `ink-900` | `#0F1411` | Podklad. Cerna do zelena, ne do modra. |
| `ink-600` | `#2E3A32` | Linky a ohraniceni |
| `ok-400` | `#2DD4BF` | Stav "v poradku" |
| `warn-400` | `#FBBF24` | Stav, ktery chce pozornost |
| `danger-400` | `#FB7185` | Chyba |
**Proc je "v poradku" modrozelene a ne zelene.** Akcent je zeleny. Kdyby byl
zeleny i stav, byly by na jedne obrazovce dve zelene, kazda o necem jinem,
a nikdo by je nerozlisil. Akcent znamena "tady se neco stane", stav znamena
"takhle to dopadlo".
**Sedy odstin ma zelenou prichut.** Neni to nahoda ani chyba prevodu: seda
s naznakem odstinu podkladu drzi paletu pohromade, ciste neutralni seda vedle
zelenocerne pusobi spinave.
### Druhy akcent uz neni barva
`accent-300` az `accent-600` **ukazuji do teze zelene rady** jako `brand-*`.
Klice zustaly, protoze je pouziva 341 mist v kodu; nechat je namirene na
fialovou by znamenalo dve akcentove barvy, prepsat je vsechny naraz zbytecne
velkou zmenu. Az se ta mista projdou, klice zmizi.
Totez plati pro utilitu `text-gradient`: uz negeneruje prechod, ale plnou
zelenou. Nazev zustal, aby se osm mist nemuselo prepisovat.
## Pismo
| Role | Pismo | Kde |
| ---------- | ------------- | ---------------------------------- |
| Nadpisy | Archivo 800 | `h1` az `h4`, trida `font-display` |
| Text | IBM Plex Sans | vychozi pismo dokumentu |
| Cisla a ID | IBM Plex Mono | casy, ID ticketu, nadtitulky |
Nadpisy maji `letter-spacing: -0.035em` a `line-height: 1.04`. Prave tesny
proklad delal v predloze ten rozdil; Inter takhle tesne nejde bez trikareni.
Plex Sans a Plex Mono jsou od jednoho autora, takze spolu ladi bez ladeni.
## Znak
Plocha bomba mirici k zemi: nos vlevo dole, tri kridelka vpravo nahore, tri
odletove cary u nosu. Kresli se svisle a otoci o 45 stupnu, aby se geometrie
dala cist a upravovat.
Je **plochy zamerne**, ne render. Plochy znak snese jakoukoliv velikost,
obarvi se jednou promennou (`currentColor`) a nezestarne s modou na 3D.
`LogoMark` je samostatny export, takze se da pouzit i mimo hlavicku - napriklad
uvnitr snimku portalu v heru.
## Hero
| Prvek | Jak to je |
| ------------ | ------------------------------------------ |
| Nad nadpisem | Verzalkova radka v mono, prokladana |
| Nadpis | Dve slova na radek, druhy radek zeleny |
| Tlacitka | Jedna zelena pilulka plus textovy odkaz |
| Pod textem | Ctyri slovesa s ikonou a jednou vetou |
| Snimek | Vybiha z prave hrany |
| Pozadi | Tri zelene radialni prechody, zadna mrizka |
**Zare je pozadi sekce, ne vrstva pod ni.** Prekryv se zapornym z-indexem se
schoval za podklad stranky a nebyl videt. Element se svym vlastnim pozadim
tenhle problem nema.
**Snimek vybiha z hrany schvalne.** Oriznuty pusobi jako vyrez z neceho
vetsiho, cely v ramecku pusobi jako obrazek.
## Ctyri slovesa
Sbira, Automatizuje, Propojuje, Deleguje. Neni to marketingova ozdoba, jsou to
ctyri kroky, ktere portal opravdu dela:
| Sloveso | Co za tim v portalu je |
| ------------ | ----------------------------- |
| Sbira | Udalosti, spoustece, webhooky |
| Automatizuje | Skripty konektoru |
| Propojuje | Strom kroku v builderu |
| Deleguje | Tickety a prirazeni lidem |
Kdyz se ctverice zmeni, musi se zmenit i tady - jinak web slibuje neco jineho,
nez aplikace dela.
## Co se pri prejmenovani nemeni
Vypada to jako jmeno, ale jsou to identifikatory:
| Co | Proc zustava |
| ----------------------- | ------------------------------------------------- |
| `automia.token` | Prejmenovani odhlasi vsechny prihlasene |
| `automia.tenant` | Zapomnela by se vybrana firma |
| `tnt_automia` | Sedi v ticketech, automatizacich i rozlozeni |
| `/apps/csbot-prototype` | Verejna adresa a routovani v Caddy, viz AGENTS.md |
| Ukazkove ucty | Prihlasovaci e-maily v seedu. Data, ne texty. |
Firma **Automia v datech je neco jineho nez produkt WorkNuke**. Je to zaznam
zakaznika v ukazkovych datech a prejmenovat ho nema duvod.
## Co chybi
| Chybi | Poznamka |
| --------------------- | --------------------------------------------------- |
| Materialy mimo web | prezentace, obrazky pro socialni site |
| Domena | `worknuke.cz` v `brand.ts`, ale nikde neni nasazena |
| Prochazeni `accent-*` | 341 mist, ktera uz nemaji duvod pouzivat druhy klic |
+41
View File
@@ -2,6 +2,47 @@
Nejnovejsi nahore.
## 2026-08-26 - rebrand na WorkNuke
Prevzeti vizualniho smeru z predlohy. Popis, jak znacka funguje v kodu, je
v [22-znacka-a-design.md](22-znacka-a-design.md).
### Zmeneno
- **Barevnost.** Akcent z cyanove na zelenou `#B7FF3C`, podklad z modrocerne
na zelenocernou `#0F1411`. Web i portal stoji na tychz tokenech, takze se to
projevilo naraz na obojim.
- **Druhy akcent uz neni barva.** `accent-*` ukazuje do teze zelene rady jako
`brand-*`. Klice zustaly, protoze je pouziva 341 mist; prepsat je vsechny
naraz by byla zbytecne velka zmena. Totez u utility `text-gradient`, ktera
uz negeneruje prechod, ale plnou zelenou.
- **Stav "v poradku" je modrozeleny.** Akcent je zeleny, a dve zelene na jedne
obrazovce, kazda o necem jinem, nikdo nerozlisi.
- **Pismo.** Archivo na nadpisy, IBM Plex Sans na text, IBM Plex Mono na cisla
a ID. Nadpisy maji tesny proklad, ktery Inter neumel bez trikareni.
- **Znak.** Plocha bomba misto pismene v gradientnim ctverci. `LogoMark` je
samostatny export, aby sel pouzit i uvnitr snimku v heru.
- **Tlacitko.** Plna zelena misto prechodu ze dvou barev. Prave tim vystupuje
z rady.
- **Hero.** Prokladany nadtitulek misto odznaku, dvouslovne radky nadpisu,
jedno primarni tlacitko plus textovy odkaz, ctyri slovesa misto tri odrazek
a snimek portalu vybihajici z prave hrany.
- **Navigace** je pri levem okraji a bez pilulky za aktivni polozkou. Jedina
pilulka na liste je primarni akce.
- **Nazev, claim a kontakt** v `brand.ts`.
### Opraveno u toho
- **Zare v heru je pozadi sekce, ne vrstva pod ni.** Prekryv se zapornym
z-indexem se schoval za podklad stranky a nebyl videt vubec.
### Co se zamerne nezmenilo
Klice v prohlizeci (`automia.token`, `automia.tenant`), ID firmy `tnt_automia`,
ID aplikace `csbot-prototype` a prihlasovaci e-maily v ukazkovych datech.
Vypadaji jako jmeno, ale jsou to identifikatory. Duvody jsou
v [22-znacka-a-design.md](22-znacka-a-design.md).
## 2026-08-26 - prepinac firmy: do sidebaru a prekresli obsah cely
Dodelavka predchoziho bodu. Tvrzeni "prepinac plati pro cely system" nebylo
+4 -4
View File
@@ -3,17 +3,17 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Automia - automatizace, voiceboti a integrace na míru</title>
<title>WorkNuke - konec ruční práce</title>
<meta
name="description"
content="Automatizujeme procesy, stavíme voiceboty a propojujeme systémy. K tomu dashboardy, tickety a incident management pod jednou střechou."
content="WorkNuke sbírá události, zautomatizuje, co jde, propojí další kroky a zapojí správné lidi. Vaše práce prostě plyne."
/>
<meta name="theme-color" content="#070b16" />
<meta name="theme-color" content="#0f1411" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap"
href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;700;800;900&family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
</head>
+19 -17
View File
@@ -1,18 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="64" y2="64" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#22d3ee" />
<stop offset="1" stop-color="#8b5cf6" />
</linearGradient>
</defs>
<rect width="64" height="64" rx="16" fill="#070b16" />
<path
d="M20 44 32 18l12 26"
fill="none"
stroke="url(#g)"
stroke-width="5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path d="M25 36h14" fill="none" stroke="url(#g)" stroke-width="5" stroke-linecap="round" />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- Znak WorkNuke. Stejna geometrie jako LogoMark, jen s vlastnim podkladem. -->
<rect width="32" height="32" rx="7" fill="#0F1411" />
<g fill="#B7FF3C">
<g transform="rotate(45 16 16)">
<rect x="11.4" y="9" width="9.2" height="15" rx="4.6" />
<rect x="13.6" y="6.6" width="4.8" height="4" rx="1.2" />
<path d="M13.6 7.4 8.2 3.6l1.4 6.2 4-1.4z" />
<path d="M18.4 7.4l5.4-3.8-1.4 6.2-4-1.4z" />
<path d="M14.6 6.8h2.8l-1.4-5z" />
</g>
<path
d="M7.4 27.2 4.4 30.2M4.6 24.6H1.4M10.4 30.4v3"
stroke="#B7FF3C"
stroke-width="2"
stroke-linecap="round"
fill="none"
/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 596 B

After

Width:  |  Height:  |  Size: 718 B

+312 -103
View File
@@ -1,133 +1,342 @@
import { ArrowRight, CheckCircle2, PhoneCall, Sparkles } from 'lucide-react';
import {
ArrowRight,
ChevronDown,
Play,
Plus,
Search,
Settings2,
Share2,
SlidersHorizontal,
Users,
Zap,
} from 'lucide-react';
import { ButtonLink } from '@/components/ui/Button';
import { Container } from '@/components/ui/Container';
import { LogoMark } from '@/components/layout/Logo';
/**
* Hero.
*
* Zacina prikazem a slibem, ne pozdravem a predstavenim firmy. Prvni je
* o zakaznikovi, druhe o nas - a na hlavni stranu patri to prvni.
*
* Slozeni: proklada nadtitulek, dvoubarevny nadpis, jedno primarni tlacitko
* plus textovy odkaz, ctyri slovesa a snimek portalu vybihajici z prave hrany.
*/
/** Ctyri kroky, ktere produkt opravdu dela. Nazvy sedi na zalozky v portalu. */
const steps = [
{
icon: Zap,
title: 'Sbírá',
text: 'Události ze všech vašich nástrojů na jednom místě.',
},
{
icon: Settings2,
title: 'Automatizuje',
text: 'Odbaví, co jde odbavit bez člověka.',
},
{
icon: Share2,
title: 'Propojuje',
text: 'Spustí navazující kroky a celé workflow.',
},
{
icon: Users,
title: 'Deleguje',
text: 'Zapojí správné lidi, když je potřeba.',
},
];
/** Krátké uvítání + hlavní CTA + mockup živého provozu. */
export function Hero() {
return (
<section className="relative overflow-hidden pt-16 pb-20 sm:pt-24 sm:pb-28">
{/* Dekorativni pozadi */}
<div aria-hidden className="pointer-events-none absolute inset-0 -z-10">
<div className="absolute inset-0 bg-grid mask-fade-b opacity-40" />
<div className="animate-pulse-slow absolute -top-40 left-1/2 size-[38rem] -translate-x-1/2 rounded-full bg-brand-500/18 blur-[120px]" />
<div className="animate-pulse-slow absolute top-40 -right-32 size-[30rem] rounded-full bg-accent-500/16 blur-[120px]" />
</div>
/*
Zelena zare je pozadi **sekce**, ne vrstva pod ni.
Prekryv se zapornym z-indexem se schoval za podklad stranky a nebyl videt;
pozadi elementu tenhle problem nema.
*/
<section
className="relative overflow-hidden pt-14 pb-16 sm:pt-20 sm:pb-20"
style={{
background:
'radial-gradient(58rem 36rem at 74% 16%, rgba(155,230,25,0.28), transparent 60%),' +
'radial-gradient(40rem 28rem at 2% 44%, rgba(155,230,25,0.14), transparent 64%),' +
'radial-gradient(32rem 22rem at 92% 86%, rgba(183,255,60,0.10), transparent 66%)',
}}
>
{/*
Kolik snimek presahne pres pravou hranu. Nula na uzkych displejich,
kde by presah znamenal jen orezany obsah bez efektu.
*/}
<style>{`
@media (min-width: 1024px) {
.hero-bleed { --hero-bleed: calc(-1 * ((100vw - min(72rem, 100vw - 4rem)) / 2 + 7rem)); }
}
`}</style>
<Container>
<div className="grid items-center gap-14 lg:grid-cols-[1.05fr_0.95fr]">
<div className="grid items-center gap-12 lg:grid-cols-[0.92fr_1.08fr]">
<div className="animate-rise">
<span className="glass inline-flex items-center gap-2 rounded-full px-4 py-1.5 text-xs font-medium text-brand-300">
<Sparkles className="size-3.5" />
Automatizace · Voiceboti · Integrace
</span>
<h1 className="mt-6 text-4xl leading-[1.08] font-extrabold text-white sm:text-5xl lg:text-6xl">
Vítejte. Děláme z ruční práce{' '}
<span className="text-gradient">procesy, které běží samy</span>.
</h1>
<p className="mt-6 max-w-xl text-lg leading-relaxed text-white/65">
Jsme malý tým, který firmám staví automatizace, hlasové asistenty a propojení systémů -
a pak je i provozuje. Vy vidíte výsledky v dashboardu, my držíme provoz.
<p className="font-mono text-xs tracking-[0.24em] text-white/45 uppercase">
Události dovnitř. Akce ven.
</p>
<div className="mt-9 flex flex-wrap items-center gap-3">
<h1 className="mt-5 text-5xl font-extrabold text-white sm:text-6xl lg:text-7xl">
Konec
<br />
<span className="text-brand-400">ruční práce.</span>
</h1>
<p className="mt-6 max-w-md text-lg leading-relaxed text-white/65">
WorkNuke sbírá události, zautomatizuje, co jde, propojí další kroky a zapojí
správné lidi, když je potřeba. Vaše práce prostě plyne.
</p>
<div className="mt-8 flex flex-wrap items-center gap-5">
<ButtonLink to="/kontakt" size="lg">
Nezávazná konzultace
Začít zdarma
<ArrowRight className="size-4" />
</ButtonLink>
<ButtonLink to="/sluzby" variant="secondary" size="lg">
Co umíme
</ButtonLink>
</div>
<ul className="mt-9 flex flex-wrap gap-x-6 gap-y-2.5 text-sm text-white/55">
{['Nasazení v týdnech, ne kvartálech', 'Provoz a podpora v ceně', 'Bez vendor lock-inu'].map(
(item) => (
<li key={item} className="flex items-center gap-2">
<CheckCircle2 className="size-4 shrink-0 text-ok-400" />
{item}
</li>
),
)}
</ul>
{/*
Vedle primarniho tlacitka uz zadne druhe. Textovy odkaz rekne,
ze je to mensi zavazek, aniz by o pozornost soutezil.
*/}
<a
href="/sluzby"
className="group inline-flex items-center gap-2.5 text-sm font-semibold text-white transition-colors hover:text-brand-300"
>
<span className="grid size-9 place-items-center rounded-full border border-ink-600/80 transition-colors group-hover:border-brand-400/60">
<Play className="size-3.5 fill-current" />
</span>
Prohlédnout si to
</a>
</div>
</div>
<HeroPanel />
<div className="hero-bleed contents">
<HeroPanel />
</div>
</div>
{/* Ctyri slovesa. Neni to slib, je to popis toho, co portal umi. */}
<ul className="mt-16 grid gap-8 sm:grid-cols-2 lg:grid-cols-4 lg:gap-10">
{steps.map((step) => (
<li key={step.title} className="animate-rise">
<step.icon className="size-5 text-brand-400" />
<p className="mt-3.5 font-display text-base font-bold text-white">{step.title}</p>
<p className="mt-1.5 text-sm leading-relaxed text-white/50">{step.text}</p>
</li>
))}
</ul>
</Container>
</section>
);
}
/** Mockup panelu "z provozu" - jen ilustrace, zadna realna data. */
function HeroPanel() {
const steps = [
{ label: 'Příchozí hovor rozpoznán', time: '0,4 s', done: true },
{ label: 'Poptávka založena v CRM', time: '1,1 s', done: true },
{ label: 'Nabídka vygenerována', time: '2,8 s', done: true },
{ label: 'Předáno obchodníkovi', time: 'právě teď', done: false },
];
/* ------------------------------------------------------------------ snimek */
/**
* Snimek portalu.
*
* Vybiha z prave hrany, protoze oriznuty snimek pusobi jako vyrez z neceho
* vetsiho, kdezto cely v ramecku pusobi jako obrazek. Data jsou ilustracni,
* ale nazvy sloupcu i stavy jsou ty, ktere portal opravdu ma.
*/
const rows = [
{
event: 'Platba selhala',
detail: 'Nepodařilo se strhnout platbu',
source: 'Stripe',
color: 'bg-[#635bff]',
status: 'Automatizováno',
tone: 'bg-lime-100 text-lime-800',
next: 'Zkusit znovu za hodinu',
time: 'před 2 min',
},
{
event: 'Nový požadavek',
detail: 'Problém s přihlášením',
source: 'Zendesk',
color: 'bg-[#03363d]',
status: 'Delegováno',
tone: 'bg-indigo-100 text-indigo-800',
next: 'Přiřazeno Petrovi',
time: 'před 12 min',
},
{
event: 'Vysoké vytížení CPU',
detail: 'Nad 90 % po 5 minut',
source: 'Datadog',
color: 'bg-[#632ca6]',
status: 'Probíhá',
tone: 'bg-sky-100 text-sky-800',
next: 'Spustit nápravu',
time: 'před 28 min',
},
{
event: 'Nová registrace',
detail: 'Zkušební účet vytvořen',
source: 'Intercom',
color: 'bg-[#1f8ded]',
status: 'Automatizováno',
tone: 'bg-lime-100 text-lime-800',
next: 'Odeslat uvítání',
time: 'před 1 hod',
},
{
event: 'Odeslán formulář',
detail: 'Poptávka z webu',
source: 'HubSpot',
color: 'bg-[#ff7a59]',
status: 'Otevřené',
tone: 'bg-orange-100 text-orange-800',
next: 'Kvalifikovat lead',
time: 'před 2 hod',
},
];
const nav = [
'Přehled',
'Události',
'Automatizace',
'Workflow',
'Lidé',
'Integrace',
'Analytika',
'Nastavení',
];
function HeroPanel() {
return (
<div className="animate-rise relative [animation-delay:150ms]">
<div className="animate-float glass rounded-2xl p-5 shadow-2xl shadow-brand-500/10">
<div className="flex items-center justify-between border-b border-ink-600/60 pb-4">
<div className="flex items-center gap-2.5">
<span className="grid size-9 place-items-center rounded-xl bg-brand-500/15 text-brand-300">
<PhoneCall className="size-4" />
</span>
<div>
<p className="text-sm font-semibold text-white">Voicebot - příjem poptávek</p>
<p className="font-mono text-xs text-white/40">AUT-02 · běží</p>
/*
Snimek musi vybihat z hrany na kazde sirce, ne jen na notebooku.
Pevny zaporny okraj ve vw prestal stacit nad 1600 px: kontejner ma strop
max-w-6xl (72rem), takze postranni mezera roste a snimek se do ni vesel.
Vypocet ji odecte, at je obrazovka jakkoliv siroka.
*/
<div
className="animate-rise relative [animation-delay:150ms]"
style={{ marginRight: 'var(--hero-bleed, 0px)' }}
>
<div className="overflow-hidden rounded-2xl border border-ink-600/70 bg-white shadow-2xl shadow-brand-500/10">
<div className="flex min-h-[26rem]">
{/* Postranni navigace */}
<aside className="hidden w-44 shrink-0 border-r border-slate-200 bg-slate-50/80 p-3 sm:block">
<div className="flex items-center gap-2 px-2 pb-4">
<LogoMark className="size-5 text-lime-500" />
<span className="font-display text-sm font-extrabold text-slate-900">WorkNuke</span>
</div>
<ul className="space-y-0.5">
{nav.map((item, index) => (
<li
key={item}
className={
index === 1
? 'rounded-lg bg-white px-2.5 py-1.5 text-xs font-semibold text-slate-900 shadow-sm'
: 'px-2.5 py-1.5 text-xs text-slate-500'
}
>
{item}
</li>
))}
</ul>
</aside>
{/* Obsah */}
<div className="min-w-0 flex-1">
<div className="flex items-center justify-between border-b border-slate-200 px-4 py-2.5">
<Search className="size-3.5 text-slate-400" />
<div className="flex items-center gap-2">
<span className="grid size-6 place-items-center rounded-full bg-slate-900 text-[0.6rem] font-bold text-white">
JK
</span>
<div className="hidden leading-tight sm:block">
<p className="text-[0.7rem] font-semibold text-slate-900">Jan Koutný</p>
<p className="text-[0.62rem] text-slate-400">Acme s.r.o.</p>
</div>
<ChevronDown className="size-3 text-slate-400" />
</div>
</div>
<div className="p-4">
<div className="flex items-center justify-between">
<h2 className="font-display text-xl font-extrabold tracking-tight text-slate-900">
Události
</h2>
<span className="inline-flex items-center gap-1.5 rounded-full bg-lime-300 px-3 py-1.5 text-[0.7rem] font-semibold text-slate-900">
<Plus className="size-3" />
Nová automatizace
</span>
</div>
<div className="mt-3 flex items-center justify-between gap-3 border-b border-slate-200 pb-2">
<ul className="flex gap-4 text-[0.7rem]">
{['Vše', 'Otevřené', 'Automatizované', 'Delegované', 'Vyřešené'].map(
(tab, index) => (
<li
key={tab}
className={
index === 0
? 'border-b-2 border-slate-900 pb-2 font-semibold text-slate-900'
: 'pb-2 text-slate-400'
}
>
{tab}
</li>
),
)}
</ul>
<span className="hidden items-center gap-1.5 rounded-lg border border-slate-200 px-2.5 py-1 text-[0.7rem] text-slate-500 lg:inline-flex">
<SlidersHorizontal className="size-3" />
Filtry
</span>
</div>
<table className="mt-1 w-full border-collapse text-left">
<thead>
<tr className="text-[0.62rem] tracking-wide text-slate-400 uppercase">
<th className="py-2 font-medium">Událost</th>
<th className="py-2 font-medium">Zdroj</th>
<th className="py-2 font-medium">Stav</th>
<th className="hidden py-2 font-medium md:table-cell">Další akce</th>
<th className="hidden py-2 font-medium lg:table-cell">Čas</th>
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr key={row.event} className="border-t border-slate-100">
<td className="py-2.5 pr-3">
<p className="text-[0.72rem] font-semibold text-slate-900">{row.event}</p>
<p className="text-[0.62rem] text-slate-400">{row.detail}</p>
</td>
<td className="py-2.5 pr-3">
<span className="inline-flex items-center gap-1.5 text-[0.7rem] text-slate-600">
<span className={`size-4 rounded ${row.color}`} />
{row.source}
</span>
</td>
<td className="py-2.5 pr-3">
<span
className={`inline-block rounded-full px-2 py-0.5 text-[0.62rem] font-semibold ${row.tone}`}
>
{row.status}
</span>
</td>
<td className="hidden py-2.5 pr-3 text-[0.7rem] text-slate-600 md:table-cell">
{row.next}
</td>
<td className="hidden py-2.5 text-[0.7rem] whitespace-nowrap text-slate-400 lg:table-cell">
{row.time}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<span className="inline-flex items-center gap-1.5 rounded-full border border-ok-400/35 bg-ok-500/12 px-2.5 py-1 text-xs font-medium text-ok-400">
<span className="size-1.5 animate-pulse rounded-full bg-ok-400" />
live
</span>
</div>
<ol className="mt-4 space-y-3">
{steps.map((step) => (
<li key={step.label} className="flex items-center gap-3">
<span
className={
step.done
? 'grid size-5 shrink-0 place-items-center rounded-full bg-ok-500/20 text-ok-400'
: 'grid size-5 shrink-0 place-items-center rounded-full bg-brand-500/20 text-brand-300'
}
>
{step.done ? (
<CheckCircle2 className="size-3.5" />
) : (
<span className="size-1.5 animate-pulse rounded-full bg-brand-300" />
)}
</span>
<span className="flex-1 text-sm text-white/75">{step.label}</span>
<span className="font-mono text-xs text-white/35">{step.time}</span>
</li>
))}
</ol>
<div className="mt-5 grid grid-cols-3 gap-3 border-t border-ink-600/60 pt-4">
{[
{ value: '137', label: 'hovorů dnes' },
{ value: '96,1 %', label: 'úspěšnost' },
{ value: '1,2 s', label: 'odezva' },
].map((stat) => (
<div key={stat.label}>
<p className="text-lg font-bold text-white">{stat.value}</p>
<p className="text-xs text-white/45">{stat.label}</p>
</div>
))}
</div>
</div>
{/* Male "odlepene" karticky pro hloubku */}
<div className="glass animate-float absolute -bottom-6 -left-6 hidden rounded-xl px-4 py-3 shadow-xl [animation-delay:1.2s] sm:block">
<p className="text-xs text-white/45">Ušetřeno tento měsíc</p>
<p className="text-base font-bold text-white">312 hodin</p>
</div>
</div>
);
+1 -1
View File
@@ -40,7 +40,7 @@ export function ProductCard({ product }: { product: Product }) {
)}
>
<div className="flex items-start justify-between gap-3">
<span className="grid size-11 place-items-center rounded-xl bg-gradient-to-br from-brand-500/20 to-accent-500/20 text-brand-300">
<span className="grid size-11 place-items-center rounded-xl bg-brand-500/15 text-brand-300">
<Icon className="size-5" />
</span>
<div className="text-right">
+61 -4
View File
@@ -2,13 +2,70 @@ import { Link } from 'react-router-dom';
import { brand } from '@/config/brand';
import { cn } from '@/lib/cn';
export function Logo({ className, to = '/' }: { className?: string; to?: string }) {
/**
* Znacka: plochy znak plus slovni znacka.
*
* Znak je bomba naklonena k zemi se tremi kridelky a dvema odletovymi carami.
* Zamerne **ploche**, ne render: plochy znak snese jakoukoliv velikost, jde
* obarvit jednou promennou a nezestarne s modou na 3D.
*/
export function LogoMark({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 32 32"
fill="none"
aria-hidden="true"
className={cn('shrink-0', className)}
>
{/*
Bomba mirici k zemi: nos vlevo dole, kridelka vpravo nahore.
Kreslena svisle a otocena o 45 stupnu, aby se geometrie dala cist.
*/}
<g transform="rotate(45 16 16)">
{/* Telo */}
<rect x="11.4" y="9" width="9.2" height="15" rx="4.6" fill="currentColor" />
{/* Krcek mezi telem a ocasem, aby to nebyla jen pilulka */}
<rect x="13.6" y="6.6" width="4.8" height="4" rx="1.2" fill="currentColor" />
{/* Tri kridelka */}
<path d="M13.6 7.4 8.2 3.6l1.4 6.2 4-1.4z" fill="currentColor" />
<path d="M18.4 7.4l5.4-3.8-1.4 6.2-4-1.4z" fill="currentColor" />
<path d="M14.6 6.8h2.8l-1.4-5z" fill="currentColor" />
</g>
{/* Odletove cary u nosu. Rikaji, ze je vypustena, ne ze lezi. */}
<path
d="M7.4 27.2 4.4 30.2M4.6 24.6H1.4M10.4 30.4v3"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
);
}
export function Logo({
className,
to = '/',
withClaim = false,
}: {
className?: string;
to?: string;
/** Podtitulek pod slovni znackou. Jen tam, kde je na nej misto. */
withClaim?: boolean;
}) {
return (
<Link to={to} className={cn('group inline-flex items-center gap-2.5', className)}>
<span className="relative grid size-9 place-items-center rounded-xl bg-gradient-to-br from-brand-400 to-accent-500 shadow-lg shadow-brand-500/25 transition-transform duration-300 group-hover:scale-105">
<span className="font-mono text-sm font-bold text-ink-950">A</span>
<LogoMark className="size-8 text-brand-400 transition-transform duration-300 group-hover:-translate-y-0.5" />
<span className="flex flex-col leading-none">
<span className="font-display text-lg font-extrabold tracking-tight text-white">
{brand.name}
</span>
{withClaim && (
<span className="mt-1 font-mono text-[0.6rem] tracking-[0.22em] text-white/40 uppercase">
{brand.claim}
</span>
)}
</span>
<span className="text-lg font-bold tracking-tight text-white">{brand.name}</span>
</Link>
);
}
+9 -6
View File
@@ -35,10 +35,11 @@ export function Navbar() {
)}
>
<Container>
<div className="flex h-18 items-center justify-between gap-4">
<div className="flex h-18 items-center gap-8">
<Logo />
<nav className="hidden items-center gap-1 md:flex">
{/* Hned vedle loga, ne na stred: predloha ma navigaci pri levem okraji. */}
<nav className="hidden flex-1 items-center gap-1 md:flex">
{mainNav.map((item) => (
<NavLink
key={item.to}
@@ -46,8 +47,10 @@ export function Navbar() {
end={item.to === '/'}
className={({ isActive }) =>
cn(
'rounded-full px-4 py-2 text-sm font-medium transition-colors',
isActive ? 'bg-white/8 text-white' : 'text-white/60 hover:text-white',
// Bez pilulky za aktivni polozkou. V predloze je navigace
// ciste textova a jedina pilulka na liste je primarni akce.
'px-3.5 py-2 text-sm font-medium transition-colors',
isActive ? 'text-white' : 'text-white/55 hover:text-white',
)
}
>
@@ -69,7 +72,7 @@ export function Navbar() {
Přihlášení
</ButtonLink>
<ButtonLink to="/kontakt" size="sm">
Nezávazná konzultace
Začít zdarma
</ButtonLink>
</>
)}
@@ -117,7 +120,7 @@ export function Navbar() {
<LogIn className="size-4" />
Přihlášení
</ButtonLink>
<ButtonLink to="/kontakt">Nezávazná konzultace</ButtonLink>
<ButtonLink to="/kontakt">Začít zdarma</ButtonLink>
</>
)}
</div>
+5 -1
View File
@@ -9,8 +9,12 @@ const base =
'inline-flex items-center justify-center gap-2 rounded-full font-semibold transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-55';
const variants: Record<Variant, string> = {
/*
* Plna zelena, tmavy text, tvar pilulky. Driv to byl prechod ze dvou barev;
* v predloze je tlacitko jednobarevne, protoze prave tim vystupuje z rady.
*/
primary:
'bg-gradient-to-r from-brand-400 to-accent-500 text-ink-950 shadow-lg shadow-brand-500/20 hover:shadow-xl hover:shadow-brand-500/30 hover:brightness-110',
'bg-brand-400 text-ink-950 shadow-lg shadow-brand-500/20 hover:bg-brand-300 hover:shadow-xl hover:shadow-brand-500/30',
secondary: 'glass text-white hover:border-brand-400/60 hover:bg-ink-700/70',
ghost: 'text-white/70 hover:bg-white/5 hover:text-white',
};
+5 -5
View File
@@ -3,12 +3,12 @@
* Prejmenovani firmy = zmena tady (viz docs/03-frontend.md).
*/
export const brand = {
name: 'Automia',
legalName: 'Automia s.r.o.',
claim: 'Automatizace, voiceboti a integrace, které vydrží provoz.',
name: 'WorkNuke',
legalName: 'WorkNuke s.r.o.',
claim: 'Konec ruční práce.',
description:
'Navrhujeme a provozujeme automatizace firemních procesů, hlasové asistenty a propojení systémů. K tomu dodáváme dashboardy, tickety a incident management pod jednou střechou.',
email: 'info@automia.cz',
'WorkNuke sbírá události ze všech vašich nástrojů, zautomatizuje, co jde, propojí další kroky a zapojí správné lidi, když je potřeba. Vaše práce prostě plyne.',
email: 'info@worknuke.cz',
phone: '+420 777 123 456',
phoneHref: '+420777123456',
address: {
+54 -33
View File
@@ -5,37 +5,51 @@
Dokumentace: docs/05-design-system.md
------------------------------------------------------------------- */
@theme {
/* Podklady - tmave modrociste odstiny */
--color-ink-950: #05070f;
--color-ink-900: #070b16;
--color-ink-850: #0a0f1f;
--color-ink-800: #0e1526;
--color-ink-700: #16203a;
--color-ink-600: #1f2c4d;
/*
* Podklady - cerna do zelena, ne do modra.
* Odstin je odvozeny z #0F1411, aby seda nikde nesklouzavala k modre
* a drzela pohromade se zelenym akcentem.
*/
--color-ink-950: #080b09;
--color-ink-900: #0f1411;
--color-ink-850: #141a16;
--color-ink-800: #1a211c;
--color-ink-700: #232c26;
--color-ink-600: #2e3a32;
/* Primarni akcent - cyan */
--color-brand-200: #a5f3fc;
--color-brand-300: #67e8f9;
--color-brand-400: #22d3ee;
--color-brand-500: #06b6d4;
--color-brand-600: #0891b2;
/* Primarni akcent - zelena. Jedina hlasita barva na strance. */
--color-brand-200: #dfffae;
--color-brand-300: #cdff7a;
--color-brand-400: #b7ff3c;
--color-brand-500: #9be619;
--color-brand-600: #7cbd0f;
/* Sekundarni akcent - violet */
--color-accent-300: #c4b5fd;
--color-accent-400: #a78bfa;
--color-accent-500: #8b5cf6;
--color-accent-600: #7c3aed;
/*
* Druhy akcent uz neexistuje jako barva, jen jako klic.
* Je namireny do teze zelene rady, takze 341 mist, ktera ho pouzivaji,
* nemuselo prepisovat - jen prestala byt fialova. Az se ta mista projdou,
* klic zmizi uplne.
*/
--color-accent-300: #cdff7a;
--color-accent-400: #b7ff3c;
--color-accent-500: #9be619;
--color-accent-600: #7cbd0f;
/* Stavove barvy (tickety, incidenty, healthchecky) */
--color-ok-400: #34d399;
--color-ok-500: #10b981;
/*
* Stavove barvy. "V poradku" je nove modrozelena, ne zelena: akcent je
* zeleny a dve zelene na jedne obrazovce, kazda o necem jinem, nikdo
* nerozlisi.
*/
--color-ok-400: #2dd4bf;
--color-ok-500: #14b8a6;
--color-warn-400: #fbbf24;
--color-warn-500: #f59e0b;
--color-danger-400: #fb7185;
--color-danger-500: #f43f5e;
--font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', monospace;
--font-display: 'Archivo', ui-sans-serif, system-ui, -apple-system, sans-serif;
--font-sans: 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;
--radius-card: 1rem;
@@ -103,12 +117,19 @@
text-wrap: pretty;
}
/*
* Nadpisy jedou displayovym pismem s tesnym prokladem. Prave to delalo
* v predloze ten rozdil: Inter takhle tesne nejde bez trikareni.
*/
h1,
h2,
h3,
h4 {
font-family: var(--font-display);
font-weight: 800;
text-wrap: balance;
letter-spacing: -0.02em;
letter-spacing: -0.035em;
line-height: 1.04;
}
::selection {
@@ -160,16 +181,16 @@
backdrop-filter: blur(14px);
}
/* Gradientni text pro zvyrazneni slov v nadpisech */
/*
* Zvyraznene slovo v nadpisu.
*
* Driv to byl gradient pres tri barvy. Ted je to plna zelena: v predloze je
* nadpis dvoubarevny, ne prechodovy, a gradient se na malych velikostech
* rozpadal a hur cetl. Nazev utility zustava, aby se osm mist nemuselo
* prepisovat.
*/
@utility text-gradient {
background-image: linear-gradient(
100deg,
var(--color-brand-300),
var(--color-brand-400) 40%,
var(--color-accent-400)
);
background-clip: text;
color: transparent;
color: var(--color-brand-400);
}
/* Jemna mrizka na pozadi sekci */