Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.x] Semantic Tailwind Markdown heading permalinks #2052

2 changes: 2 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ This serves two purposes:
- Normalized default Tailwind Typography Prose code block styles to match Torchlight's theme, ensuring consistent styling across Markdown and Torchlight code blocks in https://github.com/hydephp/develop/pull/2036.
- Extracted CSS component partials in HydeFront in https://github.com/hydephp/develop/pull/2038
- Replaced HydeFront styles with Tailwind in https://github.com/hydephp/develop/pull/2024
- The `id` attributes for heading permalinks have been moved from the anchor to the heading element in https://github.com/hydephp/develop/pull/2052

### Deprecated

Expand Down Expand Up @@ -524,6 +525,7 @@ The likelihood of impact is low, but if any of the following are true, you may n
- Rewrites the `GeneratesTableOfContents` class to use a custom implementation instead of using CommonMark
- The `execute` method of the `GeneratesTableOfContents` class now returns an array of data, instead of a string of HTML. This data should be fed into the new component
- Removed the `table-of-contents.css` file as styles are now made using Tailwind
- Removed the `heading-permalinks.css` file as styles are now made using Tailwind

## New features

Expand Down
2 changes: 1 addition & 1 deletion _media/app.css

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,21 @@
@php
$tag = 'h' . $level;
$id = $id ?? \Illuminate\Support\Str::slug($slot);

if ($addPermalink === true) {
$extraAttributes['id'] = $id;

isset($extraAttributes['class'])
? $extraAttributes['class'] .= ' group w-fit scroll-mt-2'
: $extraAttributes['class'] = 'group w-fit scroll-mt-2';
}
@endphp

<{{ $tag }} {{ $attributes->merge([...$extraAttributes]) }}>
{!! $slot !!}
@if($addPermalink === true)
<a id="{{ $id }}" href="#{{ $id }}" class="heading-permalink" title="Permalink"></a>
<a href="#{{ $id }}" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">
#
</a>
@endif
</{{ $tag }}>
</{{ $tag }}>
27 changes: 13 additions & 14 deletions packages/framework/tests/Feature/MarkdownHeadingRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function testPermalinksInDocumentationPages()
// $this->assertStringContainsString('aria-label="Permalink to this heading"', $html);

$this->assertSame(<<<'HTML'
<h2>Documentation Heading<a id="documentation-heading" href="#documentation-heading" class="heading-permalink" title="Permalink"></a></h2>
<h2 id="documentation-heading" class="group w-fit scroll-mt-2">Documentation Heading<a href="#documentation-heading" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>

HTML, $html);
}
Expand Down Expand Up @@ -111,19 +111,18 @@ public function testHeadingsWithCustomAttributes()
public function testHeadingsWithCustomAttributesAndPermalinks()
{
$markdown = <<<'MARKDOWN'
## Heading {.custom-class #custom-id}
## Heading {.custom-class}
### Another Heading {data-test="value"}
MARKDOWN;

$html = (new MarkdownService($markdown, DocumentationPage::class))->parse();

$this->assertStringContainsString('id="custom-id"', $html);
$this->assertStringContainsString('class="custom-class"', $html);
$this->assertStringContainsString('class="custom-class group w-fit scroll-mt-2"', $html);
$this->assertStringContainsString('data-test="value"', $html);

$this->assertSame(<<<'HTML'
<h2 class="custom-class" id="custom-id">Heading<a id="heading" href="#heading" class="heading-permalink" title="Permalink"></a></h2>
<h3 data-test="value">Another Heading<a id="another-heading" href="#another-heading" class="heading-permalink" title="Permalink"></a></h3>
<h2 class="custom-class group w-fit scroll-mt-2" id="heading">Heading<a href="#heading" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>
<h3 data-test="value" id="another-heading" class="group w-fit scroll-mt-2">Another Heading<a href="#another-heading" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h3>

HTML, $html);
}
Expand All @@ -145,17 +144,17 @@ public function testPermalinkConfigurationLevels()
$html = (new MarkdownService($markdown, DocumentationPage::class))->parse();

