Commit 1e114fe
Changed files (4)
src
src/components/user/index.ts
@@ -3,6 +3,7 @@ export { default as Icon } from './Icon.astro';
export { default as LinkCard } from './LinkCard.astro';
export { default as Repl } from './Repl.astro';
export { default as RepoCard } from './RepoCard.astro';
+export { default as Ruby } from './Ruby.astro';
export { default as Tabs } from './Tabs.astro';
export { default as TabItem } from './TabItem.astro';
export { default as Tooltip } from './Tooltip.astro';
src/components/user/Ruby.astro
@@ -0,0 +1,34 @@
+---
+interface RubyPair {
+ base: string;
+ text: string;
+}
+
+type Props = (RubyPair | { pairs: RubyPair[] | [string, string][] }) & {
+ rp?: [string, string];
+};
+
+const props = Astro.props;
+const rpContent = props.rp || ['(', ')'];
+const pairs = (() => {
+ const p = 'pairs' in props ? props.pairs : ([props] as RubyPair[]);
+ if (p.length < 1) return p;
+ if ('base' in p[0]) return p;
+ return (p as [string, string][]).map(([base, text]) => ({ base, text }));
+})() as RubyPair[];
+---
+
+<ruby>
+ {
+ pairs.map(({ base, text }) => {
+ return (
+ <Fragment>
+ {base}
+ <rp>{rpContent[0]}</rp>
+ <rt>{text}</rt>
+ <rp>{rpContent[1]}</rp>
+ </Fragment>
+ );
+ })
+ }
+</ruby>
src/content/posts/components.mdx
@@ -9,12 +9,11 @@ tags:
published: 2025-02-10T21:23:23+08:00
---
-import { Collapse, Icon, LinkCard, Repl, RepoCard, TabItem, Tabs, Tooltip } from '@components/user';
+import { Collapse, Icon, LinkCard, Repl, RepoCard, Ruby, TabItem, Tabs, Tooltip } from '@components/user';
Components let you easily reuse a piece of UI or styling consistently. You can use them not just in `.astro` files, but also in `.mdx` files.
-> [!TIP]
-> [MDX](https://mdxjs.com/) is a format that lets you write JSX embedded inside Markdown. And it has no difference with markdown files in other ways.
+> [!TIP] > [MDX](https://mdxjs.com/) is a format that lets you write JSX embedded inside Markdown. And it has no difference with markdown files in other ways.
> [!TIP]
> Some components are both available in `.md` and `.mdx` files, but some are only available in `.mdx` files. In `.md` files, you can use components with [remark-directive](https://github.com/remarkjs/remark-directive). Components that available in `.md` files will have a `md` tab in the example.
@@ -143,6 +142,7 @@ Components let you easily reuse a piece of UI or styling consistently. You can u
</Repl>
### LinkCard
+
<Repl>
<LinkCard
title="Astral Halo"
@@ -257,6 +257,34 @@ Components let you easily reuse a piece of UI or styling consistently. You can u
</Fragment>
</Repl>
+### Ruby
+
+<Repl>
+ <div class="flex flex-col gap-2 w-fit mx-auto">
+ <Ruby pairs={[{base: "汉", text: "hàn"}, {base: "字", text: "zì"}]} />
+ <Ruby pairs={[["漢", "ㄏㄢ"], ["字", "ㄗ"]]} />
+ <Ruby base="漢字" text="からじ" />
+ </div>
+ <Fragment slot="desc">
+ <Tabs>
+ <TabItem label="mdx" active>
+ ```jsx
+ <Ruby pairs={[{base: "汉", text: "hàn"}, {base: "字", text: "zì"}]} />
+ <Ruby pairs={[["漢", "ㄏㄢ"], ["字", "ㄗ"]]} />
+ <Ruby base="漢字" text="からじ" />
+ ```
+ </TabItem>
+ <TabItem label="md">
+ ```md
+ ::rubyc{base="汉|字" text="hàn|zì"}
+ ::rubyc{base="漢|字" text="ㄏㄢ|ㄗ"}
+ ::rubyc{base="漢字" text="からじ"}
+ ```
+ </TabItem>
+ </Tabs>
+ </Fragment>
+</Repl>
+
## Web Contents
### RepoCard
src/plugins/rehype-components-list.ts
@@ -156,6 +156,37 @@ const LinkCard = function (props: { title: string; description: string; url: str
return h('a', { class: wrapperClassName, href: url, title }, bodyNode);
};
+const Ruby = function (props: { base: string; text: string }) {
+ const pairs = (() => {
+ const { base, text } = props;
+ const pattern = /(?<!\\)\|/g;
+ const baseGroups = base.split(pattern);
+ let textGroups = text.split(pattern);
+ if (baseGroups.length > textGroups.length) {
+ console.warn('[WARN] Invalid ruby, base splitter number should lesser than text.');
+ console.warn(` base: "${base}"`);
+ console.warn(` text: "${text}"`);
+ return [{ base, text }];
+ }
+ textGroups[baseGroups.length - 1] = textGroups.slice(baseGroups.length - 1).join(' ');
+ textGroups = textGroups.slice(0, baseGroups.length);
+ return baseGroups.map((b, i) => ({ base: b, text: textGroups[i] }));
+ })();
+ return h(
+ 'ruby',
+ {},
+ pairs.flatMap(
+ ({ base, text }) =>
+ [
+ { type: 'text', value: base },
+ h('rp', {}, '('),
+ h('rt', {}, text),
+ h('rp', {}, ')'),
+ ] as Child
+ )
+ );
+};
+
const Tooltip = function (
props: {
tip: string;
@@ -172,5 +203,6 @@ export const rehypeComponentsList = {
collapse: Collapse,
icon: Icon,
linkcard: LinkCard,
+ rubyc: Ruby,
tooltip: Tooltip,
};