fix: prevent header wrapping and uploaded image 404s

This commit is contained in:
Vaka.pro
2026-04-27 21:29:47 +03:00
parent 0ada42017f
commit fbf1d2d02f
5 changed files with 43 additions and 16 deletions

View File

@@ -96,21 +96,26 @@ export function Header() {
<Button
variant="ghost"
size="sm"
className="app-header__action"
onClick={() => navigate('/settings')}
title={t('header.profileSettings')}
aria-label={t('header.profileSettings')}
>
<UserCog className="h-4 w-4" />
{t('header.profile')}
<span className="app-header__action-text">{t('header.profile')}</span>
</Button>
<Button
variant="ghost"
size="sm"
className="app-header__action"
onClick={() => {
void logout().then(() => navigate('/login'));
}}
title={t('header.logout')}
aria-label={t('header.logout')}
>
<LogOut className="h-4 w-4" />
{t('header.logout')}
<span className="app-header__action-text">{t('header.logout')}</span>
</Button>
</div>
</div>

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
@@ -25,6 +25,7 @@ export function ProfileSettingsPage() {
const refresh = useAuthStore((s) => s.refresh);
const queryClient = useQueryClient();
const fileInputRef = useRef<HTMLInputElement>(null);
const [avatarFailed, setAvatarFailed] = useState(false);
const { data, isLoading } = useQuery({
queryKey: ['profile'],
@@ -120,6 +121,10 @@ export function ProfileSettingsPage() {
const avatarPreview = watch('avatarUrl') || data?.avatarUrl;
useEffect(() => {
setAvatarFailed(false);
}, [avatarPreview]);
return (
<div className="grid max-w-2xl gap-6">
<section className="page-section">
@@ -136,8 +141,13 @@ export function ProfileSettingsPage() {
<form className="profile-form" onSubmit={submit}>
<section className="profile-form__avatar-panel">
<span className="profile-form__avatar-preview">
{avatarPreview ? (
<img src={avatarPreview} alt="" className="profile-form__avatar-image" />
{avatarPreview && !avatarFailed ? (
<img
src={avatarPreview}
alt=""
className="profile-form__avatar-image"
onError={() => setAvatarFailed(true)}
/>
) : (
<Gift className="h-6 w-6" />
)}

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import type {
@@ -19,6 +19,7 @@ export function PublicProfilePage() {
const user = useAuthStore((s) => s.user);
const { slug = '' } = useParams<{ slug: string }>();
const queryClient = useQueryClient();
const [avatarFailed, setAvatarFailed] = useState(false);
const profile = useQuery({
queryKey: ['public-profile', slug],
@@ -57,6 +58,10 @@ export function PublicProfilePage() {
return () => window.clearTimeout(t);
}, [wishes.data, markSeen, queryClient, slug]);
useEffect(() => {
setAvatarFailed(false);
}, [profile.data?.avatarUrl]);
return (
<div className="public-profile">
<div className="public-profile__toolbar">
@@ -87,11 +92,12 @@ export function PublicProfilePage() {
<>
<section className="public-profile__hero">
<span className="public-profile__avatar">
{profile.data.avatarUrl ? (
{profile.data.avatarUrl && !avatarFailed ? (
<img
src={profile.data.avatarUrl}
alt=""
className="public-profile__avatar-image"
onError={() => setAvatarFailed(true)}
/>
) : (
<Gift className="h-6 w-6" />

View File

@@ -64,7 +64,13 @@
@apply bg-primary text-primary-foreground shadow-card hover:bg-primary;
}
.app-header__actions {
@apply flex shrink-0 items-center gap-1 justify-self-start lg:justify-self-end;
@apply flex shrink-0 items-center gap-1 justify-self-start whitespace-nowrap lg:justify-self-end;
}
.app-header__action {
@apply shrink-0;
}
.app-header__action-text {
@apply hidden xl:inline;
}
.app-footer {