feat: optimize the slash menu item name & icon (#5908)

* feat: optimize the slash menu item name & icon

* feat: optimize the toolbar item name & icon

* fix: integration test

* fix: replace unaligned icons
This commit is contained in:
Lucas.Xu 2024-08-09 21:50:47 +08:00 committed by GitHub
parent 57bbb6cc41
commit a26b2a356c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 983 additions and 97 deletions

View File

@ -1,10 +1,10 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@ -25,6 +25,7 @@ void main() {
const lines = 3;
final text = List.generate(lines, (index) => 'line $index').join('\n');
AppFlowyClipboard.mockSetData(AppFlowyClipboardData(text: text));
ClipboardService.mockSetData(ClipboardServiceData(plainText: text));
await insertCodeBlockInDocument(tester);
@ -51,7 +52,9 @@ Future<void> insertCodeBlockInDocument(WidgetTester tester) async {
// open the actions menu and insert the codeBlock
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_selectionMenu_codeBlock.tr(),
LocaleKeys.document_slashMenu_name_code.tr(),
offset: 150,
);
// wait for the codeBlock to be inserted
await tester.pumpAndSettle();
}

View File

@ -1,4 +1,3 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
@ -7,7 +6,6 @@ import 'package:appflowy/plugins/inline_actions/widgets/inline_actions_handler.d
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@ -22,7 +20,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await insertReferenceDatabase(tester, ViewLayoutPB.Grid);
await insertLinkedDatabase(tester, ViewLayoutPB.Grid);
// validate the referenced grid is inserted
expect(
@ -50,7 +48,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await insertReferenceDatabase(tester, ViewLayoutPB.Board);
await insertLinkedDatabase(tester, ViewLayoutPB.Board);
// validate the referenced board is inserted
expect(
@ -66,7 +64,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await insertReferenceDatabase(tester, ViewLayoutPB.Calendar);
await insertLinkedDatabase(tester, ViewLayoutPB.Calendar);
// validate the referenced grid is inserted
expect(
@ -129,7 +127,7 @@ void main() {
}
/// Insert a referenced database of [layout] into the document
Future<void> insertReferenceDatabase(
Future<void> insertLinkedDatabase(
WidgetTester tester,
ViewLayoutPB layout,
) async {
@ -150,7 +148,7 @@ Future<void> insertReferenceDatabase(
// insert a referenced view
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
layout.referencedMenuName,
layout.slashMenuLinkedName,
);
final linkToPageMenu = find.byType(InlineActionsHandler);
@ -176,16 +174,8 @@ Future<void> createInlineDatabase(
await tester.editor.tapLineOfEditorAt(0);
// insert a referenced view
await tester.editor.showSlashMenu();
final name = switch (layout) {
ViewLayoutPB.Grid => LocaleKeys.document_slashMenu_grid_createANewGrid.tr(),
ViewLayoutPB.Board =>
LocaleKeys.document_slashMenu_board_createANewBoard.tr(),
ViewLayoutPB.Calendar =>
LocaleKeys.document_slashMenu_calendar_createANewCalendar.tr(),
_ => '',
};
await tester.editor.tapSlashMenuItemWithName(
name,
layout.slashMenuName,
);
await tester.pumpAndSettle();

View File

@ -1,7 +1,5 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@ -10,6 +8,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.da
import 'package:appflowy/startup/startup.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
@ -33,7 +32,9 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('File');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_file.tr(),
);
expect(find.byType(FileBlockComponent), findsOneWidget);
await tester.tap(find.byType(FileBlockComponent));
@ -111,7 +112,9 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('File');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_file.tr(),
);
expect(find.byType(FileBlockComponent), findsOneWidget);
await tester.tap(find.byType(FileBlockComponent));

View File

@ -1,8 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@ -17,6 +14,8 @@ import 'package:appflowy_editor/appflowy_editor.dart'
hide UploadImageMenu, ResizableImage;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
@ -43,7 +42,9 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Image');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_image.tr(),
);
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
expect(
@ -91,7 +92,9 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Image');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_image.tr(),
);
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
expect(
@ -144,7 +147,9 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Image');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_image.tr(),
);
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
expect(
@ -175,7 +180,9 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Image');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_image.tr(),
);
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
expect(

View File

@ -1,9 +1,5 @@
import 'dart:io';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
@ -20,6 +16,9 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/presentation/widgets/image_viewer/interactive_image_toolbar.dart';
import 'package:appflowy/workspace/presentation/widgets/image_viewer/interactive_image_viewer.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
@ -49,7 +48,10 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Photo gallery');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_photoGallery.tr(),
offset: 100,
);
expect(find.byType(MultiImageBlockComponent), findsOneWidget);
expect(find.byType(MultiImagePlaceholder), findsOneWidget);
@ -144,7 +146,10 @@ void main() {
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Photo gallery');
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_name_photoGallery.tr(),
offset: 100,
);
expect(find.byType(MultiImageBlockComponent), findsOneWidget);
expect(find.byType(MultiImagePlaceholder), findsOneWidget);

View File

@ -171,7 +171,8 @@ Future<void> insertOutlineInDocument(WidgetTester tester) async {
// open the actions menu and insert the outline block
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_selectionMenu_outline.tr(),
LocaleKeys.document_slashMenu_name_outline.tr(),
offset: 100,
);
await tester.pumpAndSettle();
}

View File

@ -662,4 +662,34 @@ extension ViewLayoutPBTest on ViewLayoutPB {
throw UnsupportedError('Unsupported layout: $this');
}
}
String get slashMenuName {
switch (this) {
case ViewLayoutPB.Grid:
return LocaleKeys.document_slashMenu_name_grid.tr();
case ViewLayoutPB.Board:
return LocaleKeys.document_slashMenu_name_kanban.tr();
case ViewLayoutPB.Document:
return LocaleKeys.document_slashMenu_name_doc.tr();
case ViewLayoutPB.Calendar:
return LocaleKeys.document_slashMenu_name_calendar.tr();
default:
throw UnsupportedError('Unsupported layout: $this');
}
}
String get slashMenuLinkedName {
switch (this) {
case ViewLayoutPB.Grid:
return LocaleKeys.document_slashMenu_name_linkedGrid.tr();
case ViewLayoutPB.Board:
return LocaleKeys.document_slashMenu_name_linkedKanban.tr();
case ViewLayoutPB.Document:
return LocaleKeys.document_slashMenu_name_linkedDoc.tr();
case ViewLayoutPB.Calendar:
return LocaleKeys.document_slashMenu_name_linkedCalendar.tr();
default:
throw UnsupportedError('Unsupported layout: $this');
}
}
}

View File

@ -3,7 +3,6 @@ import 'dart:ui';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
import 'package:appflowy/shared/icon_emoji_picker/emoji_skin_tone.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_add_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_option_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/cover_editor.dart';
@ -11,6 +10,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/header/doc
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/upload_image_menu/widgets/embed_image_url_widget.dart';
import 'package:appflowy/plugins/inline_actions/widgets/inline_actions_handler.dart';
import 'package:appflowy/shared/icon_emoji_picker/emoji_skin_tone.dart';
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart';
@ -170,7 +170,10 @@ class EditorOperations {
/// Tap the slash menu item with [name]
///
/// Must call [showSlashMenu] first.
Future<void> tapSlashMenuItemWithName(String name) async {
Future<void> tapSlashMenuItemWithName(
String name, {
double offset = 200,
}) async {
final slashMenu = find
.ancestor(
of: find.byType(SelectionMenuItemWidget),
@ -180,8 +183,13 @@ class EditorOperations {
)
.first;
final slashMenuItem = find.text(name, findRichText: true);
await tester.scrollUntilVisible(slashMenuItem, 200, scrollable: slashMenu);
// await tester.ensureVisible(slashMenuItem);
await tester.scrollUntilVisible(
slashMenuItem,
offset,
scrollable: slashMenu,
duration: const Duration(milliseconds: 250),
);
assert(slashMenuItem.hasFound);
await tester.tapButton(slashMenuItem);
}

View File

@ -175,7 +175,7 @@ SPEC CHECKSUMS:
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
fluttertoast: 723e187574b149e68e63ca4d39b837586b903cfa
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
@ -197,4 +197,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: d0d9b4ff572d8695c38eb3f9b490f55cdfc57eca
COCOAPODS: 1.11.3
COCOAPODS: 1.15.2

View File

@ -9,7 +9,6 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/base/forma
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/page_reference_commands.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/callout/callout_block_shortcuts.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/i18n/editor_i18n.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/slash_menu_items.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/plugins/inline_actions/handlers/date_reference.dart';
@ -146,7 +145,7 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
customizeFontToolbarItem,
];
late final List<SelectionMenuItem> slashMenuItems;
late List<SelectionMenuItem> slashMenuItems;
List<CharacterShortcutEvent> get characterShortcutEvents => [
// code block
@ -282,9 +281,17 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
focusManager = currFocusManager;
focusManager?.loseFocusNotifier.addListener(_loseFocus);
}
super.didChangeDependencies();
}
@override
void reassemble() {
super.reassemble();
slashMenuItems = _customSlashMenuItems();
}
@override
void dispose() {
focusManager?.loseFocusNotifier.removeListener(_loseFocus);
@ -387,42 +394,45 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
editorState: editorState,
editorScrollController: editorScrollController,
textDirection: textDirection,
tooltipBuilder: (context, id, message, child) => widget.styleCustomizer
.buildToolbarItemTooltip(context, id, message, child,),
tooltipBuilder: (context, id, message, child) =>
widget.styleCustomizer.buildToolbarItemTooltip(
context,
id,
message,
child,
),
child: editor,
),
);
}
List<SelectionMenuItem> _customSlashMenuItems() {
final items = [...standardSelectionMenuItems];
final imageItem = items
.firstWhereOrNull((e) => e.name == AppFlowyEditorL10n.current.image);
if (imageItem != null) {
final imageItemIndex = items.indexOf(imageItem);
if (imageItemIndex != -1) {
items[imageItemIndex] = customImageMenuItem;
}
}
return [
...items,
inlineGridMenuItem(documentBloc),
referencedGridMenuItem,
inlineBoardMenuItem(documentBloc),
referencedBoardMenuItem,
inlineCalendarMenuItem(documentBloc),
referencedCalendarMenuItem,
referencedDocumentMenuItem,
calloutItem,
outlineItem,
mathEquationItem,
codeBlockItem(LocaleKeys.document_selectionMenu_codeBlock.tr()),
toggleListBlockItem,
emojiMenuItem,
autoGeneratorMenuItem,
dateMenuItem,
multiImageMenuItem,
fileMenuItem,
aiWriterSlashMenuItem,
textSlashMenuItem,
heading1SlashMenuItem,
heading2SlashMenuItem,
heading3SlashMenuItem,
imageSlashMenuItem,
bulletedListSlashMenuItem,
numberedListSlashMenuItem,
quoteSlashMenuItem,
referencedDocSlashMenuItem,
gridSlashMenuItem(documentBloc),
referencedGridSlashMenuItem,
kanbanSlashMenuItem(documentBloc),
referencedKanbanSlashMenuItem,
calendarSlashMenuItem(documentBloc),
referencedCalendarSlashMenuItem,
calloutSlashMenuItem,
outlineSlashMenuItem,
mathEquationSlashMenuItem,
codeBlockSlashMenuItem,
toggleListSlashMenuItem,
emojiSlashMenuItem,
dateOrReminderSlashMenuItem,
photoGallerySlashMenuItem,
fileSlashMenuItem,
];
}

