1
0

Added almost everything needed to browse the website

This commit is contained in:
Richard Dern 2024-04-23 23:55:48 +02:00
parent d02e0a8602
commit acb0a153f3
44 changed files with 1215 additions and 53 deletions

View File

@ -171,10 +171,19 @@ private function fetchIsDead()
foreach (['head', 'get'] as $method) { foreach (['head', 'get'] as $method) {
try { try {
if (Http::throw()->{$method}($this->url)->ok()) { $result = Http::{$method}($this->url);
if ($result->ok()) {
$isDead = false; $isDead = false;
break; break;
} }
if ($result->status() === 403) {
$isDead = false;
break;
}
$reason = strval($result->status());
} catch (Exception $ex) { } catch (Exception $ex) {
$reason = $ex->getMessage(); $reason = $ex->getMessage();
} }
@ -271,6 +280,11 @@ private function fetchTitle(): string
$this->checked()->format('d/m/Y'), $this->checked()->format('d/m/Y'),
$this->reason() $this->reason()
); );
} else {
$title .= sprintf(
' (vérifié le %s) ',
$this->checked()->format('d/m/Y')
);
} }
$title .= sprintf(' : %s', $this->url); $title .= sprintf(' : %s', $this->url);

View File

@ -9,7 +9,7 @@ class ListItem implements ModifierInterface
{ {
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
$image->coverDown(720, 400); $image->coverDown(600, 400);
return $image; return $image;
} }

View File

@ -25,9 +25,9 @@ public function __construct(protected Bundle $bundle)
*/ */
public function renderCard() public function renderCard()
{ {
return view('article-card', [ $this->prepareRenderCard();
'bundle' => $this->bundle,
]); return view('article-card', $this->viewData);
} }
/** /**
@ -64,6 +64,28 @@ protected function prepareRender()
$this->handlePagination(); $this->handlePagination();
} }
/**
* Renders a HTML card view of the bundle
*/
protected function prepareRenderCard()
{
$coverRef = $this->bundle->metadata()->get('cover');
$cover = null;
if (!empty($coverRef)) {
$cover = $this->bundle->attachments(AttachmentsManager::Images)->getComponentByRef($coverRef, 'listitem', ['nolink' => true]);
}
$date = $this->bundle->metadata()->get('date');
if (!empty($date)) {
data_set($this->viewData, 'date', Carbon::parse($date));
}
data_set($this->viewData, 'cover', $cover ? $cover->render() : null);
data_set($this->viewData, 'section', $this->bundle->getSection());
}
/** /**
* Pre-fill view with data used by all renderers * Pre-fill view with data used by all renderers
*/ */

View File

