Skip to content

Commit

Permalink
Merge pull request #9392 from weseek/imprv/callout-custom-label
Browse files Browse the repository at this point in the history
imprv: GitHub Alert with directive syntax
  • Loading branch information
mergify[bot] authored Nov 12, 2024
2 parents 29474b0 + 6ac22ec commit b455604
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 7 deletions.
20 changes: 20 additions & 0 deletions apps/app/resource/locales/en_US/sandbox-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@
> Advises about risks or negative outcomes of certain actions.
```

You can also use [directive syntax](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444).

:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::

```markdown
:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::
```


# Quote text
- Use quoted expressions by putting `>` at the beginning of the paragraph
Expand Down
20 changes: 20 additions & 0 deletions apps/app/resource/locales/fr_FR/sandbox-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@
> Advises about risks or negative outcomes of certain actions.
```

Vous pouvez également utiliser la [syntaxe de directive](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444).

:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::

```markdown
:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::
```


# Autres
## Citations
Expand Down
20 changes: 20 additions & 0 deletions apps/app/resource/locales/ja_JP/sandbox-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@
> Advises about risks or negative outcomes of certain actions.
```

[directive](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444) を使って記述することもできます。

:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::

```markdown
:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::
```


# テキストの引用
- 行頭に `>` を記述することで引用表現を記述できます
Expand Down
20 changes: 20 additions & 0 deletions apps/app/resource/locales/zh_CN/sandbox-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@
> Advises about risks or negative outcomes of certain actions.
```

您还可以使用[directive 语法](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444)

:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::

```markdown
:::note
Useful information that users should know, even when skimming content.
:::

:::tip[Custom Label]
Useful information that users should know, even when skimming content.
:::
```


# 引用
- 在段落开头放置 `>` 即可使用带引号的表达式
Expand Down
15 changes: 9 additions & 6 deletions apps/app/src/features/callout/components/CalloutViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type CALLOUT_TO = {
[key in Callout]: string;
}

const CALLOUT_TO_TITLE: CALLOUT_TO = {
const CALLOUT_TO_TYPE: CALLOUT_TO = {
note: 'Note',
tip: 'Tip',
important: 'Important',
Expand All @@ -36,26 +36,29 @@ const CALLOUT_TO_ICON: CALLOUT_TO = {
type CalloutViewerProps = {
children: ReactNode,
node: Element,
name: string
type: string,
label?: string,
}

export const CalloutViewer = React.memo((props: CalloutViewerProps): JSX.Element => {

const { node, name, children } = props;
const {
node, type, label, children,
} = props;

if (node == null) {
return <></>;
}

return (
<div className={`${moduleClass} callout-viewer`}>
<div className={`callout callout-${CALLOUT_TO_TITLE[name].toLowerCase()}`}>
<div className={`callout callout-${CALLOUT_TO_TYPE[type].toLowerCase()}`}>
<div className="callout-indicator">
<div className="callout-hint">
<span className="material-symbols-outlined">{CALLOUT_TO_ICON[name]}</span>
<span className="material-symbols-outlined">{CALLOUT_TO_ICON[type]}</span>
</div>
<div className="callout-title">
{CALLOUT_TO_TITLE[name]}
{label ?? CALLOUT_TO_TYPE[type]}
</div>
</div>
<div className="callout-content">
Expand Down
80 changes: 80 additions & 0 deletions apps/app/src/features/callout/services/callout.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { ContainerDirective } from 'mdast-util-directive';
import remarkDirective from 'remark-directive';
import remarkParse from 'remark-parse';
import { unified } from 'unified';
import { visit } from 'unist-util-visit';
import { describe, it, expect } from 'vitest';

import * as callout from './callout';

describe('remarkPlugin', () => {
it('should transform containerDirective to callout', () => {
const processor = unified()
.use(remarkParse)
.use(remarkDirective)
.use(callout.remarkPlugin);

const markdown = `
:::info
This is an info callout.
:::
`;

const tree = processor.parse(markdown);
processor.runSync(tree);

let calloutNode;
visit(tree, 'containerDirective', (node) => {
calloutNode = node;
});

expect(calloutNode).toBeDefined();

assert(calloutNode?.data?.hName != null);
assert(calloutNode?.data?.hProperties != null);

expect(calloutNode.data.hName).toBe('callout');
expect(calloutNode.data.hProperties.type).toBe('info');
expect(calloutNode.data.hProperties.label).toBe('info');

assert('children' in calloutNode.children[0]);
assert('value' in calloutNode.children[0].children[0]);

expect(calloutNode.children[0].children[0].value).toBe('This is an info callout.');
});

it('should transform containerDirective to callout with custom label', () => {
const processor = unified()
.use(remarkParse)
.use(remarkDirective)
.use(callout.remarkPlugin);

const markdown = `
:::info[CUSTOM LABEL]
This is an info callout.
:::
`;

const tree = processor.parse(markdown);
processor.runSync(tree);

let calloutNode: ContainerDirective | undefined;
visit(tree, 'containerDirective', (node) => {
calloutNode = node;
});

expect(calloutNode).toBeDefined();

assert(calloutNode?.data?.hName != null);
assert(calloutNode?.data?.hProperties != null);

expect(calloutNode.data.hName).toBe('callout');
expect(calloutNode.data.hProperties.type).toBe('info');
expect(calloutNode.data.hProperties.label).toBe('CUSTOM LABEL');

assert('children' in calloutNode.children[0]);
assert('value' in calloutNode.children[0].children[0]);

expect(calloutNode.children[0].children[0].value).toBe('This is an info callout.');
});
});
21 changes: 20 additions & 1 deletion apps/app/src/features/callout/services/callout.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Paragraph, Text } from 'mdast';
import type { ContainerDirective } from 'mdast-util-directive';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
Expand All @@ -8,16 +9,34 @@ export const remarkPlugin: Plugin = () => {
return (tree) => {
visit(tree, 'containerDirective', (node: ContainerDirective) => {
if (AllCallout.some(name => name === node.name.toLowerCase())) {
const type = node.name.toLowerCase();
const data = node.data ?? (node.data = {});

// extract directive label
const paragraphs = (node.children ?? []).filter((child): child is Paragraph => child.type === 'paragraph');
const paragraphForDirectiveLabel = paragraphs.find(p => p.data?.directiveLabel);
const label = paragraphForDirectiveLabel != null
? (paragraphForDirectiveLabel.children[0] as Text).value
: undefined;
// remove directive label from children
if (paragraphForDirectiveLabel != null) {
node.children.splice(node.children.indexOf(paragraphForDirectiveLabel), 1);
}

data.hName = 'callout';
data.hProperties = {
name: node.name.toLocaleLowerCase(),
type,
label: label ?? type,
};

}
});
};
};

export const sanitizeOption = {
tagNames: ['callout'],
attributes: {
callout: ['type', 'label'],
},
};

0 comments on commit b455604

Please sign in to comment.