Skip to content

Commit

Permalink
Render blockquotes on the server
Browse files Browse the repository at this point in the history
  • Loading branch information
timacdonald committed Jul 15, 2024
1 parent c548128 commit aaa368b
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 110 deletions.
95 changes: 95 additions & 0 deletions app/Markdown/BlockQuoteRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace App\Markdown;

use Illuminate\Support\Str;
use League\CommonMark\Extension\CommonMark\Renderer\Block\BlockQuoteRenderer as BaseBlockQuoteRenderer;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;
use League\CommonMark\Util\HtmlElement;

class BlockQuoteRenderer implements NodeRendererInterface
{
/**
* @return \Stringable|string|null
*
* @throws InvalidArgumentException if the wrong type of Node is provided
*/
public function render(Node $node, ChildNodeRendererInterface $childRenderer)
{
$element = (new BaseBlockQuoteRenderer($node))->render($node, $childRenderer);

if (! $element instanceof HtmlElement || $element->getTagName() !== 'blockquote') {
return $element;
}

$html = trim($element->getContents(true));

if (! str_starts_with($html, '<p>')) {
return $element;
}

$htmlPartial = Str::after($html, '<p>');

if (preg_match('/^\[!(.*?)\]/', $htmlPartial, $matches)) {
// GitHub styled notes, e.g.,
// > [!NOTE] Content
// or
// > [!NOTE]
// > Content
} elseif (preg_match('/^<strong>(.*?):?<\/strong>:?/', $htmlPartial, $matches)) {
// Legacy GitHub styled notes, e.g.,
// > **Note:** Content
// or
// > **Note**: Content
// or
// > **Note** Content
// or
// > **Note:**
// > Content
// or
// > **Note**:
// > Content
// or
// > **Note**
// > Content
} elseif (preg_match('/^\{(.*?)\}/', $htmlPartial, $matches)) {
// Legacy Laravel styled notes, e.g.,
// > {tip} Content
// or
// > {tip}
// > Content
} else {
return $element;
}

[$replacing, $type] = $matches;

$bits = match ($type) {
'WARNING', 'Warning', 'note' => [Vite::content('resources/images/exclamation.svg'), 'bg-red-600'],
'NOTE', 'Note', 'tip' => [Vite::content('resources/images/lightbulb.svg'), 'bg-purple-600'],
'video' => [Vite::content('resources/images/laracast.svg'), 'bg-blue-600'],
default => null,
};

if ($bits === null) {
return $element;
}

$body = str_replace($replacing, '', $htmlPartial);

[$asset, $class] = $bits;

return <<<HTML
<div class="mb-10 max-w-2xl mx-auto px-4 py-8 shadow-lg lg:flex lg:items-center callout">
<div class="w-20 h-20 mb-6 flex items-center justify-center shrink-0 lg:mb-0 {$class}">
<div class="opacity-75">
{$asset}
</div>
</div>
<p class="mb-0 lg:ml-6 callout">{$body}
</div>
HTML;
}
}
19 changes: 18 additions & 1 deletion app/Markdown/GithubFlavoredMarkdownConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,26 @@

namespace App\Markdown;

use Illuminate\Support\Str;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\Renderer\Block\BlockQuoteRenderer;
use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
use League\CommonMark\Extension\Table\TableExtension;
use League\CommonMark\Extension\TaskList\TaskListExtension;
use League\CommonMark\MarkdownConverter;
use League\CommonMark\Environment\Environment;
use App\Markdown\GithubFlavoredMarkdownExtension;
use Illuminate\Support\Facades\Vite;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Util\HtmlElement;
use Torchlight\Commonmark\V2\TorchlightExtension;
use Laravel\Unfenced\UnfencedExtension;
use League\CommonMark\Environment\EnvironmentInterface;
use League\CommonMark\Extension\Attributes\AttributesExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
use League\CommonMark\Renderer\NodeRendererInterface;

