158 lines
3.5 KiB
TypeScript
158 lines
3.5 KiB
TypeScript
|
import { Markdown } from ':components/Markdown.tsx'
|
||
|
import { NewsFrontMatter } from ':src/blog/types.ts'
|
||
|
|
||
|
export type BlogProps = {
|
||
|
title: string
|
||
|
description: string
|
||
|
body: string
|
||
|
author: string
|
||
|
publisher: string
|
||
|
lastUpdate: Date
|
||
|
name: string
|
||
|
url: string
|
||
|
hash: string
|
||
|
options: NewsFrontMatter['x-cohabit']
|
||
|
tags: NewsFrontMatter['tags']
|
||
|
}
|
||
|
|
||
|
export function BlogCard(
|
||
|
{ title, description, author, lastUpdate, name, options, tags, publisher }:
|
||
|
BlogProps,
|
||
|
) {
|
||
|
return (
|
||
|
<div
|
||
|
class='components__blog_block components__blog_block--card'
|
||
|
style={{ backgroundImage: `url(${options.thumbnail})` }}
|
||
|
>
|
||
|
<div class='components__blog_block__spacer'></div>
|
||
|
<h3>
|
||
|
<a href={`/blog/${name}`}>{title}</a>
|
||
|
</h3>
|
||
|
<NewsLinks links={options.links} />
|
||
|
<NewsTags tags={tags} />
|
||
|
<span class='components__blog_block__publisher'>
|
||
|
{`@${publisher}`}
|
||
|
</span>
|
||
|
<NewsStatus status={options.status} />
|
||
|
<div class='components__blog_block__description'>
|
||
|
{description}
|
||
|
</div>
|
||
|
<NewsFooter author={author} lastUpdate={lastUpdate} />
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
export function BlogPost(
|
||
|
{
|
||
|
title,
|
||
|
description,
|
||
|
author,
|
||
|
lastUpdate,
|
||
|
body,
|
||
|
url,
|
||
|
options,
|
||
|
tags,
|
||
|
publisher,
|
||
|
}: BlogProps,
|
||
|
) {
|
||
|
return (
|
||
|
<div class='components__blog_block--post'>
|
||
|
<h1>{title}</h1>
|
||
|
<div class='components__blog_post__infos'>
|
||
|
<span class='components__blog_block__publisher'>
|
||
|
{`@${publisher}`}
|
||
|
</span>
|
||
|
<NewsStatus status={options.status} long />
|
||
|
<NewsLinks links={options.links} />
|
||
|
<NewsTags tags={tags} />
|
||
|
</div>
|
||
|
<div class='components__blog_post__infos'>
|
||
|
<span>{`Visibilité : ${options.visibility}`}</span>
|
||
|
<span>
|
||
|
{`Date de délivrance : ${
|
||
|
new Date(options.dueDate).toLocaleString()
|
||
|
}`}
|
||
|
</span>
|
||
|
</div>
|
||
|
<div class='components__blog_post__description'>
|
||
|
{description}
|
||
|
</div>
|
||
|
<div class='components__blog_post__body'>
|
||
|
<Markdown options={{ allowMath: true, baseUrl: url }}>
|
||
|
{body}
|
||
|
</Markdown>
|
||
|
</div>
|
||
|
<NewsFooter author={author} lastUpdate={lastUpdate} />
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function NewsTags({ tags }: Pick<BlogProps, 'tags'>) {
|
||
|
return (
|
||
|
<div class='components__blog_block__tags'>
|
||
|
{tags
|
||
|
? tags.map((tag) => <span>{tag}</span>)
|
||
|
: <span>Aucun tag</span>}
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function NewsFooter(
|
||
|
{ author, lastUpdate }: Pick<BlogProps, 'author' | 'lastUpdate'>,
|
||
|
) {
|
||
|
return (
|
||
|
<div class='components__blog_block__footer'>
|
||
|
<div>
|
||
|
<i class='ri-quill-pen-line'></i>
|
||
|
<span>{author}</span>
|
||
|
</div>
|
||
|
<div>
|
||
|
<i class='ri-refresh-line'></i>
|
||
|
<span>{lastUpdate.toLocaleDateString()}</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function NewsLinks({ links }: Pick<BlogProps['options'], 'links'>) {
|
||
|
return (
|
||
|
<div class='components__blog_block__links'>
|
||
|
{links
|
||
|
? links.flatMap(Object.entries).map((
|
||
|
[name, link],
|
||
|
) => <a href={link} target='_blank' title={name}>{name}</a>)
|
||
|
: <span>Aucun lien rapide</span>}
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function NewsStatus(
|
||
|
{ status, long = false }: Pick<BlogProps['options'], 'status'> & {
|
||
|
long?: boolean
|
||
|
},
|
||
|
) {
|
||
|
const title = status === 'canceled'
|
||
|
? 'Annulé'
|
||
|
: status === 'current'
|
||
|
? 'En cours'
|
||
|
: status === 'finished'
|
||
|
? 'Terminé'
|
||
|
: 'Prévu'
|
||
|
|
||
|
return (
|
||
|
<span
|
||
|
class='components__blog_block__status'
|
||
|
title={title}
|
||
|
>
|
||
|
{status === 'canceled'
|
||
|
? <i class='ri-calendar-close-line'></i>
|
||
|
: status === 'current'
|
||
|
? <i class='ri-calendar-2-line'></i>
|
||
|
: status === 'finished'
|
||
|
? <i class='ri-calendar-check-line'></i>
|
||
|
: <i class='ri-calendar-2-line'></i>}
|
||
|
{long ? ` ${title}` : ''}
|
||
|
</span>
|
||
|
)
|
||
|
}
|