Skip to content

Commit

Permalink
Merge pull request #2052 from hydephp/semantic-markdown-heading-perma…
Browse files Browse the repository at this point in the history
…links

[2.x] Semantic Markdown heading permalinks
  • Loading branch information
caendesilva authored Dec 5, 2024
2 parents 3d3ed48 + 9c49d46 commit 7ebd17f
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 46 deletions.
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

0 comments on commit 7ebd17f

Please sign in to comment.