@ -21,6 +21,8 @@ class Linter
*/ */
private $phraseEndingChars = ['.', '!', '?']; private $phraseEndingChars = ['.', '!', '?'];
private $htmlPlaceholders = [];
/** /**
* Constructor takes markdown content and prepares it for formatting. * Constructor takes markdown content and prepares it for formatting.
* *
@ -38,6 +40,9 @@ public function __construct(?string $markdown = '')
*/ */
public function format(): string public function format(): string
{ {
return $this->markdown;
$this->markdown = $this->replaceHtmlWithPlaceholders($this->markdown);
if (empty($this->markdown)) { if (empty($this->markdown)) {
return $this->markdown; return $this->markdown;
} }
@ -50,14 +55,30 @@ public function format(): string
return $this->formatBlock($block, $type); return $this->formatBlock($block, $type);
}, $blocks); }, $blocks);
return implode("\n\n", $processedBlocks); $result = implode("\n\n", $processedBlocks);
$result = $this->restoreHtmlFromPlaceholders($result);
return $result;
}
private function restoreHtmlFromPlaceholders($text)
{
return str_replace(array_keys($this->htmlPlaceholders), array_values($this->htmlPlaceholders), $text);
}
private function replaceHtmlWithPlaceholders($text)
{
$index = 0;
return preg_replace_callback('/<([a-zA-Z0-9\-]+)([^>]*)>(.*?)<\/\1>/s', function ($matches) use (&$index) {
$placeholder = "<!-- html-placeholder-{$index} -->";
$this->htmlPlaceholders[$placeholder] = $matches[0]; // Store the whole match
$index++;
return $placeholder;
}, $text);
} }
/**
* Segment the markdown into blocks based on empty lines, respecting code blocks and multi-line HTML.
*
* @return array Array of blocks, each containing markdown content.
*/
private function segmentMarkdown(): array private function segmentMarkdown(): array
{ {
$blocks = []; $blocks = [];
@ -116,10 +137,6 @@ private function determineBlockType(string $block): string
return 'code'; return 'code';
} }
if (preg_match('/^\s*<[^>]+>/', trim($block))) {
return 'html';
}
if (preg_match('/^\s*#/', trim($block))) { if (preg_match('/^\s*#/', trim($block))) {
return 'header'; return 'header';
} }
@ -160,8 +177,6 @@ private function formatBlock(string $block, string $type): string
switch ($type) { switch ($type) {
case 'code': case 'code':
return $this->formatCodeBlock($block); return $this->formatCodeBlock($block);
case 'html':
return $this->formatHtmlBlock($block);
case 'header': case 'header':
return $this->formatHeaderBlock($block); return $this->formatHeaderBlock($block);
case 'table': case 'table':
@ -195,12 +210,6 @@ private function formatCodeBlock(string $block): string
return implode("\n", $lines); return implode("\n", $lines);
} }
private function formatHtmlBlock(string $block): string
{
// HTML-specific formatting
return $block;
}
private function formatFootnoteBlock(string $block): string private function formatFootnoteBlock(string $block): string
{ {
// HTML-specific formatting // HTML-specific formatting
@ -215,7 +224,7 @@ private function formatHeaderBlock(string $block): string
private function formatTableBlock(string $block): string private function formatTableBlock(string $block): string
{ {
// HTML-specific formatting // Table formatting
return $block; return $block;
} }

View File

@ -0,0 +1,26 @@
<?php
namespace App\View\Components\Chat;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Me extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.chat.me');
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\View\Components\Chat;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Other extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.chat.other');
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Pagination extends Component
{
/**
* Create a new component instance.
*/
public function __construct(protected array $data)
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.pagination', [
'data' => $this->data,
]);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Paginator extends Component
{
/**
* Create a new component instance.
*/
public function __construct(protected array $data)
{
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.paginator', $this->data);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\View\Components;
use App\Classes\Bundle;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\Component;
class ReadMore extends Component
{
protected $bundles;
/**
* Create a new component instance.
*/
public function __construct(public string|array $urls, public ?string $title = 'Pour en savoir plus')
{
if (is_string($this->urls)) {
$this->urls = [$this->urls];
}
$bundles = [];
foreach ($urls as $url) {
$bundles[] = new Bundle($url, Storage::disk(env('CONTENT_DISK')));
}
$this->bundles = $bundles;
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.read-more', [
'bundles' => $this->bundles,
]);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class SiteFooter extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.site-footer');
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class SiteHeader extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.site-header');
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Spoiler extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.spoiler');
}
}

View File

@ -48,7 +48,7 @@
'apply_id_to_heading' => false, 'apply_id_to_heading' => false,
'heading_class' => '', 'heading_class' => '',
'fragment_prefix' => '', 'fragment_prefix' => '',
'insert' => 'before', 'insert' => 'after',
'min_heading_level' => 2, 'min_heading_level' => 2,
'max_heading_level' => 6, 'max_heading_level' => 6,
'title' => 'Lien direct', 'title' => 'Lien direct',

5
config/pagination.php Normal file
View File

@ -0,0 +1,5 @@
<?php
return [
'itemsPerPage' => 12,
];

View File

@ -1,2 +1,35 @@
* { @import "@fontsource/quicksand";
@import "reset";
@import "utilities";
@import "links";
@import "site-header";
@import "figure";
@import "article-main";
@import "chat";
@import "footnotes";
@import "details";
@import "tables";
@import "article-list";
@import "paginator";
@import "drop";
@import "site-footer";
@import "form";
:root {
--body-width: 800px;
--design-width: calc(800px + 4rem);
}
html,
body {
width: 100vw;
height: 100vh;
background-color: #030712;
color: #e4f1fe;
}
body {
font-family: "Quicksand";
margin: auto;
font-size: 24px;
} }

View File

@ -0,0 +1,99 @@
.article-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
width: 100%;
margin: auto;
padding: 1rem;
gap: 2rem;
.article-card-link {
text-decoration: none;
border: solid 2px #00101f;
border-radius: .5em;
color: #6c7a89;
box-shadow: 0 1px 1rem #000;
background: #01010c radial-gradient(at bottom center, #00101f, #000614, #01010c) no-repeat;
.article-card {
font-size: 1rem;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 100%;
figure {
width: 100%;
margin: 0;
img {
border-radius: .5rem .5rem 0 0;
}
}
h2 {
text-align: center;
color: #a8b4bd;
flex-grow: 1;
align-content: center;
margin: .5rem;
}
&:hover {
h2 {
color: #fff;
}
}
.article-card-body {
text-align: center;
margin-bottom: .5rem;
}
}
&:hover {
box-shadow: 0 1px 1em #021127;
border: solid 2px #021127;
figure {
img {
opacity: 1;
}
}
}
.ribbon {
position: absolute;
top: 0;
right: 0;
padding: 5px 10px;
font-size: 0.5em;
border-top-right-radius: 1em;
border-bottom-left-radius: 1em;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
&.sponsored {
background-color: #4a5568;
color: #ffffff;
}
&.dead {
background-color: #ff0000;
color: #ffffff;
font-weight: bold;
}
}
}
}
@media only screen and (max-width: 799px) {
.article-list {
grid-template-columns: repeat(2, 1fr);
}
}
@media only screen and (max-width: 399px) {
.article-list {
grid-template-columns: repeat(1, 1fr);
}
}