$this->assertStringNotContainsString('<h1>H1 No Permalink</h1><a', $html);
$this->assertStringContainsString('<h2>H2 Has Permalink<a', $html);
$this->assertStringContainsString('<h3>H3 Has Permalink<a', $html);
$this->assertStringContainsString('<h4>H4 Has Permalink<a', $html);
$this->assertStringContainsString('<h2 id="h2-has-permalink" class="group w-fit scroll-mt-2">H2 Has Permalink<a', $html);
$this->assertStringContainsString('<h3 id="h3-has-permalink" class="group w-fit scroll-mt-2">H3 Has Permalink<a', $html);
$this->assertStringContainsString('<h4 id="h4-has-permalink" class="group w-fit scroll-mt-2">H4 Has Permalink<a', $html);
$this->assertStringNotContainsString('<h5>H5 No Permalink</h1><a', $html);
$this->assertStringNotContainsString('<h6>H6 No Permalink</h1><a', $html);

$this->assertSame(<<<'HTML'
<h1>H1 No Permalink</h1>
<h2>H2 Has Permalink<a id="h2-has-permalink" href="#h2-has-permalink" class="heading-permalink" title="Permalink"></a></h2>
<h3>H3 Has Permalink<a id="h3-has-permalink" href="#h3-has-permalink" class="heading-permalink" title="Permalink"></a></h3>
<h4>H4 Has Permalink<a id="h4-has-permalink" href="#h4-has-permalink" class="heading-permalink" title="Permalink"></a></h4>
<h2 id="h2-has-permalink" class="group w-fit scroll-mt-2">H2 Has Permalink<a href="#h2-has-permalink" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>
<h3 id="h3-has-permalink" class="group w-fit scroll-mt-2">H3 Has Permalink<a href="#h3-has-permalink" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h3>
<h4 id="h4-has-permalink" class="group w-fit scroll-mt-2">H4 Has Permalink<a href="#h4-has-permalink" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h4>
<h5>H5 No Permalink</h5>
<h6>H6 No Permalink</h6>

Expand Down Expand Up @@ -186,8 +185,8 @@ public function testHeadingsWithSpecialCharacters()

// Todo: Try to normalize to heading-with-special-characters?
$this->assertSame(<<<'HTML'
<h2>Heading with &amp; special &lt; &gt; &quot;characters&quot;<a id="heading-with-amp-special-lt-gt-quotcharactersquot" href="#heading-with-amp-special-lt-gt-quotcharactersquot" class="heading-permalink" title="Permalink"></a></h2>
<h3>Heading with émojis 🎉<a id="heading-with-emojis" href="#heading-with-emojis" class="heading-permalink" title="Permalink"></a></h3>
<h2 id="heading-with-amp-special-lt-gt-quotcharactersquot" class="group w-fit scroll-mt-2">Heading with &amp; special &lt; &gt; &quot;characters&quot;<a href="#heading-with-amp-special-lt-gt-quotcharactersquot" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>
<h3 id="heading-with-emojis" class="group w-fit scroll-mt-2">Heading with émojis 🎉<a href="#heading-with-emojis" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h3>

HTML, $html);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/framework/tests/Feature/MarkdownServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function testServiceCanParseMarkdownToHtmlWithPermalinksDependingOnConfig
$this->assertIsString($html);
$this->assertStringContainsString('heading-permalink', $html, 'Permalink should be added to documentation pages by default');
$this->assertSame(
'<h2>Hello World!<a id="hello-world" href="#hello-world" class="heading-permalink" title="Permalink"></a></h2>'."\n", $html
'<h2 id="hello-world" class="group w-fit scroll-mt-2">Hello World!<a href="#hello-world" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>'."\n", $html
);

$html = (new MarkdownService($markdown))->parse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function testPageContainsExpectedContent()
{
$this->inspectHtml([
'Adventures in Wonderland',
'<h2>CHAPTER I. DOWN THE RABBIT-HOLE.<a id="chapter-i-down-the-rabbit-hole" href="#chapter-i-down-the-rabbit-hole" class="heading-permalink" title="Permalink"></a></h2>',
'<h2 id="chapter-i-down-the-rabbit-hole" class="group w-fit scroll-mt-2">CHAPTER I. DOWN THE RABBIT-HOLE.<a href="#chapter-i-down-the-rabbit-hole" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>',
'<p>So she was considering in her own mind, as well as she could',
]);
}
Expand All @@ -55,7 +55,7 @@ public function testCanCompilePageToRootOutputDirectory()

$this->inspectHtml([
'Adventures in Wonderland',
'<h2>CHAPTER I. DOWN THE RABBIT-HOLE.<a id="chapter-i-down-the-rabbit-hole" href="#chapter-i-down-the-rabbit-hole" class="heading-permalink" title="Permalink"></a></h2>',
'<h2 id="chapter-i-down-the-rabbit-hole" class="group w-fit scroll-mt-2">CHAPTER I. DOWN THE RABBIT-HOLE.<a href="#chapter-i-down-the-rabbit-hole" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>',
'<p>So she was considering in her own mind, as well as she could',
], '_site/test-page.html');
}
Expand Down
10 changes: 5 additions & 5 deletions packages/framework/tests/Unit/HeadingRendererUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function testCanRenderHeading()
$this->assertStringContainsString('<h2', $rendered);
$this->assertStringContainsString('</h2>', $rendered);

