help-beta: Add ZulipTip custom component that does not have a header.

We do not want to have a heading for every tip and thus we created a
custom component for our aside. We want to add a lightbulb icon and the
text `Tip:` is bold as a prefix for every tip as if it was already part
of the text. To do that, we cannot insert both of those as html seperate
from the slot html, we had to access the slot html and insert both of
them into the HTML tree.
This commit is contained in:
Shubham Padia
2025-07-24 10:52:05 +00:00
committed by Tim Abbott
parent 78eed0a817
commit cb852b0fa6
4 changed files with 76 additions and 4 deletions

View File

@@ -0,0 +1,66 @@
---
import assert from "node:assert/strict";
import type {Element} from "hast";
import {fromHtml} from "hast-util-from-html";
import {toHtml} from "hast-util-to-html";
import lightbulb_svg from "../../../web/shared/icons/lightbulb.svg?raw";
const lightbulb_icon_fragment = fromHtml(lightbulb_svg, {fragment: true});
const lightbulb_icon_first_child = lightbulb_icon_fragment.children[0]!;
assert.ok(
lightbulb_icon_first_child.type === "element" &&
lightbulb_icon_first_child.tagName === "svg",
);
lightbulb_icon_first_child.properties.class = "zulip-unplugin-icon";
// We need to make the fill transparent for the bulb to look hollow
// and the default vertical-align of text-bottom was not looking
// good beside the `Tip` text.
lightbulb_icon_first_child.properties.style =
"vertical-align: text-top; fill: transparent; stroke: currentColor;";
let prefix_element_list = [
lightbulb_icon_first_child,
{
type: "element",
tagName: "strong",
properties: {},
children: [
{
type: "text",
// Whitespace before the text to ensure space between
// this text and the preceding icon.
value: " Tip: ",
},
],
} as Element,
];
const tree = fromHtml(await Astro.slots.render("default"), {fragment: true});
const first_element = tree.children[0];
assert.ok(first_element?.type === "element");
// This is currently happening only in one case, for _ImportSelfHostedServerTips.mdx
// where the tip contains an unordered list. Just placing the element as is without
// a paragraph does not look good in that case.
if (first_element.tagName !== "p") {
prefix_element_list = [
{
type: "element",
tagName: "p",
properties: {},
children: [...prefix_element_list],
} as Element,
];
}
first_element.children = [...prefix_element_list, ...first_element.children];
tree.children[0] = first_element;
---
<aside aria-label="Tip" class=`starlight-aside starlight-aside--tip`>
<div class="starlight-aside__content">
<Fragment set:html={toHtml(tree)} />
</div>
</aside>