View File

@ -1,6 +1,5 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
class SelectableSvgWidget extends StatelessWidget {
@ -9,21 +8,31 @@ class SelectableSvgWidget extends StatelessWidget {
required this.data,
required this.isSelected,
required this.style,
this.size,
this.padding,
});
final FlowySvgData data;
final bool isSelected;
final SelectionMenuStyle style;
final Size? size;
final EdgeInsets? padding;
@override
Widget build(BuildContext context) {
return FlowySvg(
final child = FlowySvg(
data,
size: const Size.square(18.0),
size: size ?? const Size.square(16.0),
color: isSelected
? style.selectionMenuItemSelectedIconColor
: style.selectionMenuItemIconColor,
);
if (padding != null) {
return Padding(padding: padding!, child: child);
} else {
return child;
}
}
}

View File

@ -0,0 +1,18 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:easy_localization/easy_localization.dart';
final codeBlockSelectionMenuItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_selectionMenu_codeBlock.tr(),
iconBuilder: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.icon_code_block_s,
isSelected: onSelected,
style: style,
),
keywords: ['code', 'codeblock'],
nodeBuilder: (_, __) => codeBlockNode(),
replace: (_, node) => node.delta?.isEmpty ?? false,
);

View File

@ -40,6 +40,13 @@ class ClipboardServiceData {
}
class ClipboardService {
static ClipboardServiceData? _mockData;
@visibleForTesting
static void mockSetData(ClipboardServiceData? data) {
_mockData = data;
}
Future<void> setData(ClipboardServiceData data) async {
final plainText = data.plainText;
final html = data.html;
@ -81,6 +88,10 @@ class ClipboardService {
}
Future<ClipboardServiceData> getData() async {
if (_mockData != null) {
return _mockData!;
}
final reader = await SystemClipboard.instance?.read();
if (reader == null) {

View File

@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component/custom_image_block_component.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/multi_image_block_component/multi_image_block_component.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
final customImageMenuItem = SelectionMenuItem(
getName: () => AppFlowyEditorL10n.current.image,
@ -28,8 +29,9 @@ final customImageMenuItem = SelectionMenuItem(
final multiImageMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_plugins_photoGallery_name.tr(),
icon: (_, isSelected, style) => SelectionMenuIconWidget(
icon: Icons.photo_library_outlined,
icon: (_, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.image_s,
size: const Size.square(16.0),
isSelected: isSelected,
style: style,
),

View File

@ -1,5 +1,7 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@ -37,7 +39,11 @@ Node mathEquationNode({
// defining the callout block menu item for selection
SelectionMenuItem mathEquationItem = SelectionMenuItem.node(
getName: LocaleKeys.document_plugins_mathEquation_name.tr,
iconData: Icons.text_fields_rounded,
iconBuilder: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.icon_math_eq_s,
isSelected: onSelected,
style: style,
),
keywords: ['tex, latex, katex', 'math equation', 'formula'],
nodeBuilder: (editorState, _) => mathEquationNode(),
replace: (_, node) => node.delta?.isEmpty ?? false,

View File

@ -14,10 +14,10 @@ SelectionMenuItem dateMenuItem = SelectionMenuItem(
),
keywords: ['insert date', 'date', 'time'],
handler: (editorState, menuService, context) =>
_insertDateReference(editorState),
insertDateReference(editorState),
);
Future<void> _insertDateReference(EditorState editorState) async {
Future<void> insertDateReference(EditorState editorState) async {
final selection = editorState.selection;
if (selection == null || !selection.isCollapsed) {
return;

View File

@ -1,5 +1,7 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/build_context_extension.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/text_robot.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/error.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/discard_dialog.dart';
@ -41,7 +43,11 @@ Node autoCompletionNode({
SelectionMenuItem autoGeneratorMenuItem = SelectionMenuItem.node(
getName: LocaleKeys.document_plugins_autoGeneratorMenuItemName.tr,
iconData: Icons.generating_tokens,
iconBuilder: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.menu_item_ai_writer_s,
isSelected: onSelected,
style: style,
),
keywords: ['ai', 'openai', 'writer', 'ai writer', 'autogenerator'],
nodeBuilder: (editorState, _) {
final node = autoCompletionNode(start: editorState.selection!);

View File

@ -1,3 +1,4 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/smart_edit_action.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
@ -8,7 +9,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
const _kSmartEditToolbarItemId = 'appflowy.editor.smart_edit';
@ -65,15 +66,21 @@ class _SmartEditActionListState extends State<SmartEditActionList> {
onClosed: () => keepEditorFocusNotifier.decrease(),
buildChild: (controller) {
keepEditorFocusNotifier.increase();
final child = FlowyIconButton(
hoverColor: Colors.transparent,
preferBelow: false,
icon: const Icon(
Icons.lightbulb_outline,
size: 15,
final child = FlowyButton(
text: FlowyText.regular(
LocaleKeys.document_plugins_smartEdit.tr(),
fontSize: 13.0,
figmaLineHeight: 16.0,
color: Colors.white,
),
onPressed: () {
hoverColor: Colors.transparent,
useIntrinsicWidth: true,
leftIcon: const FlowySvg(
FlowySvgs.toolbar_item_ai_s,
size: Size.square(16.0),
color: Colors.white,
),
onTap: () {
if (isAIEnabled) {
controller.show();
} else {

View File

@ -5,6 +5,7 @@ export 'base/toolbar_extension.dart';
export 'bulleted_list/bulleted_list_icon.dart';
export 'callout/callout_block_component.dart';
export 'code_block/code_block_language_selector.dart';
export 'code_block/code_block_menu_item.dart';
export 'context_menu/custom_context_menu.dart';
export 'copy_and_paste/custom_copy_command.dart';
export 'copy_and_paste/custom_cut_command.dart';
@ -50,6 +51,7 @@ export 'openai/widgets/smart_edit_node_widget.dart';
export 'openai/widgets/smart_edit_toolbar_item.dart';
export 'outline/outline_block_component.dart';
export 'parsers/markdown_parsers.dart';
export 'slash_menu/slash_menu_items.dart';
export 'table/table_menu.dart';
export 'table/table_option_action.dart';
export 'todo_list/todo_list_icon.dart';

View File

@ -0,0 +1,459 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/prelude.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/insert_page_command.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/link_to_page_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/slash_menu_items.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_menu_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
// text menu item
final textSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_text.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_text_s,
isSelected: isSelected,
style: style,
),
keywords: ['text', 'paragraph'],
handler: (editorState, _, __) {
insertNodeAfterSelection(editorState, paragraphNode());
},
);
// heading 1 - 3 menu items
final heading1SlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_heading1.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_h1_s,
isSelected: isSelected,
style: style,
),
keywords: ['heading 1', 'h1', 'heading1'],
handler: (editorState, _, __) {
insertHeadingAfterSelection(editorState, 1);
},
);
final heading2SlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_heading2.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_h2_s,
isSelected: isSelected,
style: style,
),
keywords: ['heading 2', 'h2', 'heading2'],
handler: (editorState, _, __) {
insertHeadingAfterSelection(editorState, 2);
},
);
final heading3SlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_heading3.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_h3_s,
isSelected: isSelected,
style: style,
),
keywords: ['heading 3', 'h3', 'heading3'],
handler: (editorState, _, __) {
insertHeadingAfterSelection(editorState, 3);
},
);
// image menu item
final imageSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_image.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_image_s,
isSelected: isSelected,
style: style,
),
keywords: ['image', 'photo', 'picture', 'img'],
handler: (editorState, menuService, context) async {
// use the key to retrieve the state of the image block to show the popover automatically
final imagePlaceholderKey = GlobalKey<ImagePlaceholderState>();
await editorState.insertEmptyImageBlock(imagePlaceholderKey);
WidgetsBinding.instance.addPostFrameCallback((_) {
imagePlaceholderKey.currentState?.controller.show();
});
},
);
// bulleted list menu item
final bulletedListSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_bulletedList.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_bulleted_list_s,
isSelected: isSelected,
style: style,
),
keywords: ['bulleted list', 'list', 'unordered list'],
handler: (editorState, _, __) {
insertBulletedListAfterSelection(editorState);
},
);
// numbered list menu item
final numberedListSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_numberedList.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_numbered_list_s,
isSelected: isSelected,
style: style,
),
keywords: ['numbered list', 'list', 'ordered list'],
handler: (editorState, _, __) {
insertNumberedListAfterSelection(editorState);
},
);
// quote menu item
final quoteSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_quote.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_quote_s,
isSelected: isSelected,
style: style,
),
keywords: ['quote', 'refer'],
handler: (editorState, _, __) {
insertQuoteAfterSelection(editorState);
},
);
// grid & board & calendar menu item
SelectionMenuItem gridSlashMenuItem(DocumentBloc documentBloc) {
return SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_grid.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_grid_s,
isSelected: onSelected,
style: style,
),
keywords: ['grid', 'database'],
handler: (editorState, menuService, context) async {
// create the view inside current page
final parentViewId = documentBloc.documentId;
final value = await ViewBackendService.createView(
parentViewId: parentViewId,
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layoutType: ViewLayoutPB.Grid,
);
value.map((r) => editorState.insertInlinePage(parentViewId, r));
},
);
}
SelectionMenuItem kanbanSlashMenuItem(DocumentBloc documentBloc) {
return SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_kanban.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_kanban_s,
isSelected: onSelected,
style: style,
),
keywords: ['board', 'kanban', 'database'],
handler: (editorState, menuService, context) async {
// create the view inside current page
final parentViewId = documentBloc.documentId;
final value = await ViewBackendService.createView(
parentViewId: parentViewId,
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layoutType: ViewLayoutPB.Board,
);
value.map((r) => editorState.insertInlinePage(parentViewId, r));
},
);
}
SelectionMenuItem calendarSlashMenuItem(DocumentBloc documentBloc) {
return SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_calendar.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_calendar_s,
isSelected: onSelected,
style: style,
),
keywords: ['calendar', 'database'],
handler: (editorState, menuService, context) async {
// create the view inside current page
final parentViewId = documentBloc.documentId;
final value = await ViewBackendService.createView(
parentViewId: parentViewId,
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layoutType: ViewLayoutPB.Calendar,
);
value.map((r) => editorState.insertInlinePage(parentViewId, r));
},
);
}
// linked doc menu item
final referencedDocSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_linkedDoc.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_doc_s,
isSelected: isSelected,
style: style,
),
keywords: ['page', 'notes', 'referenced page', 'referenced document'],
handler: (editorState, menuService, context) => showLinkToPageMenu(
editorState,
menuService,
ViewLayoutPB.Document,
),
);
// linked grid & board & calendar menu item
SelectionMenuItem referencedGridSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_linkedGrid.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_grid_s,
isSelected: onSelected,
style: style,
),
keywords: ['referenced', 'grid', 'database', 'linked'],
handler: (editorState, menuService, context) =>
showLinkToPageMenu(editorState, menuService, ViewLayoutPB.Grid),
);
SelectionMenuItem referencedKanbanSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_linkedKanban.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_kanban_s,
isSelected: onSelected,
style: style,
),
keywords: ['referenced', 'board', 'kanban', 'linked'],
handler: (editorState, menuService, context) =>
showLinkToPageMenu(editorState, menuService, ViewLayoutPB.Board),
);
SelectionMenuItem referencedCalendarSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_linkedCalendar.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_calendar_s,
isSelected: onSelected,
style: style,
),
keywords: ['referenced', 'calendar', 'database', 'linked'],
handler: (editorState, menuService, context) =>
showLinkToPageMenu(editorState, menuService, ViewLayoutPB.Calendar),
);
// callout menu item
SelectionMenuItem calloutSlashMenuItem = SelectionMenuItem.node(
getName: LocaleKeys.document_plugins_callout.tr,
nameBuilder: _slashMenuItemNameBuilder,
iconBuilder: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_callout_s,
isSelected: isSelected,
style: style,
),
keywords: [CalloutBlockKeys.type],
nodeBuilder: (editorState, context) =>
calloutNode(defaultColor: Colors.transparent),
replace: (_, node) => node.delta?.isEmpty ?? false,
updateSelection: (_, path, __, ___) {
return Selection.single(path: path, startOffset: 0);
},
);
// outline menu item
SelectionMenuItem outlineSlashMenuItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_slashMenu_name_outline.tr(),
nameBuilder: _slashMenuItemNameBuilder,
iconBuilder: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_outline_s,
isSelected: isSelected,
style: style,
),
keywords: ['outline', 'table of contents'],
nodeBuilder: (editorState, _) => outlineBlockNode(),
replace: (_, node) => node.delta?.isEmpty ?? false,
);
// math equation
SelectionMenuItem mathEquationSlashMenuItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_slashMenu_name_mathEquation.tr(),
nameBuilder: _slashMenuItemNameBuilder,
iconBuilder: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_math_equation_s,
isSelected: isSelected,
style: style,
),
keywords: ['tex', 'latex', 'katex', 'math equation', 'formula'],
nodeBuilder: (editorState, _) => mathEquationNode(),
replace: (_, node) => node.delta?.isEmpty ?? false,
updateSelection: (editorState, path, __, ___) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final mathEquationState =
editorState.getNodeAtPath(path)?.key.currentState;
if (mathEquationState != null &&
mathEquationState is MathEquationBlockComponentWidgetState) {
mathEquationState.showEditingDialog();
}
});
return null;
},
);
// code block menu item
SelectionMenuItem codeBlockSlashMenuItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_slashMenu_name_code.tr(),
nameBuilder: _slashMenuItemNameBuilder,
iconBuilder: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_code_block_s,
isSelected: isSelected,
style: style,
),
keywords: ['code', 'code block'],
nodeBuilder: (_, __) => codeBlockNode(),
replace: (_, node) => node.delta?.isEmpty ?? false,
);
// toggle menu item
SelectionMenuItem toggleListSlashMenuItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_slashMenu_name_toggleList.tr(),
nameBuilder: _slashMenuItemNameBuilder,
iconBuilder: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_toggle_s,
isSelected: isSelected,
style: style,
),
keywords: ['collapsed list', 'toggle list', 'list'],
nodeBuilder: (editorState, _) => toggleListBlockNode(),
replace: (_, node) => node.delta?.isEmpty ?? false,
);
// emoji menu item
SelectionMenuItem emojiSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_emoji.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_emoji_picker_s,
isSelected: isSelected,
style: style,
),
keywords: ['emoji'],
handler: (editorState, menuService, context) {
final container = Overlay.of(context);
menuService.dismiss();
showEmojiPickerMenu(
container,
editorState,
menuService.alignment,
menuService.offset,
);
},
);
// auto generate menu item
SelectionMenuItem aiWriterSlashMenuItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_slashMenu_name_aiWriter.tr(),
nameBuilder: _slashMenuItemNameBuilder,
iconBuilder: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_ai_writer_s,
isSelected: isSelected,
style: style,
),
keywords: ['ai', 'openai', 'writer', 'ai writer', 'autogenerator'],
nodeBuilder: (editorState, _) {
final node = autoCompletionNode(start: editorState.selection!);
return node;
},
replace: (_, node) => false,
);
// date or reminder menu item
SelectionMenuItem dateOrReminderSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_dateOrReminder.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_date_or_reminder_s,
isSelected: isSelected,
style: style,
),
keywords: ['insert date', 'date', 'time', 'reminder'],
handler: (editorState, menuService, context) =>
insertDateReference(editorState),
);
// photo gallery menu item
SelectionMenuItem photoGallerySlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_photoGallery.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_photo_gallery_s,
isSelected: isSelected,
style: style,
),
keywords: [
LocaleKeys.document_plugins_photoGallery_imageKeyword.tr(),
LocaleKeys.document_plugins_photoGallery_imageGalleryKeyword.tr(),
LocaleKeys.document_plugins_photoGallery_photoKeyword.tr(),
LocaleKeys.document_plugins_photoGallery_photoBrowserKeyword.tr(),
LocaleKeys.document_plugins_photoGallery_galleryKeyword.tr(),
],
handler: (editorState, _, __) async {
final imagePlaceholderKey = GlobalKey<ImagePlaceholderState>();
await editorState.insertEmptyMultiImageBlock(imagePlaceholderKey);
WidgetsBinding.instance.addPostFrameCallback(
(_) => imagePlaceholderKey.currentState?.controller.show(),
);
},
);
// file menu item
SelectionMenuItem fileSlashMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_name_file.tr(),
nameBuilder: _slashMenuItemNameBuilder,
icon: (editorState, isSelected, style) => SelectableSvgWidget(
data: FlowySvgs.slash_menu_icon_file_s,
isSelected: isSelected,
style: style,
),
keywords: ['file upload', 'pdf', 'zip', 'archive', 'upload'],
handler: (editorState, _, __) async => editorState.insertEmptyFileBlock(),
);
Widget _slashMenuItemNameBuilder(
String name,
SelectionMenuStyle style,
bool isSelected,
) {
return FlowyText(
name,
fontSize: 12.0,
figmaLineHeight: 15.0,
color: isSelected
? style.selectionMenuItemSelectedTextColor
: style.selectionMenuItemTextColor,
);
}

View File

@ -53,8 +53,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "4536488faf458ab45e304c1715850d4d1ae517ee"
resolved-ref: "4536488faf458ab45e304c1715850d4d1ae517ee"
ref: "0317779"
resolved-ref: "031777941ce53fe1aaa9a23177f6045b142e6e73"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git
version: "3.1.0"

View File

@ -199,7 +199,7 @@ dependency_overrides:
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "4536488faf458ab45e304c1715850d4d1ae517ee"
ref: "0317779"
appflowy_editor_plugins:
git:

View File

@ -0,0 +1,13 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_22_30)">
<path d="M10.0643 6.23059L10.1655 6.33179C10.9519 7.11818 11.3451 7.51143 11.3451 8C11.3451 8.48857 10.9519 8.88182 10.1655 9.66816L10.0643 9.76941" stroke="black" stroke-linecap="round"/>
<path d="M8.76325 5.15155L7.99999 8L7.23672 10.8485" stroke="black" stroke-linecap="round"/>
<path d="M5.93572 6.23059L5.83453 6.33179C5.04813 7.11818 4.65494 7.51143 4.65494 8C4.65494 8.48857 5.04813 8.88182 5.83453 9.66816L5.93572 9.76941" stroke="black" stroke-linecap="round"/>
<path d="M2.10205 8C2.10205 5.21965 2.10205 3.82953 2.96576 2.96577C3.82951 2.10207 5.21964 2.10207 7.99999 2.10207C10.7803 2.10207 12.1705 2.10207 13.0342 2.96577C13.8979 3.82953 13.8979 5.21965 13.8979 8C13.8979 10.7803 13.8979 12.1705 13.0342 13.0342C12.1705 13.8979 10.7803 13.8979 7.99999 13.8979C5.21964 13.8979 3.82951 13.8979 2.96576 13.0342C2.10205 12.1705 2.10205 10.7803 2.10205 8Z" stroke="black"/>
</g>
<defs>
<clipPath id="clip0_22_30">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,8 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.93463 13.4183H2.15028C3.28248 13.4183 4.25293 12.6097 4.46859 11.4775L5.87036 4.5225C6.08602 3.39031 7.05645 2.5816 8.18865 2.5816H8.40431" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.61996 13.4184C8.0269 12.8253 7.64951 11.747 7.64951 10.4531C7.64951 9.15916 8.0269 8.08088 8.61996 7.48782" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.0949 13.4184C13.6879 12.8253 14.0653 11.747 14.0653 10.4531C14.0653 9.15916 13.6879 8.08088 13.0949 7.48782" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.59045 8.40425L12.0705 12.4478" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.0705 8.40425L9.59045 12.4478" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.60596 6.89473H6.94863" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.5 -0.5 16 16" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" id="Wand-Sparkles--Streamline-Lucide.svg" height="16" width="16"><desc>Wand Sparkles Streamline Icon: https://streamlinehq.com</desc><path d="m13.525 2.275 -0.8 -0.8a0.75625 0.75625 0 0 0 -1.075 0L1.4749999999999999 11.65a0.75625 0.75625 0 0 0 0 1.075l0.8 0.8a0.75 0.75 0 0 0 1.075 0L13.525 3.35a0.75 0.75 0 0 0 0 -1.075" stroke-width="1"></path><path d="m8.75 4.375 1.875 1.875" stroke-width="1"></path><path d="M3.125 3.75v2.5" stroke-width="1"></path><path d="M11.875 8.75v2.5" stroke-width="1"></path><path d="M6.25 1.25v1.25" stroke-width="1"></path><path d="M4.375 5H1.875" stroke-width="1"></path><path d="M13.125 10h-2.5" stroke-width="1"></path><path d="M6.875 1.875H5.625" stroke-width="1"></path></svg>

