Dialog jako jedna vrstva, hlavicka bez rozmazani, znacka Zive odstranena
Otevreny dialog sekal video vedle portalu. Posledni rozmazana vrstva na dashboardu byla lepici hlavicka (backdrop-blur-xl); pod prekryvem dialogu ji prohlizec prepocitaval pri kazdem prekresleni (blikajici kurzor, kolecko obnovy dat). Hlavicka ma plnou barvu, dialog je jeden fixed prekryv s vycentrovanym panelem. Tecka a znacka Zive odstraneny z dashboardu i z ukazkoveho panelu na webu, duplicitni blok prefers-reduced-motion v index.css sloucen. Dokumentace 05, 22, 99.
This commit is contained in:
@@ -24,7 +24,6 @@ import { ErrorBoundary } from '@/components/ErrorBoundary';
|
||||
import { useAuth, type AuthUser } from '@/auth/AuthContext';
|
||||
import { EventStreamProvider } from '@/components/dashboard/EventStreamProvider';
|
||||
import { EventToasts } from '@/components/dashboard/EventToasts';
|
||||
import { LiveIndicator } from '@/components/dashboard/LiveIndicator';
|
||||
import { Logo } from '@/components/layout/Logo';
|
||||
import { cn } from '@/lib/cn';
|
||||
import { CollectionsProvider, useAccess } from '@/lib/collections';
|
||||
@@ -287,8 +286,14 @@ function DashboardShell() {
|
||||
<div className="lg:pl-64">
|
||||
<ImpersonationBanner />
|
||||
|
||||
{/* Topbar */}
|
||||
<header className="sticky top-0 z-30 flex h-18 items-center gap-4 border-b border-ink-600/60 bg-ink-900/85 px-5 backdrop-blur-xl sm:px-7">
|
||||
{/*
|
||||
Topbar. Plna barva, zadne `backdrop-blur`. Rozmazana hlavicka pres
|
||||
celou sirku byla posledni na dashboardu a pod otevrenym dialogem
|
||||
(prekryv pres cely viewport lezi nad ni) prohlizec rozmazani
|
||||
prepocital pri kazdem prekresleni pod prekryvem - blikajici kurzor
|
||||
v poli dialogu stacil, aby vedle portalu sekalo video.
|
||||
*/}
|
||||
<header className="sticky top-0 z-30 flex h-18 items-center gap-4 border-b border-ink-600/60 bg-ink-900 px-5 sm:px-7">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSidebarPath(location.pathname)}
|
||||
@@ -311,8 +316,6 @@ function DashboardShell() {
|
||||
<p className="truncate text-xs text-white/40">{accessLabel(user, access.data)}</p>
|
||||
</div>
|
||||
|
||||
<LiveIndicator className="hidden sm:inline-flex" />
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="hidden text-right sm:block">
|
||||
<p className="text-sm font-medium text-white">{user?.name}</p>
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { useEventStream } from '@/components/dashboard/EventStreamProvider';
|
||||
import { cn } from '@/lib/cn';
|
||||
|
||||
/*
|
||||
* Pulz jen kdyz se neco deje (pripojuji, obnovuji). Stav "Zive" je vychozi
|
||||
* a trva hodiny; nekonecna animace v hlavicce s `backdrop-blur` nutila
|
||||
* prohlizec prepocitavat rozmazani porad dokola, a s otevrenym dialogem
|
||||
* (dalsi vrstva pres celou obrazovku) to sekalo video vedle portalu.
|
||||
*/
|
||||
const meta = {
|
||||
connecting: { label: 'Připojuji', dot: 'bg-warn-400', text: 'text-warn-400', pulse: true },
|
||||
open: { label: 'Živě', dot: 'bg-ok-400', text: 'text-ok-400', pulse: false },
|
||||
reconnecting: {
|
||||
label: 'Obnovuji spojení',
|
||||
dot: 'bg-warn-400',
|
||||
text: 'text-warn-400',
|
||||
pulse: true,
|
||||
},
|
||||
closed: { label: 'Odpojeno', dot: 'bg-white/40', text: 'text-white/45', pulse: false },
|
||||
} as const;
|
||||
|
||||
/** Stav spojeni se streamem. Uzivatel musi poznat, ze data nejsou zive. */
|
||||
export function LiveIndicator({ className }: { className?: string }) {
|
||||
const { status } = useEventStream();
|
||||
const current = meta[status];
|
||||
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1.5 rounded-full border border-ink-600/70 px-2.5 py-1 text-xs font-medium',
|
||||
current.text,
|
||||
className,
|
||||
)}
|
||||
title={
|
||||
status === 'open'
|
||||
? 'Dashboard dostává změny okamžitě, bez obnovování stránky.'
|
||||
: 'Změny se teď nemusí projevovat okamžitě.'
|
||||
}
|
||||
>
|
||||
<span
|
||||
className={cn('size-1.5 rounded-full', current.dot, current.pulse && 'animate-pulse')}
|
||||
/>
|
||||
{current.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -270,11 +270,7 @@ function HeroPanel() {
|
||||
<p className="truncate text-xs font-semibold text-white">Acme s.r.o.</p>
|
||||
<p className="truncate text-[0.65rem] text-white/40">{t('panel.role')}</p>
|
||||
</div>
|
||||
<span className="ml-auto inline-flex items-center gap-1.5 rounded-full border border-ok-400/35 bg-ok-500/12 px-2 py-0.5 text-[0.65rem] text-ok-400">
|
||||
<span className="size-1.5 rounded-full bg-ok-400" />
|
||||
{t('panel.live')}
|
||||
</span>
|
||||
<span className="grid size-7 shrink-0 place-items-center rounded-xl bg-brand-500/20 text-[0.6rem] font-bold text-brand-200">
|
||||
<span className="ml-auto grid size-7 shrink-0 place-items-center rounded-xl bg-brand-500/20 text-[0.6rem] font-bold text-brand-200">
|
||||
JK
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -10,10 +10,13 @@ import { cn } from '@/lib/cn';
|
||||
* Pri otevreni zamkne scroll stranky a preda focus dovnitr.
|
||||
*
|
||||
* **Vykresluje se portalem do `document.body`, ne na miste volani.** Samo
|
||||
* `position: fixed` nestaci: rodic s `backdrop-filter` (nase `.glass`, tedy
|
||||
* skoro kazdy panel a karta) je pro fixed potomka containing block a dialog
|
||||
* se pak vejde do te karty misto pres celou obrazovku. Bez portalu je tedy
|
||||
* dialog v karte konektoru maly a nepouzitelny.
|
||||
* `position: fixed` nestaci: rodic s `transform`, `filter` nebo
|
||||
* `backdrop-filter` je pro fixed potomka containing block a dialog se pak
|
||||
* vejde do te karty misto pres celou obrazovku. Bez portalu byl dialog
|
||||
* v karte konektoru maly a nepouzitelny.
|
||||
*
|
||||
* Prekryv nema rozmazani a nic pod nim ho mit nesmi: rozmazana vrstva pod
|
||||
* prekryvem se prepocitava pri kazdem prekresleni (i blikajici kurzor).
|
||||
*/
|
||||
export function Modal({
|
||||
open,
|
||||
@@ -73,22 +76,24 @@ export function Modal({
|
||||
if (!open) return null;
|
||||
|
||||
return createPortal(
|
||||
<div className="fixed inset-0 z-[60] flex items-start justify-center overflow-y-auto p-4 sm:items-center sm:p-6">
|
||||
{/*
|
||||
Prekryv bez rozmazani, schvalne. `backdrop-blur` pres celou obrazovku
|
||||
znamena, ze kazda animace pod dialogem (pulzujici tecka, spinner,
|
||||
obnova seznamu) prepocita rozmazani cele plochy, a to jeste pres
|
||||
rozmazanou hlavicku pod nim. Vedle portalu pak sekalo video. Tmavy
|
||||
prekryv s vyssi krytim dela tutez praci zadarmo.
|
||||
*/}
|
||||
<div className="fixed inset-0 bg-ink-950/85" onClick={onClose} aria-hidden />
|
||||
|
||||
/*
|
||||
* Jedna vrstva: tmavy prekryv pres celou obrazovku, uprostred panel.
|
||||
* Zadne rozmazani, zadna animace. Klik mimo panel zavira.
|
||||
* `m-auto` na panelu ho vycentruje a u vysokeho dialogu necha horni
|
||||
* okraj dosazitelny posuvnikem prekryvu.
|
||||
*/
|
||||
<div
|
||||
className="fixed inset-0 z-[60] flex h-screen w-screen overflow-y-auto bg-ink-950/85 p-4 sm:p-6"
|
||||
onClick={(event) => {
|
||||
if (event.target === event.currentTarget) onClose();
|
||||
}}
|
||||
>
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label={title}
|
||||
className={cn(
|
||||
'relative my-auto w-full max-w-3xl rounded-2xl border border-ink-600/70 bg-ink-900 shadow-2xl',
|
||||
'm-auto w-full max-w-3xl rounded-2xl border border-ink-600/70 bg-ink-900 shadow-2xl',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -77,7 +77,6 @@ export const cs = {
|
||||
'panel.ago24min': 'před 24 min',
|
||||
'panel.ago1h': 'před 1 hod',
|
||||
'panel.ago3h': 'před 3 hod',
|
||||
'panel.live': 'Živě',
|
||||
|
||||
// ------------------------------------------------------------ reference
|
||||
'logos.title': 'Pracujeme pro firmy, které nemají čas na ruční práci',
|
||||
|
||||
@@ -77,7 +77,6 @@ export const en: Partial<Record<MessageKey, string>> = {
|
||||
'panel.ago24min': '24 min ago',
|
||||
'panel.ago1h': '1 hour ago',
|
||||
'panel.ago3h': '3 hours ago',
|
||||
'panel.live': 'Live',
|
||||
|
||||
// ------------------------------------------------------------ reference
|
||||
'logos.title': 'Trusted by teams with no time for busywork',
|
||||
|
||||
+5
-12
@@ -183,8 +183,10 @@
|
||||
* vrstvu ve skladaci. Pri padesati kartach a zivem streamu udalosti to
|
||||
* vytizilo GPU natolik, ze vedle toho sekalo prehravani videa.
|
||||
*
|
||||
* Rozmazani zustava tam, kde neco opravdu prekryva: lepici hlavicka
|
||||
* a podklady modalu maji svoje `backdrop-blur-*` primo u sebe.
|
||||
* Na dashboardu uz `backdrop-filter` nema nic: pod otevrenym dialogem
|
||||
* (prekryv pres cely viewport) se kazda rozmazana vrstva prepocitava pri
|
||||
* kazdem prekresleni, i kdyz jen blika kurzor. Jedine rozmazani zustalo
|
||||
* v hlavicce verejneho webu, kde neni zadny stream ani dialog.
|
||||
*/
|
||||
@utility glass {
|
||||
background-color: --alpha(var(--color-ink-800) / 70%);
|
||||
@@ -225,13 +227,4 @@
|
||||
*
|
||||
* Nekonecne animace jsou to jedine, co na klidne strance porad zamestnava
|
||||
* skladac - a prave ty jsou tady zbytne.
|
||||
*/
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user