mirror of
https://github.com/R0m1k3/PleinR.git
synced 2026-10-23 15:18:04 +02:00
Page Association : mission développée et bloc « ce que l'association apporte »
Le bandeau Mission tenait en une phrase et ne disait pas ce que l'adhésion apporte concrètement. - Mission réécrite en trois paragraphes : le réseau et les rencontres, la mise en avant de chaque adhérent auprès des habitants et des professionnels, et l'objectif double clients de proximité / courants d'affaires locaux. - Nouveau bloc de quatre cartes sous le bandeau : se rencontrer, gagner en visibilité (site et réseaux sociaux), attirer des clients en B to C, développer des affaires en B to B. - Les deux contenus sont éditables dans Paramètres : la mission accepte des paragraphes séparés par une ligne vide, les apports suivent la convention « Titre|Description » déjà utilisée pour le directoire. - Migration 0009 : le texte de mission n'est remplacé que s'il est resté celui d'origine, une version réécrite à la main n'est jamais écrasée. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QXNXRC4j5VLfKvpyyisrnb
This commit is contained in:
7 files changed
+1525
-13
No files matched your search
@@ -0,0 +1,15 @@
|
|||||||
|
-- Texte de mission enrichi sur la page Association.
|
||||||
|
--
|
||||||
|
-- La clause sur `value` est volontaire : le texte n'est remplacé que s'il est
|
||||||
|
-- resté celui d'origine. Une mission déjà réécrite depuis Paramètres n'est
|
||||||
|
-- jamais écrasée. Les « apports » n'ont pas de ligne en base tant qu'ils n'ont
|
||||||
|
-- pas été édités : leur valeur par défaut s'applique d'elle-même.
|
||||||
|
UPDATE "site_settings"
|
||||||
|
SET "value" = 'Plein R fédère les commerçants, artisans et entreprises du Bassin de Pompey autour d''une conviction simple : on va plus loin ensemble. L''association crée les occasions de se rencontrer, de se connaître et de travailler les uns avec les autres.
|
||||||
|
|
||||||
|
Nous mettons chaque adhérent en avant auprès des habitants comme des autres professionnels du territoire : une fiche dans l''annuaire, des bons plans relayés sur le site et sur nos réseaux sociaux, une place dans nos rencontres et nos publications.
|
||||||
|
|
||||||
|
L''objectif est double : amener des clients aux commerces de proximité, et faire naître des courants d''affaires entre les entreprises du bassin.',
|
||||||
|
"updated_at" = now()
|
||||||
|
WHERE "key" = 'association_mission'
|
||||||
|
AND "value" = 'Créer du lien entre adhérents, encourager les échanges de proximité et porter une dynamique collective au service du Bassin de Pompey.';
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -64,6 +64,13 @@
|
|||||||
"when": 1784933339220,
|
"when": 1784933339220,
|
||||||
"tag": "0008_neat_makkari",
|
"tag": "0008_neat_makkari",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 9,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1784968500537,
|
||||||
|
"tag": "0009_texte_mission",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,13 @@ import { meetingRegistrations, meetings, pastMeetingPhotos, pastMeetings } from
|
|||||||
import { PastMeetingGallery } from "@/components/PastMeetingGallery";
|
import { PastMeetingGallery } from "@/components/PastMeetingGallery";
|
||||||
import { SiteFooter } from "@/components/SiteFooter";
|
import { SiteFooter } from "@/components/SiteFooter";
|
||||||
import { SiteHeader } from "@/components/SiteHeader";
|
import { SiteHeader } from "@/components/SiteHeader";
|
||||||
import { getSiteSettings, parseBoardMembers, splitLines } from "@/lib/site-settings";
|
import {
|
||||||
|
getSiteSettings,
|
||||||
|
parseBoardMembers,
|
||||||
|
parseParagraphs,
|
||||||
|
parsePillars,
|
||||||
|
splitLines,
|
||||||
|
} from "@/lib/site-settings";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -96,6 +102,8 @@ export default async function AssociationPage() {
|
|||||||
["Secrétariat", settings.association_secretary],
|
["Secrétariat", settings.association_secretary],
|
||||||
].filter(([, name]) => name);
|
].filter(([, name]) => name);
|
||||||
const board = parseBoardMembers(settings.association_board_members);
|
const board = parseBoardMembers(settings.association_board_members);
|
||||||
|
const missionParagraphs = parseParagraphs(settings.association_mission);
|
||||||
|
const pillars = parsePillars(settings.association_pillars);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ background: "#F6F2E8", minHeight: "100vh", fontFamily: "'Public Sans',sans-serif", color: "#33291D" }}>
|
<div style={{ background: "#F6F2E8", minHeight: "100vh", fontFamily: "'Public Sans',sans-serif", color: "#33291D" }}>
|
||||||
@@ -117,18 +125,53 @@ export default async function AssociationPage() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section style={{ background: "#13324F", color: "#fff" }}>
|
<section style={{ background: "#13324F", color: "#fff" }}>
|
||||||
<div className="container grid grid-2" style={{ paddingTop: 44, paddingBottom: 44, alignItems: "start" }}>
|
<div className="container" style={{ paddingTop: 44, paddingBottom: 48 }}>
|
||||||
<div>
|
<div className="grid grid-2" style={{ alignItems: "start" }}>
|
||||||
<div style={{ color: "#E0A63C", fontSize: 12, letterSpacing: "0.14em", textTransform: "uppercase", fontWeight: 800, marginBottom: 10 }}>
|
<div>
|
||||||
Mission
|
<div style={{ color: "#E0A63C", fontSize: 12, letterSpacing: "0.14em", textTransform: "uppercase", fontWeight: 800, marginBottom: 10 }}>
|
||||||
|
Mission
|
||||||
|
</div>
|
||||||
|
<h2 className="font-display" style={{ margin: 0, fontSize: "clamp(28px, 4vw, 44px)" }}>
|
||||||
|
Réseau, rencontres, réussite locale.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{missionParagraphs.map((paragraph, index) => (
|
||||||
|
<p
|
||||||
|
key={index}
|
||||||
|
style={{
|
||||||
|
margin: index === 0 ? 0 : "14px 0 0",
|
||||||
|
color: "#cfe0ee",
|
||||||
|
fontSize: 16,
|
||||||
|
lineHeight: 1.75,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{paragraph}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<h2 className="font-display" style={{ margin: 0, fontSize: "clamp(28px, 4vw, 44px)" }}>
|
|
||||||
Réseau, rencontres, réussite locale.
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<p style={{ margin: 0, color: "#cfe0ee", fontSize: 16, lineHeight: 1.75 }}>
|
|
||||||
{settings.association_mission}
|
{pillars.length > 0 && (
|
||||||
</p>
|
<>
|
||||||
|
<div style={{ color: "#E0A63C", fontSize: 12, letterSpacing: "0.14em", textTransform: "uppercase", fontWeight: 800, margin: "44px 0 16px" }}>
|
||||||
|
Ce que l'association vous apporte
|
||||||
|
</div>
|
||||||
|
<div className="pillars-grid">
|
||||||
|
{pillars.map((pillar, index) => (
|
||||||
|
<article key={pillar.title} className="pillar-card">
|
||||||
|
<span className="font-display pillar-card__index">
|
||||||
|
{String(index + 1).padStart(2, "0")}
|
||||||
|
</span>
|
||||||
|
<h3 className="font-display pillar-card__title">{pillar.title}</h3>
|
||||||
|
{pillar.description && (
|
||||||
|
<p className="pillar-card__text">{pillar.description}</p>
|
||||||
|
)}
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,16 @@ export default async function ParametresPage() {
|
|||||||
<Field label="Adresse" name="association_address" value={settings.association_address} />
|
<Field label="Adresse" name="association_address" value={settings.association_address} />
|
||||||
</div>
|
</div>
|
||||||
<Area label="Texte d'introduction Association" name="association_intro" value={settings.association_intro} />
|
<Area label="Texte d'introduction Association" name="association_intro" value={settings.association_intro} />
|
||||||
<Area label="Mission" name="association_mission" value={settings.association_mission} />
|
<Area
|
||||||
|
label="Mission (une ligne vide sépare les paragraphes)"
|
||||||
|
name="association_mission"
|
||||||
|
value={settings.association_mission}
|
||||||
|
/>
|
||||||
|
<Area
|
||||||
|
label="Ce que l'association apporte (Titre|Description, une ligne par point)"
|
||||||
|
name="association_pillars"
|
||||||
|
value={settings.association_pillars}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: 14, color: "#9a6638", fontSize: 13, lineHeight: 1.6 }}>
|
<div style={{ marginTop: 14, color: "#9a6638", fontSize: 13, lineHeight: 1.6 }}>
|
||||||
Les pages Facebook et LinkedIn s'affichent sur la page d'accueil et dans le pied
|
Les pages Facebook et LinkedIn s'affichent sur la page d'accueil et dans le pied
|
||||||
|
|||||||
@@ -449,6 +449,49 @@ img {
|
|||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- « Ce que l'association vous apporte » (page Association) ---- */
|
||||||
|
.pillars-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
.pillar-card {
|
||||||
|
padding: 18px 18px 20px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
.pillar-card__index {
|
||||||
|
color: var(--gold);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
.pillar-card__title {
|
||||||
|
margin: 8px 0 7px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
.pillar-card__text {
|
||||||
|
margin: 0;
|
||||||
|
color: #a9c4da;
|
||||||
|
font-size: 13.5px;
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.pillars-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 620px) {
|
||||||
|
.pillars-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- Compteurs du tableau de bord ---- */
|
/* ---- Compteurs du tableau de bord ---- */
|
||||||
.stat-card {
|
.stat-card {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ export const SITE_SETTING_DEFAULTS = {
|
|||||||
association_intro:
|
association_intro:
|
||||||
"Plein R rassemble les acteurs économiques locaux autour du réseau, des rencontres et de la mise en valeur du territoire.",
|
"Plein R rassemble les acteurs économiques locaux autour du réseau, des rencontres et de la mise en valeur du territoire.",
|
||||||
association_mission:
|
association_mission:
|
||||||
"Créer du lien entre adhérents, encourager les échanges de proximité et porter une dynamique collective au service du Bassin de Pompey.",
|
"Plein R fédère les commerçants, artisans et entreprises du Bassin de Pompey autour d'une conviction simple : on va plus loin ensemble. L'association crée les occasions de se rencontrer, de se connaître et de travailler les uns avec les autres.\n\n" +
|
||||||
|
"Nous mettons chaque adhérent en avant auprès des habitants comme des autres professionnels du territoire : une fiche dans l'annuaire, des bons plans relayés sur le site et sur nos réseaux sociaux, une place dans nos rencontres et nos publications.\n\n" +
|
||||||
|
"L'objectif est double : amener des clients aux commerces de proximité, et faire naître des courants d'affaires entre les entreprises du bassin.",
|
||||||
|
association_pillars:
|
||||||
|
"Se rencontrer|Des rendez-vous réguliers entre adhérents pour échanger, partager les bonnes pratiques et rompre l'isolement du quotidien.\n" +
|
||||||
|
"Gagner en visibilité|Une fiche dans l'annuaire, vos promotions relayées sur le site et sur les pages Facebook et LinkedIn de l'association.\n" +
|
||||||
|
"Attirer des clients (B to C)|Vos offres mises sous les yeux des habitants du bassin, pour faire vivre le commerce de proximité toute l'année.\n" +
|
||||||
|
"Développer des affaires (B to B)|Un réseau de professionnels qui se connaissent et se recommandent : prestataires, fournisseurs et partenaires à deux pas.",
|
||||||
association_address: "",
|
association_address: "",
|
||||||
association_email: "",
|
association_email: "",
|
||||||
association_phone: "",
|
association_phone: "",
|
||||||
@@ -91,6 +98,24 @@ export function splitLines(value: string) {
|
|||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Paragraphes d'un champ libre : une ligne vide sépare deux paragraphes. */
|
||||||
|
export function parseParagraphs(value: string) {
|
||||||
|
return value
|
||||||
|
.split(/\r?\n\s*\r?\n/)
|
||||||
|
.map((block) => block.replace(/\s*\r?\n\s*/g, " ").trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** « Titre|Description », une ligne par apport de l'association. */
|
||||||
|
export function parsePillars(value: string) {
|
||||||
|
return splitLines(value)
|
||||||
|
.map((line) => {
|
||||||
|
const [title, description] = line.split("|").map((part) => part.trim());
|
||||||
|
return { title, description: description ?? "" };
|
||||||
|
})
|
||||||
|
.filter((pillar) => pillar.title);
|
||||||
|
}
|
||||||
|
|
||||||
export function parseBoardMembers(value: string) {
|
export function parseBoardMembers(value: string) {
|
||||||
return splitLines(value).map((line) => {
|
return splitLines(value).map((line) => {
|
||||||
const [name, role] = line.split("|").map((part) => part.trim());
|
const [name, role] = line.split("|").map((part) => part.trim());
|
||||||
|
|||||||
Reference in new issue
Block a user