View File

@ -0,0 +1,190 @@
#article-main {
margin: auto;
padding: 1rem 0;
line-height: 175%;
> header {
margin: auto;
text-align: center;
color: #6c7a89;
h1 {
font-size: 2.5rem;
color: #fff;
line-height: 125%;
padding: 0 1em;
}
}
> #article-body {
margin-top: 2rem;
}
> #article-body,
.markdown-body {
display: flex;
flex-direction: column;
gap: 1.5rem;
.table-of-contents {
margin: 2rem auto;
line-height: 150%;
width: var(--design-width);
font-size: .8em;
ol {
padding-left: 1rem;
}
li + li {
margin: 0;
}
}
blockquote {
border-left: 4px solid #60a5fa;
padding: 0.5rem 1rem;
margin: 1rem auto;
color: #e4f1fe;
background-color: #021127;
text-align: justify;
max-width: var(--design-width);
width: 100%;
border-radius: .5rem;
p + p {
padding-top: 1rem;
}
}
> h2,
> h3,
> h4,
> h5,
> h6 {
width: var(--design-width);
margin: 1rem auto;
text-align: left;
gap: .5rem;
padding-bottom: .2rem;
position: relative;
.heading-permalink {
position: absolute;
top: 0;
right: 0;
font-size: .75rem;
}
}
> h2 {
font-size: 2.25rem;
color: #ff6347;
border-bottom: solid 1px #ff6347;
}
> h3 {
font-size: 2rem;
color: #ff8c00;
border-bottom: solid 1px #ff8c00;
}
> h4 {
font-size: 1.75rem;
color: #ffa500;
border-bottom: dotted 1px #ffa500;
}
> h5 {
font-size: 1.5rem;
color: #ffd700;
}
> h6 {
font-size: 1.25rem;
color: #ffff00;
}
hr {
width: var(--design-width);
border: none;
height: 1px;
background: linear-gradient(to right, #030712 0%, #030712 20%, #1a1f33 50%, #030712 80%, #030712 100%);
margin: 20px 0;
margin: 1em auto;
}
ol,
ul {
max-width: var(--body-width);
width: 100%;
margin: auto;
li {
text-align: justify;
}
li + li {
margin-top: .5em;
}
}
> p {
text-align: justify;
max-width: var(--body-width);
width: 100%;
margin: auto;
}
pre.shiki {
font-size: .8em;
line-height: 150%;
overflow: auto;
border: solid 2px #112;
border-radius: .5rem;
width: var(--design-width);
max-height: 80vh;
margin: 1em auto;
> code {
counter-reset: step;
counter-increment: step 0;
.line::before {
user-select: none;
content: counter(step);
counter-increment: step;
width: 3rem;
margin-right: 1rem;
display: inline-block;
text-align: right;
color: #6c7a89;
padding-left: .5rem;
padding-right: .5rem;
background-color: #112;
}
}
}
:not(pre.shiki):not(h2):not(h3):not(h4):not(h5):not(h6) {
code {
background-color: #000;
color: #aaa;
font-size: .8em;
border: solid 1px #223;
padding: .2rem;
border-radius: .25rem;
}
}
strong {
color: #fff;
font-weight: 900;
}
sup {
line-height: 100%;
margin-left: .2rem;
}
}
}

