clickable footnotes

This commit is contained in:
E. S. 2024-05-13 01:59:33 +00:00
parent b133915626
commit 803cd89fe4
7 changed files with 70 additions and 4 deletions

View File

@ -71,10 +71,10 @@ function sphinx_client(): Sphinx\SphinxClient {
function _sphinx_normalize(string $origstr): string {
$buf = preg_replace('/[Ёё]/iu', 'е', $origstr);
if (!pcre_check_error($buf, no_error: true)) {
if (!pcre_no_error($buf, no_error: true)) {
$origstr = mb_convert_encoding($origstr, 'UTF-8', 'UTF-8');
$buf = preg_replace('/[Ёё]/iu', 'е', $origstr);
pcre_check_error($buf);
pcre_no_error($buf);
}
if ($buf === null) {
logError(__METHOD__.': preg_replace() failed with error: '.preg_last_error().': '.preg_last_error_msg());

View File

@ -297,7 +297,7 @@ function is_retina(): bool { return isset($_COOKIE['is_retina']) && $_COOKIE['is
function jsonEncode($obj): ?string { return json_encode($obj, JSON_UNESCAPED_UNICODE) ?: null; }
function jsonDecode($json) { return json_decode($json, true); }
function pcre_check_error(mixed &$result, bool $no_error = false): bool {
function pcre_no_error(mixed &$result, bool $no_error = false): bool {
if ($result === null) {
if (preg_last_error() !== PREG_NO_ERROR) {
if (!$no_error)

View File

@ -505,4 +505,33 @@ body.wide .blog-post {
margin-bottom: 0;
}
}
}
span.blog-footnote-ref, a.blog-ref {
display: inline-block;
color: $blog-ref-color;
font-family: "Liberation Mono", monospace;
font-size: $fs - 2px;
letter-spacing: -0.5px;
}
a.blog-ref {
@include no-underline();
padding: 0 1px;
margin-left: -2px;
}
@media (hover: hover) {
a.blog-ref:hover {
color: $blog-ref-color-hover;
background-color: $blog-ref-bg-hover;
border-radius: 3px;
}
}
p.blog-footnote-line:target {
background-color: $blog-ref-bg-hover;
border-radius: 3px;
a {
@include no-underline(true);
}
}

View File

@ -9,6 +9,9 @@
height: 0;
}
html {
scroll-behavior: smooth;
}
html, body {
padding: 0;
margin: 0;

View File

@ -50,6 +50,10 @@ $pn-button-current-text-color: $bg;
$head-items-separator: #5e6264;
$blog-ref-color: $dark-grey;
$blog-ref-color-hover: #8c9aab;
$blog-ref-bg-hover: $hover-hl;
// colors from https://github.com/Kelbster/highlightjs-material-dark-theme/blob/master/css/materialdark.css
$hljs_fg: #CDD3D8;
$hljs_bg: #2B2B2D;

View File

@ -52,6 +52,10 @@ $pn-button-current-text-color: $fg;
$head-items-separator: #d0d0d0;
$blog-ref-color: #888;
$blog-ref-color-hover: #6a88ab;
$blog-ref-bg-hover: #f0f5fa;
// github.com style (c) Vasily Polovnyov <vast@whiteants.net>
$hljs_fg: #333;
$hljs_bg: #f8f8f8;

View File

@ -11,9 +11,35 @@ class markup {
bool $no_paragraph = false): string {
$pd = new MyParsedown(useImagePreviews: $use_image_previews, lang: $lang);
$html = $pd->text($md);
if ($no_paragraph) {
if ($no_paragraph)
$html = preg_replace('/<p>(.*?)<\/p>/', '$1', $html);
else {
// collect references
$re = '/^<p>(\[([io]?\d{1,2})]) (.*?)<\/p>/m';
$result = preg_match_all($re, $html, $matches);
if (pcre_no_error($result)) {
$reftitles_map = [];
foreach ($matches[2] as $i => $refname) {
$reftitles_map[$refname] = trim(strip_tags($matches[3][$i]));
}
$span_opening_tag = '<span class="blog-footnote-ref">';
$html = preg_replace($re, '<p class="blog-footnote-line" id="footnote_$2">'.$span_opening_tag.'$1</span> $3</p>', $html);
$re = '/'.implode('|', array_map(fn($m) => '(?:'.$span_opening_tag.')?'.preg_quote($m, '/'), $matches[1])).'/';
$html = preg_replace_callback($re,
function($match) use ($span_opening_tag, $reftitles_map) {
if (str_starts_with($match[0], $span_opening_tag))
return $match[0];
if (!preg_match('/\[([io]?\d{1,2})]/', $match[0], $refmatch))
return $match[0];
$refname = $refmatch[1];
$reftitle = $reftitles_map[$refname];
return '<a href="#footnote_'.$refname.'" class="blog-ref" title="'.htmlescape($reftitle).'">'.$match[0].'</a>';
}, $html);
}
}
return $html;
}