fix: launch review 0.8.1 (#7185)

* fix: launch review

* chore: scroll to end upon sending new message

* chore: bump editor version

* chore: scroll to bottom after adding message

* chore: code reorg

* chore: bump editor version

* chore: bump editor ver

* chore: bump editor

* chore: bump editor

* fix: file block node insertion

* fix: do the same thing on image

* chore: update icons and translations
This commit is contained in:
Richard Shiue 2025-01-14 12:35:51 +08:00 committed by GitHub
parent 2b1d1ba2f4
commit d1efda4c50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 126 additions and 147 deletions

View File

@ -312,7 +312,7 @@ class ChatAnimatedListReversedState extends State<ChatAnimatedListReversed>
// bottom of the list, set `_userHasScrolled` to false so that the scroll
// animation is triggered.
if (_userHasScrolled &&
widget.scrollController.offset >=
widget.scrollController.offset >
widget.scrollController.position.minScrollExtent) {
_userHasScrolled = false;
}
@ -325,7 +325,7 @@ class ChatAnimatedListReversedState extends State<ChatAnimatedListReversed>
// Used later to trigger scroll to end only for the last inserted message.
_lastInsertedMessageId = data.id;
if (position == _oldList.length) {
if (position == 0) {
_scrollToEnd(data);
}
}

View File

@ -49,8 +49,11 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
final focusNode = FocusNode();
final textController = TextEditingController();
bool showPredefinedFormatSection = false;
PredefinedFormat predefinedFormat = const PredefinedFormat.auto();
bool showPredefinedFormatSection = true;
PredefinedFormat predefinedFormat = const PredefinedFormat(
imageFormat: ImageFormat.text,
textFormat: TextFormat.bulletList,
);
late SendButtonState sendButtonState;
@override
@ -185,10 +188,6 @@ class _DesktopAIPromptInputState extends State<DesktopAIPromptInput> {
setState(() {
showPredefinedFormatSection =
!showPredefinedFormatSection;
if (!showPredefinedFormatSection) {
predefinedFormat =
const PredefinedFormat.auto();
}
});
},
sendButtonState: sendButtonState,
@ -466,10 +465,7 @@ class _PromptTextFieldState extends State<_PromptTextField> {
focusedBorder: InputBorder.none,
contentPadding: calculateContentPadding(),
hintText: widget.hintText,
hintStyle: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Theme.of(context).hintColor),
hintStyle: AIChatUILayout.inputHintTextStyle(context),
isCollapsed: true,
isDense: true,
),

View File

