init: the first public commit for AFFiNE
This commit is contained in:
10
libs/components/editor-blocks/src/blocks/toc/index.ts
Normal file
10
libs/components/editor-blocks/src/blocks/toc/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { BaseView } from '@toeverything/framework/virgo';
|
||||
import { Protocol } from '@toeverything/datasource/db-service';
|
||||
import { TocView } from './toc-view';
|
||||
|
||||
export class TocBlock extends BaseView {
|
||||
type = Protocol.Block.Type.toc;
|
||||
View = TocView;
|
||||
|
||||
// TODO: html2block block2html
|
||||
}
|
||||
32
libs/components/editor-blocks/src/blocks/toc/toc-util.ts
Normal file
32
libs/components/editor-blocks/src/blocks/toc/toc-util.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Protocol } from '@toeverything/datasource/db-service';
|
||||
import { AsyncBlock } from '@toeverything/framework/virgo';
|
||||
|
||||
export const is_heading_child_type = (child: AsyncBlock) => {
|
||||
if (!child) return false;
|
||||
if (
|
||||
Protocol.Block.Type.heading1 === child.type ||
|
||||
Protocol.Block.Type.heading2 === child.type ||
|
||||
Protocol.Block.Type.heading3 === child.type
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
export const get_heading_child_title = (child: AsyncBlock) => {
|
||||
return (child as any).getProperties()?.['text']?.[0]?.text;
|
||||
};
|
||||
export const get_heading_child_level = (child: AsyncBlock) => {
|
||||
let level = 1;
|
||||
switch (child.type) {
|
||||
case Protocol.Block.Type.heading1:
|
||||
level = 1;
|
||||
break;
|
||||
case Protocol.Block.Type.heading2:
|
||||
level = 2;
|
||||
break;
|
||||
case Protocol.Block.Type.heading3:
|
||||
level = 3;
|
||||
break;
|
||||
}
|
||||
return level;
|
||||
};
|
||||
85
libs/components/editor-blocks/src/blocks/toc/toc-view.tsx
Normal file
85
libs/components/editor-blocks/src/blocks/toc/toc-view.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { CreateView } from '@toeverything/framework/virgo';
|
||||
import {
|
||||
is_heading_child_type,
|
||||
get_heading_child_title,
|
||||
get_heading_child_level,
|
||||
} from './toc-util';
|
||||
import { MenuItem } from './types';
|
||||
import { styled } from '@toeverything/components/ui';
|
||||
const INITIAL_LIST: MenuItem[] = [];
|
||||
const MESSAGES = {
|
||||
NO_HEADINGS_FOUND: 'No headings found',
|
||||
};
|
||||
export const TocView: FC<CreateView> = ({ block, editor }) => {
|
||||
const [list, setList] = useState(INITIAL_LIST);
|
||||
useEffect(() => {
|
||||
const sync_toc = async () => {
|
||||
const parent_block = await block.parent();
|
||||
const parent_children = await parent_block.children();
|
||||
const tmp_list: MenuItem[] = [];
|
||||
parent_children.forEach(child => {
|
||||
if (is_heading_child_type(child)) {
|
||||
tmp_list.push({
|
||||
id: child.id,
|
||||
title: get_heading_child_title(child),
|
||||
level: get_heading_child_level(child),
|
||||
});
|
||||
}
|
||||
});
|
||||
//TODO observe block change , timely update tmp_list
|
||||
setList(tmp_list);
|
||||
};
|
||||
sync_toc();
|
||||
}, [block, block.parent]);
|
||||
|
||||
return (
|
||||
<ToContainer>
|
||||
{list.length ? (
|
||||
<ul className={'menu'}>
|
||||
{list.map((menu, index) => (
|
||||
<li
|
||||
key={menu.id}
|
||||
className={'menuItem'}
|
||||
style={{
|
||||
paddingLeft: (menu.level - 1) * 20 + 'px',
|
||||
}}
|
||||
>
|
||||
{menu.title}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p className={'noHeadingsFound'}>
|
||||
{MESSAGES.NO_HEADINGS_FOUND}
|
||||
</p>
|
||||
)}
|
||||
</ToContainer>
|
||||
);
|
||||
};
|
||||
const ToContainer = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
'.checkBoxContainer': {
|
||||
marginRight: '4px',
|
||||
padding: '10px 0',
|
||||
height: theme.affine.typography.body1.lineHeight,
|
||||
},
|
||||
'.menu': {
|
||||
listStyleType: 'none',
|
||||
width: '100%',
|
||||
},
|
||||
'.menuItem': {
|
||||
fontSize: '14px',
|
||||
height: '30px',
|
||||
lineHeight: '30px',
|
||||
color: 'var(--color-gray-400)',
|
||||
textDecorationLine: 'underline',
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--color-gray-100)',
|
||||
},
|
||||
},
|
||||
'.noHeadingsFound': {
|
||||
color: 'var(--color-gray-400)',
|
||||
},
|
||||
}));
|
||||
5
libs/components/editor-blocks/src/blocks/toc/types.ts
Normal file
5
libs/components/editor-blocks/src/blocks/toc/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface MenuItem {
|
||||
title: string;
|
||||
id: string;
|
||||
level: number;
|
||||
}
|
||||
Reference in New Issue
Block a user