Last active
October 18, 2025 00:34
-
-
Save CamKem/4c5a2eb9a0c9c470cbc790829c8da355 to your computer and use it in GitHub Desktop.
Blade in markdown
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace App\View\Components; | |
| use Closure; | |
| use Dom\Element; | |
| use Dom\HtmlDocument; | |
| use Illuminate\Support\Facades\Blade; | |
| use Illuminate\Support\Str; | |
| use Illuminate\View\Component; | |
| use Illuminate\View\ComponentAttributeBag; | |
| use Illuminate\View\ComponentSlot; | |
| final class Markdown extends Component | |
| { | |
| public function render(): Closure | |
| { | |
| return static function (array $data) { | |
| /** @var ComponentSlot $content */ | |
| $content = $data['slot']; | |
| /** @var ComponentAttributeBag|null $attributes */ | |
| $attributes = $data['attributes'] ?? null; | |
| $dom = HtmlDocument::createFromString( | |
| source: "<markdown>{$content->toHtml()}</markdown>", | |
| options: LIBXML_NOERROR | LIBXML_HTML_NOIMPLIED | |
| ); | |
| /** @var Element $doc */ | |
| $doc = $dom->documentElement; | |
| $map = collect(); | |
| foreach ($doc->childNodes as $index => $child) { | |
| if ($child instanceof Element) { | |
| $placeholder = "::=={$index}==::"; | |
| $fragment = $dom->createDocumentFragment(); | |
| $fragment->appendXml($placeholder); | |
| $doc->replaceChild($fragment, $child); | |
| $map->put($placeholder, $dom->saveHTML($child)); | |
| } | |
| } | |
| $lines = explode("\n", $doc->innerHTML); | |
| $trimmedLines = array_map( | |
| callback: static fn (string $line): string => (string) Str::of($line)->ltrim(), | |
| array: $lines, | |
| ); | |
| $trimmed = implode("\n", $trimmedLines); | |
| $parsed = Str::of($trimmed)->markdown(); | |
| foreach ($map as $placeholder => $originalHtml) { | |
| $parsed = Str::of($parsed->toString()) | |
| /** @phpstan-ignore argument.type */ | |
| ->replace($placeholder, $originalHtml); | |
| } | |
| $result = Blade::render((string) $parsed); | |
| // If attributes are provided, wrap the content with a div that has those attributes | |
| if ($attributes !== null && $attributes->isNotEmpty()) { | |
| return "<div {$attributes->toHtml()}>{$result}</div>"; | |
| } | |
| return $result; | |
| }; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <x-app-layout pageTitle="{{ __('Test Blade-in-Markdown') }}"> | |
| <x-section.component id="test"> | |
| <x-section.h1> | |
| This is Blade-in-Markdown | |
| </x-section.h1> | |
| <x-markdown> | |
| # Hello, | |
| This is a markdown file that also contains internal blade components, that need rendering | |
| - Here is and icon using the include directive: | |
| @include('components.icons.menu-icon') | |
| - Here is a component: | |
| <x-icons.alpine class="size-10"/> | |
| <pre> | |
| <x-torchlight-code language="php"> | |
| if ($this === true) { | |
| echo "this is true"; | |
| } | |
| $code = 'code'; | |
| $hasIndentations = true; | |
| if ($hasIndentations) { | |
| echo "hey, im indented"; | |
| } | |
| </x-torchlight-code> | |
| </pre> | |
| - An asset | |
| {{ asset('images/logo.svg') }} | |
| </x-markdown> | |
| </x-section.component> | |
| </x-app-layout> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment