chore: update documentation for customizing a theme

This commit is contained in:
Lucas.Xu 2022-10-27 14:52:17 +08:00
parent 862ba3173a
commit 90b9456b0b
6 changed files with 103 additions and 51 deletions

View File

@ -16,7 +16,6 @@ Widget build(BuildContext context) {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: AppFlowyEditor( child: AppFlowyEditor(
editorState: EditorState.empty(), editorState: EditorState.empty(),
editorStyle: EditorStyle.defaultStyle(),
shortcutEvents: const [], shortcutEvents: const [],
customBuilders: const {}, customBuilders: const {},
), ),
@ -93,7 +92,7 @@ ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) {
// Delete the previous 'underscore', // Delete the previous 'underscore',
// update the style of the text surrounded by the two underscores to 'italic', // update the style of the text surrounded by the two underscores to 'italic',
// and update the cursor position. // and update the cursor position.
TransactionBuilder(editorState) final transaction = editorState.transaction
..deleteText(textNode, firstUnderscore, 1) ..deleteText(textNode, firstUnderscore, 1)
..formatText( ..formatText(
textNode, textNode,
@ -108,8 +107,8 @@ ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) {
path: textNode.path, path: textNode.path,
offset: selection.end.offset - 1, offset: selection.end.offset - 1,
), ),
) );
..commit(); editorState.apply(transaction);
return KeyEventResult.handled; return KeyEventResult.handled;
}; };
@ -125,7 +124,6 @@ Widget build(BuildContext context) {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: AppFlowyEditor( child: AppFlowyEditor(
editorState: EditorState.empty(), editorState: EditorState.empty(),
editorStyle: EditorStyle.defaultStyle(),
customBuilders: const {}, customBuilders: const {},
shortcutEvents: [ shortcutEvents: [
underscoreToItalic, underscoreToItalic,
@ -138,7 +136,7 @@ Widget build(BuildContext context) {
![After](./images/customize_a_shortcut_event_after.gif) ![After](./images/customize_a_shortcut_event_after.gif)
Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic.dart) file of this example. Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart) file of this example.
## Customizing a Component ## Customizing a Component
@ -156,7 +154,6 @@ Widget build(BuildContext context) {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: AppFlowyEditor( child: AppFlowyEditor(
editorState: EditorState.empty(), editorState: EditorState.empty(),
editorStyle: EditorStyle.defaultStyle(),
shortcutEvents: const [], shortcutEvents: const [],
customBuilders: const {}, customBuilders: const {},
), ),
@ -180,7 +177,7 @@ We'll use `network_image` in this case. And we add `network_image_src` to the `a
Then, we create a class that inherits [NodeWidgetBuilder](../lib/src/service/render_plugin_service.dart). As shown in the autoprompt, we need to implement two functions: Then, we create a class that inherits [NodeWidgetBuilder](../lib/src/service/render_plugin_service.dart). As shown in the autoprompt, we need to implement two functions:
1. one returns a widget 1. one returns a widget
2. the other verifies the correctness of the [Node](../lib/src/document/node.dart). 2. the other verifies the correctness of the [Node](../lib/src/core/document/node.dart).
```dart ```dart
@ -308,7 +305,7 @@ return AppFlowyEditor(
Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) file of this example. Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) file of this example.
## Customizing a Theme (New Feature in 0.0.5, Alpha) ## Customizing a Theme (New Feature in 0.0.7)
We will use a simple example to illustrate how to quickly customize a theme. We will use a simple example to illustrate how to quickly customize a theme.
@ -322,7 +319,6 @@ Widget build(BuildContext context) {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: AppFlowyEditor( child: AppFlowyEditor(
editorState: EditorState.empty(), editorState: EditorState.empty(),
editorStyle: EditorStyle.defaultStyle(),
shortcutEvents: const [], shortcutEvents: const [],
customBuilders: const {}, customBuilders: const {},
), ),
@ -338,44 +334,41 @@ At this point, the editor looks like ...
Next, we will customize the `EditorStyle`. Next, we will customize the `EditorStyle`.
```dart ```dart
EditorStyle _customizedStyle() { ThemeData customizeEditorTheme(BuildContext context) {
final editorStyle = EditorStyle.defaultStyle(); final dark = EditorStyle.dark;
return editorStyle.copyWith( final editorStyle = dark.copyWith(
cursorColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 150),
selectionColor: Colors.blue.withOpacity(0.3), cursorColor: Colors.red.shade600,
textStyle: editorStyle.textStyle.copyWith( selectionColor: Colors.yellow.shade600.withOpacity(0.5),
defaultTextStyle: GoogleFonts.poppins().copyWith( textStyle: GoogleFonts.poppins().copyWith(
color: Colors.white, fontSize: 14,
fontSize: 14.0, color: Colors.white,
),
defaultPlaceholderTextStyle: GoogleFonts.poppins().copyWith(
color: Colors.white.withOpacity(0.5),
fontSize: 14.0,
),
bold: const TextStyle(fontWeight: FontWeight.w900),
code: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.red[300],
backgroundColor: Colors.grey.withOpacity(0.3),
),
highlightColorHex: '0x6FFFEB3B',
), ),
pluginStyles: { placeholderTextStyle: GoogleFonts.poppins().copyWith(
'text/quote': builtInPluginStyle fontSize: 14,
..update( color: Colors.grey.shade400,
'textStyle', ),
(_) { code: dark.code?.copyWith(
return (EditorState editorState, Node node) { backgroundColor: Colors.lightBlue.shade200,
return TextStyle( fontStyle: FontStyle.italic,
color: Colors.blue[200], ),
fontStyle: FontStyle.italic, highlightColorHex: '0x60FF0000', // red
fontSize: 12.0,
);
};
},
),
},
); );
final quote = QuotedTextPluginStyle.dark.copyWith(
textStyle: (_, __) => GoogleFonts.poppins().copyWith(
fontSize: 14,
color: Colors.blue.shade400,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w700,
),
);
return Theme.of(context).copyWith(extensions: [
editorStyle,
...darkPlguinStyleExtension,
quote,
]);
} }
``` ```
@ -389,7 +382,7 @@ Widget build(BuildContext context) {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: AppFlowyEditor( child: AppFlowyEditor(
editorState: EditorState.empty(), editorState: EditorState.empty(),
editorStyle: _customizedStyle(), themeData: customizeEditorTheme(context),
shortcutEvents: const [], shortcutEvents: const [],
customBuilders: const {}, customBuilders: const {},
), ),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 KiB

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:example/plugin/editor_theme.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -54,6 +55,8 @@ class _MyHomePageState extends State<MyHomePage> {
bool darkMode = false; bool darkMode = false;
Future<String>? _jsonString; Future<String>? _jsonString;
ThemeData? _editorThemeData;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -102,7 +105,7 @@ class _MyHomePageState extends State<MyHomePage> {
_editorState!.transactionStream.listen((event) { _editorState!.transactionStream.listen((event) {
debugPrint('Transaction: ${event.toJson()}'); debugPrint('Transaction: ${event.toJson()}');
}); });
final themeData = Theme.of(context).copyWith(extensions: [ _editorThemeData ??= Theme.of(context).copyWith(extensions: [
if (darkMode) ...darkEditorStyleExtension, if (darkMode) ...darkEditorStyleExtension,
if (darkMode) ...darkPlguinStyleExtension, if (darkMode) ...darkPlguinStyleExtension,
if (!darkMode) ...lightEditorStyleExtension, if (!darkMode) ...lightEditorStyleExtension,
@ -114,7 +117,7 @@ class _MyHomePageState extends State<MyHomePage> {
child: AppFlowyEditor( child: AppFlowyEditor(
editorState: _editorState!, editorState: _editorState!,
editable: true, editable: true,
themeData: themeData, themeData: _editorThemeData,
customBuilders: { customBuilders: {
'text/code_block': CodeBlockNodeWidgetBuilder(), 'text/code_block': CodeBlockNodeWidgetBuilder(),
'tex': TeXBlockNodeWidgetBuidler(), 'tex': TeXBlockNodeWidgetBuidler(),
@ -162,13 +165,22 @@ class _MyHomePageState extends State<MyHomePage> {
onPressed: () async => await _importDocument(), onPressed: () async => await _importDocument(),
), ),
ActionButton( ActionButton(
icon: const Icon(Icons.color_lens), icon: const Icon(Icons.dark_mode),
onPressed: () { onPressed: () {
setState(() { setState(() {
darkMode = !darkMode; darkMode = !darkMode;
}); });
}, },
), ),
ActionButton(
icon: const Icon(Icons.color_lens),
onPressed: () {
setState(() {
_editorThemeData = customizeEditorTheme(context);
darkMode = true;
});
},
),
], ],
); );
} }
@ -228,6 +240,7 @@ class _MyHomePageState extends State<MyHomePage> {
void _switchToPage(int pageIndex) { void _switchToPage(int pageIndex) {
if (pageIndex != _pageIndex) { if (pageIndex != _pageIndex) {
setState(() { setState(() {
_editorThemeData = null;
_editorState = null; _editorState = null;
_pageIndex = pageIndex; _pageIndex = pageIndex;
}); });

View File

@ -0,0 +1,40 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
ThemeData customizeEditorTheme(BuildContext context) {
final dark = EditorStyle.dark;
final editorStyle = dark.copyWith(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 150),
cursorColor: Colors.red.shade600,
selectionColor: Colors.yellow.shade600.withOpacity(0.5),
textStyle: GoogleFonts.poppins().copyWith(
fontSize: 14,
color: Colors.white,
),
placeholderTextStyle: GoogleFonts.poppins().copyWith(
fontSize: 14,
color: Colors.grey.shade400,
),
code: dark.code?.copyWith(
backgroundColor: Colors.lightBlue.shade200,
fontStyle: FontStyle.italic,
),
highlightColorHex: '0x60FF0000', // red
);
final quote = QuotedTextPluginStyle.dark.copyWith(
textStyle: (_, __) => GoogleFonts.poppins().copyWith(
fontSize: 14,
color: Colors.blue.shade400,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w700,
),
);
return Theme.of(context).copyWith(extensions: [
editorStyle,
...darkPlguinStyleExtension,
quote,
]);
}

View File

@ -117,7 +117,13 @@ class CheckboxPluginStyle extends ThemeExtension<CheckboxPluginStyle> {
static final light = CheckboxPluginStyle( static final light = CheckboxPluginStyle(
padding: (_, __) => const EdgeInsets.symmetric(vertical: 8.0), padding: (_, __) => const EdgeInsets.symmetric(vertical: 8.0),
textStyle: (editorState, textNode) => const TextStyle(), textStyle: (editorState, textNode) {
final isCheck = textNode.attributes.check;
return TextStyle(
decoration: isCheck ? TextDecoration.lineThrough : null,
color: isCheck ? Colors.grey.shade400 : null,
);
},
icon: (editorState, textNode) { icon: (editorState, textNode) {
final isCheck = textNode.attributes.check; final isCheck = textNode.attributes.check;
const iconSize = Size.square(20.0); const iconSize = Size.square(20.0);