Skip to content

Commit 9b96e0c

Browse files
simonhampclaude
andcommitted
Migrate stored plugin HTML heading anchors and fix TOC text extraction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent de08863 commit 9b96e0c

File tree

2 files changed

+74
-5
lines changed

2 files changed

+74
-5
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
use App\Models\Plugin;
4+
use Illuminate\Database\Migrations\Migration;
5+
6+
return new class extends Migration
7+
{
8+
/**
9+
* Move heading anchor links from before heading text to after,
10+
* and update classes for hover animation.
11+
*/
12+
public function up(): void
13+
{
14+
$oldPattern = '/(<h([1-3])\s+id="([^"]+)">)<a\s+href="#[^"]+"\s+class="mr-2\s+no-underline\s+font-medium"\s+style="border-bottom:\s*0\s*!important;">\s*<span\s+class="\s*text-gray-600\s+dark:text-gray-400\s+hover:text-\[#00aaa6\]">#<\/span><\/a>(.*?)(<\/h\2>)/s';
15+
16+
$newReplacement = '$1$4<a href="#$3" class="heading-anchor ml-2 no-underline font-medium" style="border-bottom: 0 !important;"><span class="text-gray-600 dark:text-gray-400 hover:text-[#00aaa6]">#</span></a>$5';
17+
18+
Plugin::query()
19+
->whereNotNull('readme_html')
20+
->each(function (Plugin $plugin) use ($oldPattern, $newReplacement) {
21+
$updated = preg_replace($oldPattern, $newReplacement, $plugin->readme_html);
22+
23+
if ($updated !== $plugin->readme_html) {
24+
$plugin->updateQuietly(['readme_html' => $updated]);
25+
}
26+
});
27+
28+
Plugin::query()
29+
->whereNotNull('license_html')
30+
->each(function (Plugin $plugin) use ($oldPattern, $newReplacement) {
31+
$updated = preg_replace($oldPattern, $newReplacement, $plugin->license_html);
32+
33+
if ($updated !== $plugin->license_html) {
34+
$plugin->updateQuietly(['license_html' => $updated]);
35+
}
36+
});
37+
}
38+
39+
public function down(): void
40+
{
41+
$newPattern = '/(<h([1-3])\s+id="([^"]+)">)(.*?)<a\s+href="#[^"]+"\s+class="heading-anchor\s+ml-2\s+no-underline\s+font-medium"\s+style="border-bottom:\s*0\s*!important;">\s*<span\s+class="text-gray-600\s+dark:text-gray-400\s+hover:text-\[#00aaa6\]">#<\/span><\/a>(<\/h\2>)/s';
42+
43+
$oldReplacement = '$1<a href="#$3" class="mr-2 no-underline font-medium" style="border-bottom: 0 !important;"><span class=" text-gray-600 dark:text-gray-400 hover:text-[#00aaa6]">#</span></a>$4$5';
44+
45+
Plugin::query()
46+
->whereNotNull('readme_html')
47+
->each(function (Plugin $plugin) use ($newPattern, $oldReplacement) {
48+
$updated = preg_replace($newPattern, $oldReplacement, $plugin->readme_html);
49+
50+
if ($updated !== $plugin->readme_html) {
51+
$plugin->updateQuietly(['readme_html' => $updated]);
52+
}
53+
});
54+
55+
Plugin::query()
56+
->whereNotNull('license_html')
57+
->each(function (Plugin $plugin) use ($newPattern, $oldReplacement) {
58+
$updated = preg_replace($newPattern, $oldReplacement, $plugin->license_html);
59+
60+
if ($updated !== $plugin->license_html) {
61+
$plugin->updateQuietly(['license_html' => $updated]);
62+
}
63+
});
64+
}
65+
};

resources/views/components/plugin-toc.blade.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
if (! article) return
77
88
const elements = article.querySelectorAll('h2[id], h3[id]')
9-
this.headings = Array.from(elements).map(el => ({
10-
id: el.id,
11-
text: el.textContent.replace(/\s*#$/, '').trim(),
12-
level: parseInt(el.tagName.substring(1)),
13-
}))
9+
this.headings = Array.from(elements).map(el => {
10+
const clone = el.cloneNode(true)
11+
clone.querySelectorAll('.heading-anchor').forEach(a => a.remove())
12+
return {
13+
id: el.id,
14+
text: clone.textContent.trim(),
15+
level: parseInt(el.tagName.substring(1)),
16+
}
17+
})
1418
},
1519
}"
1620
x-show="headings.length > 0"

0 commit comments

Comments
 (0)