feature/logo-nav
This commit is contained in:
@@ -9,59 +9,91 @@
|
||||
import { getBackendAssetUrl } from "$lib/utils";
|
||||
|
||||
const sidebar = useSidebar();
|
||||
|
||||
|
||||
// Derivar la URL del logo usando el endpoint específico
|
||||
let activeCompanyLogoUrl = $derived(
|
||||
companyStore.activeCompany?.logo
|
||||
? getBackendAssetUrl(`v1/a76/company/${companyStore.activeCompany.id}/logo/image?t=${new Date().getTime()}`)
|
||||
companyStore.activeCompany?.logo
|
||||
? getBackendAssetUrl(
|
||||
`v1/a76/company/${companyStore.activeCompany.id}/logo/image?t=${Date.now()}`
|
||||
)
|
||||
: null
|
||||
);
|
||||
|
||||
|
||||
// Iniciales de la compañía activa (2 primeras letras)
|
||||
let activeCompanyInitials = $derived(
|
||||
companyStore.activeCompany?.name?.slice(0, 2).toUpperCase() || 'CO'
|
||||
companyStore.activeCompany?.name?.slice(0, 2).toUpperCase() || "CO"
|
||||
);
|
||||
|
||||
// Fallback en degradé cuando no hay logo cargado
|
||||
const fallbackBg =
|
||||
"radial-gradient(circle at 30% 30%, rgba(0,0,0,0.08), rgba(0,0,0,0.12)), linear-gradient(135deg, rgba(99,102,241,0.12), rgba(14,165,233,0.18))";
|
||||
|
||||
const logoBg = $derived(
|
||||
activeCompanyLogoUrl
|
||||
? `url(${activeCompanyLogoUrl})`
|
||||
: fallbackBg
|
||||
);
|
||||
</script>
|
||||
|
||||
<Sidebar.Menu>
|
||||
<Sidebar.MenuItem>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Sidebar.MenuButton
|
||||
{...props}
|
||||
size="lg"
|
||||
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
||||
>
|
||||
<div
|
||||
class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg overflow-hidden"
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Sidebar.MenuButton
|
||||
{...props}
|
||||
size="lg"
|
||||
class="relative overflow-hidden data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground group-has-data-[state=collapsed]/sidebar-wrapper:aspect-square group-has-data-[state=collapsed]/sidebar-wrapper:h-10 group-has-data-[state=collapsed]/sidebar-wrapper:w-10 group-has-data-[state=collapsed]/sidebar-wrapper:rounded-lg group-has-data-[state=collapsed]/sidebar-wrapper:justify-center group-has-data-[state=collapsed]/sidebar-wrapper:gap-0"
|
||||
>
|
||||
{#if activeCompanyLogoUrl}
|
||||
<img
|
||||
src={activeCompanyLogoUrl}
|
||||
alt={companyStore.activeCompany?.name || 'Company'}
|
||||
class="size-full object-cover"
|
||||
onerror={(e) => { (e.currentTarget as HTMLImageElement).style.display = 'none'; }}
|
||||
/>
|
||||
{:else}
|
||||
<span class="text-sm font-semibold text-white">{activeCompanyInitials}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid flex-1 text-left text-sm leading-tight min-w-0">
|
||||
<span class="truncate font-medium">
|
||||
{companyStore.activeCompany?.name || 'Seleccionar compañía'}
|
||||
</span>
|
||||
{#if companyStore.activeCompany?.rfc}
|
||||
<span class="truncate text-xs text-muted-foreground">
|
||||
{companyStore.activeCompany.rfc}
|
||||
<!-- Logo skin visible cuando el sidebar está colapsado (icon mode) -->
|
||||
<span
|
||||
aria-hidden
|
||||
class="pointer-events-none absolute inset-0 bg-center bg-contain bg-no-repeat transition-all duration-300 opacity-0 group-has-data-[state=collapsed]/sidebar-wrapper:opacity-90 group-has-data-[state=collapsed]/sidebar-wrapper:blur-[0.6px] group-has-data-[state=collapsed]/sidebar-wrapper:scale-100"
|
||||
style:background-image={logoBg}
|
||||
/>
|
||||
<!-- Overlay para legibilidad del ícono/chevron -->
|
||||
<span
|
||||
aria-hidden
|
||||
class="pointer-events-none absolute inset-0 transition-opacity duration-300 opacity-0 group-has-data-[state=collapsed]/sidebar-wrapper:bg-black/12 group-has-data-[state=collapsed]/sidebar-wrapper:opacity-100"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg overflow-hidden group-has-data-[state=collapsed]/sidebar-wrapper:hidden"
|
||||
>
|
||||
{#if activeCompanyLogoUrl}
|
||||
<img
|
||||
src={activeCompanyLogoUrl}
|
||||
alt={companyStore.activeCompany?.name || "Company"}
|
||||
class="size-full object-cover"
|
||||
onerror={(e) => {
|
||||
(e.currentTarget as HTMLImageElement).style.display = "none";
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<span class="text-sm font-semibold text-white">{activeCompanyInitials}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid flex-1 text-left text-sm leading-tight min-w-0 group-has-data-[state=collapsed]/sidebar-wrapper:hidden">
|
||||
<span class="truncate font-medium">
|
||||
{companyStore.activeCompany?.name || "Seleccionar compañía"}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
<ChevronsUpDownIcon class="ml-auto size-4" />
|
||||
</Sidebar.MenuButton>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
{#if companyStore.activeCompany?.rfc}
|
||||
<span class="truncate text-xs text-muted-foreground">
|
||||
{companyStore.activeCompany.rfc}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
<ChevronsUpDownIcon class="ml-auto size-4 group-has-data-[state=collapsed]/sidebar-wrapper:hidden" />
|
||||
|
||||
<!-- Isotipo compacto visible solo en modo colapsado -->
|
||||
<div
|
||||
class="relative z-10 hidden size-8 items-center justify-center rounded-md bg-sidebar-primary text-sidebar-foreground text-sm font-semibold shadow-sm ring-1 ring-sidebar-border/40 group-has-data-[state=collapsed]/sidebar-wrapper:flex"
|
||||
>
|
||||
{activeCompanyInitials}
|
||||
</div>
|
||||
</Sidebar.MenuButton>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
class="w-(--bits-dropdown-menu-anchor-width) min-w-56 rounded-lg"
|
||||
align="start"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { cn, getBackendAssetUrl } from "$lib/utils.js";
|
||||
import PanelLeftIcon from "@lucide/svelte/icons/panel-left";
|
||||
import type { ComponentProps } from "svelte";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { useSidebar } from "./context.svelte.js";
|
||||
|
||||
let {
|
||||
@@ -15,6 +16,19 @@
|
||||
} = $props();
|
||||
|
||||
const sidebar = useSidebar();
|
||||
|
||||
// Derive the current company logo as a skin for the trigger when collapsed.
|
||||
let activeCompanyLogoUrl = $derived(
|
||||
companyStore.activeCompany?.logo
|
||||
? getBackendAssetUrl(
|
||||
`v1/a76/company/${companyStore.activeCompany.id}/logo/image?t=${Date.now()}`
|
||||
)
|
||||
: null
|
||||
);
|
||||
|
||||
// Keep a short fallback in case there is no logo.
|
||||
const fallbackBg =
|
||||
"radial-gradient(circle at 30% 30%, rgba(0,0,0,0.08), rgba(0,0,0,0.12)), linear-gradient(135deg, rgba(99,102,241,0.08), rgba(14,165,233,0.14))";
|
||||
</script>
|
||||
|
||||
<Button
|
||||
@@ -22,7 +36,13 @@
|
||||
data-slot="sidebar-trigger"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class={cn("size-7", className)}
|
||||
class={cn(
|
||||
"relative flex aspect-square h-10 w-10 items-center justify-center overflow-hidden rounded-lg",
|
||||
"border border-sidebar-border/60 bg-sidebar shadow-sm transition-all duration-300",
|
||||
"hover:bg-sidebar-accent/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
|
||||
"group-data-[collapsible=icon]/sidebar-wrapper:size-9",
|
||||
className
|
||||
)}
|
||||
type="button"
|
||||
onclick={(e) => {
|
||||
onclick?.(e);
|
||||
@@ -30,6 +50,28 @@
|
||||
}}
|
||||
{...restProps}
|
||||
>
|
||||
<PanelLeftIcon />
|
||||
<!-- Logo skin behind the icon; fades/blurs when collapsed for legibility -->
|
||||
<span
|
||||
aria-hidden
|
||||
class={cn(
|
||||
"absolute inset-0 bg-center bg-no-repeat transition-all duration-300",
|
||||
"bg-contain",
|
||||
sidebar.state === "collapsed"
|
||||
? "opacity-75 blur-[0.5px] scale-95"
|
||||
: "opacity-100 blur-0 scale-105"
|
||||
)}
|
||||
style:background-image={activeCompanyLogoUrl ? `url(${activeCompanyLogoUrl})` : fallbackBg}
|
||||
/>
|
||||
|
||||
<!-- Subtle overlay to keep the icon readable over the logo skin -->
|
||||
<span
|
||||
class={cn(
|
||||
"pointer-events-none absolute inset-0 transition-opacity duration-300",
|
||||
sidebar.state === "collapsed" ? "bg-black/10 opacity-100" : "opacity-0"
|
||||
)}
|
||||
aria-hidden
|
||||
/>
|
||||
|
||||
<PanelLeftIcon class="relative z-10 transition-transform duration-300" />
|
||||
<span class="sr-only">Toggle Sidebar</span>
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user