Skip to content

Commit

Permalink
优化 TOC 生成
Browse files Browse the repository at this point in the history
修正 import
  • Loading branch information
wherewhere committed Jan 25, 2025
1 parent 8d6682e commit f40f5ab
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 85 deletions.
2 changes: 1 addition & 1 deletion Wherlog/Controls/FillColorDiv.razor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as fluent from "/_content/Microsoft.FluentUI.AspNetCore.Components/Microsoft.FluentUI.AspNetCore.Components.lib.module.js"
import * as fluent from "../_content/Microsoft.FluentUI.AspNetCore.Components/Microsoft.FluentUI.AspNetCore.Components.lib.module.js"

export function setFillColor(element, color) {
if (element instanceof HTMLElement) {
Expand Down
5 changes: 5 additions & 0 deletions Wherlog/Controls/MarkdownSection.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
max-width: 100%;
}

::deep img.emoji {
height: 18px;
width: 18px;
}

::deep .snippet {
margin-bottom: 0.5rem;
border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-rest);
Expand Down
9 changes: 5 additions & 4 deletions Wherlog/Controls/PostCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

@if (Post != null)
{
<div class="post-card" @onclick="() => OnClick(Post.Url)">
<h3>@Post.Title</h3>
<div class="post-card" @onclick="() => OnClick(Post.Url)" @ref="content">
<h2>@Post.Title</h2>
@(new MarkupString(Post.Excerpt))
</div>
}
Expand All @@ -16,6 +16,7 @@
private const string JAVASCRIPT_FILE = $"./{nameof(Controls)}/{nameof(PostCard)}.razor.js";

private IJSObjectReference _jsModule;
private ElementReference content;

[Parameter]
public PostModel Post { get; set; }
Expand All @@ -28,8 +29,8 @@
{
// add highlight for any code blocks
_jsModule ??= await JSRuntime.InvokeAsync<IJSObjectReference>("import", JAVASCRIPT_FILE);
await _jsModule.InvokeVoidAsync("highlight");
await _jsModule.InvokeVoidAsync("fixImage");
await _jsModule.InvokeVoidAsync("highlight", content);
await _jsModule.InvokeVoidAsync("fixImage", content);
}
}

Expand Down
41 changes: 27 additions & 14 deletions Wherlog/Controls/PostCard.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,43 @@
max-width: 100%;
}

::deep img.emoji {
height: 18px;
margin-bottom: -3px;
}
::deep img.emoji {
height: 18px;
width: 18px;
}

::deep figure.hljs-highlight table {
::deep figure.highlight {
display: block;
border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-rest);
border-radius: calc(var(--control-corner-radius) * 1px);
background-color: var(--neutral-layer-2);
overflow-x: auto;
}

::deep td.hljs-gutter {
visibility: collapse;
}
::deep figure.highlight table {
margin-bottom: 0;
}

::deep td.hljs-code {
padding: 0px 5px 0px 0px;
}
::deep figure.highlight pre {
border: 0;
margin: 0;
padding: 1em;
}

::deep figure.highlight .gutter {
user-select: none;
}

::deep figure.highlight .gutter pre {
background-color: var(--neutral-layer-2);
padding-left: 10px;
padding-right: 10px;
text-align: right;
}