/**
* Converts GitHub Flavored Markdown to HTML.
Expand All @@ -25,11 +37,16 @@ public function __construct(array $config = [])
{
$environment = new Environment($config);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new GithubFlavoredMarkdownExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new StrikethroughExtension());
$environment->addExtension(new TableExtension());
$environment->addExtension(new TaskListExtension());
$environment->addExtension(new UnfencedExtension());
$environment->addExtension(new AttributesExtension());
$environment->addExtension(new TorchlightExtension());

$environment->addRenderer(BlockQuote::class, );

parent::__construct($environment);
}

Expand Down
21 changes: 0 additions & 21 deletions app/Markdown/GithubFlavoredMarkdownExtension.php

This file was deleted.

1 change: 0 additions & 1 deletion public/img/callouts/star.min.svg

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
84 changes: 0 additions & 84 deletions resources/js/docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import './theme'
document.addEventListener('DOMContentLoaded', () => {
wrapHeadingsInAnchors();
setupNavCurrentLinkHandling();
replaceBlockquotesWithCalloutsInDocs();
highlightSupportPolicyTable();

const skipToContentLink = document.querySelector('#skip-to-content-link');
Expand Down Expand Up @@ -48,89 +47,6 @@ function setupNavCurrentLinkHandling() {
});
}

function replaceBlockquotesWithCalloutsInDocs() {
[...document.querySelectorAll('.docs_main blockquote p')].forEach(el => {
// Legacy Laravel styled notes...
replaceBlockquote(el, /\{(.*?)\}/, (type) => {
switch (type) {
case "note":
return ['/img/callouts/exclamation.min.svg', 'bg-red-600', 6, 35];
case "tip":
return ['/img/callouts/lightbulb.min.svg', 'bg-purple-600', 28, 40];
case "laracasts":
case "video":
return ['/img/callouts/laracast.min.svg', 'bg-blue-600', 49, 40];
default:
return [null, null, 0, 0];
}
});

// GitHub styled notes...
replaceBlockquote(el, /^\[\!(.*?)\](?:<br>\n?)?/, (type) => {
switch (type) {
case "WARNING":
return ['/img/callouts/exclamation.min.svg', 'bg-red-600', 6, 35];
case "NOTE":
return ['/img/callouts/lightbulb.min.svg', 'bg-purple-600', 28, 40];
default:
return [null, null, 0, 0];
}
});

// Legagcy GitHub styled notes...
replaceBlockquote(el, /^<strong>(.*?)<\/strong>(?:<br>\n?)?/, (type) => {
switch (type) {
case "Warning":
return ['/img/callouts/exclamation.min.svg', 'bg-red-600', 6, 35];
case "Note":
return ['/img/callouts/lightbulb.min.svg', 'bg-purple-600', 28, 40];
default:
return [null, null, 0, 0];
}
});
});
}

function replaceBlockquote(el, regex, getImageAndColorByType) {
var str = el.innerHTML;
var match = str.match(regex);
var img, color, width, height;

if (match) {
var type = match[1] || false;
}

if (type) {
[img, color, width, height] = getImageAndColorByType(type);

if (img === null && color === null) {
return;
}

const wrapper = document.createElement('div');
wrapper.classList = 'mb-10 max-w-2xl mx-auto px-4 py-8 shadow-lg lg:flex lg:items-center';

const imageWrapper = document.createElement('div');
imageWrapper.classList = `w-20 h-20 mb-6 flex items-center justify-center shrink-0 ${color} lg:mb-0`;
const image = document.createElement('img');
image.src = img;
image.height = height
image.width = width
image.loading = 'lazy'
image.classList = `opacity-75`;
imageWrapper.appendChild(image);
wrapper.appendChild(imageWrapper);

el.parentNode.insertBefore(wrapper, el);

el.innerHTML = str.replace(regex, '');

el.classList = 'mb-0 lg:ml-6';
wrapper.classList.add('callout');
wrapper.appendChild(el);
}
}

function highlightSupportPolicyTable() {

function highlightCells(table) {
Expand Down
8 changes: 6 additions & 2 deletions resources/views/docs.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ class="appearance-none flex-1 w-full px-0 py-1 placeholder-gray-900 tracking-wid
<div class="callout">
<div class="mb-10 max-w-2xl mx-auto px-4 py-8 shadow-lg dark:bg-dark-600 lg:flex lg:items-center">
<div class="w-20 h-20 mb-6 flex items-center justify-center shrink-0 bg-orange-600 lg:mb-0">
<img src="{{ asset('/img/callouts/exclamation.min.svg') }}" alt="Icon" class="opacity-75" width="6" height="35"/>
<div class="opacity-75">
{!! Vite::content('resources/images/exclamation.svg') !!}
</div>
</div>

<p class="mb-0 lg:ml-4">
Expand All @@ -209,7 +211,9 @@ class="appearance-none flex-1 w-full px-0 py-1 placeholder-gray-900 tracking-wid
<div class="callout">
<div class="mb-10 max-w-2xl mx-auto px-4 py-8 shadow-lg lg:flex lg:items-center">
<div class="w-20 h-20 mb-6 flex items-center justify-center shrink-0 bg-orange-600 lg:mb-0">
<img src="{{ asset('/img/callouts/exclamation.min.svg') }}" alt="Icon" class="opacity-75" width="6" height="35"/>
<div class="opacity-75">
{!! Vite::content('resources/images/exclamation.svg') !!}
</div>
</div>

<p class="mb-0 lg:ml-4">
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const accentColors = {

export default {
content: [
'app/Markdown/*.php',
'resources/views/**/*.blade.php',
'resources/js/**/*.js',
],
Expand Down

0 comments on commit aaa368b

Please sign in to comment.