Skip to content

Commit

Permalink
feat: support heading toggle (#8829)
Browse files Browse the repository at this point in the history
  • Loading branch information
Flrande authored Dec 17, 2024
1 parent 0169084 commit 53bba9c
Show file tree
Hide file tree
Showing 162 changed files with 1,226 additions and 343 deletions.
21 changes: 20 additions & 1 deletion packages/affine/block-list/src/commands/indent-list.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { IndentContext } from '@blocksuite/affine-shared/types';
import type { Command } from '@blocksuite/block-std';

import { matchFlavours } from '@blocksuite/affine-shared/utils';
import {
getNearestHeadingBefore,
matchFlavours,
} from '@blocksuite/affine-shared/utils';

import { correctNumberedListsOrderToPrev } from './utils.js';

Expand Down Expand Up @@ -115,6 +118,22 @@ export const indentListCommand: Command<'indentContext', never> = (
correctNumberedListsOrderToPrev(doc, model);
if (nextSibling) correctNumberedListsOrderToPrev(doc, nextSibling);

// 123
// > # 456
// 789
//
// we need to update 456 collapsed state to false when indent 789
const nearestHeading = getNearestHeadingBefore(model);
if (
nearestHeading &&
matchFlavours(nearestHeading, ['affine:paragraph']) &&
nearestHeading.collapsed
) {
doc.updateBlock(nearestHeading, {
collapsed: false,
});
}

const textSelection = selection.find('text');
if (textSelection) {
host.updateComplete
Expand Down
20 changes: 16 additions & 4 deletions packages/affine/block-paragraph/src/commands/dedent-paragraph.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { IndentContext } from '@blocksuite/affine-shared/types';
import type { Command } from '@blocksuite/block-std';

import { matchFlavours } from '@blocksuite/affine-shared/utils';
import {
calculateCollapsedSiblings,
matchFlavours,
} from '@blocksuite/affine-shared/utils';

export const canDedentParagraphCommand: Command<
never,
Expand Down Expand Up @@ -82,9 +85,18 @@ export const dedentParagraphCommand: Command<'indentContext'> = (ctx, next) => {

doc.captureSync();

const nextSiblings = doc.getNexts(model);
doc.moveBlocks(nextSiblings, model);
doc.moveBlocks([model], grandParent, parent, false);
if (
matchFlavours(model, ['affine:paragraph']) &&
model.type.startsWith('h') &&
model.collapsed
) {
const collapsedSiblings = calculateCollapsedSiblings(model);
doc.moveBlocks([model, ...collapsedSiblings], grandParent, parent, false);
} else {
const nextSiblings = doc.getNexts(model);
doc.moveBlocks(nextSiblings, model);
doc.moveBlocks([model], grandParent, parent, false);
}

const textSelection = selection.find('text');
if (textSelection) {
Expand Down
55 changes: 52 additions & 3 deletions packages/affine/block-paragraph/src/commands/indent-paragraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import type { ListBlockModel } from '@blocksuite/affine-model';
import type { IndentContext } from '@blocksuite/affine-shared/types';
import type { Command } from '@blocksuite/block-std';

import { matchFlavours } from '@blocksuite/affine-shared/utils';
import {
calculateCollapsedSiblings,
getNearestHeadingBefore,
matchFlavours,
} from '@blocksuite/affine-shared/utils';

export const canIndentParagraphCommand: Command<
never,
Expand Down Expand Up @@ -80,9 +84,54 @@ export const indentParagraphCommand: Command<'indentContext'> = (ctx, next) => {
if (!previousSibling) return;

doc.captureSync();
doc.moveBlocks([model], previousSibling);

// update collapsed state
{
// > # 123
// > # 456
//
// we need to update 123 collapsed state to false when indent 456
const nearestHeading = getNearestHeadingBefore(model);
if (
nearestHeading &&
matchFlavours(nearestHeading, ['affine:paragraph']) &&
nearestHeading.collapsed
) {
doc.updateBlock(nearestHeading, {
collapsed: false,
});
}
}

if (
matchFlavours(model, ['affine:paragraph']) &&
model.type.startsWith('h') &&
model.collapsed
) {
const collapsedSiblings = calculateCollapsedSiblings(model);
doc.moveBlocks([model, ...collapsedSiblings], previousSibling);
} else {
doc.moveBlocks([model], previousSibling);
}

{
// 123
// > # 456
// 789
//
// we need to update 456 collapsed state to false when indent 789
const nearestHeading = getNearestHeadingBefore(model);
if (
nearestHeading &&
matchFlavours(nearestHeading, ['affine:paragraph']) &&
nearestHeading.collapsed
) {
doc.updateBlock(nearestHeading, {
collapsed: false,
});
}
}

// update collapsed state of affine list
if (
matchFlavours(previousSibling, ['affine:list']) &&
previousSibling.collapsed
Expand Down
2 changes: 2 additions & 0 deletions packages/affine/block-paragraph/src/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import type {
import type { splitParagraphCommand } from './commands/split-paragraph.js';
import type { ParagraphBlockService } from './paragraph-service.js';

import { effects as ParagraphHeadingIconEffects } from './heading-icon.js';
import { ParagraphBlockComponent } from './paragraph-block.js';

export function effects() {
ParagraphHeadingIconEffects();
customElements.define('affine-paragraph', ParagraphBlockComponent);
}

Expand Down
89 changes: 89 additions & 0 deletions packages/affine/block-paragraph/src/heading-icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { ParagraphBlockModel } from '@blocksuite/affine-model';

import {
Heading1Icon,
Heading2Icon,
Heading3Icon,
Heading4Icon,
Heading5Icon,
Heading6Icon,
} from '@blocksuite/affine-components/icons';
import { ShadowlessElement } from '@blocksuite/block-std';
import { WithDisposable } from '@blocksuite/global/utils';
import { cssVarV2 } from '@toeverything/theme/v2';
import { css, html, nothing, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';

function HeadingIcon(i: number) {
switch (i) {
case 1:
return Heading1Icon;
case 2:
return Heading2Icon;
case 3:
return Heading3Icon;
case 4:
return Heading4Icon;
case 5:
return Heading5Icon;
case 6:
return Heading6Icon;
default:
return Heading1Icon;
}
}

export class ParagraphHeadingIcon extends WithDisposable(ShadowlessElement) {
static override styles = css`
affine-paragraph-heading-icon .heading-icon {
display: flex;
align-items: start;
margin-top: 0.3em;
position: absolute;
left: 0;
transform: translateX(-64px);
border-radius: 4px;
padding: 2px;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease-in-out;
pointer-events: none;
background: ${unsafeCSS(cssVarV2('button/iconButtonSolid', '#FFF'))};
color: ${unsafeCSS(cssVarV2('icon/primary', '#7A7A7A'))};
box-shadow:
var(--Shadow-buttonShadow-1-x, 0px) var(--Shadow-buttonShadow-1-y, 0px)
var(--Shadow-buttonShadow-1-blur, 1px) 0px
var(--Shadow-buttonShadow-1-color, rgba(0, 0, 0, 0.12)),
var(--Shadow-buttonShadow-2-x, 0px) var(--Shadow-buttonShadow-2-y, 1px)
var(--Shadow-buttonShadow-2-blur, 5px) 0px
var(--Shadow-buttonShadow-2-color, rgba(0, 0, 0, 0.12));
}
.with-drag-handle .heading-icon {
opacity: 1;
}
`;

override render() {
const type = this.model.type;
if (!type.startsWith('h')) return nothing;

const i = parseInt(type.slice(1));

return html`<div class="heading-icon">${HeadingIcon(i)}</div>`;
}

@property({ attribute: false })
accessor model!: ParagraphBlockModel;
}

export function effects() {
customElements.define('affine-paragraph-heading-icon', ParagraphHeadingIcon);
}

declare global {
interface HTMLElementTagNameMap {
'affine-paragraph-heading-icon': ParagraphHeadingIcon;
}
}
Loading

0 comments on commit 53bba9c

Please sign in to comment.