feat: complete portable page block set

This commit is contained in:
冰朔 2026-07-17 10:30:04 +08:00
parent 9fc5e88574
commit 2b57543d78
6 changed files with 72 additions and 7 deletions

View File

@ -109,6 +109,22 @@
--tolaria-callout-bg: color-mix(in srgb, #dc2626 10%, var(--bg-primary)); --tolaria-callout-bg: color-mix(in srgb, #dc2626 10%, var(--bg-primary));
} }
.tolaria-callout[data-kind="annotation"] {
--tolaria-callout-accent: #8b5cf6;
--tolaria-callout-bg: color-mix(in srgb, #8b5cf6 11%, var(--bg-primary));
}
.tolaria-callout[data-kind="relationship"] {
--tolaria-callout-accent: #0f9f8f;
--tolaria-callout-bg: color-mix(in srgb, #0f9f8f 11%, var(--bg-primary));
}
.tolaria-callout[data-kind="path"] {
--tolaria-callout-accent: #4f7ecb;
--tolaria-callout-bg: color-mix(in srgb, #4f7ecb 11%, var(--bg-primary));
border-style: dashed;
}
.tolaria-callout__marker { .tolaria-callout__marker {
width: 4px; width: 4px;
min-height: 100%; min-height: 100%;

View File

@ -356,8 +356,11 @@ const GuanghuPortalBlock = createReactBlockSpec(
) )
const CALLOUT_LABELS: Record<TolariaCalloutKind, string> = { const CALLOUT_LABELS: Record<TolariaCalloutKind, string> = {
annotation: '批注',
danger: 'Danger', danger: 'Danger',
info: 'Info', info: 'Info',
path: '路径',
relationship: '关系',
success: 'Success', success: 'Success',
warning: 'Warning', warning: 'Warning',
} }

View File

@ -60,7 +60,7 @@ describe('tolariaEditorFormatting', () => {
]) ])
}) })
it('filters unsupported toggle slash-menu variants and removes command descriptions', () => { it('keeps Notion-style toggles, filters oversized headings, and removes command descriptions', () => {
type TolariaSlashMenuTestItem = { type TolariaSlashMenuTestItem = {
key: string key: string
title: string title: string
@ -82,6 +82,8 @@ describe('tolariaEditorFormatting', () => {
] satisfies TolariaSlashMenuTestItem[]) ] satisfies TolariaSlashMenuTestItem[])
expect(items.map((item) => item.key)).toEqual([ expect(items.map((item) => item.key)).toEqual([
'toggle_heading',
'toggle_list',
'heading', 'heading',
'heading_4', 'heading_4',
'bullet_list', 'bullet_list',
@ -94,6 +96,8 @@ describe('tolariaEditorFormatting', () => {
undefined, undefined,
undefined, undefined,
undefined, undefined,
undefined,
undefined,
]) ])
}) })
@ -280,6 +284,12 @@ describe('tolariaEditorFormatting', () => {
styles: {}, styles: {},
}], }],
}]) }])
expect(items.map(item => item.key)).toEqual(expect.arrayContaining([
'tolaria_callout_annotation',
'tolaria_callout_relationship',
'tolaria_callout_path',
]))
}) })
it('creates a math slash command with a default display equation', () => { it('creates a math slash command with a default display equation', () => {

View File

@ -9,6 +9,7 @@ import {
CheckCircle, CheckCircle,
File, File,
FlowArrow, FlowArrow,
GitBranch,
ImageSquare, ImageSquare,
Info, Info,
ListBullets, ListBullets,
@ -21,6 +22,7 @@ import {
ScribbleLoop, ScribbleLoop,
Smiley, Smiley,
SpeakerHigh, SpeakerHigh,
Tag,
Table, Table,
TextHOne, TextHOne,
TextHTwo, TextHTwo,
@ -90,10 +92,6 @@ const UNSUPPORTED_FORMATTING_TOOLBAR_KEYS = new Set([
const UNSUPPORTED_SLASH_MENU_KEYS = new Set([ const UNSUPPORTED_SLASH_MENU_KEYS = new Set([
'heading_5', 'heading_5',
'heading_6', 'heading_6',
'toggle_heading',
'toggle_heading_2',
'toggle_heading_3',
'toggle_list',
]) ])
const TOLARIA_BLOCK_TYPE_SELECT_ICONS: Record<RichEditorBlockTypeKey, PhosphorIcon> = { const TOLARIA_BLOCK_TYPE_SELECT_ICONS: Record<RichEditorBlockTypeKey, PhosphorIcon> = {
@ -131,6 +129,9 @@ const TOLARIA_SLASH_MENU_ICONS: Partial<Record<string, PhosphorIcon>> = {
quote: Quotes, quote: Quotes,
tolaria_callout_danger: XCircle, tolaria_callout_danger: XCircle,
tolaria_callout_info: Info, tolaria_callout_info: Info,
tolaria_callout_annotation: Tag,
tolaria_callout_path: FlowArrow,
tolaria_callout_relationship: GitBranch,
tolaria_callout_success: CheckCircle, tolaria_callout_success: CheckCircle,
tolaria_callout_warning: Warning, tolaria_callout_warning: Warning,
table: Table, table: Table,
@ -237,6 +238,24 @@ export function createCalloutSlashMenuItems(
aliases: ['callout', 'danger', 'risk', 'error', '风险', '危险'], aliases: ['callout', 'danger', 'risk', 'error', '风险', '危险'],
kind: 'danger', kind: 'danger',
}), }),
createCalloutSlashMenuItem(editor, {
key: 'tolaria_callout_annotation',
title: '批注 / Annotation',
aliases: ['annotation', 'comment', 'note', '批注', '注释'],
kind: 'annotation',
}),
createCalloutSlashMenuItem(editor, {
key: 'tolaria_callout_relationship',
title: '关系卡 / Relationship',
aliases: ['relationship', 'relation', 'wikilink', '关系', '关联'],
kind: 'relationship',
}),
createCalloutSlashMenuItem(editor, {
key: 'tolaria_callout_path',
title: '路径包 / Path map',
aliases: ['path', 'breadcrumb', 'route', 'map', '路径', '面包屑', '导航'],
kind: 'path',
}),
] ]
} }

View File

@ -127,6 +127,15 @@ describe('BlockNote direct Markdown serialization', () => {
children: [], children: [],
}, },
]).markdown).toBe('> [!success] Package is ready') ]).markdown).toBe('> [!success] Package is ready')
expect(blocksToMarkdownDirect([
{
type: TOLARIA_CALLOUT_BLOCK_TYPE,
props: { kind: 'relationship' },
content: [{ type: 'text', text: '[[TCS]] → [[HoloLake]]', styles: {} }],
children: [],
},
]).markdown).toBe('> [!relationship] [[TCS]] → [[HoloLake]]')
}) })
it('caches unchanged block objects across rich-editor body serialization', () => { it('caches unchanged block objects across rich-editor body serialization', () => {

View File

@ -2,11 +2,19 @@ import type { BlockLike } from './durableMarkdownBlocks'
export const TOLARIA_CALLOUT_BLOCK_TYPE = 'tolariaCallout' export const TOLARIA_CALLOUT_BLOCK_TYPE = 'tolariaCallout'
export const TOLARIA_CALLOUT_KINDS = ['info', 'success', 'warning', 'danger'] as const export const TOLARIA_CALLOUT_KINDS = [
'info',
'success',
'warning',
'danger',
'annotation',
'relationship',
'path',
] as const
export type TolariaCalloutKind = typeof TOLARIA_CALLOUT_KINDS[number] export type TolariaCalloutKind = typeof TOLARIA_CALLOUT_KINDS[number]
const CALLOUT_MARKER_RE = /^\[!(info|success|warning|danger)\]\s*(.*)$/iu const CALLOUT_MARKER_RE = /^\[!(info|success|warning|danger|annotation|relationship|path)\]\s*(.*)$/iu
function isCalloutKind(value: unknown): value is TolariaCalloutKind { function isCalloutKind(value: unknown): value is TolariaCalloutKind {
return typeof value === 'string' && TOLARIA_CALLOUT_KINDS.includes(value as TolariaCalloutKind) return typeof value === 'string' && TOLARIA_CALLOUT_KINDS.includes(value as TolariaCalloutKind)