After

Width:  |  Height:  |  Size: 855 B

View File

@ -0,0 +1,16 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_25_68)">
<path d="M13.4459 8.09759C13.9034 7.64013 14.0371 6.95191 13.6556 6.42895C13.4234 6.11243 13.167 5.81439 12.8887 5.53747C12.6118 5.25921 12.3137 5.0028 11.9972 4.77055C11.4743 4.3891 10.786 4.52254 10.3286 4.98027L4.82179 10.4868C4.6622 10.6464 4.55707 10.8513 4.53739 11.0758C4.501 11.4934 4.46299 12.2835 4.54063 13.4009C4.55842 13.6604 4.76545 13.8672 5.02504 13.8853C6.14268 13.9629 6.93253 13.9249 7.35009 13.8885C7.57464 13.8688 7.77952 13.7637 7.93883 13.6041L13.4459 8.09759Z" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.3641 8.9171C12.3641 8.9171 12.2005 8.18845 11.219 7.20694C10.2377 6.2257 9.50906 6.06207 9.50906 6.06207" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.64283 13.6381C7.64283 13.6381 7.47921 12.9094 6.49797 11.9282C5.51646 10.9467 4.78781 10.7831 4.78781 10.7831" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.87563 6.2036C6.84113 6.66672 6.49931 7.04304 6.03781 7.09858C5.63588 7.14683 5.10078 7.19131 4.49559 7.19131C3.89041 7.19131 3.35558 7.14683 2.95338 7.09858C2.49188 7.04304 2.15006 6.66672 2.11555 6.2036C2.09129 5.87365 2.06946 5.49193 2.06946 5.16953C2.06946 4.03787 2.97926 3.16123 4.11092 3.14963C4.36736 3.14706 4.62383 3.14706 4.88027 3.14963C6.01193 3.16096 6.92173 4.03787 6.92173 5.16953C6.92173 5.49166 6.90016 5.87365 6.87563 6.2036Z" stroke="black"/>
<path d="M4.49561 2.06946V3.14774" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.68689 5.03473V5.3043" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.30432 5.03473V5.3043" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_25_68">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,8 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.5238 4.28572H13.5714" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.5238 8H13.5714" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.5238 11.7143H13.5714" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.42856 4.28572H2.43397" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.42856 8H2.43397" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.42856 11.7143H2.43397" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 694 B