32
resources/css/chat.css Normal file
View File

@ -0,0 +1,32 @@
.chat {
background-color: #282828;
border: 1px solid #444;
border-radius: 8px;
padding: 10px;
margin: 20px auto;
width: var(--design-width);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
font-size: .8em;
line-height: 125%;
}
.chat-me,
.chat-other {
padding: 8px 12px;
border-radius: 15px;
margin-bottom: 4px;
color: #fff;
display: block;
max-width: 70%;
}
.chat-me {
background-color: #3178c6;
align-self: flex-end;
margin-left: auto;
}
.chat-other {
background-color: #4b5563;
align-self: flex-start;
}

22
resources/css/details.css Normal file
View File

@ -0,0 +1,22 @@
.spoiler {
border-left: 4px solid #d08770;
margin: 1rem auto;
color: #e4f1fe;
background-color: #564d33;
max-width: var(--design-width);
width: 100%;
border-radius: .5rem;
summary {
user-select: none;
cursor: pointer;
display: block;
padding-left: 1rem;
font-weight: bold;
&:hover {
text-decoration: underline;
color: #fff;
}
}
}

79
resources/css/drop.css Normal file
View File

@ -0,0 +1,79 @@
.drop {
padding: 2px 5px;
display: block;
color: #6c7a89;
text-decoration: none;
white-space: nowrap;
position: relative;
summary {
display: block;
cursor: pointer;
user-select: none;
}
summary::-webkit-details-marker {
display: none;
}
summary::after {
margin-left: .5em;
font-family: monospace;
content: '▶';
}
&.down {
summary ~ * {
top: 2em;
}
&[open] {
summary::after {
font-family: monospace;
content: '▼';
}
}
}
&.up {
summary ~ * {
bottom: 2em;
}
&[open] {
summary::after {
font-family: monospace;
content: '▲';
}
}
}
summary ~ * {
z-index: 100;
position: absolute;
border: solid 2px #00101f;
border-radius: .5em;
background: #01010c radial-gradient(at bottom center, #00101f, #000614, #01010c) no-repeat;
box-shadow: 0 1px 1em #000;
max-height: 50vh;
overflow: auto;
left: 30%;
}
nav a {
display: block;
padding: .2em 3em;
color: #6c7a89;
text-decoration: none;
&.selected {
color: orange;
}
&:hover {
color: #fff;
text-decoration: underline;
background: #01010c radial-gradient(at bottom center, #00101f, #000614, #01010c) no-repeat;
}
}
}

39
resources/css/figure.css Normal file
View File

@ -0,0 +1,39 @@
figure {
width: var(--design-width);
margin: 1rem auto;
img,
video {
max-width: 100%;
max-height: 80vh;
height: auto;
margin: auto;
border-radius: .5rem;
opacity: .5;
&:hover {
opacity: 1;
}
&.bg-white {
background-color: #fff;
}
}
audio {
margin: auto;
display: block;
}
figcaption {
line-height: 125%;
margin: .75rem auto;
text-align: center;
color: #a8b4bd;
font-size: .85em;
p {
text-align: center !important;
}
}
}

View File

@ -0,0 +1,28 @@
.footnote-ref {
font-size: .8rem;
}
.footnotes {
font-size: 1rem;
line-height: 1.4;
color: #ccc;
background-color: #1e2230;
border-top: 1px solid #444;
padding: 10px 20px;
margin-top: 20px;
width: 100%;
box-sizing: border-box;
}
.footnotes hr {
display: none;
}
.footnotes ol {
padding-left: 20px;
list-style-type: decimal;
}
.footnotes li {
margin-bottom: 5px;
}

35
resources/css/form.css Normal file
View File

@ -0,0 +1,35 @@
form {
width: var(--design-width);
margin: auto;
input[type=checkbox] {
display: none;
}
input[type=email] {
display: block;
border-radius: .5rem;
color: #fff;
background-color: #1a1f33;
border: none;
margin: auto;
padding: .2rem .5rem;
text-align: center;
}
input[type=submit] {
display: block;
border-radius: .5rem;
color: #fff;
background-color: #1a1f33;
border: none;
margin: .5rem auto;
padding: .2rem 1rem;
cursor: pointer;
&:hover {
background-color: darkgreen;
text-decoration: none;
}
}
}

