mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-20 15:57:06 +08:00
refactor(editor): unify directories naming (#11516)
**Directory Structure Changes** - Renamed multiple block-related directories by removing the "block-" prefix: - `block-attachment` → `attachment` - `block-bookmark` → `bookmark` - `block-callout` → `callout` - `block-code` → `code` - `block-data-view` → `data-view` - `block-database` → `database` - `block-divider` → `divider` - `block-edgeless-text` → `edgeless-text` - `block-embed` → `embed`
This commit is contained in:
75
blocksuite/affine/blocks/list/src/utils/forward-delete.ts
Normal file
75
blocksuite/affine/blocks/list/src/utils/forward-delete.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { ListBlockModel } from '@blocksuite/affine-model';
|
||||
import {
|
||||
getNextContentBlock,
|
||||
matchModels,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { type BlockStdScope, TextSelection } from '@blocksuite/std';
|
||||
import type { Text } from '@blocksuite/store';
|
||||
|
||||
// When deleting at line end of a list block,
|
||||
// check current block's children and siblings
|
||||
/**
|
||||
* Example:
|
||||
- Line1 <-(cursor here)
|
||||
- Line2
|
||||
- Line3
|
||||
- Line4
|
||||
- Line5
|
||||
- Line6
|
||||
- Line7
|
||||
- Line8
|
||||
- Line9
|
||||
*/
|
||||
export function forwardDelete(std: BlockStdScope): true | undefined {
|
||||
const text = std.selection.find(TextSelection);
|
||||
if (!text) return;
|
||||
const isCollapsed = text.isCollapsed();
|
||||
const doc = std.store;
|
||||
const model = doc.getBlock(text.from.blockId)?.model;
|
||||
if (!model || !matchModels(model, [ListBlockModel])) return;
|
||||
const isEnd = isCollapsed && text.from.index === model.props.text.length;
|
||||
if (!isEnd) return;
|
||||
// Has children in list
|
||||
const firstChild = model.firstChild();
|
||||
if (firstChild) {
|
||||
model.props.text.join(firstChild.text as Text);
|
||||
const grandChildren = firstChild.children;
|
||||
if (grandChildren) {
|
||||
doc.moveBlocks(grandChildren, model);
|
||||
doc.deleteBlock(firstChild);
|
||||
return true;
|
||||
}
|
||||
|
||||
doc.deleteBlock(firstChild);
|
||||
return true;
|
||||
}
|
||||
|
||||
const parent = doc.getParent(model);
|
||||
// Has text sibling
|
||||
const nextSibling = doc.getNext(model);
|
||||
const nextText = nextSibling?.text;
|
||||
if (nextSibling && nextText) {
|
||||
model.props.text.join(nextText);
|
||||
if (nextSibling.children) {
|
||||
if (!parent) return;
|
||||
doc.moveBlocks(nextSibling.children, parent, model, false);
|
||||
}
|
||||
|
||||
doc.deleteBlock(nextSibling);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Has next text block in other note block
|
||||
const nextBlock = getNextContentBlock(std.host, model);
|
||||
const nextBlockText = nextBlock?.text;
|
||||
if (nextBlock && nextBlockText) {
|
||||
model.props.text.join(nextBlock.text as Text);
|
||||
if (nextBlock.children) {
|
||||
const nextBlockParent = doc.getParent(nextBlock);
|
||||
if (!nextBlockParent) return;
|
||||
doc.moveBlocks(nextBlock.children, nextBlockParent, parent, false);
|
||||
}
|
||||
doc.deleteBlock(nextBlock);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
78
blocksuite/affine/blocks/list/src/utils/get-list-icon.ts
Normal file
78
blocksuite/affine/blocks/list/src/utils/get-list-icon.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { ListBlockModel } from '@blocksuite/affine-model';
|
||||
import {
|
||||
BulletedList01Icon,
|
||||
BulletedList02Icon,
|
||||
BulletedList03Icon,
|
||||
BulletedList04Icon,
|
||||
CheckBoxCheckSolidIcon,
|
||||
CheckBoxUnIcon,
|
||||
ToggleDownIcon,
|
||||
ToggleRightIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import { html } from 'lit';
|
||||
|
||||
import { getNumberPrefix } from './get-number-prefix.js';
|
||||
|
||||
const getListDeep = (model: ListBlockModel): number => {
|
||||
let deep = 0;
|
||||
let parent = model.doc.getParent(model);
|
||||
while (parent?.flavour === model.flavour) {
|
||||
deep++;
|
||||
parent = model.doc.getParent(parent);
|
||||
}
|
||||
return deep;
|
||||
};
|
||||
|
||||
const BulletIcons = [
|
||||
BulletedList01Icon({ width: '24px', height: '24px' }),
|
||||
BulletedList02Icon({ width: '24px', height: '24px' }),
|
||||
BulletedList03Icon({ width: '24px', height: '24px' }),
|
||||
BulletedList04Icon({ width: '24px', height: '24px' }),
|
||||
];
|
||||
|
||||
export function getListIcon(
|
||||
model: ListBlockModel,
|
||||
showChildren: boolean,
|
||||
onClick: (e: MouseEvent) => void
|
||||
) {
|
||||
const deep = getListDeep(model);
|
||||
switch (model.props.type) {
|
||||
case 'bulleted':
|
||||
return html`<div
|
||||
contenteditable="false"
|
||||
class="affine-list-block__prefix"
|
||||
@click=${onClick}
|
||||
>
|
||||
${BulletIcons[deep % BulletIcons.length]}
|
||||
</div>`;
|
||||
case 'numbered':
|
||||
return html`<div
|
||||
contenteditable="false"
|
||||
class="affine-list-block__prefix affine-list-block__numbered"
|
||||
@click=${onClick}
|
||||
>
|
||||
${model.props.order ? getNumberPrefix(model.props.order, deep) : '1.'}
|
||||
</div>`;
|
||||
case 'todo':
|
||||
return html`<div
|
||||
contenteditable="false"
|
||||
class=${`affine-list-block__prefix affine-list-block__todo-prefix ${model.doc.readonly ? 'readonly' : ''}`}
|
||||
@click=${onClick}
|
||||
>
|
||||
${model.props.checked
|
||||
? CheckBoxCheckSolidIcon({ style: 'color: #1E96EB' })
|
||||
: CheckBoxUnIcon()}
|
||||
</div>`;
|
||||
case 'toggle':
|
||||
return html`<div
|
||||
contenteditable="false"
|
||||
class="affine-list-block__prefix"
|
||||
@click=${onClick}
|
||||
>
|
||||
${showChildren ? ToggleDownIcon() : ToggleRightIcon()}
|
||||
</div>`;
|
||||
default:
|
||||
console.error('Unknown list type', model.props.type, model);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
52
blocksuite/affine/blocks/list/src/utils/get-number-prefix.ts
Normal file
52
blocksuite/affine/blocks/list/src/utils/get-number-prefix.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
function number2letter(n: number) {
|
||||
const ordA = 'a'.charCodeAt(0);
|
||||
const ordZ = 'z'.charCodeAt(0);
|
||||
const len = ordZ - ordA + 1;
|
||||
let s = '';
|
||||
while (n >= 0) {
|
||||
s = String.fromCharCode((n % len) + ordA) + s;
|
||||
n = Math.floor(n / len) - 1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// Derive from https://gist.github.com/imilu/00f32c61e50b7ca296f91e9d96d8e976
|
||||
export function number2roman(num: number) {
|
||||
const lookup: Record<string, number> = {
|
||||
M: 1000,
|
||||
CM: 900,
|
||||
D: 500,
|
||||
CD: 400,
|
||||
C: 100,
|
||||
XC: 90,
|
||||
L: 50,
|
||||
XL: 40,
|
||||
X: 10,
|
||||
IX: 9,
|
||||
V: 5,
|
||||
IV: 4,
|
||||
I: 1,
|
||||
};
|
||||
let romanStr = '';
|
||||
for (const i in lookup) {
|
||||
while (num >= lookup[i]) {
|
||||
romanStr += i;
|
||||
num -= lookup[i];
|
||||
}
|
||||
}
|
||||
return romanStr;
|
||||
}
|
||||
|
||||
function getPrefix(depth: number, index: number) {
|
||||
const map = [
|
||||
() => index,
|
||||
() => number2letter(index - 1),
|
||||
() => number2roman(index),
|
||||
];
|
||||
return map[depth % map.length]();
|
||||
}
|
||||
|
||||
export function getNumberPrefix(index: number, depth: number) {
|
||||
const prefix = getPrefix(depth, index);
|
||||
return `${prefix}.`;
|
||||
}
|
||||
Reference in New Issue
Block a user