View File

@ -0,0 +1,13 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_25_52)">
<path d="M2.10205 7.85254C2.10205 5.62826 2.10205 4.51617 2.79301 3.82516C3.48403 3.13419 4.59612 3.13419 6.8204 3.13419H9.17958C11.4038 3.13419 12.516 3.13419 13.2069 3.82516C13.8979 4.51617 13.8979 5.62826 13.8979 7.85254V9.03213C13.8979 11.2564 13.8979 12.3686 13.207 13.0595C12.516 13.7505 11.4038 13.7505 9.17958 13.7505H6.8204C4.59612 13.7505 3.48403 13.7505 2.79301 13.0595C2.10205 12.3686 2.10205 11.2564 2.10205 9.03213V7.85254Z" stroke="black"/>
<path d="M5.05099 3.13419V2.24946" stroke="black" stroke-linecap="round"/>
<path d="M10.949 3.13419V2.24946" stroke="black" stroke-linecap="round"/>
<path d="M2.39691 6.08314H13.6031" stroke="black" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_25_52">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 948 B

View File

@ -0,0 +1,13 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_25_51)">
<path d="M2.10205 7.85254C2.10205 5.62826 2.10205 4.51617 2.79301 3.82516C3.48403 3.13419 4.59612 3.13419 6.8204 3.13419H9.17958C11.4038 3.13419 12.516 3.13419 13.2069 3.82516C13.8979 4.51617 13.8979 5.62826 13.8979 7.85254V9.03213C13.8979 11.2564 13.8979 12.3686 13.207 13.0595C12.516 13.7505 11.4038 13.7505 9.17958 13.7505H6.8204C4.59612 13.7505 3.48403 13.7505 2.79301 13.0595C2.10205 12.3686 2.10205 11.2564 2.10205 9.03213V7.85254Z" stroke="black"/>
<path d="M5.05099 3.1342V2.24947" stroke="black" stroke-linecap="round"/>
<path d="M10.949 3.1342V2.24947" stroke="black" stroke-linecap="round"/>
<path d="M2.39691 6.08314H13.6031" stroke="black" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_25_51">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 946 B

