feat: ✨ add projects card and routes
This commit is contained in:
parent
996b622b38
commit
972a84f241
66
components/ProjectCard.css
Normal file
66
components/ProjectCard.css
Normal 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;
|
||||||
|
}
|
93
components/ProjectCard.tsx
Normal file
93
components/ProjectCard.tsx
Normal 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'}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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
12
routes/projets/[id].tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Reference in a new issue