mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: improve outline block (#4722)
This commit is contained in:
parent
2abb396467
commit
cea1c17b76
@ -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);
|
||||
|
||||
|
@ -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<OutlineBlockWidget>
|
||||
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,8 +126,29 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
|
||||
final textDirection = calculateTextDirection(
|
||||
layoutDirection: Directionality.maybeOf(context),
|
||||
);
|
||||
final (status, headings) = getHeadingNodes();
|
||||
|
||||
final children = getHeadingNodes()
|
||||
Widget child;
|
||||
|
||||
switch (status) {
|
||||
case _OutlineBlockStatus.noHeadings:
|
||||
child = Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
LocaleKeys.document_plugins_outline_addHeadingToCreateOutline.tr(),
|
||||
style: configuration.placeholderTextStyle(node),
|
||||
),
|
||||
);
|
||||
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(
|
||||
@ -135,17 +162,20 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
final child = children.isEmpty
|
||||
? Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
LocaleKeys.document_plugins_outline_addHeadingToCreateOutline
|
||||
.tr(),
|
||||
style: configuration.placeholderTextStyle(node),
|
||||
child = Padding(
|
||||
padding: const EdgeInsets.only(left: 15.0),
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 40.0,
|
||||
),
|
||||
padding: padding,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 2.0,
|
||||
horizontal: 5.0,
|
||||
@ -155,7 +185,6 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
|
||||
color: backgroundColor,
|
||||
),
|
||||
child: Column(
|
||||
key: ValueKey(children.hashCode),
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
textDirection: textDirection,
|
||||
@ -165,36 +194,29 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const VSpace(8.0),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 15.0),
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
child,
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
return Container(
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 40.0,
|
||||
),
|
||||
padding: padding,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Iterable<Node> getHeadingNodes() {
|
||||
(_OutlineBlockStatus, Iterable<Node>) 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 {
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user