31
resources/css/links.css Normal file
View File

@ -0,0 +1,31 @@
a {
color: #60a5fa;
&:hover {
color: #bfdbfe;
}
&.external {
color: #34d399;
&:hover {
color: #a7f3d0;
}
}
&.affiliate {
color: #e879f9;
&:hover {
color: #f5d0fe;
}
}
&.dead {
color: #ff0000;
&:hover {
color: #ffa07a;
}
}
}

View File

@ -0,0 +1,52 @@
.paginator {
color: #6c7a89;
text-align: center;
background: #01010c radial-gradient(at bottom center, #00101f, #000614, #01010c) no-repeat;
box-shadow: 0 1px 1rem #000;
display: grid;
grid-template-columns: repeat(3, 1fr);
border-radius: .5rem;
border: solid 2px #00101f;
margin: 1rem;
padding: .5rem 1rem;
&.up {
margin-top: 2rem;
}
&.down {
margin-bottom: 2rem;
}
a {
color: #ccc;
text-decoration: none;
display: block;
&:hover {
color: #fff;
}
}
> details {
grid-column: 2;
}
.left {
text-align: left;
grid-column: 1;
}
.right {
text-align: right;
grid-column: 3;
}
.paginator-filters {
grid-column: 1 / 4;
font-size: .6rem;
display: flex;
align-items: center;
gap: 1rem;
}
}

View File

@ -0,0 +1,16 @@
body > footer {
background-color: #001;
padding: 2rem;
font-size: 1rem;
nav {
display: flex;
justify-content: center;
align-items: center;
a {
text-decoration: none;
margin: 0 2rem;
}
}
}

View File

@ -0,0 +1,42 @@
body > header {
margin: auto;
text-align: center;
nav {
margin: .5rem auto 1rem auto;
text-align: center;
font-family: sans-serif;
text-transform: uppercase;
font-size: .6em;
a {
color: #6c7a89;
display: inline-block;
padding: .5rem 1rem;
text-decoration: none;
&:hover {
color: #e4f1fe;
text-decoration: none;
}
}
}
#logo {
display: block;
width: 256px;
height: 256px;
margin: auto;
border-radius: 100%;
background-image: var(--logo-large-url);
text-decoration: none;
border: solid 2px #00101f;
box-shadow: 0 0 1rem #000;
&:hover {
background-image: var(--logo-large-hover-url);
box-shadow: 0 0 1rem #006bc3;
text-decoration: none;
}
}
}

27
resources/css/tables.css Normal file
View File

@ -0,0 +1,27 @@
table {
width: var(--design-width); /* Utilise toute la largeur disponible */
border-collapse: collapse; /* Les bordures des cellules sont fusionnées */
margin: 1em auto; /* Espacement autour du tableau */
background-color: #282c34; /* Fond sombre pour les tableaux */
color: #e4f1fe; /* Texte en couleur claire pour un bon contraste */
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); /* Ombre subtile pour un effet de profondeur */
font-size: 1rem;
line-height: 125%;
}
th,
td {
border: 1px solid #3a3f4b; /* Bordures des cellules en gris sombre */
padding: 8px 12px; /* Padding pour rendre le texte plus lisible */
text-align: left; /* Alignement du texte à gauche */
vertical-align: middle; /* Alignement vertical au milieu */
}
th {
background-color: #1c2028; /* Fond des entêtes un peu plus distinct */
font-weight: bold; /* Texte en gras pour les entêtes */
}
tbody tr:nth-child(odd) {
background-color: #32363f; /* Alternance de couleurs pour les lignes */
}

View File

@ -0,0 +1,3 @@
.hidden {
display: none;
}

View File

@ -0,0 +1,16 @@
<a class="article-card-link" href="{{ $bundle->getPath() }}">
<article class="article-card">
@if (!empty($cover))
{!! $cover !!}
@endif
<h2>{!! $bundle->getArticleTitle() !!}</h2>
<section class="article-card-body">
@if (!empty($date))
<p><time datetime="{{ $date->toIso8601String() }}">{{ $date->isoFormat('LL') }}</time></p>
@endif
@if (!empty($section))
<p>{!! $section->getArticleTitle() !!}</p>
@endif
</section>
</article>
</a>