View File

@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_25_49)">
<path d="M2.25056 8H13.8744M2.25056 10.6418H13.8744M2.25056 13.2836H13.8744M3.57146 2.71642H12.5536C13.5704 2.71642 14.2059 3.81718 13.6975 4.69776C13.4615 5.10643 13.0255 5.35821 12.5536 5.35821H3.57146C2.55464 5.35826 1.91915 4.25755 2.42751 3.37692C2.66343 2.96819 3.09955 2.71642 3.57146 2.71642Z" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_25_49">
<rect width="14" height="14" fill="white" transform="translate(1.0625 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 639 B

View File

@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_27_125)">
<path d="M2.07443 7.99999C2.07443 5.20662 2.07443 3.80999 2.94218 2.94218C3.80999 2.07443 5.20662 2.07443 7.99999 2.07443C10.7933 2.07443 12.19 2.07443 13.0578 2.94218C13.9256 3.80999 13.9256 5.20662 13.9256 7.99999C13.9256 10.7933 13.9256 12.19 13.0578 13.0578C12.1901 13.9256 10.7933 13.9256 7.99999 13.9256C5.20662 13.9256 3.80999 13.9256 2.94218 13.0578C2.07443 12.1901 2.07443 10.7933 2.07443 7.99999Z" stroke="black"/>
<path d="M5.92606 8.2963L7.11117 9.48141L10.0739 6.5186" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_27_125">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 816 B

View File

@ -0,0 +1,13 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_22_30)">
<path d="M10.0643 6.23059L10.1655 6.33179C10.9519 7.11818 11.3451 7.51143 11.3451 8C11.3451 8.48857 10.9519 8.88182 10.1655 9.66816L10.0643 9.76941" stroke="black" stroke-linecap="round"/>
<path d="M8.76325 5.15155L7.99999 8L7.23672 10.8485" stroke="black" stroke-linecap="round"/>
<path d="M5.93572 6.23059L5.83453 6.33179C5.04813 7.11818 4.65494 7.51143 4.65494 8C4.65494 8.48857 5.04813 8.88182 5.83453 9.66816L5.93572 9.76941" stroke="black" stroke-linecap="round"/>
<path d="M2.10205 8C2.10205 5.21965 2.10205 3.82953 2.96576 2.96577C3.82951 2.10207 5.21964 2.10207 7.99999 2.10207C10.7803 2.10207 12.1705 2.10207 13.0342 2.96577C13.8979 3.82953 13.8979 5.21965 13.8979 8C13.8979 10.7803 13.8979 12.1705 13.0342 13.0342C12.1705 13.8979 10.7803 13.8979 7.99999 13.8979C5.21964 13.8979 3.82951 13.8979 2.96576 13.0342C2.10205 12.1705 2.10205 10.7803 2.10205 8Z" stroke="black"/>
</g>
<defs>
<clipPath id="clip0_22_30">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,15 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_31_8)">
<path d="M13.1326 4.9808V4.07505C13.1326 3.40808 12.5919 2.86737 11.925 2.86737H3.47123C2.80425 2.86737 2.26355 3.40808 2.26355 4.07505V12.5288C2.26355 13.1958 2.8042 13.7365 3.47123 13.7365H5.58466" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.1134 1.6597V4.07505" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.28271 1.6597V4.07505" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.26355 6.49042H5.28274" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.0192 11.0192L10.1134 10.2946V8.90576" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.49042 10.1134C6.49042 12.9025 9.50961 14.6456 11.925 13.2511C13.0459 12.6039 13.7365 11.4078 13.7365 10.1134C13.7365 7.32439 10.7173 5.58129 8.30193 6.97578C7.18095 7.62297 6.49042 8.81905 6.49042 10.1134Z" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_31_8">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.6597 8C1.6597 7.68169 1.9178 7.42359 2.23611 7.42359H13.7639C14.0822 7.42359 14.3403 7.68169 14.3403 8C14.3403 8.31831 14.0822 8.57641 13.7639 8.57641H2.23611C1.9178 8.57641 1.6597 8.31831 1.6597 8Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 370 B

View File

@ -0,0 +1,13 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_27_123)">
<path d="M3.541 2.267H12.459C12.459 2.267 13.733 2.267 13.733 3.541V12.459C13.733 12.459 13.733 13.733 12.459 13.733H3.541C3.541 13.733 2.267 13.733 2.267 12.459V3.541C2.267 3.541 2.267 2.267 3.541 2.267Z" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.815 5.452H11.185" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.815 8H11.185" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.815 10.548H11.185" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_27_123">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 827 B

View File

@ -0,0 +1,13 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_25_66)">
<path d="M7.99999 13.8979C4.74266 13.8979 2.10205 11.2573 2.10205 8C2.10205 4.74267 4.74266 2.10207 7.99999 2.10207C11.2573 2.10207 13.8979 4.74267 13.8979 8C13.8979 11.2573 11.2573 13.8979 7.99999 13.8979Z" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.6541 9.4745C10.6541 9.4745 9.76941 10.6541 8 10.6541C6.23059 10.6541 5.34592 9.4745 5.34592 9.4745" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.0643 6.23059C9.90144 6.23059 9.76941 6.09855 9.76941 5.93573C9.76941 5.77291 9.90144 5.64082 10.0643 5.64082C10.2271 5.64082 10.3592 5.77286 10.3592 5.93573C10.3592 6.09861 10.2271 6.23059 10.0643 6.23059Z" fill="black" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.93575 6.23059C5.77287 6.23059 5.64084 6.09855 5.64084 5.93573C5.64084 5.77291 5.77287 5.64082 5.93575 5.64082C6.09862 5.64082 6.23061 5.77286 6.23061 5.93573C6.23061 6.09861 6.09857 6.23059 5.93575 6.23059Z" fill="black" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_25_66">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,12 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_26_76)">
<path d="M9.18512 13.4812H6.81489V14.37H9.18512V13.4812ZM2.51883 9.18512V6.8149H1.63001V9.18512H2.51883ZM13.4811 8.92615V9.18512H14.37V8.92615H13.4811ZM9.71319 3.62172L12.059 5.73292L12.6536 5.07225L10.3078 2.96105L9.71319 3.62172ZM14.37 8.92615C14.37 7.92564 14.3789 7.29222 14.1265 6.72542L13.3146 7.08703C13.4722 7.44096 13.4811 7.84715 13.4811 8.92615H14.37ZM12.059 5.73292C12.861 6.45469 13.1569 6.73311 13.3146 7.08703L14.1265 6.72542C13.8741 6.15862 13.3972 5.74153 12.6536 5.07225L12.059 5.73292ZM6.83255 2.51889C7.76985 2.51889 8.12356 2.52577 8.43876 2.64672L8.7572 1.81689C8.25248 1.62319 7.70252 1.63007 6.83255 1.63007V2.51889ZM10.3078 2.96105C9.66428 2.38184 9.26198 2.01053 8.7572 1.81689L8.43876 2.64672C8.75411 2.76773 9.02007 2.99794 9.71319 3.62172L10.3078 2.96105ZM6.81489 13.4812C5.68498 13.4812 4.88228 13.4802 4.27328 13.3983C3.67713 13.3182 3.33366 13.1679 3.08292 12.9171L2.45437 13.5456C2.89783 13.9891 3.46013 14.1858 4.15488 14.2793C4.83683 14.3709 5.71011 14.37 6.81489 14.37V13.4812ZM1.63001 9.18512C1.63001 10.2899 1.62908 11.1632 1.72073 11.8451C1.81417 12.5398 2.01091 13.1022 2.45437 13.5456L3.08292 12.9171C2.83213 12.6664 2.68181 12.3228 2.60165 11.7267C2.5198 11.1177 2.51883 10.315 2.51883 9.18512H1.63001ZM9.18512 14.37C10.2898 14.37 11.1632 14.3709 11.8451 14.2793C12.5398 14.1858 13.1021 13.9891 13.5456 13.5456L12.9171 12.9171C12.6663 13.1679 12.3228 13.3182 11.7267 13.3983C11.1177 13.4802 10.315 13.4812 9.18512 13.4812V14.37ZM13.4811 9.18512C13.4811 10.315 13.4802 11.1177 13.3983 11.7267C13.3182 12.3228 13.1678 12.6664 12.9171 12.9171L13.5456 13.5456C13.989 13.1022 14.1858 12.5398 14.2792 11.8451C14.3709 11.1632 14.37 10.2899 14.37 9.18512H13.4811ZM2.51883 6.8149C2.51883 5.68504 2.5198 4.88229 2.60165 4.27334C2.68181 3.67719 2.83213 3.33372 3.08292 3.08292L2.45437 2.45443C2.01096 2.89789 1.81417 3.46019 1.72073 4.15494C1.62908 4.83684 1.63001 5.71012 1.63001 6.8149H2.51883ZM6.83255 1.63007C5.72181 1.63007 4.84426 1.62909 4.15953 1.72074C3.46236 1.81407 2.89816 2.01064 2.45437 2.45443L3.08292 3.08292C3.33333 2.83251 3.67783 2.68198 4.27746 2.60171C4.88948 2.51981 5.69678 2.51889 6.83255 2.51889V1.63007Z" fill="black"/>
<path d="M8.59253 2.37073V3.85213C8.59253 5.24876 8.59253 5.94714 9.0264 6.38101C9.46033 6.81489 10.1587 6.81489 11.5553 6.81489H13.9256" stroke="black"/>
<path d="M5.92602 11.8516V8.88889M5.92602 8.88889L4.74091 9.9999M5.92602 8.88889L7.11113 9.9999" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_26_76">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,14 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_27_103)">
<path d="M3.541 2.267H12.459C12.459 2.267 13.733 2.267 13.733 3.541V12.459C13.733 12.459 13.733 13.733 12.459 13.733H3.541C3.541 13.733 2.267 13.733 2.267 12.459V3.541C2.267 3.541 2.267 2.267 3.541 2.267Z" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.267 6.089H13.733" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.267 9.911H13.733" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.08899 6.089V13.733" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.91101 6.089V13.733" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_27_103">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 930 B

