feat: add projects card and routes

This commit is contained in:
Julien Oculi 2024-02-15 12:50:40 +01:00
parent 996b622b38
commit 972a84f241
6 changed files with 186 additions and 3 deletions

View file

@ -0,0 +1,66 @@
.components__project_card {
min-width: 30rem;
aspect-ratio: 2 / 1;
display: grid;
grid-template-columns: 1fr 2fr;
padding: var(--_gap-half);
gap: var(--_gap);
box-shadow: 0 0 0.4rem 0.2rem var(--_translucent);
border: var(--_border-size) solid transparent;
&:has(a:focus-visible),
&:hover {
border: var(--_border-size) solid var(--_accent-color);
}
& h3 {
margin: 0;
}
& a {
outline: none;
text-decoration: none;
background-color: var(--_accent-color);
padding: var(--_gap-half);
color: var(--_background-color);
border: var(--_border-size) solid var(--_accent-color);
&:hover,
&:focus-visible {
color: var(--_accent-color);
background-color: var(--_background-color);
}
}
}
.components__project_card__icon {
height: 100%;
object-fit: cover;
overflow: hidden;
}
.components__project_card__content {
display: flex;
flex-direction: column;
}
.components__project_card__state {
padding: var(--_gap-half);
font-weight: bold;
}
.components__project_card__tags {
display: flex;
flex-wrap: wrap;
gap: var(--_gap-half);
& span {
padding: var(--_gap-half);
background-color: var(--_translucent);
}
}
.components__project_card__summary {
text-wrap: balance;
flex-grow: 1;
}

View file

@ -0,0 +1,93 @@
import { JSX } from 'preact'
type ProjectCardProps = {
id: string
icon: string
title: string
summary: string
tags: string[]
state: 'complete' | 'progress' | 'stale' | 'pending'
}
export function ProjectCard(
{ id, icon, title, summary, tags, state }: ProjectCardProps,
) {
return (
<div class='components__project_card'>
<img src={icon} class='components__project_card__icon' />
<div class='components__project_card__content'>
<h3>{title}</h3>
<span class='components__project_card__state'>
{toStateSpan(state)}
</span>
<div class='components__project_card__tags'>
{tags.map((tag) => <span>{tag}</span>)}
</div>
<div class='components__project_card__summary'>
{`${summary.slice(0, 150)} ...`}
</div>
<a href={`/projets/${id}`}>
{state === 'complete' ? 'En savoir plus' : 'Participer'}
</a>
</div>
</div>
)
}
const summary =
'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Qui, perferendis enim blanditiis consequatur at porro quod, eligendi alias recusandae modi aliquam non? Quos voluptates quisquam provident animi nisi in ratione.'
export const projectMock: ProjectCardProps[] = Array(50).fill(undefined).map(
(_, index) => {
return {
//
title: `Awesome project ${index}`,
summary,
tags: ['3D', 'électronique', 'informatique'],
state: randomState(),
icon: `https://picsum.photos/id/${index + 20}/300`,
id: String(index),
}
},
)
function randomState(): ProjectCardProps['state'] {
const rand = Math.random()
if (rand > 3 / 4) return 'complete'
if (rand > 2 / 4) return 'progress'
if (rand > 1 / 4) return 'stale'
return 'pending'
}
function toStateSpan(state: ProjectCardProps['state']): JSX.Element {
if (state === 'complete') {
return (
<>
<i class='ri-checkbox-circle-line'></i>
{' Terminé'}
</>
)
}
if (state === 'pending') {
return (
<>
<i class='ri-error-warning-line'></i>
{' Non démarré'}
</>
)
}
if (state === 'progress') {
return (
<>
<i class='ri-play-circle-line'></i>
{' En cours'}
</>
)
}
return (
<>
<i class='ri-pause-circle-line'></i>
{' En pause'}
</>
)
}

View file

@ -3,6 +3,7 @@ import { BlogCard, blogMock } from '../components/BlogCard.tsx'
import { CohabitInfoTable } from '../components/CohabitInfoTable.tsx' import { CohabitInfoTable } from '../components/CohabitInfoTable.tsx'
import { Heros } from '../components/Heros.tsx' import { Heros } from '../components/Heros.tsx'
import { MachineCard, machineMock } from '../components/MachineCard.tsx' import { MachineCard, machineMock } from '../components/MachineCard.tsx'
import { ProjectCard, projectMock } from '../components/ProjectCard.tsx'
import { SponsorCards } from '../components/SponsorCards.tsx' import { SponsorCards } from '../components/SponsorCards.tsx'
export default function Home() { export default function Home() {

12
routes/projets/[id].tsx Normal file
View file

@ -0,0 +1,12 @@
import { PageProps } from '$fresh/server.ts'
import { ProjectCard, projectMock } from '../../components/ProjectCard.tsx'
export default function Projets({ params }: PageProps) {
const Projets = projectMock.at(Number(params.id))
return (
Projets
? ProjectCard(Projets)
: <h3>Projets inconnu, peut être un futur</h3>
)
}

View file

@ -1,8 +1,18 @@
export default function Machines() { import { ProjectCard, projectMock } from '../../components/ProjectCard.tsx'
export default function Project() {
return ( return (
<> <>
<h1>Nos projets</h1> <h1>Nos Projets</h1>
<section></section> <section
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(30rem, 1fr));',
gap: 'var(--_gap)',
}}
>
{projectMock.map(ProjectCard)}
</section>
</> </>
) )
} }

View file

@ -5,5 +5,6 @@
@import url('../../components/CohabitInfoTable.css'); @import url('../../components/CohabitInfoTable.css');
@import url('../../components/BlogCard.css'); @import url('../../components/BlogCard.css');
@import url('../../components/MachineCard.css'); @import url('../../components/MachineCard.css');
@import url('../../components/ProjectCard.css');
@import url('../../islands/ThemePicker.css'); @import url('../../islands/ThemePicker.css');
@import url('../../islands/SearchBox.css'); @import url('../../islands/SearchBox.css');