mirror of
https://github.com/R0m1k3/PleinR.git
synced 2026-10-19 05:08:20 +02:00
- Espace adhérent : /backend/espace (profil, inscriptions, droit à l'image) et /backend/espace/promotions (dépôt et suivi). Bandeau et onglets communs (EspaceHeader) avec le nombre d'offres en ligne ; la page promotions ouvre sur « Mes promotions en cours », puis le formulaire, puis les offres en attente et l'historique. Deux entrées dans le menu, titres de page dédiés, revalidation des deux chemins. - Fiche adhérent : colonne members.contact_email (migration 0013), saisie dans l'espace adhérent et la fiche staff ; la fiche publique et le JSON-LD affichent contact_email, sinon l'e-mail du compte. - VitrineImage : sans photo de couverture, le logo est contenu à ~60 % d'un cadre à hauteur fixe sur un fond du logo flouté ; le conteneur sans hauteur qui laissait le logo déborder est supprimé. - Promotions : la catégorie devient un type de produit ou de service (src/lib/promo-categories.ts, 10 groupes, ~85 entrées) pré-sélectionné depuis le métier de l'adhérent, à la place de la liste des métiers. - Tests : catégories de promo (largeur, unicité, pré-sélection pour chaque métier du référentiel). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDbKbJrPWweXXYSxA8MXW7
99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
import type { CSSProperties, ReactNode } from "react";
|
|
|
|
const STRIPE_WARM =
|
|
"repeating-linear-gradient(45deg,#efe9da,#efe9da 12px,#e6ddc9 12px,#e6ddc9 24px)";
|
|
|
|
/**
|
|
* Zone d'image "vitrine" d'un adhérent.
|
|
* - Photo de couverture présente -> affichée en plein cadre (cover).
|
|
* - Sinon, le logo est affiché centré et réduit (contain, ~60 % du cadre) sur
|
|
* un fond fait du logo lui-même flouté : le cadre prend les couleurs de la
|
|
* marque sans que le logo soit étiré ni ne déborde.
|
|
* - Sinon, fond rayé + texte placeholder.
|
|
*/
|
|
export function VitrineImage({
|
|
coverUrl,
|
|
logoUrl,
|
|
height,
|
|
stripe = STRIPE_WARM,
|
|
placeholder = "photo vitrine",
|
|
children,
|
|
}: {
|
|
coverUrl?: string | null;
|
|
logoUrl?: string | null;
|
|
height: number;
|
|
stripe?: string;
|
|
placeholder?: string;
|
|
children?: ReactNode;
|
|
}) {
|
|
const cover = coverUrl || null;
|
|
const logoOnly = !cover && logoUrl ? logoUrl : null;
|
|
|
|
const base: CSSProperties = {
|
|
position: "relative",
|
|
height,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
overflow: "hidden",
|
|
};
|
|
|
|
if (cover) {
|
|
return (
|
|
<div style={{ ...base, background: `center/cover no-repeat url(${cover})` }}>{children}</div>
|
|
);
|
|
}
|
|
|
|
if (logoOnly) {
|
|
// `height` est fixe sur le cadre : les max-height en % du logo sont donc
|
|
// résolus, là où un conteneur intermédiaire sans hauteur les laissait sans
|
|
// effet et le logo débordait.
|
|
return (
|
|
<div style={{ ...base, background: "linear-gradient(160deg,#fffdf8 0%,#f3ecdc 100%)" }}>
|
|
<div
|
|
aria-hidden
|
|
style={{
|
|
position: "absolute",
|
|
inset: 0,
|
|
backgroundImage: `url(${logoOnly})`,
|
|
backgroundSize: "cover",
|
|
backgroundPosition: "center",
|
|
filter: "blur(28px) saturate(1.25)",
|
|
transform: "scale(1.25)",
|
|
opacity: 0.32,
|
|
}}
|
|
/>
|
|
<div
|
|
aria-hidden
|
|
style={{ position: "absolute", inset: 0, background: "linear-gradient(180deg, rgba(255,253,248,0.35) 0%, rgba(246,242,232,0.6) 100%)" }}
|
|
/>
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
<img
|
|
src={logoOnly}
|
|
alt=""
|
|
style={{
|
|
position: "relative",
|
|
maxWidth: "62%",
|
|
maxHeight: "62%",
|
|
width: "auto",
|
|
height: "auto",
|
|
objectFit: "contain",
|
|
display: "block",
|
|
filter: "drop-shadow(0 12px 24px rgba(40,30,15,0.18))",
|
|
}}
|
|
/>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div style={{ ...base, background: stripe }}>
|
|
<span style={{ fontSize: 10.5, letterSpacing: "0.12em", color: "#a99c82", textTransform: "uppercase" }}>
|
|
{placeholder}
|
|
</span>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|