View File

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.3378 7.64612H8" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.3378 11.8928V3.39948" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 11.8928V3.39948" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.5389 7.64612L13.6622 6.23053V11.8928" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 509 B

View File

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.30054 7.66476H7.66477" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.30054 11.6879V3.6416" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.66476 11.6879V3.6416" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.6995 11.6879H11.0174C11.0174 9.00577 13.6995 9.67629 13.6995 7.66476C13.6995 6.65894 12.3584 5.98841 11.0174 6.99423" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 601 B

View File

@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.30054 7.60458H7.66477" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.30054 11.6278V3.58142" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.66476 11.6278V3.58142" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.3527 6.59877C12.4925 5.9283 13.6995 6.59877 13.6995 7.60459C13.6995 8.34521 13.0991 8.94565 12.3584 8.94565" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.0174 11.2925C12.3584 12.2983 13.6995 11.4936 13.6995 10.2867C13.6995 9.54603 13.0991 8.94565 12.3584 8.94565" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 783 B

View File

@ -0,0 +1,12 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_27_152)">
<path d="M3.541 2.267H12.459C12.459 2.267 13.733 2.267 13.733 3.541V12.459C13.733 12.459 13.733 13.733 12.459 13.733H3.541C3.541 13.733 2.267 13.733 2.267 12.459V3.541C2.267 3.541 2.267 2.267 3.541 2.267Z" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.815 6.08901C4.815 7.06975 5.87667 7.6827 6.726 7.19233C7.12017 6.96472 7.363 6.54417 7.363 6.08901C7.363 5.10826 6.30134 4.49531 5.452 4.98568C5.05783 5.21329 4.815 5.63384 4.815 6.08901Z" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.733 9.911L11.7672 7.94524C11.2697 7.44788 10.4633 7.44788 9.96577 7.94524L4.17801 13.733" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_27_152">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 978 B

View File

@ -0,0 +1,13 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_27_95)">
<path d="M3.541 2.267H12.459C12.459 2.267 13.733 2.267 13.733 3.541V12.459C13.733 12.459 13.733 13.733 12.459 13.733H3.541C3.541 13.733 2.267 13.733 2.267 12.459V3.541C2.267 3.541 2.267 2.267 3.541 2.267Z" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.452 4.815V9.274" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 4.815V7.363" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.548 4.815V10.548" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_27_95">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 823 B

View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.3378 12.954L8 7.29182" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 12.954L2.3378 7.29182" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.6622 7.99962H10.8311C10.8311 6.93796 11.1439 6.58403 11.8928 6.23016C12.6416 5.87629 13.6622 5.40488 13.6622 4.46216C13.6622 4.12806 13.5419 3.80393 13.3196 3.54913C12.8529 3.02111 12.0801 2.89236 11.4674 3.24049C11.1701 3.40965 10.945 3.67506 10.8311 3.99075" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 645 B

View File

@ -0,0 +1,8 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.7619 4.28572H13.5714" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.7619 8H13.5714" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.7619 11.7143H13.5714" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.04761 4.28572H3.66665V6.76191" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.04761 6.7619H4.2857" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.2857 11.7143H3.04761C3.04761 11.0952 4.2857 10.4762 4.2857 9.85714C4.2857 9.2381 3.66666 8.92857 3.04761 9.2381" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 796 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.45224 3.24477H13.5478M2.45224 6.41493H10.3776M2.45224 9.58508H13.5478M2.45224 12.7552H7.20747" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 274 B

View File

@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.91919 4.09786C4.91919 3.66203 5.09232 3.24405 5.4005 2.93587C5.70868 2.62769 6.12666 2.45456 6.56249 2.45456H11.9021C12.338 2.45456 12.756 2.62769 13.0641 2.93587C13.3723 3.24405 13.5455 3.66203 13.5455 4.09786V9.43752C13.5455 9.87335 13.3723 10.2913 13.0641 10.5995C12.756 10.9077 12.338 11.0808 11.9021 11.0808H6.56249C6.12666 11.0808 5.70868 10.9077 5.4005 10.5995C5.09232 10.2913 4.91919 9.87335 4.91919 9.43752V4.09786Z" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.07811 5.07941C2.88916 5.18712 2.732 5.34282 2.62251 5.53075C2.51302 5.71868 2.45508 5.93218 2.45456 6.14968V12.3113C2.45456 12.9891 3.0091 13.5436 3.68688 13.5436H9.8485C10.3106 13.5436 10.562 13.3064 10.7727 12.9275" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.0808 4.91919H11.0859" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.91919 8.61616L7.16448 6.37087C7.23372 6.30156 7.31594 6.24658 7.40644 6.20907C7.49694 6.17156 7.59395 6.15225 7.69192 6.15225C7.78988 6.15225 7.88689 6.17156 7.97739 6.20907C8.06789 6.24658 8.15011 6.30156 8.21935 6.37087L10.4646 8.61616" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.84848 7.99999L10.8614 6.98702C10.9307 6.91771 11.0129 6.86273 11.1034 6.82522C11.1939 6.78771 11.2909 6.7684 11.3889 6.7684C11.4869 6.7684 11.5839 6.78771 11.6744 6.82522C11.7649 6.86273 11.8471 6.91771 11.9163 6.98702L13.5455 8.61615" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.6879 3.97683H2.30054" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.37 8H5.65317" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.37 12.0232H5.65317" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.30054 8V12.0232" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 491 B

