Simplification de l'aventure
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
---
|
||||
import GameLayout from '../layouts/GameLayout.astro';
|
||||
import ParchmentCard from '../components/ui/ParchmentCard.astro';
|
||||
---
|
||||
<GameLayout title="Le Sanctuaire des Grains - Sweet Journey">
|
||||
<ParchmentCard>
|
||||
<h1>🏜️ Le Sanctuaire des Grains</h1>
|
||||
<p>
|
||||
Entrez dans mon lieu de méditation. D'où je viens, la création n'est pas une affaire de métal et de feu, mais de patience, de concentration et de sable. Chaque grain est une possibilité, chaque ligne de code un chemin tracé dans les dunes de l'esprit. Cette section dévoile les arts que j'emploie pour donner forme à ce monde.
|
||||
</p>
|
||||
|
||||
<h2>Le Façonnage du Sable : Les Arts Techniques</h2>
|
||||
<p>
|
||||
Au lieu d'une forge, mon art s'exprime par le façonnage. Les idées brutes sont comme du sable sauvage ; il faut le canaliser, le modeler avec discipline pour qu'il devienne une histoire, une expérience. Pour invoquer un monde 3D dans le navigateur, le choix des arts est aussi crucial que le choix du sable.
|
||||
</p>
|
||||
<h3>Pourquoi Three.js ?</h3>
|
||||
<p><strong>Three.js</strong> est mon art martial numérique. C'est un ensemble de katas (fonctions) en JavaScript qui me permet de maîtriser le flux de la 3D dans le navigateur. Chaque mouvement est précis : je peux dicter la course de la lumière, orchestrer la danse des objets et appliquer les textures comme on applique un pigment. C'est le ki qui donne vie à la matière inerte.</p>
|
||||
<h3>Pourquoi Blender ?</h3>
|
||||
<p>Si Three.js est l'art du mouvement, <strong>Blender</strong> est l'art de la méditation. C'est dans ce monde intérieur que je voyage pour façonner les personnages, les paysages et les rêves de mon peuple. C'est un outil open source qui me permet de donner une forme tangible à mes visions, avant de leur insuffler le souffle de vie sur le web.</p>
|
||||
|
||||
<h2>Le Kit du Pèlerin : Outils de Prédilection</h2>
|
||||
<p>Tout pèlerin transporte avec lui des outils essentiels. Les miens ne sont pas faits de bois ou de métal, mais ils sont tout aussi vitaux pour mon voyage.</p>
|
||||
<dl>
|
||||
<dt><strong>Visual Studio Code : Mon Grimoire de Rituels</strong></dt>
|
||||
<dd>C'est ici que je calligraphie les incantations (le code) qui donnent leurs instructions au sable. Chaque fonction est un mantra, chaque variable un grain choisi avec soin pour construire le monde.</dd>
|
||||
|
||||
<dt><strong>Lenovo Yoga 530 (Ubuntu) : Ma Pierre de Méditation</strong></dt>
|
||||
<dd>C'est sur cette surface que je m'installe pour me concentrer. Sa flexibilité me permet de trouver la posture juste, et son cœur (Ubuntu) bat au rythme du partage et de la liberté, des valeurs chères à tout pèlerin.</dd>
|
||||
|
||||
<dt><strong>Wacom One, GIMP & Krita : Ma Toile de Sable et mes Pigments de Songe</strong></dt>
|
||||
<dd>La tablette est une étendue de sable fin sur laquelle je dessine les premières formes de mes visions. GIMP et Krita m'offre les pigments extraits des rêves pour leur donner couleur et vie.</dd>
|
||||
|
||||
<dt><strong>Obsidian & Carnet à dessin : Ma Carte des Étoiles et mon Journal de Piste</strong></dt>
|
||||
<dd>Le carnet recueille les croquis bruts de mon voyage. Obsidian, lui, est ma carte du ciel intérieure ; il me permet de relier chaque idée, chaque souvenir et chaque rêve en une constellation de savoir qui guide ma quête.</dd>
|
||||
|
||||
<dt><strong>Raspberry Pi : Mon Foyer de Pèlerin</strong></dt>
|
||||
<dd>Ce petit autel est le cœur de mon campement numérique. C'est un serveur humble mais résilient, d'où je publie mes récits et partage mes créations avec le monde. Il bat au rythme de plusieurs esprits bienveillants :</dd>
|
||||
<dd>
|
||||
<ul>
|
||||
<li><strong>Docker :</strong> L'art de créer des bocaux à songes. Chaque service est contenu dans son propre terrarium magique, parfait et isolé, pour s'assurer que les rêves ne se mélangent pas.</li>
|
||||
<li><strong>Nginx Proxy Manager :</strong> Le gardien des carrefours, qui guide les visiteurs égarés vers la bonne histoire, le bon outil.</li>
|
||||
<li><strong>Nextcloud & Wallabag :</strong> Ma besace sans fond et mon filet à murmures. L'un stocke mes trouvailles et mes grains de sable précieux, l'autre capture les histoires du vent pour une lecture future.</li>
|
||||
<li><strong>Dolibarr & Superset :</strong> Mon grand livre de marchand et ma lentille d'analyse. Ils m'aident à tenir les comptes de mes échanges de rêves et à scruter la nature profonde de chaque grain de sable (donnée) que je collecte.</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</ParchmentCard>
|
||||
</GameLayout>
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
import GameLayout from '../layouts/GameLayout.astro';
|
||||
import ParchmentCard from '../components/ui/ParchmentCard.astro';
|
||||
---
|
||||
|
||||
<GameLayout title="L'Artisan des Rêves - Nicolas Latchimy">
|
||||
<ParchmentCard>
|
||||
<h1>🐸 L'Artisan derrière le Pèlerin</h1>
|
||||
<p>
|
||||
Je suis G'Mas, un pèlerin fait de sable et de songes. Mais qui est l'artisan qui me rêve ? Qui est celui dont les mains façonnent mon voyage ? Laissez-moi vous parler de lui, car son histoire est la source de la mienne.
|
||||
</p>
|
||||
<p>
|
||||
Il se nomme <strong>Nicolas Latchimy</strong>. Artiste, développeur, un esprit ubiquiste qui, depuis l'âge de trois ans, utilise le dessin pour donner une forme à ses émotions. Son parcours est un long pèlerinage entre deux mondes : celui de l'Art, étudié à Paris et à La Réunion, et celui du Code, appris plus tard pour construire de nouvelles formes de récits.
|
||||
</p>
|
||||
|
||||
<h2>Hatjan Krâpo, le Cousin du grung</h2>
|
||||
<p>
|
||||
Avant que je n'existe, un autre batracien est né de son crayon : <strong>Hatjan Krâpo</strong>. Mon lointain cousin de papier. Si je suis un pèlerin des sables, Hatjan est un symbole du rejet, du dégoût, mais aussi d'une humanité cinglante. À travers lui, Nicolas explore les thèmes qui le hantent : l'exclusion, les discriminations, le harcèlement. C'est un cri silencieux contre les écarts qui fracturent nos sociétés.
|
||||
</p>
|
||||
|
||||
<h2>Mosaic Chantilly, l'Armateur d'Art</h2>
|
||||
<p>
|
||||
Le 14 septembre 2024, un autre chemin s'est ouvert. Sous le nom de <strong>Mosaic Chantilly</strong>, il est devenu un "armateur d'art à corps perdu". Sa mission : déconstruire l'art comme une mosaïque pour en révéler l'essence. C'est une quête de dix ans qui commence, un nouveau voyage dans la matière et la forme.
|
||||
</p>
|
||||
|
||||
<h2>Du Pinceau au Code</h2>
|
||||
<p>
|
||||
Après des années à questionner le monde à travers l'art, il s'est tourné vers le développement web. Non pas pour abandonner le dessin, mais pour lui offrir un nouveau terrain de jeu. Il voit le code comme un autre langage pour raconter des histoires, pour créer des ponts. Ce site en est la preuve : un lieu où la 3D, la narration et la technique se rencontrent.
|
||||
</p>
|
||||
|
||||
<h2>Retrouver l'Artisan</h2>
|
||||
<p>Pour suivre ses autres pérégrinations, qu'elles soient dessinées ou codées :</p>
|
||||
<ul>
|
||||
<li><strong>Portfolio Artistique :</strong> <a href="https://www.pinterest.com/imazmaronrstones/errances-cr%C3%A9atives/" target="_blank" rel="noopener noreferrer">Errances Créatives sur Pinterest</a></li>
|
||||
<li><strong>Page Auteur :</strong> <a href="https://www.la-reunion-des-livres.re/auteur/latchimy-nicolas/" target="_blank" rel="noopener noreferrer">La Réunion des Livres</a></li>
|
||||
<li><strong>Forum Dessiné :</strong> <a href="https://www.forum-dessine.fr/auteurs/krapo" target="_blank" rel="noopener noreferrer">Profil de Krâpo</a></li>
|
||||
<li><strong>23h de la BD (2019) :</strong> <a href="https://23hbd.com/participants/2019/krapo/" target="_blank" rel="noopener noreferrer">Participation 2019</a></li>
|
||||
<li><strong>23h de la BD (2020) :</strong> <a href="https://23hbd.com/participants/2020/krapo/" target="_blank" rel="noopener noreferrer">Participation 2020</a></li>
|
||||
<li><strong>Webtoon (Liestral) :</strong> <a href="https://www.webtoons.com/fr/canvas/liestral/list?title_no=1049110" target="_blank" rel="noopener noreferrer">Découvrir son webtoon</a></li>
|
||||
<li><strong>Instagram :</strong> <a href="https://www.instagram.com/mosaic_chantilly/" target="_blank" rel="noopener noreferrer">@mosaic_chantilly</a></li>
|
||||
<li><strong>CV en ligne :</strong> <a href="https://nohay.github.io/" target="_blank" rel="noopener noreferrer">Découvrir son parcours</a></li>
|
||||
</ul>
|
||||
</ParchmentCard>
|
||||
|
||||
<ParchmentCard>
|
||||
<h2>📖 Le Journal de Bord de l'Artisan</h2>
|
||||
<p>
|
||||
Au-delà des chroniques et des lignes de code, il y a le quotidien. Une quête d'équilibre entre la vie, la passion et la discipline. Ce journal de bord est une tentative de cartographier ce voyage intérieur.
|
||||
</p>
|
||||
<div class="text-center mt-4">
|
||||
<a href="/bujo" class="bg-stone-700 text-white font-bold py-2 px-4 rounded hover:bg-stone-800 transition-colors duration-300">Accéder au Journal de Bord</a>
|
||||
</div>
|
||||
</ParchmentCard>
|
||||
</GameLayout>
|
||||
|
||||
</Layout>
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
import GameLayout from '../layouts/GameLayout.astro';
|
||||
import ParchmentCard from '../components/ui/ParchmentCard.astro';
|
||||
---
|
||||
|
||||
<GameLayout title="La Boussole Éthique - Sweet Journey">
|
||||
<ParchmentCard>
|
||||
<h1>⚖️ La Boussole Éthique</h1>
|
||||
<p>
|
||||
Mon voyage a commencé à cause d'un fléau : un sable sombre, dépourvu de vie, qui corrompt mes terres et empoisonne les rêves de mon peuple. Cette quête m'a enseigné à distinguer le sable pur du sable vicié. Il en va de même pour les créations des mortels. Certaines sont conçues pour apporter un repos réparateur, d'autres sont des pièges, aussi subtils que le poison sur ma peau.
|
||||
</p>
|
||||
|
||||
<h2>Les Sables de Vie : Les Chemins à Suivre</h2>
|
||||
<p>Ce sont les modèles basés sur le respect et la valeur. L'**Open Source**, par exemple, est comme une oasis où chaque pèlerin peut puiser de l'eau, mais aussi y ajouter une goutte pour le suivant. C'est un cycle de don où la connaissance n'est pas un trésor gardé, mais une source qui abreuve la communauté. Ma conviction est que l'on peut bâtir de grandes choses avec des matériaux que d'autres jugent obsolètes, en laissant une empreinte légère. L'autonomie est possible sans dévaster le monde ; c'est une question de culture. Se souvenir de la naissance de la grande toile (le web) et voir où elle en est aujourd'hui doit nous inspirer à créer en harmonie avec l'ensemble.</p>
|
||||
|
||||
<h2>Les Marécages de Sable Noir : Les Chemins à Éviter</h2>
|
||||
<p>Ici se trouvent les sables mouvants. Je perçois dans le monde une tendance à la démesure, une soif de pouvoir qui oublie l'équilibre. On y cherche à dominer plutôt qu'à harmoniser, à prendre plutôt qu'à partager. Cette philosophie ressemble au sable noir : elle crée des systèmes où quelques-uns s'enrichissent en asséchant les rêves de la multitude. Mon art se refuse à emprunter cette voie.</p>
|
||||
</ParchmentCard>
|
||||
</GameLayout>
|
||||
@@ -1,132 +0,0 @@
|
||||
---
|
||||
import { getCollection, render } from 'astro:content';
|
||||
import LifeLayout from '../../layouts/LifeLayout.astro';
|
||||
|
||||
// Import des composants de page pour les garder modulaires
|
||||
import BujoIndex from '../../components/bujo/BujoIndex.astro';
|
||||
import BujoKeys from '../../components/bujo/BujoKeys.astro';
|
||||
import MonthlyLog from '../../components/bujo/MonthlyLog.astro';
|
||||
import BujoFutureLog from '../../components/bujo/BujoFutureLog.astro';
|
||||
import CollectionTracker from '../../components/bujo/CollectionTracker.astro';
|
||||
import CollectionObjectifs from '../../components/bujo/CollectionObjectifs.astro';
|
||||
import CollectionBooks from '../../components/bujo/CollectionBooks.astro';
|
||||
import CollectionPlaceholder from '../../components/bujo/CollectionPlaceholder.astro';
|
||||
import CollectionFilms from '../../components/bujo/CollectionFilms.astro';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const bujoEntries = await getCollection('bujo');
|
||||
const paths = bujoEntries.map(entry => {
|
||||
const slug = entry.id.replace(/\.(md|mdx)$/, '');
|
||||
return { params: { slug } };
|
||||
});
|
||||
// Ajouter les routes statiques/virtuelles
|
||||
paths.push({ params: { slug: undefined } }); // Index
|
||||
paths.push({ params: { slug: 'keys' } });
|
||||
paths.push({ params: { slug: 'future-log' } });
|
||||
paths.push({ params: { slug: 'collections/livres-a-lire' } });
|
||||
paths.push({ params: { slug: 'collections/trackers-mensuels' } });
|
||||
paths.push({ params: { slug: 'collections/objectifs-du-mois' } });
|
||||
paths.push({ params: { slug: 'collections/suivi-depenses' } });
|
||||
paths.push({ params: { slug: 'collections/gratitude' } });
|
||||
paths.push({ params: { slug: 'collections/brain-dump' } });
|
||||
paths.push({ params: { slug: 'collections/bucket-list' } });
|
||||
paths.push({ params: { slug: 'collections/films-a-voir' } });
|
||||
|
||||
// Ajouter les routes pour les mois
|
||||
const uniqueMonths = new Set<string>();
|
||||
bujoEntries.forEach(log => {
|
||||
const [year, month] = log.id.split('/');
|
||||
if (year && month && !isNaN(parseInt(year)) && !isNaN(parseInt(month))) {
|
||||
uniqueMonths.add(`${year}/${month}`);
|
||||
}
|
||||
});
|
||||
uniqueMonths.forEach(monthPath => {
|
||||
paths.push({ params: { slug: monthPath } });
|
||||
});
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
const { slug } = Astro.params;
|
||||
|
||||
// 1. Gérer la page d'index (/bujo)
|
||||
if (slug === undefined) {
|
||||
const allLogs = await getCollection('bujo');
|
||||
const uniqueMonths = new Set<string>();
|
||||
allLogs.forEach(log => {
|
||||
const [year, month] = log.id.split('/');
|
||||
if (year && month && !isNaN(parseInt(year)) && !isNaN(parseInt(month))) {
|
||||
uniqueMonths.add(`${year}/${month}`);
|
||||
}
|
||||
});
|
||||
Astro.props.page = 'index';
|
||||
Astro.props.months = Array.from(uniqueMonths);
|
||||
}
|
||||
// 2. Gérer les pages statiques (clés, etc.)
|
||||
else if (slug === 'keys') {
|
||||
Astro.props.page = 'keys';
|
||||
}
|
||||
else if (slug === 'future-log') {
|
||||
Astro.props.page = 'bujo-future-log';
|
||||
}
|
||||
// 3. Gérer les collections
|
||||
else if (slug.startsWith('collections/')) {
|
||||
if (slug === 'collections/trackers-mensuels') {
|
||||
Astro.props.page = 'collection-tracker';
|
||||
} else if (slug === 'collections/livres-a-lire') {
|
||||
Astro.props.page = 'collection-books';
|
||||
} else if (slug === 'collections/objectifs-du-mois') {
|
||||
Astro.props.page = 'collection-objectifs';
|
||||
} else if (slug === 'collections/films-a-voir') {
|
||||
Astro.props.page = 'collection-films';
|
||||
}
|
||||
else {
|
||||
Astro.props.page = 'collection-placeholder';
|
||||
Astro.props.collectionTitle = slug.split('/')[1].replace(/-/g, ' ');
|
||||
}
|
||||
}
|
||||
// 4. Gérer les logs mensuels (ex: /bujo/2026/01)
|
||||
else if (slug.match(/^\d{4}\/\d{2}$/)) {
|
||||
const [year, month] = slug.split('/');
|
||||
const monthlyLogs = await getCollection('bujo', ({ id }) => id.startsWith(slug));
|
||||
Astro.props.page = 'monthly-log';
|
||||
Astro.props.logs = monthlyLogs;
|
||||
Astro.props.year = year;
|
||||
Astro.props.month = month;
|
||||
}
|
||||
// 5. Gérer les entrées de contenu (Daily Logs)
|
||||
else {
|
||||
const bujoEntries = await getCollection('bujo');
|
||||
const entry = bujoEntries.find(e => e.id.replace(/\.(md|mdx)$/, '') === slug);
|
||||
if (entry) {
|
||||
const { Content } = await render(entry);
|
||||
Astro.props.page = 'entry';
|
||||
Astro.props.entry = entry;
|
||||
Astro.props.Content = Content;
|
||||
}
|
||||
}
|
||||
|
||||
const { page, entry, Content, months, logs, year, month, collectionTitle } = Astro.props;
|
||||
const title = page === 'index' ? 'Journal de Bord' : (entry ? entry.data.title : collectionTitle || 'Journal');
|
||||
---
|
||||
|
||||
<LifeLayout title={title}>
|
||||
{page === 'index' && <BujoIndex months={months} />}
|
||||
{page === 'keys' && <BujoKeys />}
|
||||
{page === 'bujo-future-log' && <BujoFutureLog />}
|
||||
|
||||
{page === 'collection-tracker' && <CollectionTracker />}
|
||||
{page === 'collection-objectifs' && <CollectionObjectifs />}
|
||||
{page === 'collection-books' && <CollectionBooks />}
|
||||
{page === 'collection-films' && <CollectionFilms />}
|
||||
{page === 'collection-placeholder' && <CollectionPlaceholder collectionTitle={collectionTitle} />}
|
||||
|
||||
{page === 'monthly-log' && <MonthlyLog logs={logs} year={year} month={month} />}
|
||||
|
||||
{page === 'entry' && Content && (
|
||||
<article class="prose prose-slate lg:prose-xl max-w-none">
|
||||
<h1 class="text-3xl font-bold mb-2">{entry.data.title}</h1>
|
||||
<Content />
|
||||
</article>
|
||||
)}
|
||||
</LifeLayout>
|
||||
@@ -1,152 +0,0 @@
|
||||
---
|
||||
import { getCollection, type CollectionEntry } from "astro:content";
|
||||
import GameLayout from "../../layouts/GameLayout.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const codexEntries = await getCollection("codex");
|
||||
return codexEntries.map((entry) => ({
|
||||
params: { slug: entry.slug },
|
||||
}));
|
||||
}
|
||||
|
||||
const { slug } = Astro.params;
|
||||
const codexEntries = await getCollection("codex");
|
||||
|
||||
const entry = codexEntries.find((entry) => entry.slug === slug);
|
||||
|
||||
if (!entry) {
|
||||
return Astro.redirect("/404");
|
||||
}
|
||||
|
||||
const { Content } = await entry.render();
|
||||
---
|
||||
|
||||
<GameLayout title={entry.data.title}>
|
||||
<main class="codex-entry-container">
|
||||
<article class="parchment-card">
|
||||
<div class="header">
|
||||
<h1>{entry.data.title}</h1>
|
||||
<h2>{entry.data.subtitle}</h2>
|
||||
<p class="publish-date">
|
||||
Savoir acquis le : {
|
||||
entry.data.publishDate.toLocaleDateString("fr-FR", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
})
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="transmutation-table">
|
||||
<div class="table-row header">
|
||||
<div class="col-title">Ancien Monde (2D)</div>
|
||||
<div class="col-title">Mécanique</div>
|
||||
<div class="col-title">Monde de Demain (3D)</div>
|
||||
</div>
|
||||
<div class="table-row">
|
||||
<div>{entry.data.concept2D}</div>
|
||||
<div>{entry.data.mecanique}</div>
|
||||
<div>{entry.data.vision3D}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{entry.data.tags && (
|
||||
<div class="tags-container">
|
||||
{entry.data.tags.map((tag) => (
|
||||
<a href={`/codex/tags/${tag.toLowerCase()}`} class="tag">{tag}</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="prose">
|
||||
<Content />
|
||||
</div>
|
||||
|
||||
<a href="/codex" class="back-link"> ← Retourner au Codex </a>
|
||||
</article>
|
||||
</main>
|
||||
</GameLayout>
|
||||
|
||||
<style>
|
||||
.codex-entry-container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.parchment-card {
|
||||
background: linear-gradient(145deg, #fefbf3, #f8f1e4);
|
||||
border: 2px solid #dcd0b9;
|
||||
border-radius: 15px;
|
||||
padding: 2rem 3rem;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.header h2 {
|
||||
font-family: "EB Garamond", serif;
|
||||
font-style: italic;
|
||||
font-size: 1.4rem;
|
||||
color: #4a4130;
|
||||
margin-top: 0;
|
||||
}
|
||||
/* On retire l'ornement pour le h2 de la carte */
|
||||
.header h2::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.publish-date {
|
||||
font-style: italic;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.transmutation-table {
|
||||
margin: 2rem 0;
|
||||
font-size: 0.9rem;
|
||||
background-color: rgba(253, 246, 232, 0.5);
|
||||
border: 1px solid #dcd0b9;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.5fr 1.5fr;
|
||||
gap: 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.table-row.header {
|
||||
background-color: rgba(220, 208, 185, 0.4);
|
||||
}
|
||||
|
||||
.table-row:not(.header) {
|
||||
border-top: 1px solid #dcd0b9;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
font-family: "Cinzel", serif;
|
||||
font-weight: bold;
|
||||
color: #4a4130;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-top: 3rem;
|
||||
font-family: "Cinzel", serif;
|
||||
color: #b8860b;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.back-link:hover {
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
</style>
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import GameLayout from "../../layouts/GameLayout.astro";
|
||||
import ContentSearch from "../../components/ContentSearch.astro";
|
||||
|
||||
// 1. Récupérer toutes les entrées du codex
|
||||
const codexEntries = await getCollection("codex");
|
||||
|
||||
// 2. Trier les entrées par date de publication
|
||||
const sortedEntries = codexEntries.sort(
|
||||
(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf()
|
||||
);
|
||||
|
||||
// 3. Extraire tous les domaines uniques pour les catégories
|
||||
const allDomains = [...new Set(codexEntries.map(entry => entry.data.domain))];
|
||||
---
|
||||
|
||||
<GameLayout title="Codex de la Substance">
|
||||
<h1>Le Codex de la Substance</h1>
|
||||
<p style="text-align: center; margin-bottom: 3rem;">
|
||||
Le laboratoire où le pèlerin dissèque les mécanismes du réel (le code)
|
||||
pour insuffler le "souffle de vie" (Hebel) à ses créations.
|
||||
</p>
|
||||
|
||||
<!-- On passe les entrées, les domaines (en tant que tags) et le chemin de base au composant de recherche -->
|
||||
<ContentSearch posts={sortedEntries} tags={allDomains} basePath="codex" />
|
||||
|
||||
</GameLayout>
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import GameLayout from "../../../layouts/GameLayout.astro";
|
||||
import CodexCard from "../../../components/ui/CodexCard.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const allCodexEntries = await getCollection("codex");
|
||||
const allTags = allCodexEntries.flatMap((entry) => entry.data.tags);
|
||||
const uniqueTags = [...new Set(allTags)];
|
||||
|
||||
return uniqueTags.map((tag) => {
|
||||
return {
|
||||
params: { tag: tag.toLowerCase() },
|
||||
props: { tag },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { tag } = Astro.props;
|
||||
|
||||
const allCodexEntries = await getCollection("codex");
|
||||
|
||||
const filteredEntries = allCodexEntries.filter((entry) =>
|
||||
entry.data.tags.map(t => t.toLowerCase()).includes(Astro.params.tag)
|
||||
);
|
||||
---
|
||||
|
||||
<GameLayout title={`Domaine : ${tag}`}>
|
||||
<main class="codex-container">
|
||||
<h1>Domaine : {tag}</h1>
|
||||
<p>
|
||||
Liste de tous les savoirs et mécaniques liés au domaine "{tag}".
|
||||
</p>
|
||||
<div class="card-grid">
|
||||
{filteredEntries.map((entry) => <CodexCard entry={entry} />)}
|
||||
</div>
|
||||
</main>
|
||||
</GameLayout>
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
import GameLayout from "../layouts/GameLayout.astro";
|
||||
import GoldButton from "../components/ui/GoldButton.astro";
|
||||
---
|
||||
|
||||
<GameLayout title="Bienvenue sur JDRSweetJourney">
|
||||
<h1>Bienvenue sur le projet JDR Sweet Journey !</h1>
|
||||
<h2>L'Ambition</h2>
|
||||
<p>
|
||||
L'objectif est de créer un clone entièrement web de l'application mobile <strong
|
||||
>AFK Journey</strong
|
||||
>. Ce projet sera une vitrine technologique utilisant :
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
La modélisation 3D et l'animation (2D et 3D) réalisées avec <strong
|
||||
>Blender</strong
|
||||
>.
|
||||
</li>
|
||||
<li>
|
||||
La retranscription de ces éléments dans le navigateur grâce à <strong
|
||||
>Three.js</strong
|
||||
>.
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="card-grid">
|
||||
<GoldButton
|
||||
href="https://threejs-journey.com"
|
||||
title="🎓 Formation : Three.js Journey"
|
||||
body="Ce projet s'appuie sur les enseignements de Three.js Journey pour garantir une base technique solide."
|
||||
/>
|
||||
</ul>
|
||||
<p>
|
||||
Si en plus, cette plateforme peut servir de point de repère pour nos
|
||||
aventures de jeu de rôle, c'est une pierre deux coups !
|
||||
</p>
|
||||
|
||||
<h2>Le Voyage</h2>
|
||||
<p>
|
||||
Ce site est aussi un levier pour maîtriser les paradigmes technologiques
|
||||
de demain. Explorez le <strong>journal d'aventure</strong> pour suivre la
|
||||
quête, ou consultez les <strong>logs de construction</strong> pour voir les
|
||||
coulisses techniques.
|
||||
</p>
|
||||
|
||||
<ul class="card-grid">
|
||||
<GoldButton
|
||||
href="/atelier"
|
||||
title="🏜️ Le Sanctuaire des Grains"
|
||||
body="Découvrez les arts et les outils du pèlerin pour façonner le sable et les rêves."
|
||||
/>
|
||||
<GoldButton
|
||||
href="/observatoire"
|
||||
title="🎨 L'Observatoire"
|
||||
body="Explorez les sources d'inspiration : artistes, développeurs, podcasts et jeux qui nourrissent ce projet."
|
||||
/>
|
||||
<GoldButton
|
||||
href="/boussole"
|
||||
title="⚖️ La Boussole Éthique"
|
||||
body="Une réflexion sur les modèles économiques vertueux et ceux à éviter dans le monde du jeu vidéo."
|
||||
/>
|
||||
</ul>
|
||||
|
||||
<p>Quelle ambition, jeune batracien...</p>
|
||||
</GameLayout>
|
||||
@@ -1,45 +1,147 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import GameLayout from '../../layouts/GameLayout.astro';
|
||||
import ParchmentCard from '../../components/ui/ParchmentCard.astro';
|
||||
// 1. Ajoute "render" dans ton import
|
||||
import { getCollection, render } from "astro:content";
|
||||
import GameLayout from "../../layouts/GameLayout.astro";
|
||||
|
||||
// 1. Génère une page statique pour chaque article de la collection
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('journal');
|
||||
return posts.map((post) => ({
|
||||
params: { slug: post.slug },
|
||||
props: post,
|
||||
}));
|
||||
const journalEntries = await getCollection("journal");
|
||||
return journalEntries.map((entry) => ({
|
||||
params: { slug: entry.id },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
|
||||
// 2. Récupère les props de l'article correspondant
|
||||
const post = Astro.props;
|
||||
const { Content } = await post.render();
|
||||
const { entry } = Astro.props;
|
||||
|
||||
if (!entry) {
|
||||
return Astro.redirect("/404");
|
||||
}
|
||||
|
||||
// 2. Utilise la fonction render(entry) au lieu de entry.render()
|
||||
const { Content } = await render(entry);
|
||||
---
|
||||
|
||||
<GameLayout title={post.data.title}>
|
||||
<ParchmentCard>
|
||||
<h1>{post.data.title}</h1>
|
||||
<div class="meta">
|
||||
Par {post.data.author} • Le {post.data.publishDate.toLocaleDateString('fr-FR')}
|
||||
</div>
|
||||
{post.data.tags && (
|
||||
<div class="tags-container">
|
||||
{post.data.tags.map((tag) => (
|
||||
<a href={`/journal/tags/${tag}`} class="tag">{tag}</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<article class="prose">
|
||||
<Content />
|
||||
</article>
|
||||
</ParchmentCard>
|
||||
<GameLayout title={entry.data.title}>
|
||||
<main class="codex-entry-container">
|
||||
<article class="parchment-card">
|
||||
<div class="header">
|
||||
<h1>{entry.data.title}</h1>
|
||||
<p class="publish-date">
|
||||
Savoir acquis le : {
|
||||
entry.data.publishDate.toLocaleDateString("fr-FR", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
})
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{
|
||||
entry.data.tags && (
|
||||
<div class="tags-container">
|
||||
{entry.data.tags.map((tag) => (
|
||||
<a
|
||||
href={`/journal/tags/${tag.toLowerCase()}`}
|
||||
class="tag"
|
||||
>
|
||||
{tag}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="prose">
|
||||
<Content />
|
||||
</div>
|
||||
|
||||
<a href="/journal" class="back-link">
|
||||
← Retourner au Journal
|
||||
</a>
|
||||
</article>
|
||||
</main>
|
||||
</GameLayout>
|
||||
|
||||
<style>
|
||||
.meta {
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
</style>
|
||||
.codex-entry-container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.parchment-card {
|
||||
background: linear-gradient(145deg, #fefbf3, #f8f1e4);
|
||||
border: 2px solid #dcd0b9;
|
||||
border-radius: 15px;
|
||||
padding: 2rem 3rem;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.header h2 {
|
||||
font-family: "EB Garamond", serif;
|
||||
font-style: italic;
|
||||
font-size: 1.4rem;
|
||||
color: #4a4130;
|
||||
margin-top: 0;
|
||||
}
|
||||
/* On retire l'ornement pour le h2 de la carte */
|
||||
.header h2::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.publish-date {
|
||||
font-style: italic;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.transmutation-table {
|
||||
margin: 2rem 0;
|
||||
font-size: 0.9rem;
|
||||
background-color: rgba(253, 246, 232, 0.5);
|
||||
border: 1px solid #dcd0b9;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.5fr 1.5fr;
|
||||
gap: 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.table-row.header {
|
||||
background-color: rgba(220, 208, 185, 0.4);
|
||||
}
|
||||
|
||||
.table-row:not(.header) {
|
||||
border-top: 1px solid #dcd0b9;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
font-family: "Cinzel", serif;
|
||||
font-weight: bold;
|
||||
color: #4a4130;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-top: 3rem;
|
||||
font-family: "Cinzel", serif;
|
||||
color: #b8860b;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.back-link:hover {
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import GameLayout from '../../../layouts/GameLayout.astro';
|
||||
import GoldButton from '../../../components/ui/GoldButton.astro';
|
||||
import { getCollection } from "astro:content";
|
||||
import GameLayout from "../../../layouts/GameLayout.astro";
|
||||
import GoldButton from "../../../components/ui/GoldButton.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const allPosts = await getCollection('journal');
|
||||
const allTags = [...new Set(allPosts.flatMap((post) => post.data.tags || []))];
|
||||
const allPosts = await getCollection("journal");
|
||||
const allTags = [
|
||||
...new Set(allPosts.flatMap((post) => post.data.tags || [])),
|
||||
];
|
||||
|
||||
return allTags.map((tag) => {
|
||||
const filteredPosts = allPosts.filter((post) => post.data.tags?.includes(tag));
|
||||
return {
|
||||
params: { tag },
|
||||
props: { posts: filteredPosts },
|
||||
};
|
||||
});
|
||||
return allTags.map((tag) => {
|
||||
const filteredPosts = allPosts.filter((post) =>
|
||||
post.data.tags?.includes(tag),
|
||||
);
|
||||
return {
|
||||
params: { tag },
|
||||
props: { posts: filteredPosts },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { tag } = Astro.params;
|
||||
@@ -21,19 +25,23 @@ const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<GameLayout title={`Récits: ${tag}`}>
|
||||
<h1>Récits avec la balise : <span class="tag-title">{tag}</span></h1>
|
||||
<h1>Récits avec la balise : <span class="tag-title">{tag}</span></h1>
|
||||
|
||||
<div class="card-grid">
|
||||
{
|
||||
posts.map((post) => (
|
||||
<GoldButton href={`/journal/${post.slug}/`} title={post.data.title} body={`Publié le ${post.data.publishDate.toLocaleDateString('fr-FR')}`} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div class="card-grid">
|
||||
{
|
||||
posts.map((post) => (
|
||||
<GoldButton
|
||||
href={`/journal/${post.id}/`}
|
||||
title={post.data.title}
|
||||
body={`Publié le ${post.data.publishDate.toLocaleDateString("fr-FR")}`}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</GameLayout>
|
||||
|
||||
<style>
|
||||
.tag-title {
|
||||
color: #c89b3c;
|
||||
}
|
||||
</style>
|
||||
.tag-title {
|
||||
color: #c89b3c;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import GameLayout from '../../layouts/GameLayout.astro';
|
||||
import ParchmentCard from '../../components/ui/ParchmentCard.astro';
|
||||
|
||||
// 1. Génère une page pour chaque entrée de la collection 'logs'
|
||||
export async function getStaticPaths() {
|
||||
const logEntries = await getCollection('logs');
|
||||
return logEntries.map((entry) => ({
|
||||
params: { slug: entry.slug },
|
||||
props: entry,
|
||||
}));
|
||||
}
|
||||
|
||||
// 2. Récupère les props pour la page actuelle
|
||||
const post = Astro.props;
|
||||
const { Content } = await post.render();
|
||||
---
|
||||
|
||||
<GameLayout title={post.data.title}>
|
||||
<ParchmentCard>
|
||||
<h1>{post.data.title}</h1>
|
||||
<div class="meta">
|
||||
Publié le {post.data.publishDate.toLocaleDateString('fr-FR')}
|
||||
</div>
|
||||
{post.data.tags && (
|
||||
<div class="tags-container">
|
||||
{post.data.tags.map((tag) => (
|
||||
<a href={`/logs/tags/${tag}`} class="tag">{tag}</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<article class="prose">
|
||||
<Content />
|
||||
</article>
|
||||
</ParchmentCard>
|
||||
</GameLayout>
|
||||
|
||||
<style>
|
||||
/* Les styles des tags sont maintenant globaux dans GameLayout.astro */
|
||||
|
||||
.meta {
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import GameLayout from '../../layouts/GameLayout.astro';
|
||||
import ContentSearch from '../../components/ContentSearch.astro';
|
||||
|
||||
// 1. Récupère TOUS les logs et les trie.
|
||||
const allPosts = await getCollection('logs');
|
||||
const sortedPosts = allPosts.sort(
|
||||
(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf()
|
||||
);
|
||||
|
||||
// 2. Extrait toutes les balises uniques
|
||||
const allTags = [...new Set(allPosts.flatMap(post => post.data.tags || []))];
|
||||
---
|
||||
|
||||
<GameLayout title="Logs de Construction">
|
||||
<h1>⚙️ Logs de Construction</h1>
|
||||
<p style="text-align: center; margin-bottom: 3rem;">
|
||||
Les coulisses techniques du projet. Utilisez la barre de recherche pour trouver un log.
|
||||
</p>
|
||||
|
||||
<!-- 3. On utilise le composant de recherche pour les logs -->
|
||||
<ContentSearch posts={sortedPosts} tags={allTags} basePath="logs" />
|
||||
|
||||
</GameLayout>
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import GameLayout from '../../../layouts/GameLayout.astro';
|
||||
import GoldButton from '../../../components/ui/GoldButton.astro';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const allPosts = await getCollection('logs');
|
||||
const allTags = [...new Set(allPosts.flatMap((post) => post.data.tags || []))];
|
||||
|
||||
return allTags.map((tag) => {
|
||||
const filteredPosts = allPosts.filter((post) => post.data.tags?.includes(tag));
|
||||
return {
|
||||
params: { tag },
|
||||
props: { posts: filteredPosts },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { tag } = Astro.params;
|
||||
const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<GameLayout title={`Logs: ${tag}`}>
|
||||
<h1>Logs avec la balise : <span class="tag-title">{tag}</span></h1>
|
||||
|
||||
<div class="card-grid">
|
||||
{
|
||||
posts.map((post) => (
|
||||
<GoldButton href={`/logs/${post.slug}/`} title={post.data.title} body={`Publié le ${post.data.publishDate.toLocaleDateString('fr-FR')}`} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</GameLayout>
|
||||
|
||||
<style>
|
||||
.tag-title {
|
||||
color: #c89b3c;
|
||||
}
|
||||
</style>
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
import GameLayout from '../layouts/GameLayout.astro';
|
||||
import ParchmentCard from '../components/ui/ParchmentCard.astro';
|
||||
---
|
||||
|
||||
<GameLayout title="L'Observatoire des Songes - Sweet Journey">
|
||||
<ParchmentCard>
|
||||
<h1>🔭 L'Observatoire des Songes</h1>
|
||||
<p>
|
||||
Un pèlerin, même dans les mers de sable, doit lever les yeux vers les constellations pour ne pas perdre son chemin. Mon voyage n'est pas solitaire ; il est guidé par les échos d'autres mondes, les murmures d'autres créateurs. Cet observatoire est ma carte du ciel, où chaque étoile est une âme dont la lumière m'inspire.
|
||||
</p>
|
||||
|
||||
<h2>Les Tisseurs de Rêves : Artistes & Développeurs</h2>
|
||||
<p>Certains artisans, comme le maître Hayao Miyazaki, créent des mondes où le vent, les arbres et les esprits ont une voix. Leurs récits sont des leçons d'harmonie, un rappel que même la plus petite créature a sa place dans le grand cycle. J'étudie leurs œuvres comme un ancien grimoire, y cherchant la maîtrise de la forme et du mouvement.</p>
|
||||
|
||||
<h2>Mes Compagnons de Quête</h2>
|
||||
<p>Mon pèlerinage serait vain sans ceux qui marchent à mes côtés. Chacun est une étoile dans ma nuit, une source de force et de récits inattendus. Leur courage et leurs bizarreries nourrissent mon voyage autant que le sable :</p>
|
||||
<ul>
|
||||
<li><strong>Orson, le Gardien du Froid :</strong> Notre Maître de Jeu, un être aussi énigmatique et froid que sa patrie gelée. Il tisse les fils de notre destinée tout en suivant la sienne : une quête de vengeance pour sa sœur disparue, marquée au fer rouge par un symbole arcanique. Il est le vent glacial qui nous pousse en avant.</li>
|
||||
<li><strong>Gurdill "Cul Brillant" :</strong> Un prince nain en exil, dont le surnom lumineux cache une profonde connaissance de la forge. Banni par les siens, il cherche à prouver sa valeur, son marteau elfique à la main. Sa quête de rédemption est aussi flamboyante que son fameux caleçon.</li>
|
||||
<li><strong>Bulle aux Mains d’Or :</strong> Une fée guérisseuse, exilée volontaire de son royaume pour comprendre la souffrance du monde matériel. Sa lumière est un baume pour nos blessures, et sa naïveté un rappel constant de la pureté que nous cherchons à protéger.</li>
|
||||
<li><strong>Jinn le Mélodiste :</strong> Un barde Genasi au sang de feu, dont la musique est aussi ardente que son tempérament. Sa quête pour retrouver l'épée de ses ancêtres est un chant d'honneur qui rythme nos pas et enflamme nos cœurs.</li>
|
||||
<li><strong>Nyrae la Guérisseuse :</strong> Une Tabaxi dont les pas silencieux la guident loin de sa forêt natale. Son instinct et sa connaissance des onguents sont un réconfort précieux, une présence sauvage et apaisante dans notre groupe hétéroclite.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Les Murmures du Vent</h2>
|
||||
|
||||
<h2>Les Chroniques d'Autres Mondes</h2>
|
||||
</ParchmentCard>
|
||||
</GameLayout>
|
||||
|
||||
</Layout>
|
||||
Reference in New Issue
Block a user