$this->assertSame('<h2>Test Heading<a id="test-heading" href="#test-heading" class="heading-permalink" title="Permalink"></a></h2>', $rendered);
$this->assertSame('<h2 id="test-heading" class="group w-fit scroll-mt-2">Test Heading<a href="#test-heading" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>', $rendered);
}

public function testAddsPermalinkToValidHeadings()
Expand Down Expand Up @@ -124,7 +124,7 @@ public function testForwardsHeadingAttributes()
$heading->data->set('attributes', ['class' => 'custom-class']);
$rendered = $renderer->render($heading, $childRenderer);

$this->assertStringContainsString('class="custom-class"', $rendered);
$this->assertStringContainsString('class="custom-class group w-fit scroll-mt-2', $rendered);
}

public function testForwardsArbitraryHeadingAttributes()
Expand All @@ -148,7 +148,7 @@ public function testMergesAllHeadingAttributes()
$heading->data->set('attributes', ['class' => 'custom-class', 'foo' => 'bar']);
$rendered = $renderer->render($heading, $childRenderer);

$this->assertStringContainsString('class="custom-class"', $rendered);
$this->assertStringContainsString('class="custom-class group w-fit scroll-mt-2"', $rendered);
$this->assertStringContainsString('foo="bar"', $rendered);
}

Expand Down Expand Up @@ -186,12 +186,12 @@ public function testPostProcessMethodNormalizesInputToMatchCommonMark()
$html = <<<'HTML'
<h2 >
Test Heading
<a id="test-heading" href="#test-heading" class="heading-permalink" title="Permalink"></a>
<a id="test-heading" href="#test-heading" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a>
</h2>
HTML;

// What CommonMark would generate from the same input Markdown
$expected = '<h2>Test Heading<a id="test-heading" href="#test-heading" class="heading-permalink" title="Permalink"></a></h2>';
$expected = '<h2>Test Heading<a id="test-heading" href="#test-heading" class="heading-permalink opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 group-hover:opacity-100 focus:opacity-100 group-hover:grayscale-0 focus:grayscale-0" title="Permalink">#</a></h2>';

$this->assertSame($expected, (new HeadingRenderer())->postProcess($html));
}
Expand Down
20 changes: 0 additions & 20 deletions packages/hydefront/components/heading-permalinks.css

This file was deleted.

1 change: 0 additions & 1 deletion resources/assets/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
* See https://hydephp.com/docs/1.x/managing-assets#loading-from-cdn
*/

@import 'hydefront/components/heading-permalinks.css';
@import 'hydefront/components/torchlight.css';
@import 'hydefront/components/blockquotes.css';

Expand Down
Loading