View File

@ -0,0 +1,12 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_27_108)">
<path d="M3.541 2.267H12.459C12.459 2.267 13.733 2.267 13.733 3.541V12.459C13.733 12.459 13.733 13.733 12.459 13.733H3.541C3.541 13.733 2.267 13.733 2.267 12.459V3.541C2.267 3.541 2.267 2.267 3.541 2.267Z" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.267 8H13.733" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 2.267V13.733" stroke="#171717" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_27_108">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 726 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 2.12H5.38667C4.1547 2.12 3.53878 2.12 3.15603 2.50274C2.77335 2.88542 2.77335 3.50141 2.77335 4.73332V5.35402M8 2.12H10.6133C11.8452 2.12 12.4612 2.12 12.844 2.50274C13.2266 2.88542 13.2266 3.50141 13.2266 4.73332V5.35402M8 2.12V13.88" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.73331 13.88H11.2667" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 512 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.84344 11.7334V4.18547L11.774 7.95946L5.84344 11.7334Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 185 B

View File

@ -0,0 +1,9 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.9">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.03559 3.91001C8.24508 3.76431 8.49414 3.68622 8.74931 3.68622C9.00448 3.68622 9.25353 3.76431 9.46302 3.91001C9.67251 4.0557 9.83239 4.26202 9.92118 4.50124L9.92169 4.50261L11.4217 8.57292L11.4235 8.57578L11.4263 8.57758L15.498 10.0781C15.7373 10.1669 15.9436 10.3268 16.0893 10.5363C16.235 10.7458 16.3131 10.9948 16.3131 11.25C16.3131 11.5051 16.235 11.7542 16.0893 11.9637C15.9436 12.1732 15.7373 12.3331 15.498 12.4219L15.4967 12.4224L11.4264 13.9224L11.4235 13.9242L11.4217 13.927L9.92169 17.9973L9.92118 17.9987C9.83239 18.2379 9.6725 18.4443 9.46302 18.59C9.25353 18.7356 9.00448 18.8137 8.74931 18.8137C8.49414 18.8137 8.24508 18.7356 8.03559 18.59C7.82611 18.4443 7.66623 18.2379 7.57743 17.9987L7.57692 17.9973L6.07692 13.927L6.07511 13.9242L6.07383 13.9231L6.07228 13.9224L2.00194 12.4224L2.00057 12.4219C1.76134 12.3331 1.55503 12.1732 1.40933 11.9637C1.26364 11.7542 1.18555 11.5051 1.18555 11.25C1.18555 10.9948 1.26364 10.7458 1.40933 10.5363C1.55503 10.3268 1.76134 10.1669 2.00057 10.0781L2.00194 10.0776L6.07225 8.5776L6.07511 8.57578L6.07691 8.57295L7.57692 4.50261L7.57743 4.50124C7.66623 4.26202 7.82611 4.0557 8.03559 3.91001ZM10.2488 13.4948C10.3117 13.324 10.4109 13.169 10.5396 13.0403C10.6683 12.9116 10.8234 12.8124 10.9941 12.7495L15.0631 11.25L10.9942 9.7505C10.8234 9.68758 10.6683 9.58834 10.5396 9.45966C10.4109 9.33098 10.3117 9.17592 10.2488 9.00516L8.74931 4.93622L7.24983 9.00513C7.1869 9.17588 7.08767 9.33098 6.95899 9.45966C6.83031 9.58834 6.67524 9.68756 6.50449 9.75049L2.43555 11.25L6.50446 12.7495C6.67521 12.8124 6.83031 12.9116 6.95899 13.0403C7.08767 13.169 7.18689 13.324 7.24981 13.4948L8.74931 17.5637L10.2488 13.4948Z" fill="#8427E0"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.7493 0.625C14.0945 0.625 14.3743 0.904822 14.3743 1.25V5C14.3743 5.34518 14.0945 5.625 13.7493 5.625C13.4042 5.625 13.1243 5.34518 13.1243 5V1.25C13.1243 0.904822 13.4042 0.625 13.7493 0.625Z" fill="#8427E0"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.2493 3.125C11.2493 2.77982 11.5292 2.5 11.8743 2.5H15.6243C15.9695 2.5 16.2493 2.77982 16.2493 3.125C16.2493 3.47018 15.9695 3.75 15.6243 3.75H11.8743C11.5292 3.75 11.2493 3.47018 11.2493 3.125Z" fill="#8427E0"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.4993 5C17.8445 5 18.1243 5.27982 18.1243 5.625V8.125C18.1243 8.47018 17.8445 8.75 17.4993 8.75C17.1542 8.75 16.8743 8.47018 16.8743 8.125V5.625C16.8743 5.27982 17.1542 5 17.4993 5Z" fill="#8427E0"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.6243 6.875C15.6243 6.52982 15.9042 6.25 16.2493 6.25H18.7493C19.0945 6.25 19.3743 6.52982 19.3743 6.875C19.3743 7.22018 19.0945 7.5 18.7493 7.5H16.2493C15.9042 7.5 15.6243 7.22018 15.6243 6.875Z" fill="#8427E0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1464,12 +1464,44 @@
},
"document": {
"selectADocumentToLinkTo": "Select a Document to link to"
},
"name": {
"text": "Text",
"heading1": "Heading 1",
"heading2": "Heading 2",
"heading3": "Heading 3",
"image": "Image",
"bulletedList": "Bulleted List",
"numberedList": "Numbered List",
"checkbox": "Checkbox",
"doc": "Doc",
"linkedDoc": "Linked Doc",
"grid": "Grid",
"linkedGrid": "Linked Grid",
"kanban": "Kanban",
"linkedKanban": "Linked Kanban",
"calendar": "Calendar",
"linkedCalendar": "Linked Calendar",
"quote": "Quote",
"divider": "Divider",
"table": "Table",
"callout": "Callout",
"outline": "Outline",
"mathEquation": "Math Equation",
"code": "Code",
"toggleList": "Toggle list",
"emoji": "Emoji",
"aiWriter": "AI Writer",
"dateOrReminder": "Date or Reminder",
"photoGallery": "Photo Gallery",
"file": "File"
}
},
"selectionMenu": {
"outline": "Outline",
"codeBlock": "Code Block"
},
"plugins": {
"referencedBoard": "Referenced Board",
"referencedGrid": "Referenced Grid",
@ -1482,7 +1514,7 @@
"autoGeneratorHintText": "Ask AI ...",
"autoGeneratorCantGetOpenAIKey": "Can't get AI key",
"autoGeneratorRewrite": "Rewrite",
"smartEdit": "AI Assistants",
"smartEdit": "Ask AI",
"aI": "AI",
"smartEditFixSpelling": "Fix spelling & grammar",
"warning": "⚠️ AI responses can be inaccurate or misleading.",