feat: replace dynamic avatar generation with static image assets
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
import NotificationBell from '$lib/components/chat/NotificationBell.svelte';
|
||||
import ChatWidget from '$lib/components/chat/ChatWidget.svelte';
|
||||
import PresenceManager from '$lib/components/chat/PresenceManager.svelte';
|
||||
import { getAvatarUrl } from '$lib/utils/avatarGenerator';
|
||||
|
||||
import { Menu, User, Home, UserPlus, XCircle, LogIn, Tag, Plus, Check } from 'lucide-svelte';
|
||||
import { authClient } from '$lib/auth';
|
||||
import { resolve } from '$app/paths';
|
||||
@@ -33,8 +33,8 @@
|
||||
return currentUser.data.avatar;
|
||||
}
|
||||
|
||||
// Fallback: gerar avatar baseado no nome
|
||||
return getAvatarUrl(currentUser.data.nome);
|
||||
// Fallback: retornar null para usar o ícone User do Lucide
|
||||
return null;
|
||||
});
|
||||
|
||||
// Função para gerar classes do menu ativo
|
||||
@@ -328,8 +328,9 @@
|
||||
>Contato</a
|
||||
>
|
||||
<span class="text-base-content/30">•</span>
|
||||
<a href={resolve('/abrir-chamado')} class="link link-hover hover:text-primary transition-colors"
|
||||
>Suporte</a
|
||||
<a
|
||||
href={resolve('/abrir-chamado')}
|
||||
class="link link-hover hover:text-primary transition-colors">Suporte</a
|
||||
>
|
||||
<span class="text-base-content/30">•</span>
|
||||
<a href={resolve('/')} class="link link-hover hover:text-primary transition-colors"
|
||||
@@ -365,7 +366,7 @@
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
{#each setores as s}
|
||||
{#each setores as s (s.link)}
|
||||
{@const isActive = currentPath.startsWith(s.link)}
|
||||
<li class="rounded-xl">
|
||||
<a
|
||||
@@ -400,7 +401,7 @@
|
||||
<!-- Botão de fechar moderno -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-ghost absolute top-4 right-4 z-10 hover:bg-error/20 hover:text-error transition-all duration-200"
|
||||
class="btn btn-sm btn-circle btn-ghost hover:bg-error/20 hover:text-error absolute top-4 right-4 z-10 transition-all duration-200"
|
||||
onclick={closeLoginModal}
|
||||
aria-label="Fechar modal"
|
||||
>
|
||||
@@ -408,28 +409,20 @@
|
||||
</button>
|
||||
|
||||
<!-- Decoração de fundo -->
|
||||
<div
|
||||
class="absolute -top-20 -right-20 h-40 w-40 rounded-full bg-primary/10 blur-3xl"
|
||||
></div>
|
||||
<div
|
||||
class="absolute -bottom-20 -left-20 h-40 w-40 rounded-full bg-primary/5 blur-3xl"
|
||||
></div>
|
||||
<div class="bg-primary/10 absolute -top-20 -right-20 h-40 w-40 rounded-full blur-3xl"></div>
|
||||
<div class="bg-primary/5 absolute -bottom-20 -left-20 h-40 w-40 rounded-full blur-3xl"></div>
|
||||
|
||||
<div class="relative z-10 p-8">
|
||||
<!-- Header com logo e título -->
|
||||
<div class="mb-8 text-center">
|
||||
<div class="avatar mb-5 mx-auto">
|
||||
<div class="avatar mx-auto mb-5">
|
||||
<div
|
||||
class="group relative w-24 overflow-hidden rounded-2xl bg-white p-4 shadow-xl ring-2 ring-primary/20 transition-all duration-300 hover:scale-105 hover:shadow-2xl"
|
||||
class="group ring-primary/20 relative w-24 overflow-hidden rounded-2xl bg-white p-4 shadow-xl ring-2 transition-all duration-300 hover:scale-105 hover:shadow-2xl"
|
||||
>
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-br from-primary/10 to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100"
|
||||
class="from-primary/10 absolute inset-0 bg-gradient-to-br to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100"
|
||||
></div>
|
||||
<img
|
||||
src={logo}
|
||||
alt="Logo SGSE"
|
||||
class="relative z-10 h-full w-full object-contain"
|
||||
/>
|
||||
<img src={logo} alt="Logo SGSE" class="relative z-10 h-full w-full object-contain" />
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="text-primary mb-2 text-4xl font-bold tracking-tight">Login</h3>
|
||||
@@ -441,7 +434,7 @@
|
||||
<!-- Mensagem de erro -->
|
||||
{#if erroLogin}
|
||||
<div
|
||||
class="alert alert-error mb-6 border-error/30 bg-error/10 shadow-lg backdrop-blur-sm"
|
||||
class="alert alert-error border-error/30 bg-error/10 mb-6 shadow-lg backdrop-blur-sm"
|
||||
>
|
||||
<XCircle class="h-5 w-5 shrink-0 stroke-current" strokeWidth={2.5} />
|
||||
<span class="font-medium">{erroLogin}</span>
|
||||
@@ -453,16 +446,14 @@
|
||||
<!-- Campo Matrícula/E-mail -->
|
||||
<div class="form-control">
|
||||
<label class="label pb-2" for="login-matricula">
|
||||
<span class="text-primary label-text text-sm font-semibold"
|
||||
>Matrícula ou E-mail</span
|
||||
>
|
||||
<span class="text-primary label-text text-sm font-semibold">Matrícula ou E-mail</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="login-matricula"
|
||||
type="text"
|
||||
placeholder="Digite sua matrícula ou e-mail"
|
||||
class="input input-bordered input-primary w-full border-2 transition-all duration-200 focus:border-primary focus:shadow-lg focus:shadow-primary/20 disabled:opacity-50"
|
||||
class="input input-bordered input-primary focus:border-primary focus:shadow-primary/20 w-full border-2 transition-all duration-200 focus:shadow-lg disabled:opacity-50"
|
||||
bind:value={matricula}
|
||||
required
|
||||
disabled={carregandoLogin}
|
||||
@@ -481,7 +472,7 @@
|
||||
id="login-password"
|
||||
type="password"
|
||||
placeholder="Digite sua senha"
|
||||
class="input input-bordered input-primary w-full border-2 transition-all duration-200 focus:border-primary focus:shadow-lg focus:shadow-primary/20 disabled:opacity-50"
|
||||
class="input input-bordered input-primary focus:border-primary focus:shadow-primary/20 w-full border-2 transition-all duration-200 focus:shadow-lg disabled:opacity-50"
|
||||
bind:value={senha}
|
||||
required
|
||||
disabled={carregandoLogin}
|
||||
@@ -494,7 +485,7 @@
|
||||
<div class="form-control pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary btn-lg group relative w-full overflow-hidden border-0 bg-gradient-to-r from-primary via-primary to-primary/90 shadow-xl transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl disabled:opacity-50"
|
||||
class="btn btn-primary btn-lg group from-primary via-primary to-primary/90 relative w-full overflow-hidden border-0 bg-gradient-to-r shadow-xl transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl disabled:opacity-50"
|
||||
disabled={carregandoLogin}
|
||||
>
|
||||
<!-- Efeito de brilho animado -->
|
||||
@@ -506,14 +497,17 @@
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
<span class="font-semibold">Entrando...</span>
|
||||
{:else}
|
||||
<LogIn class="h-5 w-5 transition-transform duration-300 group-hover:scale-110" strokeWidth={2.5} />
|
||||
<LogIn
|
||||
class="h-5 w-5 transition-transform duration-300 group-hover:scale-110"
|
||||
strokeWidth={2.5}
|
||||
/>
|
||||
<span class="font-semibold">Entrar</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Links auxiliares -->
|
||||
<div class="pt-4 space-y-3 text-center">
|
||||
<div class="space-y-3 pt-4 text-center">
|
||||
<a
|
||||
href={resolve('/abrir-chamado')}
|
||||
class="link link-primary block text-sm font-medium transition-all duration-200 hover:scale-105"
|
||||
@@ -548,7 +542,7 @@
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2 z-10 hover:bg-base-300"
|
||||
class="btn btn-sm btn-circle btn-ghost hover:bg-base-300 absolute top-2 right-2 z-10"
|
||||
onclick={closeAboutModal}
|
||||
>
|
||||
✕
|
||||
@@ -558,7 +552,7 @@
|
||||
<!-- Logo e Título -->
|
||||
<div class="flex flex-col items-center gap-3">
|
||||
<div class="avatar">
|
||||
<div class="w-20 rounded-xl bg-white p-3 shadow-lg ring-2 ring-primary/20">
|
||||
<div class="ring-primary/20 w-20 rounded-xl bg-white p-3 shadow-lg ring-2">
|
||||
<img src={logo} alt="Logo SGSE" class="h-full w-full object-contain" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -574,10 +568,12 @@
|
||||
<div class="divider my-1"></div>
|
||||
|
||||
<!-- Informações de Versão -->
|
||||
<div class="bg-gradient-to-br from-primary/10 to-primary/5 space-y-2 rounded-xl border border-primary/10 p-4 shadow-sm">
|
||||
<div
|
||||
class="from-primary/10 to-primary/5 border-primary/10 space-y-2 rounded-xl border bg-gradient-to-br p-4 shadow-sm"
|
||||
>
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<Tag class="text-primary h-4 w-4" strokeWidth={2} />
|
||||
<p class="text-base-content/60 text-xs font-medium uppercase tracking-wide">Versão</p>
|
||||
<p class="text-base-content/60 text-xs font-medium tracking-wide uppercase">Versão</p>
|
||||
</div>
|
||||
<p class="text-primary text-2xl font-bold tracking-tight">1.0 11_2025</p>
|
||||
<div class="badge badge-warning badge-sm gap-1.5 px-3 py-1.5 text-xs">
|
||||
@@ -588,7 +584,9 @@
|
||||
|
||||
<!-- Desenvolvido por -->
|
||||
<div class="space-y-1.5">
|
||||
<p class="text-base-content/50 text-xs font-medium uppercase tracking-wide">Desenvolvido por</p>
|
||||
<p class="text-base-content/50 text-xs font-medium tracking-wide uppercase">
|
||||
Desenvolvido por
|
||||
</p>
|
||||
<p class="text-primary text-sm font-semibold">Secretaria de Esportes de Pernambuco</p>
|
||||
</div>
|
||||
|
||||
@@ -597,12 +595,16 @@
|
||||
|
||||
<!-- Informações Adicionais -->
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="bg-base-200/60 rounded-lg border border-base-300/50 p-3 shadow-sm transition-all hover:shadow-md">
|
||||
<p class="text-primary mb-1 text-xs font-semibold uppercase tracking-wide">Governo</p>
|
||||
<div
|
||||
class="bg-base-200/60 border-base-300/50 rounded-lg border p-3 shadow-sm transition-all hover:shadow-md"
|
||||
>
|
||||
<p class="text-primary mb-1 text-xs font-semibold tracking-wide uppercase">Governo</p>
|
||||
<p class="text-base-content/60 text-xs font-medium">Estado de Pernambuco</p>
|
||||
</div>
|
||||
<div class="bg-base-200/60 rounded-lg border border-base-300/50 p-3 shadow-sm transition-all hover:shadow-md">
|
||||
<p class="text-primary mb-1 text-xs font-semibold uppercase tracking-wide">Ano</p>
|
||||
<div
|
||||
class="bg-base-200/60 border-base-300/50 rounded-lg border p-3 shadow-sm transition-all hover:shadow-md"
|
||||
>
|
||||
<p class="text-primary mb-1 text-xs font-semibold tracking-wide uppercase">Ano</p>
|
||||
<p class="text-base-content/60 text-xs font-medium">2025</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import ChatList from './ChatList.svelte';
|
||||
import ChatWindow from './ChatWindow.svelte';
|
||||
import { getAvatarUrl } from '$lib/utils/avatarGenerator';
|
||||
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
const count = useQuery(api.chat.contarNotificacoesNaoLidas, {});
|
||||
@@ -38,11 +38,8 @@
|
||||
return usuario.fotoPerfilUrl;
|
||||
}
|
||||
|
||||
if (usuario.avatar) {
|
||||
return getAvatarUrl(usuario.avatar);
|
||||
}
|
||||
// Fallback: gerar avatar baseado no nome
|
||||
return getAvatarUrl(usuario.nome);
|
||||
// Fallback: retornar null para usar o ícone User do Lucide
|
||||
return null;
|
||||
});
|
||||
|
||||
// Posição do widget (arrastável)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import UserAvatar from './UserAvatar.svelte';
|
||||
import ScheduleMessageModal from './ScheduleMessageModal.svelte';
|
||||
import SalaReuniaoManager from './SalaReuniaoManager.svelte';
|
||||
import { getAvatarUrl } from '$lib/utils/avatarGenerator';
|
||||
|
||||
import { Bell, X, ArrowLeft, LogOut, MoreVertical, Users, Clock, XCircle } from 'lucide-svelte';
|
||||
|
||||
interface Props {
|
||||
@@ -59,10 +59,7 @@
|
||||
const c = conversa();
|
||||
if (!c) return '💬';
|
||||
if (c.tipo === 'grupo') {
|
||||
return c.avatar || '👥';
|
||||
}
|
||||
if (c.outroUsuario?.avatar) {
|
||||
return c.outroUsuario.avatar;
|
||||
return '👥';
|
||||
}
|
||||
return '👤';
|
||||
}
|
||||
@@ -138,7 +135,6 @@
|
||||
<div class="relative shrink-0">
|
||||
{#if conversa() && conversa()?.tipo === 'individual' && conversa()?.outroUsuario}
|
||||
<UserAvatar
|
||||
avatar={conversa()?.outroUsuario?.avatar}
|
||||
fotoPerfilUrl={conversa()?.outroUsuario?.fotoPerfilUrl}
|
||||
nome={conversa()?.outroUsuario?.nome || 'Usuário'}
|
||||
size="md"
|
||||
@@ -195,18 +191,12 @@
|
||||
alt={participante.nome}
|
||||
class="h-full w-full object-cover"
|
||||
/>
|
||||
{:else if participante.avatar}
|
||||
<img
|
||||
src={getAvatarUrl(participante.avatar)}
|
||||
alt={participante.nome}
|
||||
class="h-full w-full object-cover"
|
||||
/>
|
||||
{:else}
|
||||
<img
|
||||
src={getAvatarUrl(participante.nome)}
|
||||
alt={participante.nome}
|
||||
class="h-full w-full object-cover"
|
||||
/>
|
||||
<div
|
||||
class="bg-base-200 flex h-full w-full items-center justify-center text-xs font-semibold"
|
||||
>
|
||||
{participante.nome.substring(0, 2).toUpperCase()}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -1,41 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { getAvatarUrl as generateAvatarUrl } from "$lib/utils/avatarGenerator";
|
||||
|
||||
interface Props {
|
||||
avatar?: string;
|
||||
fotoPerfilUrl?: string | null;
|
||||
nome: string;
|
||||
size?: "xs" | "sm" | "md" | "lg";
|
||||
}
|
||||
import { User } from 'lucide-svelte';
|
||||
|
||||
let { avatar, fotoPerfilUrl, nome, size = "md" }: Props = $props();
|
||||
interface Props {
|
||||
fotoPerfilUrl?: string | null;
|
||||
nome: string;
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
}
|
||||
|
||||
const sizeClasses = {
|
||||
xs: "w-8 h-8",
|
||||
sm: "w-10 h-10",
|
||||
md: "w-12 h-12",
|
||||
lg: "w-16 h-16",
|
||||
};
|
||||
let { fotoPerfilUrl, nome, size = 'md' }: Props = $props();
|
||||
|
||||
function getAvatarUrl(avatarId: string): string {
|
||||
// Usar gerador local ao invés da API externa
|
||||
return generateAvatarUrl(avatarId);
|
||||
}
|
||||
const sizeClasses = {
|
||||
xs: 'w-8 h-8',
|
||||
sm: 'w-10 h-10',
|
||||
md: 'w-12 h-12',
|
||||
lg: 'w-16 h-16',
|
||||
xl: 'w-32 h-32'
|
||||
};
|
||||
|
||||
const avatarUrlToShow = $derived(() => {
|
||||
if (fotoPerfilUrl) return fotoPerfilUrl;
|
||||
if (avatar) return getAvatarUrl(avatar);
|
||||
return getAvatarUrl(nome); // Fallback usando o nome
|
||||
});
|
||||
const iconSizes = {
|
||||
xs: 16,
|
||||
sm: 20,
|
||||
md: 24,
|
||||
lg: 32,
|
||||
xl: 64
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="avatar">
|
||||
<div class={`${sizeClasses[size]} rounded-full bg-base-200 overflow-hidden`}>
|
||||
<img
|
||||
src={avatarUrlToShow()}
|
||||
alt={`Avatar de ${nome}`}
|
||||
class="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div class="avatar placeholder">
|
||||
<div
|
||||
class={`${sizeClasses[size]} bg-base-200 text-base-content/50 flex items-center justify-center overflow-hidden rounded-full`}
|
||||
>
|
||||
{#if fotoPerfilUrl}
|
||||
<img
|
||||
src={fotoPerfilUrl}
|
||||
alt={`Foto de perfil de ${nome}`}
|
||||
class="h-full w-full object-cover"
|
||||
/>
|
||||
{:else}
|
||||
<User size={iconSizes[size]} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user