View File

@ -1,12 +1,28 @@
<!DOCTYPE html> @extends('layouts.main')
<html lang="fr">
<head> @section('main')
<meta charset="UTF-8"> <article id="article-main">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <header>
@vite('resources/css/app.css') @if (empty($bundle->metadata()->get('hide_title')))
</head> <h1>{{ $articleTitle }}</h1>
<body> @endif
<h1>{!! $articleTitle !!}</h1> @if (!empty($date))
<div class="article">{!! $body !!}</div> <time datetime="{{ $date->toIso8601String() }}">{{ $date->isoFormat('LL') }}</time>
</body> @endif
</html>
@if (!empty($cover))
{!! $cover !!}
@endif
</header>
@if (!empty($body))
<section id="article-body">
{!! $body !!}
</section>
@endif
</article>
@if (!empty($pagination['items']))
<x-pagination :data="$pagination" />
@endif
@endsection

View File

@ -0,0 +1 @@
<div class="chat">{!! $slot !!}</div>

View File

@ -0,0 +1 @@
<div class="chat-me markdown-body">{!! (new \App\Services\Markdown\Formatter($slot))->render() !!}</div>

View File

@ -0,0 +1,3 @@
@props(['name'])
<div class="chat-other markdown-body">{!! (new \App\Services\Markdown\Formatter($slot))->render() !!}</div>

View File

@ -1,18 +1,23 @@
<figure> <figure>
<a href="{{ $originalUrl }}" title="Voir l'image à taille réelle"> @if (!empty($originalData['prompt']) && empty($options['nolink']))
<img src="{{ $variantUrl }}" @if (!empty($class)) class="{{ $class }}" @endif /> <figcaption class="markdown-body">
</a>
@if (!empty($originalData['title']) || !empty($originalData['prompt']) || !empty($originalData['attribution']))
<figcaption>
@if (!empty($originalData['prompt']))
{!! (new \App\Services\Markdown\Formatter($originalData['prompt']))->render() !!} {!! (new \App\Services\Markdown\Formatter($originalData['prompt']))->render() !!}
@endif </figcaption>
@endif
@if(!empty($options['nolink']))
<img src="{{ $variantUrl }}" @if (!empty($originalData['class'])) class="{{ $originalData['class'] }}" @endif />
@else
<a href="{{ $originalUrl }}" title="Voir l'image à taille réelle">
<img src="{{ $variantUrl }}" @if (!empty($originalData['class'])) class="{{ $originalData['class'] }}" @endif />
</a>
@endif
@if (empty($options['nolink']) && (!empty($originalData['title']) || !empty($originalData['attribution'])))
<figcaption class="markdown-body">
@if (!empty($originalData['title'])) @if (!empty($originalData['title']))
{!! (new \App\Services\Markdown\Formatter($originalData['title']))->render() !!} {!! (new \App\Services\Markdown\Formatter($originalData['title']))->render() !!}
@endif @endif
@if (!empty($originalData['attribution'])) @if (!empty($originalData['attribution']))
{!! (new \App\Services\Markdown\Formatter($originalData['attribution']))->render() !!} {!! (new \App\Services\Markdown\Formatter($originalData['attribution']))->render() !!}
@endif @endif
</figcaption> </figcaption>
@endif @endif

View File

@ -0,0 +1,11 @@
@if (!empty($data['items']))
<x-paginator :data="$data" orientation="down" />
<section class="article-list">
@foreach ($data['items'] as $bundle)
{!! $bundle->renderCard() !!}
@endforeach
</section>
<x-paginator :data="$data" orientation="up" />
@endif

View File

@ -0,0 +1,29 @@
@props(['orientation'])
@if ($totalPages > 1)
<div class="paginator">
@if ($currentPage > 1)
<div class="left">
<a href="{{ $root }}page/{{ $currentPage - 1 }}/" title="Articles plus récents">&larr;</a>
</div>
@endif
@if ($totalPages > 1)
<details class="drop {{ $orientation }}">
<summary>{{ $currentPage }}</summary>
<nav>
@for ($i = 1; $i <= $totalPages; $i++)
<a href="{{ $root }}page/{{ $i }}/"
@if ($i === $currentPage) class="selected" @endif
title="Afficher la page {{ $i }} sur {{ $totalPages }}">{{ $i }}</a>
@endfor
</nav>
</details>
@endif
@if ($currentPage < $totalPages)
<div class="right">
<a href="{{ $root }}page/{{ $currentPage + 1 }}/" title="Articles plus anciens">&rarr;</a>
</div>
@endif
</div>
@endif

