From cea1c17b768b3b084285255b7a2edb0c39206652 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Sat, 24 Feb 2024 20:54:21 +0700 Subject: [PATCH] feat: improve outline block (#4722) --- .../editor_plugins/actions/option_action.dart | 9 +- .../outline/outline_block_component.dart | 150 ++++++++++-------- frontend/resources/translations/en.json | 3 +- 3 files changed, 92 insertions(+), 70 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/option_action.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/option_action.dart index dd5dc93f5b..47e06be639 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/option_action.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/option_action.dart @@ -114,9 +114,12 @@ enum OptionAlignType { } enum OptionDepthType { - h1(1, "H1"), - h2(2, "H2"), - h3(3, "H3"); + h1(1, 'H1'), + h2(2, 'H2'), + h3(3, 'H3'), + h4(4, 'H4'), + h5(5, 'H5'), + h6(6, 'H6'); const OptionDepthType(this.level, this.description); diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/outline/outline_block_component.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/outline/outline_block_component.dart index dd271326d6..1c467ee90f 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/outline/outline_block_component.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/outline/outline_block_component.dart @@ -32,6 +32,12 @@ Node outlineBlockNode() { ); } +enum _OutlineBlockStatus { + noHeadings, + noMatchHeadings, + success; +} + class OutlineBlockComponentBuilder extends BlockComponentBuilder { OutlineBlockComponentBuilder({ super.configuration, @@ -75,7 +81,7 @@ class _OutlineBlockWidgetState extends State BlockComponentTextDirectionMixin, BlockComponentBackgroundColorMixin { // Change the value if the heading block type supports heading levels greater than '3' - static const finalHeadingLevel = 3; + static const maxVisibleDepth = 6; @override BlockComponentConfiguration get configuration => widget.configuration; @@ -120,81 +126,97 @@ class _OutlineBlockWidgetState extends State final textDirection = calculateTextDirection( layoutDirection: Directionality.maybeOf(context), ); + final (status, headings) = getHeadingNodes(); - final children = getHeadingNodes() - .map( - (e) => Container( - padding: const EdgeInsets.only( - bottom: 4.0, - ), - width: double.infinity, - child: OutlineItemWidget( - node: e, - textDirection: textDirection, - ), + Widget child; + + switch (status) { + case _OutlineBlockStatus.noHeadings: + child = Align( + alignment: Alignment.centerLeft, + child: Text( + LocaleKeys.document_plugins_outline_addHeadingToCreateOutline.tr(), + style: configuration.placeholderTextStyle(node), ), - ) - .toList(); - - final child = children.isEmpty - ? Align( - alignment: Alignment.centerLeft, - child: Text( - LocaleKeys.document_plugins_outline_addHeadingToCreateOutline - .tr(), - style: configuration.placeholderTextStyle(node), - ), - ) - : Container( - padding: const EdgeInsets.symmetric( - vertical: 2.0, - horizontal: 5.0, - ), - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - color: backgroundColor, - ), - child: Column( - key: ValueKey(children.hashCode), - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - textDirection: textDirection, - children: [ - Text( - LocaleKeys.document_outlineBlock_placeholder.tr(), - style: Theme.of(context).textTheme.titleLarge, + ); + case _OutlineBlockStatus.noMatchHeadings: + child = Align( + alignment: Alignment.centerLeft, + child: Text( + LocaleKeys.document_plugins_outline_noMatchHeadings.tr(), + style: configuration.placeholderTextStyle(node), + ), + ); + case _OutlineBlockStatus.success: + final children = headings + .map( + (e) => Container( + padding: const EdgeInsets.only( + bottom: 4.0, ), - const VSpace(8.0), - Padding( - padding: const EdgeInsets.only(left: 15.0), - child: Column( - children: children, - ), + width: double.infinity, + child: OutlineItemWidget( + node: e, + textDirection: textDirection, ), - ], - ), - ); + ), + ) + .toList(); + child = Padding( + padding: const EdgeInsets.only(left: 15.0), + child: Column( + children: children, + ), + ); + } return Container( constraints: const BoxConstraints( minHeight: 40.0, ), padding: padding, - child: child, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 5.0, + ), + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + color: backgroundColor, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + textDirection: textDirection, + children: [ + Text( + LocaleKeys.document_outlineBlock_placeholder.tr(), + style: Theme.of(context).textTheme.titleLarge, + ), + const VSpace(8.0), + child, + ], + ), + ), ); } - Iterable getHeadingNodes() { + (_OutlineBlockStatus, Iterable) getHeadingNodes() { final children = editorState.document.root.children; final int level = - node.attributes[OutlineBlockKeys.depth] ?? finalHeadingLevel; - - return children.where( - (element) => - element.type == HeadingBlockKeys.type && - element.delta?.isNotEmpty == true && - element.attributes[HeadingBlockKeys.level] <= level, + node.attributes[OutlineBlockKeys.depth] ?? maxVisibleDepth; + var headings = children.where( + (e) => e.type == HeadingBlockKeys.type && e.delta?.isNotEmpty == true, ); + if (headings.isEmpty) { + return (_OutlineBlockStatus.noHeadings, []); + } + headings = + headings.where((e) => e.attributes[HeadingBlockKeys.level] <= level); + if (headings.isEmpty) { + return (_OutlineBlockStatus.noMatchHeadings, []); + } + return (_OutlineBlockStatus.success, headings); } } @@ -263,12 +285,8 @@ extension on Node { return 0.0; } final level = attributes[HeadingBlockKeys.level]; - if (level == 2) { - return 20; - } else if (level == 3) { - return 40; - } - return 0; + final indent = (level - 1) * 15.0 + 10.0; + return indent; } String get outlineItemText { diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 98a134dcc0..8edabed32e 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -793,7 +793,8 @@ "copiedToPasteBoard": "The link has been copied to the clipboard" }, "outline": { - "addHeadingToCreateOutline": "Add headings to create a table of contents." + "addHeadingToCreateOutline": "Add headings to create a table of contents.", + "noMatchHeadings": "No matching headings found." }, "table": { "addAfter": "Add after",