carte du jour
This commit is contained in:
@@ -5,9 +5,9 @@ const { name, monthly_allowance, type = "FLUX" } = frontmatter;
|
|||||||
|
|
||||||
// --- LOGIQUE DE COULEUR SUBTILE ---
|
// --- LOGIQUE DE COULEUR SUBTILE ---
|
||||||
const bankConfigs = {
|
const bankConfigs = {
|
||||||
UpDéjeuner: { color: "#f97316", icon: "🍴" }, // Orange Up
|
UpDéjeuner: { color: "#f97316", icon: "🍴" },
|
||||||
"La Banque Postale": { color: "#137bb1", icon: "🏦" }, // Bleu BP
|
"La Banque Postale": { color: "#137bb1", icon: "🏦" },
|
||||||
Sumeria: { color: "#116853", icon: "⚡" }, // Vert d'eau
|
Sumeria: { color: "#116853", icon: "⚡" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = bankConfigs[name as keyof typeof bankConfigs] || {
|
const config = bankConfigs[name as keyof typeof bankConfigs] || {
|
||||||
@@ -16,25 +16,36 @@ const config = bankConfigs[name as keyof typeof bankConfigs] || {
|
|||||||
};
|
};
|
||||||
const color = config.color;
|
const color = config.color;
|
||||||
|
|
||||||
const now = new Date();
|
// --- LOGIQUE DE RÉCUPÉRATION TEMPORELLE DYNAMIQUE ---
|
||||||
// Importe le type si nécessaire (Astro le génère pour toi)
|
|
||||||
// import type { CollectionEntry } from 'astro:content';
|
|
||||||
|
|
||||||
const currentMonthEntries = allHumans.filter((h: any) => {
|
// 1. On cherche toutes les entrées qui contiennent réellement des flux
|
||||||
// Remplace 'any' par 'CollectionEntry<"humans">' si tu veux être strict
|
const entriesWithFlux = allHumans.filter((h: any) =>
|
||||||
const d = new Date(h.data.date);
|
h.data.manifestations?.some((m: any) => m.cercle === "FLX"),
|
||||||
return (
|
|
||||||
d.getMonth() === now.getMonth() && d.getFullYear() === now.getFullYear()
|
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
// Somme des flux
|
// 2. On trouve la date de la toute dernière transaction enregistrée (pour ne pas être bloqué par un changement de mois vide)
|
||||||
// BankCard.astro (Partie Logique)
|
const lastFluxEntry = entriesWithFlux.sort(
|
||||||
const totalFlux = currentMonthEntries.reduce((acc: number, entry: any) => {
|
(a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(),
|
||||||
|
)[0];
|
||||||
|
|
||||||
|
// 3. On définit la période de référence (Mois/Année)
|
||||||
|
const refDate = lastFluxEntry ? new Date(lastFluxEntry.data.date) : new Date();
|
||||||
|
const refMonth = refDate.getMonth();
|
||||||
|
const refYear = refDate.getFullYear();
|
||||||
|
|
||||||
|
// 4. Somme des flux pour cette période et pour cette banque spécifique
|
||||||
|
const totalFlux = allHumans.reduce((acc: number, entry: any) => {
|
||||||
|
const d = new Date(entry.data.date);
|
||||||
|
const isSamePeriod =
|
||||||
|
d.getMonth() === refMonth && d.getFullYear() === refYear;
|
||||||
|
|
||||||
|
if (!isSamePeriod) return acc;
|
||||||
|
|
||||||
const flxManifests =
|
const flxManifests =
|
||||||
entry.data.manifestations?.filter((m: any) => {
|
entry.data.manifestations?.filter((m: any) => {
|
||||||
// ON FILTRE : cercle FLX ET la source doit correspondre au nom de la carte
|
const sourceName = m.source?.trim().toLowerCase();
|
||||||
return m.cercle === "FLX" && m.source === name;
|
const cardName = name?.trim().toLowerCase();
|
||||||
|
return m.cercle === "FLX" && sourceName === cardName;
|
||||||
}) || [];
|
}) || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -46,6 +57,11 @@ const totalFlux = currentMonthEntries.reduce((acc: number, entry: any) => {
|
|||||||
);
|
);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
|
// Log de contrôle dans ton terminal Lenovo
|
||||||
|
console.log(
|
||||||
|
`[${name}] Bilan basé sur : ${refMonth + 1}/${refYear} | Total : ${totalFlux}`,
|
||||||
|
);
|
||||||
|
|
||||||
const percentage = Math.max(
|
const percentage = Math.max(
|
||||||
0,
|
0,
|
||||||
Math.min(100, Math.round((totalFlux / monthly_allowance) * 100)),
|
Math.min(100, Math.round((totalFlux / monthly_allowance) * 100)),
|
||||||
@@ -128,9 +144,8 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
.bank-card {
|
.bank-card {
|
||||||
background: linear-gradient(135deg, #fff 0%, #f8fafc 100%);
|
background: linear-gradient(135deg, #fff 0%, #f8fafc 100%);
|
||||||
color: #1a202c;
|
color: #1a202c;
|
||||||
border-color: var(
|
border-color: var(--accent) !important;
|
||||||
--accent
|
border-width: 2px;
|
||||||
) !important; /* Bordure subtile de la couleur de la banque */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-inner {
|
.card-inner {
|
||||||
@@ -145,7 +160,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #e2e8f0; /* Souligné subtil */
|
border-bottom: 1px solid #e2e8f0;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
@@ -154,7 +169,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-family: "Philosopher", serif;
|
font-family: "Philosopher", serif;
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
color: var(--accent); /* Nom coloré subtilement */
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.visual-container {
|
.visual-container {
|
||||||
@@ -169,10 +184,11 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.circular-chart {
|
.circular-chart {
|
||||||
max-width: 100px;
|
max-width: 80px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.circle-bg {
|
.circle-bg {
|
||||||
@@ -182,7 +198,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
}
|
}
|
||||||
.circle {
|
.circle {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: var(--accent); /* La jauge prend la couleur de la banque */
|
stroke: var(--accent);
|
||||||
stroke-width: 2.8;
|
stroke-width: 2.8;
|
||||||
stroke-linecap: round;
|
stroke-linecap: round;
|
||||||
transition: stroke-dasharray 1s ease;
|
transition: stroke-dasharray 1s ease;
|
||||||
@@ -196,15 +212,13 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-badge {
|
.status-badge {
|
||||||
background: var(
|
background: var(--state-color);
|
||||||
--state-color
|
|
||||||
); /* Garde la couleur d'état (vert/orange/rouge) pour la sécurité */
|
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
padding: 1px 6px;
|
padding: 2px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-type-line {
|
.card-type-line {
|
||||||
@@ -223,6 +237,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
min-height: 1.5rem;
|
min-height: 1.5rem;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-row {
|
.stat-row {
|
||||||
@@ -238,12 +253,12 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
}
|
}
|
||||||
.segment {
|
.segment {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 4px;
|
height: 6px;
|
||||||
background: #e2e8f0;
|
background: #e2e8f0;
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
}
|
}
|
||||||
.segment.active {
|
.segment.active {
|
||||||
background: var(--accent); /* Segments de la couleur de la banque */
|
background: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-footer {
|
.card-footer {
|
||||||
@@ -253,5 +268,6 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" };
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 0.6rem;
|
font-size: 0.6rem;
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
139
src/components/ShoppingCard.astro
Normal file
139
src/components/ShoppingCard.astro
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
---
|
||||||
|
// components/ShoppingCard.astro
|
||||||
|
const { item, remaining, total, unit, category } = Astro.props;
|
||||||
|
|
||||||
|
// Calcul du pourcentage pour la jauge
|
||||||
|
const percentage = Math.max(0, Math.min(100, (remaining / total) * 100));
|
||||||
|
const isLow = remaining > 0 && percentage < 25;
|
||||||
|
const isEmpty = remaining <= 0;
|
||||||
|
---
|
||||||
|
|
||||||
|
<article
|
||||||
|
class={`tcg-card shopping-card ${isEmpty ? "empty" : ""} ${isLow ? "low" : ""}`}
|
||||||
|
>
|
||||||
|
<div class="card-inner">
|
||||||
|
<header class="card-header">
|
||||||
|
<span class="card-name">{item}</span>
|
||||||
|
<span class="card-icon">{isEmpty ? "❌" : "📦"}</span>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="visual-container">
|
||||||
|
<div class="stock-display">
|
||||||
|
<span class="remaining-num">{remaining}</span>
|
||||||
|
<span class="unit-text">{unit}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="progress-track">
|
||||||
|
<div class="progress-fill" style={`width: ${percentage}%`}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="category-badge">{category || "Logistique"}</div>
|
||||||
|
<p class="stock-total">Capacité max: {total} {unit}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.shopping-card {
|
||||||
|
--primary: #10b981;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shopping-card.low {
|
||||||
|
--primary: #f59e0b;
|
||||||
|
}
|
||||||
|
.shopping-card.empty {
|
||||||
|
--primary: #ef4444;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-inner {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-family: "Philosopher", serif;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visual-container {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px 10px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px inset rgba(0, 0, 0, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-display {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remaining-num {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 900;
|
||||||
|
color: #1e293b;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-text {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: #94a3b8;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
background: #e2e8f0;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-top: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background: var(--primary);
|
||||||
|
box-shadow: 0 0 8px var(--primary);
|
||||||
|
transition: width 0.8s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
margin-top: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-badge {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--primary);
|
||||||
|
background: rgba(0, 0, 0, 0.03);
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
text-transform: uppercase;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-total {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
color: #cbd5e1;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,31 +4,62 @@ import Layout from "../layouts/Layout.astro";
|
|||||||
import Card from "../components/Card.astro";
|
import Card from "../components/Card.astro";
|
||||||
import EventCard from "../components/EventCard.astro";
|
import EventCard from "../components/EventCard.astro";
|
||||||
import BankCard from "../components/BankCard.astro";
|
import BankCard from "../components/BankCard.astro";
|
||||||
|
import ShoppingCard from "../components/ShoppingCard.astro";
|
||||||
|
|
||||||
const allHumans = await getCollection("humans");
|
const allHumans = await getCollection("humans");
|
||||||
|
const allEvents = await getCollection("events");
|
||||||
|
const allBanks = await getCollection("banks");
|
||||||
|
const allStocks = await getCollection("stocks");
|
||||||
|
|
||||||
const myHumans = allHumans.filter((entry: any) =>
|
const myHumans = allHumans.filter((entry: any) =>
|
||||||
entry.id.startsWith("latchimynicolas/"),
|
entry.id.startsWith("latchimynicolas/"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const allEvents = await getCollection("events");
|
const inventoryWithStatus = allStocks.map((stock) => {
|
||||||
const allBanks = await getCollection("banks");
|
const itemName = stock.data.item || "";
|
||||||
|
const consumed = allHumans.reduce((acc, human) => {
|
||||||
|
const manifestations = human.data.manifestations || [];
|
||||||
|
const consosForItem = manifestations.filter(
|
||||||
|
(m: any) =>
|
||||||
|
m.type === "conso" &&
|
||||||
|
m.item?.trim().toLowerCase() === itemName.trim().toLowerCase(),
|
||||||
|
);
|
||||||
|
const totalConsumedByHuman = consosForItem.reduce(
|
||||||
|
(sum: number, m: any) => sum + (Number(m.amount) || 1),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
return acc + totalConsumedByHuman;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...stock,
|
||||||
|
remaining: (stock.data.quantity || 0) - consumed,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupedStocks = inventoryWithStatus.reduce((acc: any, item: any) => {
|
||||||
|
const pathParts = item.id.split("/");
|
||||||
|
const datePath =
|
||||||
|
pathParts.length >= 3 ? pathParts.slice(0, 3).join("/") : "Divers";
|
||||||
|
if (!acc[datePath]) acc[datePath] = [];
|
||||||
|
acc[datePath].push(item);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const sortedStockDates = Object.keys(groupedStocks).sort((a, b) =>
|
||||||
|
b.localeCompare(a),
|
||||||
|
);
|
||||||
|
|
||||||
// 1. Tri
|
|
||||||
const sortedEntries = allHumans.sort(
|
const sortedEntries = allHumans.sort(
|
||||||
(a: any, b: any) =>
|
(a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(),
|
||||||
new Date(b.data.date).getTime() - new Date(a.data.date).getTime(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const sortedEvents = allEvents.sort(
|
const sortedEvents = allEvents.sort(
|
||||||
(a: any, b: any) =>
|
(a, b) => new Date(a.data.date).getTime() - new Date(b.data.date).getTime(),
|
||||||
new Date(a.data.date).getTime() - new Date(b.data.date).getTime(),
|
|
||||||
);
|
);
|
||||||
|
const sortedBanks = allBanks.sort((a, b) =>
|
||||||
const sortedBanks = allBanks.sort((a: any, b: any) =>
|
|
||||||
a.data.name.localeCompare(b.data.name),
|
a.data.name.localeCompare(b.data.name),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2. Groupement
|
|
||||||
const groupedHumans = sortedEntries.reduce((acc: any, entry: any) => {
|
const groupedHumans = sortedEntries.reduce((acc: any, entry: any) => {
|
||||||
const userName = entry.data.name;
|
const userName = entry.data.name;
|
||||||
if (!acc[userName]) acc[userName] = [];
|
if (!acc[userName]) acc[userName] = [];
|
||||||
@@ -41,30 +72,26 @@ const groupedHumans = sortedEntries.reduce((acc: any, entry: any) => {
|
|||||||
<header class="collection-header">
|
<header class="collection-header">
|
||||||
<a href="/" class="back-link">← Retour au flux</a>
|
<a href="/" class="back-link">← Retour au flux</a>
|
||||||
<h1>Collection</h1>
|
<h1>Collection</h1>
|
||||||
<p class="back-link">
|
|
||||||
Cliquer sur un titre pour ouvrir/fermer, ou une carte pour les
|
|
||||||
détails.
|
|
||||||
</p>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="collection-container">
|
<main class="collection-container">
|
||||||
{/* SECTION HUMAINS */}
|
{/* HUMAINS */}
|
||||||
{
|
{
|
||||||
Object.entries(groupedHumans).map(([userName, cards]) => (
|
Object.entries(groupedHumans).map(([userName, cards]) => (
|
||||||
<details class="user-collection">
|
<details class="user-collection" open>
|
||||||
<summary class="user-title">
|
<summary class="user-title">
|
||||||
{userName}
|
{userName} <span>({(cards as any[]).length})</span>
|
||||||
<span>({(cards as any[]).length} souffles)</span>
|
|
||||||
</summary>
|
</summary>
|
||||||
|
<div class="scroll-container">
|
||||||
<div class="user-flex-row">
|
|
||||||
{(cards as any[]).map((entry) => (
|
{(cards as any[]).map((entry) => (
|
||||||
|
<div class="card-item">
|
||||||
<a
|
<a
|
||||||
href={`/${entry.id.replace(/\.md$/, "")}`}
|
href={`/${entry.id.replace(/\.md$/, "")}`}
|
||||||
class="card-link"
|
class="card-wrapper"
|
||||||
>
|
>
|
||||||
<div class="card-scaler">
|
<div class="card-scaler tcg-fixed-size">
|
||||||
<Card frontmatter={entry.data} />
|
<Card frontmatter={entry.data} />
|
||||||
|
</div>
|
||||||
<div class="entry-meta">
|
<div class="entry-meta">
|
||||||
<p>
|
<p>
|
||||||
{new Date(
|
{new Date(
|
||||||
@@ -72,55 +99,75 @@ const groupedHumans = sortedEntries.reduce((acc: any, entry: any) => {
|
|||||||
).toLocaleDateString("fr-FR")}
|
).toLocaleDateString("fr-FR")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<hr class="separator" />
|
|
||||||
</details>
|
</details>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
{/* SECTION ÉVÉNEMENTS */}
|
{/* ÉVÉNEMENTS */}
|
||||||
|
<details class="user-collection" open>
|
||||||
|
<summary class="user-title">Événements</summary>
|
||||||
|
<div class="scroll-container">
|
||||||
{
|
{
|
||||||
sortedEvents.length > 0 && (
|
sortedEvents.map((event) => (
|
||||||
<details class="user-collection">
|
<div class="card-item">
|
||||||
<summary class="user-title">
|
|
||||||
Événements <span>({sortedEvents.length} cartes)</span>
|
|
||||||
</summary>
|
|
||||||
<div class="user-flex-row">
|
|
||||||
{sortedEvents.map((event) => (
|
|
||||||
<a
|
<a
|
||||||
href={`/${event.id.replace(/\.md$/, "")}`}
|
href={`/${event.id.replace(/\.md$/, "")}`}
|
||||||
class="card-link"
|
class="card-wrapper"
|
||||||
>
|
>
|
||||||
<div class="card-scaler">
|
<div class="card-scaler tcg-fixed-size">
|
||||||
<EventCard frontmatter={event.data} />
|
<EventCard frontmatter={event.data} />
|
||||||
<div class="entry-meta">
|
|
||||||
<p>
|
|
||||||
Détecté le :{" "}
|
|
||||||
{event.data.target_date}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="entry-meta">
|
||||||
|
<p>{event.data.target_date}</p>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
{/* LOGISTIQUE */}
|
||||||
|
<details class="user-collection" open>
|
||||||
|
<summary class="user-title">Logistique du Souffle</summary>
|
||||||
|
{
|
||||||
|
sortedStockDates.map((date) => (
|
||||||
|
<div class="stock-day">
|
||||||
|
<h4 class="stock-date-title">
|
||||||
|
{date.split("/").reverse().join(" / ")}
|
||||||
|
</h4>
|
||||||
|
<div class="scroll-container">
|
||||||
|
{groupedStocks[date].map((stock: any) => (
|
||||||
|
<div class="card-item">
|
||||||
|
<div class="fluid-container">
|
||||||
|
<ShoppingCard
|
||||||
|
item={stock.data.item}
|
||||||
|
remaining={stock.remaining}
|
||||||
|
total={stock.data.quantity}
|
||||||
|
unit={stock.data.unit}
|
||||||
|
category={stock.data.category}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<hr class="separator" />
|
</div>
|
||||||
</details>
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
</details>
|
||||||
|
|
||||||
{/* SECTION TRÉSORERIES */}
|
{/* TRÉSORERIES */}
|
||||||
<details class="user-collection">
|
<details class="user-collection" open>
|
||||||
<summary class="user-title">
|
<summary class="user-title">Trésoreries</summary>
|
||||||
Trésoreries <span>(Sources de Flux)</span>
|
<div class="scroll-container">
|
||||||
</summary>
|
|
||||||
<div class="user-flex-row">
|
|
||||||
{
|
{
|
||||||
sortedBanks.map((bank) => (
|
sortedBanks.map((bank) => (
|
||||||
<div class="card-link">
|
<div class="card-item">
|
||||||
<div class="card-scaler">
|
<div class="fluid-container">
|
||||||
{bank.data.sub_category === "finances" ? (
|
{bank.data.sub_category === "finances" ? (
|
||||||
<BankCard
|
<BankCard
|
||||||
frontmatter={bank.data}
|
frontmatter={bank.data}
|
||||||
@@ -136,141 +183,109 @@ const groupedHumans = sortedEntries.reduce((acc: any, entry: any) => {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<hr class="separator" />
|
|
||||||
</details>
|
</details>
|
||||||
</main>
|
</main>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.collection-header {
|
|
||||||
padding: 40px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-link {
|
|
||||||
color: #64748b;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-container {
|
.collection-container {
|
||||||
max-width: 1400px;
|
max-width: 1400px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 20px 40px;
|
padding: 20px;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accordéon Style */
|
/* NETTOYAGE GLOBAL DES COMPOSANTS */
|
||||||
.user-collection {
|
:global(.tcg-card),
|
||||||
margin-bottom: 20px;
|
:global(.shopping-card),
|
||||||
display: block;
|
:global(.bank-card),
|
||||||
|
:global(.event-card) {
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
height: auto !important; /* ON AUTORISE LA CARTE À GRANDIR */
|
||||||
|
min-height: 440px; /* Mais on garde une base élégante */
|
||||||
}
|
}
|
||||||
|
|
||||||
summary {
|
/* CONTAINER DE SCROLL HORIZONTAL */
|
||||||
|
.scroll-container {
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
gap: 25px;
|
||||||
|
padding: 20px 0;
|
||||||
|
scroll-snap-type: x mandatory;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
align-items: flex-start; /* Aligne le haut des cartes */
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
.scroll-container::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LARGEUR STRICTE DU SLOT DE CARTE */
|
||||||
|
.card-item {
|
||||||
|
flex: 0 0 300px;
|
||||||
|
width: 300px;
|
||||||
|
scroll-snap-align: start;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-title {
|
/* ON ENLÈVE LE HEIGHT FIXE ET LE OVERFLOW HIDDEN ICI */
|
||||||
font-family: "Philosopher", serif;
|
.card-scaler,
|
||||||
font-size: 1.5rem;
|
.fluid-container {
|
||||||
color: #1e293b;
|
width: 100%;
|
||||||
margin-bottom: 25px;
|
height: auto;
|
||||||
border-left: 5px solid #333;
|
min-height: 440px;
|
||||||
padding-left: 15px;
|
|
||||||
cursor: pointer;
|
|
||||||
list-style: none; /* Cache la flèche par défaut */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-title::-webkit-details-marker {
|
.card-wrapper {
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-title::before {
|
|
||||||
content: "▸";
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #94a3b8;
|
|
||||||
transition: transform 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
details[open] .user-title::before {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-title span {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: #94a3b8;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-flex-row {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 45px;
|
|
||||||
justify-content: flex-start;
|
|
||||||
padding: 20px 0;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entry-meta {
|
|
||||||
font-family: "Inter", sans-serif;
|
|
||||||
position: relative;
|
|
||||||
top: 5px;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
color: #94a3b8;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-align: center;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-link {
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: transform 0.3s ease;
|
|
||||||
width: 230px;
|
|
||||||
height: 375px;
|
|
||||||
overflow: visible;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-link:hover {
|
.entry-meta p {
|
||||||
transform: translateY(-5px);
|
font-size: 0.75rem;
|
||||||
}
|
color: #94a3b8;
|
||||||
|
text-align: center;
|
||||||
.card-scaler {
|
|
||||||
transform: scale(0.8);
|
|
||||||
transform-origin: top left;
|
|
||||||
width: 300px;
|
|
||||||
height: 440px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separator {
|
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
border: 0;
|
font-weight: bold;
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-title {
|
||||||
|
font-family: "Philosopher", serif;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
padding: 10px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 2px solid #f1f5f9;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- MOBILE (Samsung) --- */
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.user-flex-row {
|
.scroll-container {
|
||||||
gap: 10px;
|
gap: 15px;
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-link {
|
.card-item {
|
||||||
width: calc(45%);
|
flex: 0 0 280px;
|
||||||
height: 190px;
|
width: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-scaler {
|
.card-scaler,
|
||||||
transform: scale(0.4) !important;
|
.fluid-container {
|
||||||
width: 300px;
|
min-height: 410px;
|
||||||
height: 440px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry-meta {
|
:global(.tcg-card),
|
||||||
font-size: 0.5rem;
|
:global(.shopping-card),
|
||||||
margin-top: -5px;
|
:global(.bank-card),
|
||||||
|
:global(.event-card) {
|
||||||
|
min-height: 410px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ const allEvents = await getCollection("events", ({ data }) => {
|
|||||||
|
|
||||||
// Récupération de la banque
|
// Récupération de la banque
|
||||||
const allBanks = await getCollection("banks");
|
const allBanks = await getCollection("banks");
|
||||||
const upCard = allBanks.find((b) => b.id === "up" || b.id === "up.md");
|
|
||||||
|
|
||||||
// 2. Tris temporels
|
// 2. Tris temporels
|
||||||
const sortedAll = allHumans.sort(
|
const sortedAll = allHumans.sort(
|
||||||
@@ -144,17 +143,17 @@ const latestPerUser = Array.from(
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
upCard && (
|
allBanks.map((bank) => (
|
||||||
<div class="card-focus">
|
<div class="card-focus">
|
||||||
<BankCard
|
<BankCard
|
||||||
frontmatter={upCard.data}
|
frontmatter={bank.data}
|
||||||
allHumans={allHumans}
|
allHumans={allHumans}
|
||||||
/>
|
/>
|
||||||
<div class="entry-meta">
|
<div class="entry-meta">
|
||||||
<p>État du cercle FLX</p>
|
<p>{bank.data.title || "État du cercle"}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -192,8 +191,6 @@ const latestPerUser = Array.from(
|
|||||||
padding: 60px 20px;
|
padding: 60px 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
-ms-overflow-style: none;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-flex::-webkit-scrollbar {
|
.hero-flex::-webkit-scrollbar {
|
||||||
@@ -255,7 +252,11 @@ const latestPerUser = Array.from(
|
|||||||
/* 6. Centrage Desktop (Lenovo) */
|
/* 6. Centrage Desktop (Lenovo) */
|
||||||
@media (min-width: 1025px) {
|
@media (min-width: 1025px) {
|
||||||
.hero-flex {
|
.hero-flex {
|
||||||
justify-content: center;
|
justify-content: flex-start;
|
||||||
|
padding-left: calc(
|
||||||
|
50vw - 160px
|
||||||
|
); /* Optionnel : pour centrer la PREMIÈRE carte au milieu de l'écran */
|
||||||
|
padding-right: 50vw;
|
||||||
gap: 40px;
|
gap: 40px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user