View File

@ -0,0 +1,5 @@
<section class="article-list">
@foreach ($bundles as $bundle)
{!! $bundle->renderCard() !!}
@endforeach
</section>

View File

@ -0,0 +1,9 @@
<footer role="contentinfo">
<nav>
<a href="/index.xml" title="Suivez mon actualité avec mon flux RSS">Flux RSS</a>
<a href="/pages/newsletter/" title="Abonnez-vous à ma newsletter pour du contenu exclusif">Newsletter</a>
<a href="https://git.athaliasoft.com" title="Mes dépôts de code source">Forge logicielle</a>
<a href="/pages/a-propos/" title="À propos de moi">À propos</a>
<a href="/pages/contact/" title="Différences façons de communiquer avec moi">Me contacter</a>
</nav>
</footer>

View File

@ -0,0 +1,13 @@
<header role="banner">
<nav>
<a href="/blog/" title="Mes articles de blog">Blog</a>
<a href="/dossiers/" title="Regroupements d'articles">Dossiers</a>
<a href="/critiques/films/" title="Mes critiques de films">Films</a>
<a href="/critiques/series/" title="Mes critiques de séries">Séries</a>
<a href="/critiques/jeux-video/" title="Mes critiques de jeux-vidéo">Jeux-vidéo</a>
<a href="/critiques/livres/" title="Mes critiques de livres">Livres</a>
<a href="/collections/" title="Mes objets de collection">Collections</a>
<a href="/liens-interessants/" title="Des liens intéressants collectés sur le web">Liens</a>
</nav>
<a id="logo" href="/" title="Retour à la page d'accueil"><span class="hidden">Accueil</span></a>
</header>

View File

@ -1,6 +1,10 @@
<figure> <figure>
<audio controls preload="{{ $preload }}"> <audio controls preload="metadata">
<source src="{{ $sndUrl }}" type="{{ $type }}"> <source src="{{ $originalUrl }}" type="audio/mpeg">
</audio> </audio>
<figcaption>{!! $caption !!}</figcaption> <figcaption class="markdown-body">
@if (!empty($originalData['title']))
{!! (new \App\Services\Markdown\Formatter($originalData['title']))->render() !!}
@endif
</figcaption>
</figure> </figure>

View File

@ -0,0 +1,4 @@
<details class="spoiler">
<summary>Spoiler</summary>
<div class="markdown-body">{!! (new \App\Services\Markdown\Formatter($slot))->render() !!}</div>
</details>

View File

@ -1,6 +1,6 @@
<figure> <figure>
<video width="{{ $width }}" height="{{ $height }}" controls> <video width="{{ $originalData['width'] }}" height="{{ $originalData['height'] }}" controls>
<source src="{{ $videoUrl }}" type="{{ $type }}"> <source src="{{ $originalUrl }}" type="{{ $originalData['type'] }}">
Quelque chose ne fonctionne pas ! Quelque chose ne fonctionne pas !
</video> </video>
</figure> </figure>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="description" content="{{ env('APP_DESCRIPTION') }}" />
<meta name="author" content="Richard Dern" />
<title>{{ $siteTitle }} - {{ env('APP_NAME') }}</title>
<link rel="icon" type="image/png" href="{{ Vite::asset('resources/images/favicon.png') }}" />
<link rel="alternate" type="application/rss+xml" href="/index.xml" title="{{ env('APP_NAME') }}" />
<link rel="preload" as="image" href="{{ Vite::asset('resources/images/logo-large.png') }}" />
<link rel="preload" as="image" href="{{ Vite::asset('resources/images/logo-large-hover.png') }}" />
<style>
:root {
--logo-large-url: url('{{ Vite::asset('resources/images/logo-large.png') }}');
--logo-large-hover-url: url('{{ Vite::asset('resources/images/logo-large-hover.png') }}');
}
</style>
@if (Vite::isRunningHot())
@vite(['resources/css/REVENGE.css', 'resources/css/app.css'])
@else
@vite(['resources/css/app.css'])
@endif
</head>
<body>
<x-site-header />
<main>
@yield('main')
</main>
<x-site-footer />
</body>
</html>