@ -43,8 +43,11 @@ class _MobileAIPromptInputState extends State<MobileAIPromptInput> {
final focusNode = FocusNode();
final textController = TextEditingController();
bool showPredefinedFormatSection = false;
PredefinedFormat predefinedFormat = const PredefinedFormat.auto();
bool showPredefinedFormatSection = true;
PredefinedFormat predefinedFormat = const PredefinedFormat(
imageFormat: ImageFormat.text,
textFormat: TextFormat.bulletList,
);
late SendButtonState sendButtonState;
@override
@ -265,6 +268,7 @@ class _MobileAIPromptInputState extends State<MobileAIPromptInput> {
AIType.appflowyAI => LocaleKeys.chat_inputMessageHint.tr(),
AIType.localAI => LocaleKeys.chat_inputLocalAIMessageHint.tr()
},
hintStyle: AIChatUILayout.inputHintTextStyle(context),
isCollapsed: true,
isDense: true,
),
@ -304,9 +308,6 @@ class _MobileAIPromptInputState extends State<MobileAIPromptInput> {
onTogglePredefinedFormatSection: () {
setState(() {
showPredefinedFormatSection = !showPredefinedFormatSection;
if (!showPredefinedFormatSection) {
predefinedFormat = const PredefinedFormat.auto();
}
});
},
onUpdateSelectedSources: widget.onUpdateSelectedSources,

View File

@ -24,50 +24,25 @@ class PromptInputDesktopToggleFormatButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: SizedBox(
height: DesktopAIPromptSizes.actionBarButtonSize,
child: FlowyHover(
style: const HoverStyle(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Padding(
padding: const EdgeInsetsDirectional.all(6.0),
child: FlowyText(
_getDescription(),
fontSize: 12.0,
figmaLineHeight: 16.0,
return FlowyIconButton(
tooltipText: showFormatBar
? LocaleKeys.chat_changeFormat_defaultDescription.tr()
: LocaleKeys.chat_changeFormat_blankDescription.tr(),
width: 28.0,
onPressed: onTap,
icon: showFormatBar
? const FlowySvg(
FlowySvgs.m_aa_text_s,
size: Size.square(16.0),
color: Color(0xFF666D76),
)
: const FlowySvg(
FlowySvgs.ai_text_image_s,
size: Size(21.0, 16.0),
color: Color(0xFF666D76),
),
),
),
),
);
}
String _getDescription() {
if (!showFormatBar) {
return LocaleKeys.chat_changeFormat_blankDescription.tr();
}
return switch ((predefinedFormat, predefinedTextFormat)) {
(ImageFormat.image, _) => predefinedFormat.i18n,
(ImageFormat.text, TextFormat.auto) =>
LocaleKeys.chat_changeFormat_defaultDescription.tr(),
(ImageFormat.text, _) when predefinedTextFormat != null =>
predefinedTextFormat!.i18n,
(ImageFormat.textAndImage, TextFormat.auto) =>
LocaleKeys.chat_changeFormat_textWithImageDescription.tr(),
(ImageFormat.textAndImage, TextFormat.bulletList) =>
LocaleKeys.chat_changeFormat_bulletWithImageDescription.tr(),
(ImageFormat.textAndImage, TextFormat.numberedList) =>
LocaleKeys.chat_changeFormat_numberWithImageDescription.tr(),
(ImageFormat.textAndImage, TextFormat.table) =>
LocaleKeys.chat_changeFormat_tableWithImageDescription.tr(),
_ => throw UnimplementedError(),
};
}
}
class ChangeFormatBar extends StatelessWidget {
@ -80,7 +55,7 @@ class ChangeFormatBar extends StatelessWidget {
required this.onSelectPredefinedFormat,
});
final PredefinedFormat predefinedFormat;
final PredefinedFormat? predefinedFormat;
final double buttonSize;
final double iconSize;
final double spacing;
@ -97,7 +72,7 @@ class ChangeFormatBar extends StatelessWidget {
_buildFormatButton(context, ImageFormat.text),
_buildFormatButton(context, ImageFormat.textAndImage),
_buildFormatButton(context, ImageFormat.image),
if (predefinedFormat.imageFormat.hasText) ...[
if (predefinedFormat?.imageFormat.hasText ?? true) ...[
_buildDivider(),
_buildTextFormatButton(context, TextFormat.auto),
_buildTextFormatButton(context, TextFormat.bulletList),
@ -113,11 +88,12 @@ class ChangeFormatBar extends StatelessWidget {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (format == predefinedFormat.imageFormat) {
if (predefinedFormat != null &&
format == predefinedFormat!.imageFormat) {
return;
}
if (format.hasText) {
final textFormat = predefinedFormat.textFormat ?? TextFormat.auto;
final textFormat = predefinedFormat?.textFormat ?? TextFormat.auto;
onSelectPredefinedFormat(
PredefinedFormat(imageFormat: format, textFormat: textFormat),
);
@ -132,7 +108,7 @@ class ChangeFormatBar extends StatelessWidget {
child: SizedBox.square(
dimension: buttonSize,
child: FlowyHover(
isSelected: () => format == predefinedFormat.imageFormat,
isSelected: () => format == predefinedFormat?.imageFormat,
child: Center(
child: FlowySvg(
format.icon,
@ -162,12 +138,13 @@ class ChangeFormatBar extends StatelessWidget {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (format == predefinedFormat.textFormat) {
if (predefinedFormat != null &&
format == predefinedFormat!.textFormat) {
return;
}
onSelectPredefinedFormat(
PredefinedFormat(
imageFormat: predefinedFormat.imageFormat,
imageFormat: predefinedFormat?.imageFormat ?? ImageFormat.text,
textFormat: format,
),
);
@ -177,7 +154,7 @@ class ChangeFormatBar extends StatelessWidget {
child: SizedBox.square(
dimension: buttonSize,
child: FlowyHover(
isSelected: () => format == predefinedFormat.textFormat,
isSelected: () => format == predefinedFormat?.textFormat,
child: Center(
child: FlowySvg(
format.icon,
@ -211,8 +188,8 @@ class PromptInputMobileToggleFormatButton extends StatelessWidget {
expandText: false,
text: showFormatBar
? const FlowySvg(
FlowySvgs.ai_text_auto_s,
size: Size.square(24.0),
FlowySvgs.m_aa_text_s,
size: Size.square(20.0),
)
: const FlowySvg(
FlowySvgs.ai_text_image_s,

View File

@ -1,3 +1,4 @@
import 'package:appflowy/util/theme_extension.dart';
import 'package:flutter/material.dart';
import 'package:universal_platform/universal_platform.dart';
@ -17,6 +18,14 @@ class AIChatUILayout {
static EdgeInsets get messageMargin => UniversalPlatform.isMobile
? const EdgeInsets.symmetric(horizontal: 16)
: EdgeInsets.zero;
static TextStyle? inputHintTextStyle(BuildContext context) {
return Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).isLightMode
? const Color(0xFFBDC2C8)
: const Color(0xFF3C3E51),
);
}
}
class DesktopAIPromptSizes {

View File

@ -28,7 +28,7 @@ class _ChangeFormatBottomSheetContent extends StatefulWidget {
class _ChangeFormatBottomSheetContentState
extends State<_ChangeFormatBottomSheetContent> {
PredefinedFormat predefinedFormat = const PredefinedFormat.auto();
PredefinedFormat? predefinedFormat;
@override
Widget build(BuildContext context) {
@ -106,7 +106,7 @@ class _Body extends StatelessWidget {
required this.onSelectPredefinedFormat,
});
final PredefinedFormat predefinedFormat;
final PredefinedFormat? predefinedFormat;
final void Function(PredefinedFormat) onSelectPredefinedFormat;
@override
@ -119,7 +119,7 @@ class _Body extends StatelessWidget {
_buildFormatButton(ImageFormat.image),
const VSpace(32.0),
Opacity(
opacity: predefinedFormat.imageFormat.hasText ? 1 : 0,
opacity: predefinedFormat?.imageFormat.hasText ?? true ? 1 : 0,
child: Column(
children: [
_buildTextFormatButton(TextFormat.auto, true),
@ -139,7 +139,7 @@ class _Body extends StatelessWidget {
]) {
return FlowyOptionTile.checkbox(
text: format.i18n,
isSelected: format == predefinedFormat.imageFormat,
isSelected: format == predefinedFormat?.imageFormat,
showTopBorder: isFirst,
leftIcon: FlowySvg(
format.icon,
@ -148,11 +148,12 @@ class _Body extends StatelessWidget {
: const Size.square(20),
),
onTap: () {
if (format == predefinedFormat.imageFormat) {
if (predefinedFormat != null &&
format == predefinedFormat!.imageFormat) {
return;
}
if (format.hasText) {
final textFormat = predefinedFormat.textFormat ?? TextFormat.auto;
final textFormat = predefinedFormat?.textFormat ?? TextFormat.auto;
onSelectPredefinedFormat(
PredefinedFormat(imageFormat: format, textFormat: textFormat),
);
@ -171,19 +172,20 @@ class _Body extends StatelessWidget {
]) {
return FlowyOptionTile.checkbox(
text: format.i18n,
isSelected: format == predefinedFormat.textFormat,
isSelected: format == predefinedFormat?.textFormat,
showTopBorder: isFirst,
leftIcon: FlowySvg(
format.icon,
size: const Size.square(20),
),
onTap: () {
if (format == predefinedFormat.textFormat) {
if (predefinedFormat != null &&
format == predefinedFormat!.textFormat) {
return;
}
onSelectPredefinedFormat(
PredefinedFormat(
imageFormat: predefinedFormat.imageFormat,
imageFormat: predefinedFormat?.imageFormat ?? ImageFormat.text,
textFormat: format,
),
);

View File

@ -301,7 +301,7 @@ class _ChangeFormatPopoverContent extends StatefulWidget {
class _ChangeFormatPopoverContentState
extends State<_ChangeFormatPopoverContent> {
PredefinedFormat predefinedFormat = const PredefinedFormat.auto();
PredefinedFormat? predefinedFormat;
@override
Widget build(BuildContext context) {
@ -362,7 +362,10 @@ class _ChangeFormatPopoverContentState
cursor: SystemMouseCursors.click,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => widget.onRegenerate?.call(predefinedFormat),
onTap: () {
widget.onRegenerate
?.call(predefinedFormat ?? const PredefinedFormat.auto());
},
child: SizedBox.square(
dimension: DesktopAIPromptSizes.predefinedFormatButtonHeight,
child: Center(
@ -467,7 +470,9 @@ class _SaveToPageButtonState extends State<SaveToPageButton> {
final documentId = getOpenedDocumentId();
if (documentId != null) {
await onAddToExistingPage(context, documentId);
await forceReloadAndUpdateSelection(documentId);
await forceReload(documentId);
await Future.delayed(const Duration(milliseconds: 500));
await updateSelection(documentId);
} else {
widget.onOverrideVisibility?.call(true);
if (spaceView != null) {
@ -497,6 +502,8 @@ class _SaveToPageButtonState extends State<SaveToPageButton> {
if (context.mounted) {
openPageFromMessage(context, view);
}
await Future.delayed(const Duration(milliseconds: 500));
await updateSelection(documentId);
},
),
);
@ -565,14 +572,20 @@ class _SaveToPageButtonState extends State<SaveToPageButton> {
);
}
Future<void> forceReloadAndUpdateSelection(String documentId) async {
Future<void> forceReload(String documentId) async {
final bloc = DocumentBloc.findOpen(documentId);
if (bloc == null) {
return;
}
await bloc.forceReloadDocumentState();
await Future.delayed(const Duration(milliseconds: 500));
}
Future<void> updateSelection(String documentId) async {
final bloc = DocumentBloc.findOpen(documentId);
if (bloc == null) {
return;
}
await bloc.forceReloadDocumentState();
final editorState = bloc.state.editorState;
final lastNodePath = editorState?.getLastSelectable()?.$1.path;
if (editorState == null || lastNodePath == null) {

View File

@ -9,26 +9,19 @@ extension InsertFile on EditorState {
if (selection == null || !selection.isCollapsed) {
return;
}
final node = getNodeAtPath(selection.end.path);
if (node == null) {
final path = selection.end.path;
final node = getNodeAtPath(path);
final delta = node?.delta;
if (node == null || delta == null) {
return;
}
final file = fileNode(url: '')..extraInfos = {'global_key': key};
final transaction = this.transaction;
// if the current node is empty paragraph, replace it with the file node
if (node.type == ParagraphBlockKeys.type &&
(node.delta?.isEmpty ?? false)) {
transaction
..insertNode(node.path, file)
..deleteNode(node);
} else {
transaction.insertNode(node.path.next, file);
}
transaction.afterSelection =
Selection.collapsed(Position(path: node.path.next));
transaction.selectionExtraInfo = {};
final insertedPath = delta.isEmpty ? path : path.next;
final transaction = this.transaction
..insertNode(insertedPath, file)
..insertNode(insertedPath, paragraphNode())
..afterSelection = Selection.collapsed(Position(path: insertedPath.next));
return apply(transaction);
}

View File

@ -58,26 +58,20 @@ extension InsertImage on EditorState {
if (selection == null || !selection.isCollapsed) {
return;
}
final node = getNodeAtPath(selection.end.path);
if (node == null) {
final path = selection.end.path;
final node = getNodeAtPath(path);
final delta = node?.delta;
if (node == null || delta == null) {
return;
}
final emptyImage = imageNode(url: '')
..extraInfos = {kImagePlaceholderKey: key};
final transaction = this.transaction;
// if the current node is empty paragraph, replace it with image node
if (node.type == ParagraphBlockKeys.type &&
(node.delta?.isEmpty ?? false)) {
transaction
..insertNode(node.path, emptyImage)
..deleteNode(node);
} else {
transaction.insertNode(node.path.next, emptyImage);
}
transaction.afterSelection =
Selection.collapsed(Position(path: node.path.next));
transaction.selectionExtraInfo = {};
final insertedPath = delta.isEmpty ? path : path.next;
final transaction = this.transaction
..insertNode(insertedPath, emptyImage)
..insertNode(insertedPath, paragraphNode())
..afterSelection = Selection.collapsed(Position(path: insertedPath.next));
return apply(transaction);
}
@ -87,26 +81,20 @@ extension InsertImage on EditorState {
if (selection == null || !selection.isCollapsed) {
return;
}
final node = getNodeAtPath(selection.end.path);
if (node == null) {
final path = selection.end.path;
final node = getNodeAtPath(path);
final delta = node?.delta;
if (node == null || delta == null) {
return;
}
final emptyBlock = multiImageNode()
..extraInfos = {kMultiImagePlaceholderKey: key};
final transaction = this.transaction;
// if the current node is empty paragraph, replace it with image node
if (node.type == ParagraphBlockKeys.type &&
(node.delta?.isEmpty ?? false)) {
transaction
..insertNode(node.path, emptyBlock)
..deleteNode(node);
} else {
transaction.insertNode(node.path.next, emptyBlock);
}
transaction.afterSelection =
Selection.collapsed(Position(path: node.path.next));
transaction.selectionExtraInfo = {};
final insertedPath = delta.isEmpty ? path : path.next;
final transaction = this.transaction
..insertNode(insertedPath, emptyBlock)
..insertNode(insertedPath, paragraphNode())
..afterSelection = Selection.collapsed(Position(path: insertedPath.next));
return apply(transaction);
}

View File

@ -61,8 +61,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "448174b"
resolved-ref: "448174bb11ae4cfb3bb093522ef02f10f856abdf"
ref: "5352bb4"
resolved-ref: "5352bb4a2483039b97073f40c32a93f8fc5e7242"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git
version: "4.0.0"

View File

@ -174,7 +174,7 @@ dependency_overrides:
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "448174b"
ref: "5352bb4"
appflowy_editor_plugins:
git:

View File

@ -1,12 +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_3551_49504)">
<path d="M2.01758 8.00012C2.01758 5.17988 2.01758 3.76982 2.89367 2.89367C3.76982 2.01758 5.17988 2.01758 8.00012 2.01758C10.8203 2.01758 12.2304 2.01758 13.1065 2.89367C13.9827 3.76982 13.9827 5.17988 13.9827 8.00012C13.9827 10.8203 13.9827 12.2304 13.1065 13.1065C12.2305 13.9827 10.8203 13.9827 8.00012 13.9827C5.17988 13.9827 3.76982 13.9827 2.89367 13.1065C2.01758 12.2305 2.01758 10.8203 2.01758 8.00012Z" stroke="black"/>
<path d="M9.19727 5.60711C9.1953 6.52816 10.1912 7.10599 10.9898 6.64716C11.3621 6.43328 11.5912 6.03641 11.5903 5.60711C11.5923 4.68601 10.5964 4.10824 9.79774 4.56707C9.42548 4.78089 9.19634 5.17782 9.19727 5.60711Z" fill="black" stroke="black" stroke-width="0.2"/>
<path d="M2.01758 8.29931L3.06545 7.38242C3.61063 6.90544 4.43231 6.93278 4.94451 7.44498L7.51088 10.0114C7.92197 10.4225 8.5692 10.4786 9.04492 10.1442L9.22331 10.0189C9.90784 9.53777 10.834 9.59349 11.4559 10.1532L13.3844 11.8888" stroke="black" stroke-linecap="round"/>
<g clip-path="url(#clip0_4912_80381)">
<path d="M2.44453 7.99973C2.44453 5.38094 2.44453 4.0716 3.25805 3.25803C4.07162 2.44452 5.38096 2.44452 7.99975 2.44452C10.6185 2.44452 11.9279 2.44452 12.7414 3.25803C13.555 4.0716 13.555 5.38094 13.555 7.99973C13.555 10.6185 13.555 11.9279 12.7414 12.7414C11.9279 13.5549 10.6185 13.5549 7.99975 13.5549C5.38096 13.5549 4.07162 13.5549 3.25805 12.7414C2.44453 11.9279 2.44453 10.6185 2.44453 7.99973Z" stroke="black"/>
<path d="M9.11211 5.77811C9.11028 6.63337 10.035 7.16992 10.7766 6.74387C11.1223 6.54526 11.3351 6.17674 11.3342 5.77811C11.336 4.9228 10.4113 4.3863 9.66969 4.81235C9.32402 5.01091 9.11125 5.37948 9.11211 5.77811Z" fill="black" stroke="black" stroke-width="0.2"/>
<path d="M2.44453 8.27756L3.41755 7.42616C3.92379 6.98325 4.68678 7.00864 5.1624 7.48425L7.54546 9.86732C7.92718 10.2491 8.52818 10.3011 8.96993 9.99066L9.13557 9.87427C9.7712 9.42755 10.6312 9.4793 11.2087 9.99904L12.9995 11.6107" stroke="black" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_3551_49504">
<rect width="14" height="14" fill="white" transform="translate(1 1)"/>
<clipPath id="clip0_4912_80381">
<rect width="13" height="13" fill="white" transform="translate(1.5 1.5)"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,14 +1,14 @@
<svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3551_49505)">
<path d="M1.49414 7.99955C1.49414 5.38076 1.49414 4.07142 2.30766 3.25785C3.12122 2.44434 4.43057 2.44434 7.04935 2.44434C9.66809 2.44434 10.9775 2.44434 11.791 3.25785C12.6046 4.07142 12.6046 5.38076 12.6046 7.99955C12.6046 10.6183 12.6046 11.9277 11.791 12.7412C10.9775 13.5548 9.66809 13.5548 7.04935 13.5548C4.43057 13.5548 3.12122 13.5548 2.30766 12.7412C1.49414 11.9277 1.49414 10.6183 1.49414 7.99955Z" stroke="black"/>
<path d="M8.16211 5.77817C8.16028 6.63343 9.08501 7.16999 9.82662 6.74393C10.1723 6.54533 10.3851 6.17681 10.3842 5.77817C10.386 4.92286 9.4613 4.38636 8.71969 4.81242C8.37402 5.01097 8.16125 5.37954 8.16211 5.77817Z" fill="black" stroke="black" stroke-width="0.2"/>
<path d="M1.49414 8.27689L2.46716 7.42549C2.9734 6.98257 3.73639 7.00796 4.212 7.48358L6.59507 9.86664C6.97679 10.2484 7.57779 10.3005 8.01953 9.98999L8.18518 9.8736C8.82081 9.42688 9.68084 9.47863 10.2583 9.99837L12.0491 11.61" stroke="black" stroke-linecap="round"/>
<g clip-path="url(#clip0_4912_80370)">
<path d="M1.49336 7.99973C1.49336 5.38094 1.49336 4.0716 2.30688 3.25803C3.12044 2.44452 4.42979 2.44452 7.04858 2.44452C9.66731 2.44452 10.9767 2.44452 11.7902 3.25803C12.6038 4.0716 12.6038 5.38094 12.6038 7.99973C12.6038 10.6185 12.6038 11.9279 11.7902 12.7414C10.9768 13.5549 9.66731 13.5549 7.04858 13.5549C4.42979 13.5549 3.12044 13.5549 2.30688 12.7414C1.49336 11.9279 1.49336 10.6185 1.49336 7.99973Z" stroke="black"/>
<path d="M8.16094 5.77811C8.15912 6.63337 9.08384 7.16992 9.82545 6.74387C10.1711 6.54526 10.3839 6.17674 10.383 5.77811C10.3849 4.9228 9.46013 4.3863 8.71852 4.81235C8.37285 5.01091 8.16008 5.37948 8.16094 5.77811Z" fill="black" stroke="black" stroke-width="0.2"/>
<path d="M1.49336 8.27756L2.46638 7.42616C2.97262 6.98325 3.73561 7.00864 4.21123 7.48425L6.59429 9.86732C6.97601 10.2491 7.57701 10.3011 8.01875 9.99066L8.1844 9.87427C8.82003 9.42755 9.68006 9.4793 10.2575 9.99904L12.0483 11.6107" stroke="black" stroke-linecap="round"/>
</g>
<path d="M21.4512 3.51465H14.5488" stroke="black" stroke-linecap="round"/>
<path d="M19.3805 8H14.5488" stroke="black" stroke-linecap="round"/>
<path d="M18 12.4854H14.5488" stroke="black" stroke-linecap="round"/>
<path d="M21.4512 3.51453H14.5488" stroke="black" stroke-linecap="round"/>
<path d="M19.3805 8.00012H14.5488" stroke="black" stroke-linecap="round"/>
<path d="M18 12.4857H14.5488" stroke="black" stroke-linecap="round"/>
<defs>
<clipPath id="clip0_3551_49505">
<clipPath id="clip0_4912_80370">
<rect width="13" height="13" fill="white" transform="translate(0.548828 1.5)"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -233,7 +233,7 @@
"number": "Numbered list",
"table": "Table",
"blankDescription": "Format response",
"defaultDescription": "Auto",
"defaultDescription": "Auto mode",
"textWithImageDescription": "@:chat.changeFormat.text with image",
"numberWithImageDescription": "@:chat.changeFormat.number with image",
"bulletWithImageDescription": "@:chat.changeFormat.bullet with image",
@ -3069,7 +3069,7 @@
}
}
},
"ai":{
"ai": {
"contentPolicyViolation": "Image generation failed due to sensitive content. Please rephrase your input and try again"
}
}