Mise à jour Camille

This commit is contained in:
Camilledenoray 2026-05-14 17:22:34 +02:00
parent 1dd4060314
commit b373875a61
33 changed files with 883 additions and 150 deletions

View file

@ -34,3 +34,14 @@ If you are familiar with Git, you can clone Kirby's Plainkit repository from Git
© 2009 Bastian Allgeier
[getkirby.com](https://getkirby.com) · [License agreement](https://getkirby.com/license)
----------------
QUESTIONS
-

35
assets/css/mobile.css Normal file
View file

@ -0,0 +1,35 @@
@media screen and (max-width: 1000px) {
body {
background-color: red;
}
.project-slideshow {
position: fixed;
top: 0;
width: 100vw;
left: 0;
margin: 0;
height: 50vh;
}
.project-slideshow img {
width: 100%;
height: 100%;
object-fit: cover;
}
.main-title {
z-index: 2;
position: fixed;
}
.project-index :has(.selected) {
}
.fix {
display: block;
}
.project-toggler.grid {
display: block;
}
}

133
assets/css/nav.css Normal file
View file

@ -0,0 +1,133 @@
nav.main-menu {
width: calc(100% - var(--body-margin) * 2);
opacity: 0;
transition-duration: var(--disparition-duration);
transition-property: opacity;
position: absolute;
pointer-events: none;
z-index: 2;
/*! margin: var(--margin-XL); */
top: 0;
font-size: var(--font-size-XL);
padding-bottom: 4rem;
}
nav ul {
margin-top: var(--line-height-S);
padding: 0;
list-style: none;
font-size: var(--font-size-L);
z-index: 2;
position: absolute;
}
nav li {
float: left;
}
nav li a {
list-style: none;
text-decoration: none;
text-transform: initial;
cursor: pointer;
}
.title-nav {
font-size: var(--font-size-XL);
line-break: strict;
left: -0.65vw;
position: relative;
top: -0.7vw;
margin-top: var(--body-margin);
line-height: 0.75;
}
.title-nav a {
text-decoration: none;
padding-bottom: var(--nav-margin);
/* background-color: yellow; */
}
.main-title {
z-index: 2;
font-size: var(--font-size-S);
top: var(--body-margin);
transition-duration: var(--disparition-duration);
cursor: pointer;
width: fit-content;
position: fixed;
}
header {
width: 100%;
position: fixed;
z-index: 2;
height: auto;
overflow: visible;
}
.main-title a {
text-decoration: none;
}
.main-title:hover ~ nav {
opacity: 1;
transition-duration: var(--apparition-duration);
transition-property: opacity;
pointer-events: all;
z-index: 1;
}
header:hover ~ main {
opacity: var(--low-opacity);
transition-duration: var(--apparition-duration);
}
.main-title:hover {
opacity: var(--low-opacity);
transition-duration: var(--apparition-duration);
}
.main-title:has(+ nav:hover) {
opacity: var(--low-opacity);
transition-duration: var(--apparition-duration);
}
nav.main-menu:hover {
opacity: 1;
position: absolute;
pointer-events: all;
z-index: 1;
}
[data-template="home"] nav li .nav-item-home {
text-decoration: underline;
}
[data-template="index"] nav li .nav-item-projects {
text-decoration: underline;
}
[data-template="infos"] nav li .nav-item-about {
text-decoration: underline;
}
/* SPECIFIC TO HOME */
[data-template="home"] .main-title {
font-size: var(--font-size-XL);
line-break: strict;
left: -0.65vw;
position: relative;
top: -0.7vw;
margin-top: var(--body-margin);
line-height: 0.75;
}
[data-template="home"] .main-title a {
color: transparent;
}
[data-template="home"] .main-title span {
color: var(--text-color);
}

8
assets/css/reset.css Normal file
View file

@ -0,0 +1,8 @@
button {
border: none;
padding: 0;
margin: 0;
text-align: inherit;
font: inherit;
cursor: pointer;
}

View file

@ -1,11 +1,70 @@
* {
--main-font: sans-serif;
--font-size-L: 11vw;
@import url("https://p.typekit.net/p.css?s=1&k=wdg5nfi&ht=tk&f=39496.39497&a=95222337&app=typekit&e=css");
@font-face {
font-family: "neue-haas-grotesk-display";
src:
url("https://use.typekit.net/af/174ae3/00000000000000007735bb5a/31/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n5&v=3")
format("woff2"),
url("https://use.typekit.net/af/174ae3/00000000000000007735bb5a/31/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n5&v=3")
format("woff"),
url("https://use.typekit.net/af/174ae3/00000000000000007735bb5a/31/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n5&v=3")
format("opentype");
font-display: auto;
font-style: normal;
font-weight: 500;
font-stretch: normal;
}
@font-face {
font-family: "neue-haas-grotesk-display";
src:
url("https://use.typekit.net/af/db1ce7/00000000000000007735bb5e/31/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=i5&v=3")
format("woff2"),
url("https://use.typekit.net/af/db1ce7/00000000000000007735bb5e/31/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=i5&v=3")
format("woff"),
url("https://use.typekit.net/af/db1ce7/00000000000000007735bb5e/31/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=i5&v=3")
format("opentype");
font-display: auto;
font-style: italic;
font-weight: 500;
font-stretch: normal;
}
:root {
--main-font: "neue-haas-grotesk-display", sans-serif;
--font-size-S: 0.9rem;
--font-size-L: 1.6rem;
--font-size-XL: 11vw;
--line-height-S: var(--font-size-S);
--text-color: black;
--body-margin: 0.6rem;
--nav-margin: 1rem;
--apparition-duration: 0.3s;
--disparition-duration: 0.3s;
--indentation: 2rem;
--low-opacity: 0.2;
--half-screen: 50vw;
--index-width: 40rem;
--close-cursor: url(/assets/images/close-cursor.png), crosshair;
}
body {
font-family: var(--main-font);
font-size: var(--font-size-S);
margin: var(--body-margin);
top: 0;
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
main {
grid-template-columns: 8;
}
a {
color: var(--text-color);
}
h1 {
@ -14,43 +73,287 @@ h1 {
margin: 0;
}
a {
color: var(--text-color);
p {
/*! padding: var(--margin-S); */
box-sizing: border-box;
margin: 0;
width: 50rem;
max-width: 100%;
}
/* menu */
p + p {
/*! text-indent: var(--indentation); */
}
menu {
ul {
list-style: none;
margin: 0;
padding: 0;
list-style: none;
margin: 0;
}
menu li a {
[data-template="infos"] p:first-of-type {
margin-top: var(--line-height-S);
}
#slideshow {
inset: 0;
position: absolute;
z-index: 0;
}
.projects-index summary {
cursor: pointer;
}
nav.filter-menu {
display: flex;
opacity: 1;
position: relative;
font-size: var(--font-size-L);
list-style: none;
pointer-events: all;
gap: calc(2 * var(--body-margin));
margin: calc(4 * var(--line-height-S)) 0 var(--line-height-S) 0;
}
nav.filter-menu a {
text-decoration: none;
text-transform: initial;
}
[data-template="home"] menu li .menu-item-home {
text-decoration: underline;
/* PROJECT SLIDESHOW */
.project-slideshow {
position: fixed;
right: 0;
top: 0;
/*! width: calc(50vw - var(--body-margin)); */
height: fit-content;
z-index: 0;
overflow: hidden;
box-sizing: border-box;
margin: var(--body-margin) var(--body-margin) var(--body-margin) 0;
left: calc(var(--index-width) + var(--body-margin));
text-align: right;
}
.projects menu li .menu-item-projects {
text-decoration: underline;
button {
background-color: transparent;
}
.about menu li .menu-item-about {
text-decoration: underline;
button.prev {
position: absolute;
top: 0;
height: 100%;
border: none;
cursor: w-resize;
z-index: 1;
width: 50%;
left: 0;
padding: 0;
}
button.next {
position: absolute;
top: 0;
right: 0;
height: 100%;
border: none;
cursor: e-resize;
z-index: 1;
width: 50%;
padding: 0;
}
.project-slideshow img {
max-width: 100%;
max-height: calc(100vh - var(--body-margin) * 2);
text-align:;
vertical-align: bottom;
}
.project-slideshow img:not(.active) {
display: none;
}
/* PROJECT TOGGLE */
.fix {
width: 100%;
z-index: 1;
position: relative;
/*! margin-top: var(--line-height-S); */
display: grid;
grid-template-columns: var(--index-width) auto;
pointer-events: none;
}
.fix:hover .slide-number {
display: block;
}
.toggle {
display: none;
/*! margin-bottom: var(--line-height-S); */
}
.fix:hover + .toggle {
display: block;
}
.fix .date {
text-align: right;
}
.toggle p {
z-index: 1;
position: relative;
width: calc(3 / 6 * var(--index-width) - var(--body-margin));
display: none;
}
.project-closer {
display: none;
}
.selected .project-closer {
display: block;
}
.unselected {
opacity: var(--low-opacity);
}
.unselected:hover {
opacity: 1;
}
.unselected:hover .toggle {
display: none;
}
.selected {
opacity: 1;
}
.selected .toggle {
display: grid;
grid-template-columns:
calc(3 / 6 * var(--index-width) - var(--body-margin))
calc(3 / 6 * var(--index-width));
gap: var(--body-margin);
}
.selected .toggle p {
display: block;
}
.unselected .toggle {
display: none;
}
.slide-number {
text-align: right;
display: none;
}
.selected .slide-number {
display: block;
}
.project-toggler.grid {
display: grid;
grid-template-columns:
calc(3 / 6 * var(--index-width) - var(--body-margin))
calc(2 / 6 * var(--index-width) - var(--body-margin)) calc(
1 / 6 * var(--index-width) - var(--body-margin)
);
gap: var(--body-margin);
pointer-events: all;
padding-bottom: var(--line-height-S);
}
.project-description {
margin-bottom: var(--line-height-S);
display: none;
}
.selected .project-description {
display: block;
}
.project-toggler.closer {
cursor: var(--close-cursor);
display: none;
}
.selected .project-toggler.closer {
display: block;
}
.all-projects-closer {
position: fixed;
height: 100%;
width: var(--index-width);
cursor: var(--close-cursor);
display: none;
}
.selected + .all-projects-closer {
display: block;
}
.unselected + .all-projects-closer {
display: block;
}
/* HOME SLIDESHOW */
#home-slideshow {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#home-slideshow img {
display: none;
width: 100%;
height: 100%;
object-fit: cover;
}
#home-slideshow img:first-child {
display: block;
}
/* HOME */
[data-template="home"] h1 {
font-size: var(--font-size-L);
.main-infos {
width: calc(3 / 4 * var(--index-width));
position: relative;
float: left;
}
/* PROJECTS */
.skills {
width: calc(2 / 4 * var(--index-width));
position: relative;
float: left;
}
/* ABOUT */
.clients {
width: calc(2 / 4 * var(--index-width));
position: relative;
float: left;
}
/* INFOS */
[data-template="infos"] div {
padding-right: var(--body-margin);
}
[data-template="infos"] main {
position: absolute;
top: calc(var(--line-height-S) + 0.35rem);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="14.168749mm"
height="14.168741mm"
viewBox="0 0 14.168749 14.168741"
version="1.1"
id="svg1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm">
<inkscape:page
x="0"
y="0"
width="14.168749"
height="14.168741"
id="page2"
margin="0"
bleed="0" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-97.91562,-141.41563)">
<g
id="g2">
<path
style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 98.009168,141.50917 13.981662,13.98166"
id="path1" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 111.99083,141.50917 98.009172,155.49083"
id="path2" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,25 @@
document.querySelectorAll(".project-slideshow").forEach((slideshow) => {
function goToNextSlide() {
const currentSlide = document.querySelector(".project-images .active");
const slideToShow = currentSlide.nextElementSibling
? currentSlide.nextElementSibling
: document.querySelector(".project-images img");
currentSlide.classList.toggle("active");
slideToShow.classList.toggle("active");
}
const images = slideshow.querySelector(".project-images");
const prevButton = slideshow.querySelector(".prev");
const nextButton = slideshow.querySelector(".next");
nextButton.addEventListener("click", () => {
goToNextSlide();
});
prevButton.addEventListener("click", () => {
currentIndex =
(currentIndex - 1 + images.children.length) % images.children.length;
goToPrevSlide();
});
});

View file

@ -0,0 +1,36 @@
const allProjects = document.querySelectorAll(".projects-index li");
allProjects.forEach((project) => {
project.addEventListener("click", () => {
allProjects.forEach((unselected) => {
unselected.classList.add("unselected");
unselected.classList.remove("selected");
});
project.classList.add("selected");
project.classList.remove("unselected");
});
});
const projectTogglers = document.querySelectorAll(".project-toggler");
projectTogglers.forEach((button) => {
button.addEventListener("click", (event) => {
const parentLi = button.closest("li");
if (parentLi.classList.contains("selected")) {
event.stopPropagation();
allProjects.forEach((project) => {
project.classList.remove("unselected");
parentLi.classList.remove("selected");
});
}
});
});
const allProjectsCloser = document.querySelector(".all-projects-closer");
allProjectsCloser.addEventListener("click", (event) => {
allProjects.forEach((project) => {
project.classList.remove("selected");
project.classList.remove("unselected");
});
});

View file

@ -1,9 +0,0 @@
label: Projets
type: pages
layout: cards
template: project
search: true
info: "tags: {{ page.tags }} --------- {{ page.date.toDate('d/m/Y') }}"
sortBy: date desc
image:
ratio: 12/9

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,3 @@
title: Slideshow files
accept:
extension: jpg, png, webp, svg, gif, avif, mp4, mov, avi, wmv, flv, 3gp, webm

View file

@ -1,7 +0,0 @@
sections:
Fields:
type: fields
fields:
presentation:
label: Presentation
type: writer

View file

@ -1,5 +1,4 @@
sections:
Carroussel:
type: fields
fields:
@ -7,8 +6,5 @@ sections:
type: files
label: Images
layout: cards
accept:
- image/jpg
- image/png
- image/svg
- image/webp
uploads:
template: slideshow-files

View file

@ -0,0 +1,28 @@
title: Index
status:
unlisted:
label: Non listé
text: La page est accessible uniquement par son URL
options:
move: false
duplicate: false
delete: false
changeStatus: false
tabs:
projects:
label: Projets
icon: bars
sections:
projects:
type: pages
layout: cards
template: projet
search: true
info: "{{ page.categorie }}, {{ page.date.toDate('Y') }}"
sortBy: date desc
image:
ratio: 12/9
files: tabs/files
seo:
icon: search

View file

@ -0,0 +1,18 @@
label: À propos
icon: info
sections:
Fields:
type: fields
fields:
presentation:
label: Presentation
type: writer
contact:
label: Contact
type: writer
skills:
label: Compétences
type: writer
clients:
label: Clients
type: writer

View file

@ -1,18 +0,0 @@
sections:
Fields:
type: fields
fields:
date:
label: Date
type: date
tags:
label: project tags
type: tags
options:
- tag test 1
- tag test 2
- tag test 3
description:
label: description
type: writer

View file

@ -1,20 +0,0 @@
title: Projets
status:
unlisted:
label: Non listé
text: La page est accessible uniquement par son URL
options:
move: false
duplicate: false
delete: false
changeStatus: false
tabs:
content:
label: Contenu
icon: bars
sections:
projects: fields/projects
files: tabs/files
seo:
icon: search

View file

@ -0,0 +1,43 @@
columns:
- width: 1/3
fields:
shownTitle:
label: Titre affiché
type: writer
help: Le titre à afficher (il est possible de mettre le titre ou une partie en italique ou en exposant en sélectionnat du texte)
marks:
- italic
- sup
nodes: false
category:
label: Catégorie
type: tags
icon: folder
help: Sélectionner une ou plusieurs catégories, ou en créer de nouvelles
options:
type: query
query: page.siblings.pluck("category", ",", true)
date:
label: Date
type: date
tags:
label: Tags
type: tags
help: Sélectionner un ou plusieurs tags, ou en créer de nouveaux
options:
type: query
query: page.siblings.pluck("tags", ",", true)
- width: 2/3
fields:
slideshow:
type: files
min: 1
layout: cardlets
image:
ratio: 16/9
back: transparent
uploads:
template: slideshow-files
description:
label: Description
type: writer

View file

@ -1,17 +1,12 @@
title: Site
tabs:
dashboard:
label: Tableau de bord
icon: star
sections:
slideshowSection:
type: fields
fields:
slideshow:
label: Carrousel
type: files
projects:
extends: fields/projects
parent: page('projets')
files: tabs/files
content:
fields:
slideshow:
type: files
label: Carroussel
layout: cards
image:
back: transparent
uploads:
template: slideshow-files

View file

@ -2,5 +2,8 @@
return [
'debug'=> true,
'home' => 'projets'
'panel' => [
'menu' => require_once __DIR__ . '/menu.php',
'home' => 'pages/home',
],
];

20
site/config/menu.php Normal file
View file

@ -0,0 +1,20 @@
<?php
return [
'site' => [
'label' => 'Accueil',
],
'index' => [
'icon' => 'list-bullet',
'label' => 'Index',
'link' => 'pages/index',
],
'about' => [
'icon' => 'info',
'label' => 'Infos',
'link' => 'pages/infos',
],
'-',
'users',
'system'
];

View file

@ -0,0 +1,33 @@
<?php
return function($page) {
function array_flatten($array) {
if (!is_array($array)) {
return false;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, array_flatten($value));
} else {
$result = array_merge($result, array($key => $value));
}
}
return $result;
}
function getSingleCategories($pages) {
$categoriesRawFields = $pages->pluck('category'); // return ["A, B, C", "A, B"]
$splittedCategoriesFields = array_map(function($field) {
return explode(',', $field);
}, $categoriesRawFields); // return [["A", "B", "C",], ["A", "B"]]
$flattenedCategories = array_flatten($splittedCategoriesFields);
$filters = array_unique($flattenedCategories);
return $filters;
}
return [
'categories' => getSingleCategories($page->children())
];
};

View file

@ -5,9 +5,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="/assets/css/style.css">
<link rel="stylesheet" href="/assets/css/nav.css">
<link rel="stylesheet" href="/assets/css/reset.css">
<link rel="stylesheet" href="/assets/css/mobile.css">
</head>
<body data-template="<?= $page->intendedTemplate() ?>">
<?= snippet('nav') ?>
<header>
<?= snippet('nav') ?>
</header>
<main>

View file

@ -1,21 +1,21 @@
<header>
<nav>
<ul>
<li>
<a class="menu-item-home" href="<?= page('home')->url() ?>">
<?= page('home')->title() ?>
</a>
</li>
<li>
<a class="menu-item-projects" href="<?= page('projets')->url() ?>">
<?= page('projets')->title() ?>
</a>
</li>
<li>
<a class="menu-item-about" href="<?= page('about')->url() ?>">
<?= page('about')->title() ?>
</a>
</li>
</ul>
</nav>
</header>
<h1 class="main-title">
<a href="<?= $site->url() ?>"><span>H</span>ic et <span>N</span>unc <span>S</span>tudio</a>
</h1>
<nav class="main-menu">
<h1 class="title-nav">
<a href="<?= page('home')->url() ?>">
<span>Hic&nbsp;et&nbsp;Nunc&nbsp;Studio</span>
</a>
</h1>
<ul>
<li>
<a class="nav-item-home" href="<?= page('home')->url() ?>"><?= page('home')->title() ?></a>,&nbsp;
</li>
<li>
<a class="nav-item-projects" href="<?= page('index')->url() ?>"><?= page('index')->title() ?></a>,&nbsp;
</li>
<li>
<a class="nav-item-about" href="<?= page('infos')->url() ?>"><?= page('infos')->title() ?></a>
</li>
</ul>
</nav>

View file

@ -1,5 +0,0 @@
<?php snippet('header') ?>
<h1><?= $site->title() ?></h1>
<?php snippet('footer') ?>

View file

@ -1,8 +1,12 @@
<?php snippet('header') ?>
<h1><?= $site->title() ?></h1>
<?php foreach ($site->slideshow()->toFiles() as $image): ?>
<img src="<?= $image->url() ?>">
<?php endforeach; ?>
<div id="home-slideshow">
<?php foreach ($site->images() as $image): ?>
<img src="<?= $image->url() ?>">
<?php endforeach; ?>
<button class="prev"></button>
<button class="next"></button>
<div>
<?php snippet('footer') ?>

38
site/templates/index.php Normal file
View file

@ -0,0 +1,38 @@
<?php snippet('header') ?>
<nav class="filter-menu">
<?php foreach ($categories as $key => $category): ?>
<a href=""><?= $category ?></a>
<?php endforeach; ?>
</nav>
<ul class="projects-index">
<?php foreach ($page->children()->listed()->sortBy('date', 'desc') as $project): ?>
<li>
<div class="fix">
<button class="project-toggler grid">
<span> <?= $project->shownTitle() ?> </span>
<span> <?= $project->tags() ?> </span>
<span class="date"> <?= $project->date()->toDate('Y') ?> </span>
</button>
<span class="slide-number">slide number/total slides</span>
</div>
<section class="toggle">
<div class="project-slideshow">
<?php foreach ($project->images() as $image): ?>
<img <?= e($image->indexOf() === 0, 'class="active"') ?> src="<?= $image->url() ?>">
<?php endforeach; ?>
<button class="prev"></button>
<button class="next"></button>
</div>
<div class="project-description"><?= $project->description() ?></div>
<button class="project-toggler closer"></button>
</section>
</li>
<?php endforeach; ?>
<button class="all-projects-closer"></button>
</ul>
<script src="/assets/js/project-slideshow.js"></script>
<script src="/assets/js/project-toggle.js"></script>
<?php snippet('footer') ?>

24
site/templates/infos.php Normal file
View file

@ -0,0 +1,24 @@
<?php snippet('header') ?>
<div class="main-infos">
<p>
<?= $page->presentation() ?>
<br>
<?= $page->contact() ?>
</p>
</div>
<div class="skills">
<p>
<?= $page->skills() ?>
</p>
</div>
<div class="clients">
<p class="clients">
<?= $page->clients() ?>
</p>
</div>
<?php snippet('footer') ?>

View file

@ -1,22 +0,0 @@
<?php snippet('header') ?>
<ul class="projects-index">
<?php foreach ($page->children()->listed()->sortBy('date', 'desc') as $project): ?>
<li>
<details>
<summary>
<span> <?= $project->title() ?> </span>
<span> <?= $project->tags() ?> </span>
<span> <?= $project->date() ?> </span>
</summary>
<p><?= $project->description() ?></p>
</details>
</li>
<?php endforeach; ?>
</ul>
<?php snippet('footer') ?>