veza/apps/web/src/components/pwa/PWAInstallBanner.tsx
senke 8b5239fdd1 aesthetic-improvements: apply design direction to components batch 1 (Action 11.5.1.6)
- UI components: FAB (removed scale transforms), tabs (removed decorative shadow)
- Upload components: FileUploadZone, MetadataEditor, BulkUploadModal (removed scale transforms and decorative gradient)
- Search: SearchBar (removed decorative shadow)
- PWA: PWAInstallBanner (removed decorative shadow)
- Social: ExploreView (removed decorative shadow and image zoom)
- Live: LiveStreamDetailView (removed decorative shadow)
- Player: VisualizerSettingsModal (removed scale transform)
- Marketplace: ReviewProductModal, ProductDetailView (removed scale transforms)
- Library: PlaylistsView (removed scale transform)
- Settings: AppearanceSettingsView (removed scale transform)
- Theme: ThemeSwitcher (removed scale transform)
- Studio: ProjectsManager, CloudFileBrowser (removed scale transforms)
- Social: GroupCard (removed image zoom)
- Seller: CreateProductView (removed scale transform)
- Modals: CreatorModal (removed scale transform)
- Replaced decorative scale transforms with subtle opacity changes or removed entirely
- Action 11.5.1.6: Apply direction to all components - Batch 1 complete (17 components)
2026-01-16 12:06:00 +01:00

94 lines
3.3 KiB
TypeScript

/**
* PWA Install Banner Component
* Shows a banner prompting users to install the app
*/
import { Download, Smartphone } from 'lucide-react';
import { Button } from '@veza/design-system';
import { usePWAInstallBanner } from '@/hooks/usePWA';
import { useTranslation } from 'react-i18next';
import { cn } from '@/lib/utils';
export function PWAInstallBanner() {
const { showBanner, isInstalling, handleInstall, handleDismiss } =
usePWAInstallBanner();
const { t } = useTranslation();
if (!showBanner) {
return null;
}
return (
<div
className={cn(
'fixed bottom-8 right-8 z-50 w-80 glass-hud rounded-2xl border-white/10 p-6 shadow-2xl animate-slideInRight hud-corner group overflow-hidden',
'before:absolute before:inset-0 before:bg-gradient-to-br before:from-kodo-cyan/5 before:to-transparent before:opacity-0 group-hover:before:opacity-100 before:transition-opacity',
)}
>
<div className="flex flex-col gap-4 relative z-10">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-kodo-steel/10 flex items-center justify-center border border-kodo-steel/30 animate-pulse-glow">
<Smartphone className="h-4 w-4 text-kodo-steel" />
</div>
<div>
<div className="text-hud">System.Uplink</div>
<h3 className="font-display font-black text-xs text-white uppercase tracking-wider">
{t('pwa.install.title', 'Native_Access')}
</h3>
</div>
</div>
<button
onClick={handleDismiss}
className="p-1 px-2 rounded-md bg-white/5 text-kodo-secondary hover:text-white transition-all text-[10px] font-mono border border-transparent hover:border-white/10"
>
DISMISS
</button>
</div>
<p className="text-[11px] font-mono text-white/50 leading-relaxed uppercase tracking-tighter">
{t(
'pwa.install.description',
'ESTABLISH_LOCAL_UPLINK_FOR_LOW_LATENCY_OPERATIONS',
)}
</p>
<div className="flex gap-2">
<Button
variant="gaming"
className="flex-1 h-9 text-[10px] font-black font-mono tracking-widest bg-kodo-cyan group hover:opacity-90 transition-opacity"
onClick={handleInstall}
disabled={isInstalling}
>
<Download className="h-3.5 w-3.5 mr-2 group-hover:translate-y-0.5 transition-transform" />
{isInstalling ? 'RUNNING...' : 'INITIATE_INSTALL'}
</Button>
</div>
<div className="absolute -bottom-8 -right-8 w-16 h-16 bg-kodo-steel/10 blur-2xl rounded-full" />
</div>
</div>
);
}
/**
* PWA Update Banner Component
* Shows a banner when app update is available
*/
export function PWAUpdateBanner() {
// This would need to be implemented with the PWA hook
// For now, returning null as it requires more complex state management
return null;
}
/**
* Offline Banner Component
* Shows when the app is offline
*/
export function OfflineBanner() {
// This would integrate with the offline detection hook
// For now, returning null as it requires more complex state management
return null;
}