::deep td.hljs-code pre {
margin-bottom: 0px;
tab-size: 2em;
::deep figure.highlight .code pre {
padding-left: 10px;
width: 100%;
}

::deep figcaption {
Expand Down
54 changes: 28 additions & 26 deletions Wherlog/Controls/PostCard.razor.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
export function highlight() {
const elements = document.getElementsByClassName("highlight");
const numberOfElements = elements.length;
for (let i = 0; i < numberOfElements; i++) {
setElements(elements[i]);
}
function setElements(element) {
if (element instanceof Element) {
const className = [];
element.classList.forEach(x => className.push("hljs-" + x));
element.className = className.join(' ');
const numberOfElements = +element?.children.length;
for (let i = 0; i < numberOfElements; i++) {
setElements(element.children[i]);
}
export function highlight(element) {
if (!(element instanceof Element)) { return; }
const figure = element.querySelectorAll("figure.highlight");
figure.forEach(element => {
// Skip pre > .mermaid for folding and copy button
if (element.querySelector(".mermaid")) return;
let span = element.querySelectorAll(".code .line span");
if (span.length === 0) {
// Hljs without line_number and wrap
span = element.querySelectorAll("code.highlight span");
}
}
span.forEach(s => {
s.classList.forEach(name => {
if (!name.startsWith("hljs-")) {
s.classList.replace(name, `hljs-${name}`);
}
});
});
});
}

export function fixImage() {
const images = document.getElementsByTagName("img");
const numberOfElements = images.length;
for (let i = 0; i < numberOfElements; i++) {
const image = images[i];
const src = image.getAttribute("data-src");
if (src) {
image.removeAttribute("data-src");
image.setAttribute("src", src);
}
export function fixImage(element) {
if (element instanceof Element) {
const images = element.querySelectorAll("img[data-src]:not([src])");
images.forEach(image => {
const src = image.getAttribute("data-src");
if (src) {
image.removeAttribute("data-src");
image.setAttribute("src", src);
}
});
}
}
20 changes: 6 additions & 14 deletions Wherlog/Controls/TableOfContents.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public override int GetHashCode()
}

private Anchor[] _anchors;
private bool _expanded = true;
private bool _expanded = false;
private bool _isMobile = false;

private IJSObjectReference _jsModule;

Expand All @@ -71,7 +72,6 @@ public override int GetHashCode()
/// <summary>
/// Gets or sets the content to be rendered inside the component.
/// </summary>

[Parameter]
public RenderFragment ChildContent { get; set; }

Expand All @@ -80,12 +80,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
if (firstRender)
{
_jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", JAVASCRIPT_FILE);
bool mobile = await _jsModule.InvokeAsync<bool>("isDevice");

if (mobile)
{
_expanded = false;
}
_isMobile = await _jsModule.InvokeAsync<bool>("isDevice");

await BackToTopAsync();
await QueryDomAsync();
Expand Down Expand Up @@ -116,14 +111,13 @@ private async Task QueryDomAsync()
}

_anchors = foundAnchors;
_expanded = !_isMobile && _anchors?.Length > 0;
StateHasChanged();
}

private static bool AnchorsEqual(Anchor[] firstSet, Anchor[] secondSet)
{
return (firstSet ?? [])
private static bool AnchorsEqual(Anchor[] firstSet, Anchor[] secondSet) =>
(firstSet ?? [])
.SequenceEqual(secondSet ?? []);
}

protected override void OnInitialized()
{
Expand Down Expand Up @@ -152,7 +146,6 @@ private RenderFragment GetTocItems(IEnumerable<Anchor> items)
? new RenderFragment(builder =>
{
int i = 0;

builder.OpenElement(i++, "ul");
foreach (Anchor item in items)
{
Expand All @@ -177,7 +170,6 @@ private RenderFragment GetTocItems(IEnumerable<Anchor> items)
{
builder.AddContent(0, ChildContent);
});

}

public async ValueTask DisposeAsync()
Expand Down
27 changes: 25 additions & 2 deletions Wherlog/Controls/TableOfContents.razor.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
::deep ul {
list-style: none;
text-overflow: ellipsis;
margin-bottom: 0;
line-height: 1.5;
}

::deep ul:first-of-type {
Expand All @@ -11,11 +13,33 @@
padding-right: 1rem;
}


li {
text-overflow: ellipsis;
}

::deep fluent-accordion-item {
box-sizing: border-box;
box-shadow: var(--elevation-shadow-card-rest);
border-radius: calc(var(--control-corner-radius) * 1px);
}

::deep fluent-accordion-item:hover {
background: var(--neutral-fill-input-hover);
border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-layer-hover);
box-shadow: var(--elevation-shadow-card-hover);
}

::deep fluent-accordion-item:active {
background: var(--neutral-fill-input-active);
border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-layer-active);
box-shadow: var(--elevation-shadow-card-pressed);
}

::deep fluent-accordion-item::part(region),
::deep fluent-accordion-item .region {
border-bottom-left-radius: calc((var(--control-corner-radius) - var(--stroke-width)) * 1px);
border-bottom-right-radius: calc((var(--control-corner-radius) - var(--stroke-width)) * 1px);
}

::deep fluent-anchor::part(control) {
color: var(--neutral-foreground-rest);
Expand All @@ -35,7 +59,6 @@ li {
text-decoration: underline;
}


::deep fluent-button {
position: fixed;
bottom: -300px;
Expand Down
83 changes: 59 additions & 24 deletions Wherlog/Controls/TableOfContents.razor.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,74 @@
export function queryDomForTocEntries() {
const article = document.getElementById("article");
const headings = article.querySelectorAll("h2, h3, h4");
const headings = article.querySelectorAll("h2, h3, h4, h5, h6");
if (!headings.length) { return []; }

const tocArray = [];
let chapter = null;
let subchapter = null;

for (let element of headings) {
const levels = [false, false, false, false, false];
for (const element of headings) {
if (!element.id) {
const anchorText = element.innerText;
const elementId = anchorText.replaceAll(' ', '-', '/', '\\', '#', '$', '@', ':', ',').toLowerCase();
element.id = elementId;
}
if (element.innerText) {
const anchor = {
level: element.nodeName,
text: element.innerText,
href: '#' + element.id,
anchors: []
};

if ("H3" === element.nodeName) {
if (chapter) {
subchapter = anchor;
chapter.anchors.push(subchapter);
}
} else if ("H4" === element.nodeName) {
if (subchapter) {
subchapter.anchors.push(anchor);
}
if (!levels[0] && element.nodeName === "H2") {
levels[0] = true;
}
else if (!levels[1] && element.nodeName === "H3") {
levels[1] = true;
}
else if (!levels[2] && element.nodeName === "H4") {
levels[2] = true;
}
else if (!levels[3] && element.nodeName === "H5") {
levels[3] = true;
}
else if (!levels[4] && element.nodeName === "H6") {
levels[4] = true;
}
}

let tag, chapterTag, subchapterTag;
for (let i = 0; i < levels.length; i++) {
if (levels[i]) {
if (!tag) {
tag = `H${i + 2}`;
}
else if (!chapterTag) {
chapterTag = `H${i + 2}`;
}
else if (!subchapterTag) {
subchapterTag = `H${i + 2}`;
}
else {
chapter = anchor;
break;
}
}
}

function createAnchor(element) {
return {
level: element.nodeName,
text: element.innerText,
href: '#' + element.id,
anchors: []
};
}

const tocArray = [];
let chapter = null, subchapter = null;
for (const element of headings) {
if (element.innerText) {
if (element.nodeName === tag) {
chapter = createAnchor(element);
tocArray.push(chapter);
}
else if (chapter && chapterTag && element.nodeName === chapterTag) {
subchapter = createAnchor(element);
chapter.anchors.push(subchapter);
}
else if (subchapter && subchapterTag && element.nodeName === subchapterTag) {
subchapter.anchors.push(createAnchor(element));
}
}
}
return tocArray;
Expand Down

0 comments on commit f40f5ab

Please sign in to comment.