feat: new property ui revamp (#4063)

* feat: implement new property page

* feat: implement date option

* feat: add include time

* feat: add field header

* feat: implement new property page

* feat: add icons

* feat: add color list

* feat: add color list

* feat: integrate new property page

* feat: support creating property with values

* fix: select option doesn't work

* feat: set textinputaction to done
This commit is contained in:
Lucas.Xu 2023-12-01 20:16:43 +08:00 committed by GitHub
parent b43b522d97
commit af07b53484
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1704 additions and 159 deletions

View File

@ -1,3 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class AppBarBackButton extends StatelessWidget { class AppBarBackButton extends StatelessWidget {
@ -17,6 +20,26 @@ class AppBarBackButton extends StatelessWidget {
} }
} }
class AppBarCancelButton extends StatelessWidget {
const AppBarCancelButton({
super.key,
required this.onTap,
});
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return AppBarButton(
onTap: onTap,
child: FlowyText(
LocaleKeys.button_cancel.tr(),
fontSize: 16.0,
),
);
}
}
class AppBarMoreButton extends StatelessWidget { class AppBarMoreButton extends StatelessWidget {
const AppBarMoreButton({ const AppBarMoreButton({
super.key, super.key,
@ -56,6 +79,9 @@ class AppBarButton extends StatelessWidget {
return InkWell( return InkWell(
enableFeedback: true, enableFeedback: true,
borderRadius: BorderRadius.circular(28), borderRadius: BorderRadius.circular(28),
splashColor: Colors.transparent,
focusColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: onTap, onTap: onTap,
child: Padding( child: Padding(
padding: EdgeInsets.all(extent), padding: EdgeInsets.all(extent),

View File

@ -0,0 +1,56 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart';
class OptionColorList extends StatelessWidget {
const OptionColorList({
super.key,
this.selectedColor,
required this.onSelectedColor,
});
final SelectOptionColorPB? selectedColor;
final void Function(SelectOptionColorPB color) onSelectedColor;
@override
Widget build(BuildContext context) {
return GridView.count(
crossAxisCount: 6,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: SelectOptionColorPB.values.map(
(colorPB) {
final color = colorPB.toColor(context);
final isSelected = selectedColor?.value == colorPB.value;
return GestureDetector(
onTap: () => onSelectedColor(colorPB),
child: Container(
margin: const EdgeInsets.all(
8.0,
),
decoration: BoxDecoration(
color: color,
borderRadius: Corners.s12Border,
border: Border.all(
color: isSelected
? const Color(0xff00C6F1)
: Theme.of(context).dividerColor,
),
),
alignment: Alignment.center,
child: isSelected
? const FlowySvg(
FlowySvgs.blue_check_s,
size: Size.square(28.0),
blendMode: null,
)
: null,
),
);
},
).toList(),
);
}
}

View File

@ -44,7 +44,7 @@ Future<T?> showMobileBottomSheet<T>(
if (showHeader) { if (showHeader) {
children.addAll([ children.addAll([
const VSpace(4), VSpace(padding.top),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -81,10 +81,12 @@ Future<T?> showMobileBottomSheet<T>(
if (resizeToAvoidBottomInset) { if (resizeToAvoidBottomInset) {
children.add( children.add(
AnimatedPadding( AnimatedPadding(
padding: padding + padding: EdgeInsets.only(
EdgeInsets.only( top: showHeader ? 0 : padding.top,
bottom: MediaQuery.of(context).viewInsets.bottom, left: padding.left,
), right: padding.right,
bottom: padding.bottom + MediaQuery.of(context).viewInsets.bottom,
),
duration: Duration.zero, duration: Duration.zero,
child: child, child: child,
), ),

View File

@ -0,0 +1,100 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_new_field_option.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class MobileNewPropertyScreen extends StatefulWidget {
static const routeName = '/new_property';
static const argViewId = 'view_id';
static const argFieldTypeId = 'field_type_id';
const MobileNewPropertyScreen({
super.key,
required this.viewId,
this.fieldType,
});
final String viewId;
final FieldType? fieldType;
@override
State<MobileNewPropertyScreen> createState() =>
_MobileNewPropertyScreenState();
}
class _MobileNewPropertyScreenState extends State<MobileNewPropertyScreen> {
late FieldOptionValues optionValues;
@override
void initState() {
super.initState();
final type = widget.fieldType ?? FieldType.RichText;
optionValues = FieldOptionValues(
type: type,
name: type.i18n,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: FlowyText(
LocaleKeys.grid_field_newProperty.tr(),
fontSize: 16.0,
),
leading: AppBarCancelButton(
onTap: () => context.pop(),
),
leadingWidth: 120,
actions: [
_SaveButton(
onSave: () {
context.pop(optionValues);
},
),
],
),
body: FieldOption(
mode: FieldOptionMode.add,
defaultValues: optionValues,
onOptionValuesChanged: (optionValues) {
this.optionValues = optionValues;
},
),
);
}
}
class _SaveButton extends StatelessWidget {
const _SaveButton({
required this.onSave,
});
final VoidCallback onSave;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: onSave,
child: FlowyText(
LocaleKeys.button_save.tr(),
color: const Color(0xFF00ADDC),
fontSize: 16.0,
),
),
),
);
}
}

View File

@ -0,0 +1,114 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
const _supportedFieldTypes = [
FieldType.RichText,
FieldType.Number,
FieldType.URL,
FieldType.SingleSelect,
FieldType.MultiSelect,
FieldType.DateTime,
FieldType.Checkbox,
FieldType.Checklist,
];
class FieldOptions extends StatelessWidget {
const FieldOptions({
super.key,
required this.onAddField,
this.scrollController,
});
final void Function(FieldType) onAddField;
final ScrollController? scrollController;
@override
Widget build(BuildContext context) {
return Column(
children: [
const _FieldHeader(),
const VSpace(12.0),
Expanded(
child: GridView.count(
controller: scrollController,
crossAxisCount: 3,
childAspectRatio: 0.9,
mainAxisSpacing: 12.0,
children: _supportedFieldTypes
.map(
(e) => _Field(
type: e,
onTap: () => onAddField(e),
),
)
.toList(),
),
),
],
);
}
}
class _FieldHeader extends StatelessWidget {
const _FieldHeader();
@override
Widget build(BuildContext context) {
return SizedBox(
height: 56,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 120,
child: AppBarCancelButton(
onTap: () => context.pop(),
),
),
FlowyText.medium(
LocaleKeys.titleBar_addField.tr(),
fontSize: 16.0,
),
const HSpace(120),
],
),
);
}
}
class _Field extends StatelessWidget {
const _Field({
required this.type,
required this.onTap,
});
final FieldType type;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return GestureDetector(
onTap: onTap,
child: Column(
children: [
FlowySvg(
type.svgData,
blendMode: null,
size: Size.square(width / 4.0),
),
const VSpace(6.0),
FlowyText(type.i18n),
],
),
);
}
}

View File

@ -0,0 +1,867 @@
import 'dart:math';
import 'dart:typed_data';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/option_color_list.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/number_format_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_service.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:protobuf/protobuf.dart';
enum FieldOptionMode {
add,
edit,
}
class FieldOptionValues {
FieldOptionValues({
required this.type,
required this.name,
this.dateFormate,
this.includeTime = false,
this.timeFormat,
this.numberFormat,
this.selectOption = const [],
});
FieldType type;
String name;
// FieldType.Date
DateFormatPB? dateFormate;
bool includeTime;
TimeFormatPB? timeFormat;
// FieldType.Num
NumberFormatPB? numberFormat;
// FieldType.Select
// FieldType.MultiSelect
List<SelectOptionPB> selectOption;
Future<void> create({
required String viewId,
}) async {
Uint8List? typeOptionData;
switch (type) {
case FieldType.RichText:
break;
case FieldType.URL:
break;
case FieldType.Checkbox:
break;
case FieldType.Number:
typeOptionData = NumberTypeOptionPB(
format: numberFormat,
).writeToBuffer();
break;
case FieldType.DateTime:
typeOptionData = DateTypeOptionPB(
dateFormat: dateFormate,
timeFormat: timeFormat,
).writeToBuffer();
break;
case FieldType.SingleSelect:
typeOptionData = SingleSelectTypeOptionPB(
options: selectOption,
).writeToBuffer();
case FieldType.MultiSelect:
typeOptionData = MultiSelectTypeOptionPB(
options: selectOption,
).writeToBuffer();
break;
default:
throw UnimplementedError();
}
await TypeOptionBackendService.createFieldTypeOption(
viewId: viewId,
fieldType: type,
fieldName: name,
typeOptionData: typeOptionData,
);
}
}
class FieldOption extends StatefulWidget {
const FieldOption({
super.key,
required this.mode,
required this.defaultValues,
required this.onOptionValuesChanged,
});
final FieldOptionMode mode;
final FieldOptionValues defaultValues;
final void Function(FieldOptionValues values) onOptionValuesChanged;
@override
State<FieldOption> createState() => _FieldOptionState();
}
class _FieldOptionState extends State<FieldOption> {
final controller = TextEditingController();
late FieldOptionValues values;
@override
void initState() {
super.initState();
values = widget.defaultValues;
controller.text = values.type.i18n;
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.secondaryContainer,
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: Column(
children: [
const _Divider(),
_OptionTextField(
controller: controller,
type: values.type,
onTextChanged: (value) {
_updateOptionValues(name: value);
},
),
const _Divider(),
_PropertyType(
type: values.type,
onSelected: (type) => setState(
() {
controller.text = type.i18n;
_updateOptionValues(type: type, name: type.i18n);
},
),
),
const _Divider(),
..._buildOption(),
..._buildOptionActions(),
],
),
),
);
}
List<Widget> _buildOption() {
switch (values.type) {
case FieldType.RichText:
return [
const _TextOption(),
];
case FieldType.URL:
return [
const _URLOption(),
];
case FieldType.Checkbox:
return [
const _CheckboxOption(),
];
case FieldType.Number:
return [
_NumberOption(
selectedFormat: values.numberFormat ?? NumberFormatPB.Num,
onSelected: (format) => setState(
() => _updateOptionValues(
numberFormat: format,
),
),
),
];
case FieldType.DateTime:
return [
_DateOption(
selectedFormat: values.dateFormate ?? DateFormatPB.Local,
onSelected: (format) => _updateOptionValues(
dateFormate: format,
),
),
const _Divider(),
_TimeOption(
includeTime: values.includeTime,
selectedFormat: values.timeFormat ?? TimeFormatPB.TwelveHour,
onSelected: (includeTime, format) => _updateOptionValues(
includeTime: includeTime,
timeFormat: format,
),
),
];
case FieldType.SingleSelect:
case FieldType.MultiSelect:
return [
_SelectOption(
mode: widget.mode,
selectOption: values.selectOption,
onAddOptions: (options) {
if (values.selectOption.lastOrNull?.name.isEmpty == true) {
// ignore the add action if the last one doesn't have a name
return;
}
setState(() {
_updateOptionValues(
selectOption: values.selectOption + options,
);
});
},
onUpdateOptions: (options) {
_updateOptionValues(selectOption: options);
},
),
];
default:
return [];
}
}
List<Widget> _buildOptionActions() {
return switch (widget.mode) {
FieldOptionMode.add => [],
FieldOptionMode.edit => [
FlowyOptionTile.text(
text: LocaleKeys.button_delete.tr(),
leftIcon: const FlowySvg(FlowySvgs.delete_s),
),
FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.button_duplicate.tr(),
leftIcon: const FlowySvg(FlowySvgs.copy_s),
),
FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.grid_field_hide.tr(),
leftIcon: const FlowySvg(FlowySvgs.hide_s),
),
]
};
}
void _updateOptionValues({
FieldType? type,
String? name,
DateFormatPB? dateFormate,
bool? includeTime,
TimeFormatPB? timeFormat,
NumberFormatPB? numberFormat,
List<SelectOptionPB>? selectOption,
}) {
if (type != null) {
values.type = type;
}
if (name != null) {
values.name = name;
}
if (dateFormate != null) {
values.dateFormate = dateFormate;
}
if (includeTime != null) {
values.includeTime = includeTime;
}
if (timeFormat != null) {
values.timeFormat = timeFormat;
}
if (numberFormat != null) {
values.numberFormat = numberFormat;
}
if (selectOption != null) {
values.selectOption = selectOption;
}
widget.onOptionValuesChanged(values);
}
}
class _OptionTextField extends StatelessWidget {
const _OptionTextField({
required this.controller,
required this.type,
required this.onTextChanged,
});
final TextEditingController controller;
final FieldType type;
final void Function(String value) onTextChanged;
@override
Widget build(BuildContext context) {
return FlowyOptionTile.textField(
controller: controller,
textFieldPadding: const EdgeInsets.symmetric(horizontal: 12.0),
onTextChanged: onTextChanged,
leftIcon: Padding(
padding: const EdgeInsets.only(left: 16.0),
child: FlowySvg(
type.svgData,
size: const Size.square(36.0),
blendMode: null,
),
),
);
}
}
class _PropertyType extends StatelessWidget {
const _PropertyType({
required this.type,
required this.onSelected,
});
final FieldType type;
final void Function(FieldType type) onSelected;
@override
Widget build(BuildContext context) {
return FlowyOptionTile.text(
text: LocaleKeys.grid_field_propertyType.tr(),
trailing: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FlowySvg(
type.smallSvgData,
),
const HSpace(6.0),
FlowyText(
type.i18n,
color: Theme.of(context).hintColor,
fontSize: 16.0,
),
const HSpace(4.0),
FlowySvg(
FlowySvgs.arrow_right_s,
color: Theme.of(context).hintColor,
size: const Size.square(18.0),
),
],
),
onTap: () {
showMobileBottomSheet(
context,
padding: EdgeInsets.zero,
builder: (context) {
return DraggableScrollableSheet(
expand: false,
snap: true,
initialChildSize: 0.7,
minChildSize: 0.7,
builder: (context, controller) => FieldOptions(
scrollController: controller,
onAddField: (type) {
onSelected(type);
context.pop();
},
),
);
},
);
},
);
}
}
class _Divider extends StatelessWidget {
const _Divider();
@override
Widget build(BuildContext context) {
return const VSpace(
24.0,
);
}
}
class _TextOption extends StatelessWidget {
const _TextOption();
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _URLOption extends StatelessWidget {
const _URLOption();
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _CheckboxOption extends StatelessWidget {
const _CheckboxOption();
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _DateOption extends StatefulWidget {
const _DateOption({
required this.selectedFormat,
required this.onSelected,
});
final DateFormatPB selectedFormat;
final Function(DateFormatPB format) onSelected;
@override
State<_DateOption> createState() => _DateOptionState();
}
class _DateOptionState extends State<_DateOption> {
DateFormatPB selectedFormat = DateFormatPB.Local;
@override
void initState() {
super.initState();
selectedFormat = widget.selectedFormat;
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 6.0,
horizontal: 16.0,
),
child: FlowyText(
LocaleKeys.grid_field_dateFormat.tr(),
fontSize: 16.0,
color: Theme.of(context).hintColor,
),
),
...DateFormatPB.values.mapIndexed((index, format) {
return FlowyOptionTile.checkbox(
text: format.title(),
isSelected: selectedFormat == format,
showTopBorder: index == 0,
onTap: () {
widget.onSelected(format);
setState(() {
selectedFormat = format;
});
},
);
}),
],
);
}
}
class _TimeOption extends StatefulWidget {
const _TimeOption({
required this.includeTime,
required this.selectedFormat,
required this.onSelected,
});
final bool includeTime;
final TimeFormatPB selectedFormat;
final Function(bool includeTime, TimeFormatPB format) onSelected;
@override
State<_TimeOption> createState() => _TimeOptionState();
}
class _TimeOptionState extends State<_TimeOption> {
TimeFormatPB selectedFormat = TimeFormatPB.TwelveHour;
bool includeTime = false;
@override
void initState() {
super.initState();
selectedFormat = widget.selectedFormat;
includeTime = widget.includeTime;
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 6.0,
horizontal: 16.0,
),
child: FlowyText(
LocaleKeys.grid_field_timeFormat.tr(),
fontSize: 16.0,
color: Theme.of(context).hintColor,
),
),
FlowyOptionTile.switcher(
text: LocaleKeys.grid_field_includeTime.tr(),
isSelected: includeTime,
onValueChanged: (includeTime) {
widget.onSelected(includeTime, selectedFormat);
setState(() {
this.includeTime = includeTime;
});
},
),
if (includeTime)
...TimeFormatPB.values.mapIndexed((index, format) {
return FlowyOptionTile.checkbox(
text: format.title(),
isSelected: selectedFormat == format,
showTopBorder: false,
onTap: () {
widget.onSelected(includeTime, format);
setState(() {
selectedFormat = format;
});
},
);
}),
],
);
}
}
class _NumberOption extends StatelessWidget {
const _NumberOption({
required this.selectedFormat,
required this.onSelected,
});
final NumberFormatPB selectedFormat;
final void Function(NumberFormatPB format) onSelected;
@override
Widget build(BuildContext context) {
return FlowyOptionTile.text(
text: LocaleKeys.grid_field_numberFormat.tr(),
trailing: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FlowyText(
selectedFormat.title(),
color: Theme.of(context).hintColor,
fontSize: 16.0,
),
const HSpace(4.0),
FlowySvg(
FlowySvgs.arrow_right_s,
color: Theme.of(context).hintColor,
size: const Size.square(18.0),
),
],
),
onTap: () {
showMobileBottomSheet(
context,
padding: EdgeInsets.zero,
builder: (context) {
return DraggableScrollableSheet(
expand: false,
snap: true,
initialChildSize: 0.6,
minChildSize: 0.6,
builder: (context, scrollController) => _NumberFormatList(
scrollController: scrollController,
selectedFormat: selectedFormat,
onSelected: (type) {
onSelected(type);
context.pop();
},
),
);
},
);
},
);
}
}
class _NumberFormatList extends StatelessWidget {
const _NumberFormatList({
this.scrollController,
required this.selectedFormat,
required this.onSelected,
});
final NumberFormatPB selectedFormat;
final ScrollController? scrollController;
final void Function(NumberFormatPB format) onSelected;
@override
Widget build(BuildContext context) {
return ListView(
controller: scrollController,
children: NumberFormatPB.values
.mapIndexed(
(index, element) => FlowyOptionTile.checkbox(
text: element.title(),
isSelected: selectedFormat == element,
showTopBorder: index == 0,
onTap: () => onSelected(element),
),
)
.toList(),
);
}
}
// single select or multi select
class _SelectOption extends StatelessWidget {
_SelectOption({
required this.mode,
required this.selectOption,
required this.onAddOptions,
required this.onUpdateOptions,
});
final List<SelectOptionPB> selectOption;
final void Function(List<SelectOptionPB> options) onAddOptions;
final void Function(List<SelectOptionPB> options) onUpdateOptions;
final FieldOptionMode mode;
final random = Random();
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 6.0,
horizontal: 16.0,
),
child: FlowyText(
LocaleKeys.grid_field_optionTitle.tr(),
fontSize: 16.0,
color: Theme.of(context).hintColor,
),
),
_SelectOptionList(
selectOptions: selectOption,
onUpdateOptions: onUpdateOptions,
),
FlowyOptionTile.text(
text: LocaleKeys.grid_field_addOption.tr(),
leftIcon: const FlowySvg(FlowySvgs.add_s),
onTap: () {
onAddOptions([
SelectOptionPB(
id: uuid(),
name: '',
color: SelectOptionColorPB.valueOf(
random.nextInt(SelectOptionColorPB.values.length),
),
),
]);
},
),
],
);
}
}
class _SelectOptionList extends StatefulWidget {
const _SelectOptionList({
required this.selectOptions,
required this.onUpdateOptions,
});
final List<SelectOptionPB> selectOptions;
final void Function(List<SelectOptionPB> options) onUpdateOptions;
@override
State<_SelectOptionList> createState() => _SelectOptionListState();
}
class _SelectOptionListState extends State<_SelectOptionList> {
late List<SelectOptionPB> options;
@override
void initState() {
super.initState();
options = widget.selectOptions;
}
@override
void didUpdateWidget(covariant _SelectOptionList oldWidget) {
super.didUpdateWidget(oldWidget);
options = widget.selectOptions;
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
if (widget.selectOptions.isEmpty) {
return const SizedBox.shrink();
}
return ListView(
shrinkWrap: true,
padding: EdgeInsets.zero,
children: widget.selectOptions
.mapIndexed(
(index, option) => _SelectOptionTile(
option: option,
showTopBorder: index == 0,
showBottomBorder: index != widget.selectOptions.length - 1,
onUpdateOption: (option) {
_updateOption(index, option);
},
),
)
.toList(),
);
}
void _updateOption(int index, SelectOptionPB option) {
final options = [...this.options];
options[index] = option;
this.options = options;
widget.onUpdateOptions(options);
}
}
class _SelectOptionTile extends StatefulWidget {
const _SelectOptionTile({
required this.option,
required this.showTopBorder,
required this.showBottomBorder,
required this.onUpdateOption,
});
final SelectOptionPB option;
final bool showTopBorder;
final bool showBottomBorder;
final void Function(SelectOptionPB option) onUpdateOption;
@override
State<_SelectOptionTile> createState() => __SelectOptionTileState();
}
class __SelectOptionTileState extends State<_SelectOptionTile> {
final TextEditingController controller = TextEditingController();
late SelectOptionPB option;
@override
void initState() {
super.initState();
controller.text = widget.option.name;
option = widget.option;
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FlowyOptionTile.textField(
controller: controller,
textFieldHintText: LocaleKeys.grid_field_typeANewOption.tr(),
showTopBorder: widget.showTopBorder,
showBottomBorder: widget.showBottomBorder,
textFieldPadding: const EdgeInsets.symmetric(horizontal: 16.0),
trailing: _SelectOptionColor(
color: option.color,
onChanged: (color) {
setState(() {
option.freeze();
option = option.rebuild((p0) => p0.color = color);
widget.onUpdateOption(option);
});
context.pop();
},
),
onTextChanged: (name) {
setState(() {
option.freeze();
option = option.rebuild((p0) => p0.name = name);
widget.onUpdateOption(option);
});
},
);
}
}
class _SelectOptionColor extends StatelessWidget {
const _SelectOptionColor({
required this.color,
required this.onChanged,
});
final SelectOptionColorPB color;
final void Function(SelectOptionColorPB) onChanged;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
showMobileBottomSheet(
context,
showHeader: true,
showCloseButton: true,
title: LocaleKeys.grid_selectOption_colorPanelTitle.tr(),
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
builder: (context) {
return OptionColorList(
selectedColor: color,
onSelectedColor: onChanged,
);
},
);
},
child: Container(
decoration: BoxDecoration(
color: color.toColor(context),
borderRadius: Corners.s10Border,
),
width: 32,
height: 32,
alignment: Alignment.center,
child: const FlowySvg(
FlowySvgs.arrow_down_s,
size: Size.square(20),
),
),
);
}
}

View File

@ -207,17 +207,15 @@ class _EndDateSwitch extends StatelessWidget {
return BlocSelector<DateCellCalendarBloc, DateCellCalendarState, bool>( return BlocSelector<DateCellCalendarBloc, DateCellCalendarState, bool>(
selector: (state) => state.isRange, selector: (state) => state.isRange,
builder: (context, isRange) { builder: (context, isRange) {
return FlowyOptionTile( return FlowyOptionTile.switcher(
text: LocaleKeys.grid_field_isRange.tr(), text: LocaleKeys.grid_field_isRange.tr(),
leftIcon: const FlowySvg(FlowySvgs.date_s), leftIcon: const FlowySvg(FlowySvgs.date_s),
leading: _Switcher( isSelected: isRange,
value: isRange, onValueChanged: (value) {
onChanged: (value) { context
context .read<DateCellCalendarBloc>()
.read<DateCellCalendarBloc>() .add(DateCellCalendarEvent.setIsRange(value));
.add(DateCellCalendarEvent.setIsRange(value)); },
},
),
); );
}, },
); );
@ -232,18 +230,16 @@ class _IncludeTimeSwitch extends StatelessWidget {
return BlocSelector<DateCellCalendarBloc, DateCellCalendarState, bool>( return BlocSelector<DateCellCalendarBloc, DateCellCalendarState, bool>(
selector: (state) => state.includeTime, selector: (state) => state.includeTime,
builder: (context, includeTime) { builder: (context, includeTime) {
return FlowyOptionTile( return FlowyOptionTile.switcher(
showTopBorder: false, showTopBorder: false,
text: LocaleKeys.grid_field_includeTime.tr(), text: LocaleKeys.grid_field_includeTime.tr(),
leftIcon: const FlowySvg(FlowySvgs.clock_alarm_s), leftIcon: const FlowySvg(FlowySvgs.clock_alarm_s),
leading: _Switcher( isSelected: includeTime,
value: includeTime, onValueChanged: (value) {
onChanged: (value) { context
context .read<DateCellCalendarBloc>()
.read<DateCellCalendarBloc>() .add(DateCellCalendarEvent.setIncludeTime(value));
.add(DateCellCalendarEvent.setIncludeTime(value)); },
},
),
); );
}, },
); );
@ -379,7 +375,7 @@ class _ClearDateButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FlowyOptionTile( return FlowyOptionTile.text(
showTopBorder: false, showTopBorder: false,
text: LocaleKeys.grid_field_clearDate.tr(), text: LocaleKeys.grid_field_clearDate.tr(),
onTap: () => context onTap: () => context
@ -398,7 +394,7 @@ class _TimeFormatOption extends StatelessWidget {
TimeFormatPB>( TimeFormatPB>(
selector: (state) => state.dateTypeOptionPB.timeFormat, selector: (state) => state.dateTypeOptionPB.timeFormat,
builder: (context, state) { builder: (context, state) {
return FlowyOptionTile( return FlowyOptionTile.text(
showTopBorder: false, showTopBorder: false,
text: LocaleKeys.settings_appearance_timeFormat_label.tr(), text: LocaleKeys.settings_appearance_timeFormat_label.tr(),
leftIcon: const FlowySvg(FlowySvgs.time_s), leftIcon: const FlowySvg(FlowySvgs.time_s),
@ -431,7 +427,7 @@ class _DateFormatOption extends StatelessWidget {
DateFormatPB>( DateFormatPB>(
selector: (state) => state.dateTypeOptionPB.dateFormat, selector: (state) => state.dateTypeOptionPB.dateFormat,
builder: (context, state) { builder: (context, state) {
return FlowyOptionTile( return FlowyOptionTile.text(
text: LocaleKeys.settings_appearance_dateFormat_label.tr(), text: LocaleKeys.settings_appearance_dateFormat_label.tr(),
leftIcon: const FlowySvg(FlowySvgs.clock_alarm_s), leftIcon: const FlowySvg(FlowySvgs.clock_alarm_s),
); );
@ -453,28 +449,3 @@ class _DateFormatOption extends StatelessWidget {
); );
} }
} }
class _Switcher extends StatelessWidget {
const _Switcher({
required this.value,
required this.onChanged,
});
final bool value;
final void Function(bool value) onChanged;
@override
Widget build(BuildContext context) {
return SizedBox(
width: 48,
child: FittedBox(
fit: BoxFit.fill,
child: Switch.adaptive(
value: value,
activeColor: const Color(0xFF00BCF0),
onChanged: onChanged,
),
),
);
}
}

View File

@ -16,6 +16,7 @@ class FlowyOptionDecorateBox extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DecoratedBox( return DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
border: Border( border: Border(
top: showTopBorder top: showTopBorder
? BorderSide( ? BorderSide(

View File

@ -1,52 +1,271 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart'; import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
enum FlowyOptionTileType {
text,
textField,
checkbox,
}
// used in cell editor // used in cell editor
class FlowyOptionTile extends StatelessWidget { class FlowyOptionTile extends StatelessWidget {
const FlowyOptionTile({ const FlowyOptionTile._({
super.key, required this.type,
this.showTopBorder = true, this.showTopBorder = true,
this.showBottomBorder = true, this.showBottomBorder = true,
required this.text, this.text,
this.leftIcon, this.controller,
this.onTap,
this.leading, this.leading,
this.onTap,
this.trailing,
this.textFieldPadding = const EdgeInsets.symmetric(
horizontal: 16.0,
),
this.isSelected = false,
this.textFieldHintText,
this.onTextChanged,
this.onTextSubmitted,
}); });
factory FlowyOptionTile.text({
required String text,
bool showTopBorder = true,
bool showBottomBorder = true,
Widget? leftIcon,
Widget? trailing,
VoidCallback? onTap,
}) {
return FlowyOptionTile._(
type: FlowyOptionTileType.text,
text: text,
controller: null,
onTap: onTap,
showTopBorder: showTopBorder,
showBottomBorder: showBottomBorder,
leading: leftIcon,
trailing: trailing,
);
}
factory FlowyOptionTile.textField({
required TextEditingController controller,
void Function(String value)? onTextChanged,
void Function(String value)? onTextSubmitted,
EdgeInsets textFieldPadding = const EdgeInsets.symmetric(
horizontal: 16.0,
),
bool showTopBorder = true,
bool showBottomBorder = true,
Widget? leftIcon,
Widget? trailing,
String? textFieldHintText,
}) {
return FlowyOptionTile._(
type: FlowyOptionTileType.text,
controller: controller,
textFieldPadding: textFieldPadding,
text: null,
onTap: null,
showTopBorder: showTopBorder,
showBottomBorder: showBottomBorder,
leading: leftIcon,
trailing: trailing,
textFieldHintText: textFieldHintText,
onTextChanged: onTextChanged,
onTextSubmitted: onTextSubmitted,
);
}
factory FlowyOptionTile.checkbox({
required String text,
required bool isSelected,
required VoidCallback? onTap,
bool showTopBorder = true,
bool showBottomBorder = true,
}) {
return FlowyOptionTile._(
type: FlowyOptionTileType.checkbox,
isSelected: isSelected,
text: text,
onTap: onTap,
showTopBorder: showTopBorder,
showBottomBorder: showBottomBorder,
trailing: isSelected
? const FlowySvg(
FlowySvgs.blue_check_s,
size: Size.square(24.0),
blendMode: null,
)
: null,
);
}
factory FlowyOptionTile.switcher({
required String text,
required bool isSelected,
required void Function(bool value) onValueChanged,
bool showTopBorder = true,
bool showBottomBorder = true,
Widget? leftIcon,
}) {
return FlowyOptionTile._(
type: FlowyOptionTileType.text,
text: text,
controller: null,
onTap: null,
showTopBorder: showTopBorder,
showBottomBorder: showBottomBorder,
leading: leftIcon,
trailing: _Switcher(value: isSelected, onChanged: onValueChanged),
);
}
final bool showTopBorder; final bool showTopBorder;
final bool showBottomBorder; final bool showBottomBorder;
final String text; final String? text;
final TextEditingController? controller;
final EdgeInsets textFieldPadding;
final void Function()? onTap; final void Function()? onTap;
final Widget? leftIcon;
final Widget? leading; final Widget? leading;
final Widget? trailing;
// only used in checkbox or switcher
final bool isSelected;
// only used in textfield
final String? textFieldHintText;
final void Function(String value)? onTextChanged;
final void Function(String value)? onTextSubmitted;
final FlowyOptionTileType type;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FlowyOptionDecorateBox( final child = ColoredBox(
showTopBorder: showTopBorder, color: Theme.of(context).colorScheme.surface,
showBottomBorder: showBottomBorder, child: FlowyOptionDecorateBox(
child: Row( showTopBorder: showTopBorder,
children: [ showBottomBorder: showBottomBorder,
FlowyButton( child: Row(
useIntrinsicWidth: true, children: [
text: FlowyText( _buildText(),
text, ..._buildTextField(),
fontSize: 16.0, const Spacer(),
), trailing ?? const SizedBox.shrink(),
margin: const EdgeInsets.symmetric( const HSpace(12.0),
horizontal: 12.0, ],
vertical: 16.0, ),
), ),
leftIcon: leftIcon, );
leftIconSize: const Size.square(24.0),
iconPadding: 8.0, if (type == FlowyOptionTileType.checkbox ||
onTap: onTap, type == FlowyOptionTileType.text) {
return FlowyButton(
expandText: true,
margin: EdgeInsets.zero,
onTap: onTap,
text: child,
);
}
return child;
}
Widget _buildText() {
if (text == null) {
return const SizedBox.shrink();
}
switch (type) {
case FlowyOptionTileType.text:
return FlowyButton(
useIntrinsicWidth: true,
text: FlowyText(
text!,
fontSize: 16.0,
), ),
const Spacer(), margin: const EdgeInsets.symmetric(
leading ?? const SizedBox.shrink(), horizontal: 16.0,
const HSpace(12.0), vertical: 16.0,
], ),
leftIcon: leading,
leftIconSize: const Size.square(24.0),
iconPadding: 8.0,
onTap: onTap,
);
case FlowyOptionTileType.textField:
return const SizedBox.shrink();
case FlowyOptionTileType.checkbox:
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 16.0,
),
child: FlowyText(
text!,
fontSize: 16.0,
),
);
}
}
List<Widget> _buildTextField() {
if (controller == null) {
return [
const SizedBox.shrink(),
];
}
return [
if (leading != null) leading!,
Expanded(
child: ConstrainedBox(
constraints: const BoxConstraints.tightFor(
height: 52.0,
width: double.infinity,
),
child: TextField(
controller: controller,
textInputAction: TextInputAction.done,
decoration: InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
contentPadding: textFieldPadding,
hintText: textFieldHintText,
),
onChanged: onTextChanged,
onSubmitted: onTextSubmitted,
),
),
),
];
}
}
class _Switcher extends StatelessWidget {
const _Switcher({
required this.value,
required this.onChanged,
});
final bool value;
final void Function(bool value) onChanged;
@override
Widget build(BuildContext context) {
return SizedBox(
width: 48,
child: FittedBox(
fit: BoxFit.fill,
child: Switch.adaptive(
value: value,
activeColor: const Color(0xFF00BCF0),
onChanged: onChanged,
),
), ),
); );
} }

View File

@ -1,7 +1,9 @@
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'dart:typed_data';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:dartz/dartz.dart';
class TypeOptionBackendService { class TypeOptionBackendService {
final String viewId; final String viewId;
@ -26,12 +28,22 @@ class TypeOptionBackendService {
static Future<Either<TypeOptionPB, FlowyError>> createFieldTypeOption({ static Future<Either<TypeOptionPB, FlowyError>> createFieldTypeOption({
required String viewId, required String viewId,
FieldType fieldType = FieldType.RichText, FieldType fieldType = FieldType.RichText,
String? fieldName,
Uint8List? typeOptionData,
CreateFieldPosition position = CreateFieldPosition.End, CreateFieldPosition position = CreateFieldPosition.End,
String? targetFieldId, String? targetFieldId,
}) { }) {
final payload = CreateFieldPayloadPB.create() final payload = CreateFieldPayloadPB.create()
..viewId = viewId ..viewId = viewId
..fieldType = FieldType.RichText; ..fieldType = fieldType;
if (fieldName != null) {
payload.fieldName = fieldName;
}
if (typeOptionData != null) {
payload.typeOptionData = typeOptionData;
}
if (position == CreateFieldPosition.Before || if (position == CreateFieldPosition.Before ||
position == CreateFieldPosition.After && targetFieldId != null) { position == CreateFieldPosition.After && targetFieldId != null) {

View File

@ -1,5 +1,9 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_field_screen.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_new_field_option.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/grid/application/grid_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/grid_bloc.dart';
import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart';
@ -8,11 +12,12 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log; import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:reorderables/reorderables.dart'; import 'package:reorderables/reorderables.dart';
import '../../../../application/field/type_option/type_option_service.dart'; import '../../../../application/field/type_option/type_option_service.dart';
import '../../layout/sizes.dart'; import '../../layout/sizes.dart';
import 'field_cell.dart'; import 'field_cell.dart';
@ -230,13 +235,17 @@ class _CreateFieldButtonState extends State<CreateFieldButton> {
), ),
hoverColor: AFThemeExtension.of(context).greyHover, hoverColor: AFThemeExtension.of(context).greyHover,
onTap: () async { onTap: () async {
final result = await TypeOptionBackendService.createFieldTypeOption( if (PlatformExtension.isMobile) {
viewId: widget.viewId, _showCreateFieldBottomSheet(context);
); } else {
result.fold( final result = await TypeOptionBackendService.createFieldTypeOption(
(typeOptionPB) => widget.onFieldCreated(typeOptionPB.field_2.id), viewId: widget.viewId,
(err) => Log.error("Failed to create field type option: $err"), );
); result.fold(
(typeOptionPB) => widget.onFieldCreated(typeOptionPB.field_2.id),
(err) => Log.error("Failed to create field type option: $err"),
);
}
}, },
leftIcon: FlowySvg( leftIcon: FlowySvg(
FlowySvgs.add_s, FlowySvgs.add_s,
@ -244,4 +253,40 @@ class _CreateFieldButtonState extends State<CreateFieldButton> {
), ),
); );
} }
void _showCreateFieldBottomSheet(BuildContext context) {
showMobileBottomSheet(
context,
padding: EdgeInsets.zero,
builder: (context) {
return DraggableScrollableSheet(
expand: false,
snap: true,
initialChildSize: 0.7,
minChildSize: 0.7,
builder: (context, controller) => FieldOptions(
scrollController: controller,
onAddField: (type) async {
final optionValues = await context.push<FieldOptionValues>(
Uri(
path: MobileNewPropertyScreen.routeName,
queryParameters: {
MobileNewPropertyScreen.argViewId: widget.viewId,
MobileNewPropertyScreen.argFieldTypeId:
type.value.toString(),
},
).toString(),
);
if (optionValues != null) {
await optionValues.create(viewId: widget.viewId);
if (context.mounted) {
context.pop();
}
}
},
),
);
},
);
}
} }

View File

@ -60,6 +60,7 @@ class _MobileTabBarHeaderState extends State<MobileTabBarHeader> {
maxLines: null, maxLines: null,
controller: controller, controller: controller,
textAlignVertical: TextAlignVertical.top, textAlignVertical: TextAlignVertical.top,
textInputAction: TextInputAction.done,
decoration: const InputDecoration( decoration: const InputDecoration(
border: InputBorder.none, border: InputBorder.none,
enabledBorder: InputBorder.none, enabledBorder: InputBorder.none,

View File

@ -1,5 +1,6 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/option_color_list.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart'; import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/base/drag_handler.dart'; import 'package:appflowy/plugins/base/drag_handler.dart';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart'; import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
@ -92,7 +93,6 @@ class _MobileSelectOptionEditorState extends State<MobileSelectOptionEditor> {
const iconWidth = 36.0; const iconWidth = 36.0;
const height = 44.0; const height = 44.0;
return Stack( return Stack(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
@ -510,17 +510,11 @@ class _MoreOptions extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
VSpace(8.0, color: color), const VSpace(8.0),
_buildRenameTextField(context), _buildRenameTextField(context),
VSpace( const VSpace(16.0),
16.0,
color: color,
),
_buildDeleteButton(context), _buildDeleteButton(context),
VSpace( const VSpace(16.0),
16.0,
color: color,
),
Padding( Padding(
padding: const EdgeInsets.only(left: 12.0), padding: const EdgeInsets.only(left: 12.0),
child: ColoredBox( child: ColoredBox(
@ -531,11 +525,22 @@ class _MoreOptions extends StatelessWidget {
), ),
), ),
), ),
VSpace( const VSpace(4.0),
4.0, FlowyOptionDecorateBox(
color: color, showTopBorder: true,
showBottomBorder: true,
child: Padding(
padding: const EdgeInsets.only(
top: 12.0,
left: 6.0,
right: 6.0,
),
child: OptionColorList(
selectedColor: option.color,
onSelectedColor: (color) => onUpdate(null, color),
),
),
), ),
_buildColorOptions(context),
], ],
), ),
); );
@ -544,66 +549,17 @@ class _MoreOptions extends StatelessWidget {
Widget _buildRenameTextField(BuildContext context) { Widget _buildRenameTextField(BuildContext context) {
return ConstrainedBox( return ConstrainedBox(
constraints: const BoxConstraints.tightFor(height: 52.0), constraints: const BoxConstraints.tightFor(height: 52.0),
child: FlowyOptionDecorateBox( child: FlowyOptionTile.textField(
showTopBorder: true, controller: controller,
showBottomBorder: true,
child: TextField(
controller: controller,
decoration: const InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
contentPadding: EdgeInsets.only(left: 16.0),
),
onChanged: (value) {},
onSubmitted: (value) => onUpdate(value, null),
),
), ),
); );
} }
Widget _buildDeleteButton(BuildContext context) { Widget _buildDeleteButton(BuildContext context) {
return FlowyOptionTile( return FlowyOptionTile.text(
text: LocaleKeys.button_delete.tr(), text: LocaleKeys.button_delete.tr(),
leftIcon: const FlowySvg(FlowySvgs.delete_s), leftIcon: const FlowySvg(FlowySvgs.delete_s),
onTap: onDelete, onTap: onDelete,
); );
} }
Widget _buildColorOptions(BuildContext context) {
return FlowyOptionDecorateBox(
showTopBorder: true,
showBottomBorder: true,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: GridView.count(
crossAxisCount: 6,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: SelectOptionColorPB.values.map(
(colorPB) {
final color = colorPB.toColor(context);
return GestureDetector(
onTap: () => onUpdate(null, colorPB),
child: Container(
margin: const EdgeInsets.all(
10.0,
),
decoration: BoxDecoration(
color: color,
borderRadius: Corners.s12Border,
border: Border.all(
color: option.color.value == colorPB.value
? const Color(0xff00C6F1)
: Theme.of(context).dividerColor,
),
),
),
);
},
).toList(),
),
),
);
}
} }

View File

@ -1,5 +1,6 @@
import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.dart'; import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.dart';
import 'package:appflowy/mobile/presentation/database/card/card.dart'; import 'package:appflowy/mobile/presentation/database/card/card.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_field_screen.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_row_field_screen.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_row_field_screen.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/card_property_edit_screen.dart'; import 'package:appflowy/mobile/presentation/database/card/card_property_edit/card_property_edit_screen.dart';
import 'package:appflowy/mobile/presentation/database/date_picker/mobile_date_picker_screen.dart'; import 'package:appflowy/mobile/presentation/database/date_picker/mobile_date_picker_screen.dart';
@ -23,6 +24,7 @@ import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/presentation/presentation.dart'; import 'package:appflowy/user/presentation/presentation.dart';
import 'package:appflowy/util/platform_extension.dart'; import 'package:appflowy/util/platform_extension.dart';
import 'package:appflowy/workspace/presentation/home/desktop_home_screen.dart'; import 'package:appflowy/workspace/presentation/home/desktop_home_screen.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:flowy_infra/time/duration.dart'; import 'package:flowy_infra/time/duration.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -61,6 +63,7 @@ GoRouter generateRouter(Widget child) {
_mobileCardPropertyEditScreenRoute(), _mobileCardPropertyEditScreenRoute(),
_mobileDateCellEditScreenRoute(), _mobileDateCellEditScreenRoute(),
_mobileCreateRowFieldScreenRoute(), _mobileCreateRowFieldScreenRoute(),
_mobileNewPropertyPageRoute(),
// home // home
// MobileHomeSettingPage is outside the bottom navigation bar, thus it is not in the StatefulShellRoute. // MobileHomeSettingPage is outside the bottom navigation bar, thus it is not in the StatefulShellRoute.
@ -348,6 +351,28 @@ GoRoute _mobileFontPickerPageRoute() {
); );
} }
GoRoute _mobileNewPropertyPageRoute() {
return GoRoute(
parentNavigatorKey: AppGlobals.rootNavKey,
path: MobileNewPropertyScreen.routeName,
pageBuilder: (context, state) {
final viewId = state
.uri.queryParameters[MobileNewPropertyScreen.argViewId] as String;
final fieldTypeId =
state.uri.queryParameters[MobileNewPropertyScreen.argFieldTypeId] ??
FieldType.RichText.value.toString();
final value = int.parse(fieldTypeId);
return MaterialPage(
fullscreenDialog: true,
child: MobileNewPropertyScreen(
viewId: viewId,
fieldType: FieldType.valueOf(value),
),
);
},
);
}
GoRoute _mobileCalendarEventsPageRoute() { GoRoute _mobileCalendarEventsPageRoute() {
return GoRoute( return GoRoute(
path: MobileCalendarEventsScreen.routeName, path: MobileCalendarEventsScreen.routeName,

View File

@ -0,0 +1,46 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
extension FieldTypeExtension on FieldType {
String get i18n => switch (this) {
FieldType.RichText => LocaleKeys.grid_field_textFieldName.tr(),
FieldType.Number => LocaleKeys.grid_field_numberFieldName.tr(),
FieldType.DateTime => LocaleKeys.grid_field_dateFieldName.tr(),
FieldType.SingleSelect =>
LocaleKeys.grid_field_singleSelectFieldName.tr(),
FieldType.MultiSelect =>
LocaleKeys.grid_field_multiSelectFieldName.tr(),
FieldType.Checkbox => LocaleKeys.grid_field_checkboxFieldName.tr(),
FieldType.Checklist => LocaleKeys.grid_field_checklistFieldName.tr(),
FieldType.URL => LocaleKeys.grid_field_urlFieldName.tr(),
FieldType.LastEditedTime =>
LocaleKeys.grid_field_updatedAtFieldName.tr(),
FieldType.CreatedTime => LocaleKeys.grid_field_createdAtFieldName.tr(),
_ => throw UnimplementedError(),
};
FlowySvgData get svgData => switch (this) {
FieldType.RichText => FlowySvgs.field_option_text_xl,
FieldType.Number => FlowySvgs.field_option_number_xl,
FieldType.DateTime => FlowySvgs.field_option_date_xl,
FieldType.SingleSelect => FlowySvgs.field_option_select_xl,
FieldType.MultiSelect => FlowySvgs.field_option_multiselect_xl,
FieldType.Checkbox => FlowySvgs.field_option_checkbox_xl,
FieldType.Checklist => FlowySvgs.field_option_checklist_xl,
FieldType.URL => FlowySvgs.field_option_url_xl,
_ => throw UnimplementedError(),
};
FlowySvgData get smallSvgData => switch (this) {
FieldType.RichText => FlowySvgs.field_option_text_s,
FieldType.Number => FlowySvgs.field_option_number_s,
FieldType.DateTime => FlowySvgs.field_option_date_s,
FieldType.SingleSelect => FlowySvgs.field_option_select_s,
FieldType.MultiSelect => FlowySvgs.field_option_select_s,
FieldType.Checkbox => FlowySvgs.field_option_checkbox_s,
FieldType.URL => FlowySvgs.field_option_url_s,
_ => throw UnimplementedError(),
};
}

View File

@ -30,6 +30,7 @@ class FlowyTextField extends StatefulWidget {
final TextStyle? hintStyle; final TextStyle? hintStyle;
final InputDecoration? decoration; final InputDecoration? decoration;
final TextAlignVertical? textAlignVertical; final TextAlignVertical? textAlignVertical;
final TextInputAction? textInputAction;
const FlowyTextField({ const FlowyTextField({
super.key, super.key,
@ -58,6 +59,7 @@ class FlowyTextField extends StatefulWidget {
this.hintStyle, this.hintStyle,
this.decoration, this.decoration,
this.textAlignVertical, this.textAlignVertical,
this.textInputAction,
}); });
@override @override
@ -127,6 +129,7 @@ class FlowyTextFieldState extends State<FlowyTextField> {
_onChanged(text); _onChanged(text);
} }
}, },
textInputAction: widget.textInputAction,
onSubmitted: (text) => _onSubmitted(text), onSubmitted: (text) => _onSubmitted(text),
onEditingComplete: widget.onEditingComplete, onEditingComplete: widget.onEditingComplete,
minLines: 1, minLines: 1,

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 11.8L6.76923 14.5L16 5.5" stroke="#00BCF0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 226 B

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.14301 4.54341C4.29304 4.39338 4.49653 4.30909 4.7087 4.30909H12.7087C13.0702 4.30909 13.3632 4.01604 13.3632 3.65455C13.3632 3.29305 13.0702 3 12.7087 3H4.7087C4.14933 3 3.61288 3.22221 3.21735 3.61774C2.82182 4.01327 2.59961 4.54973 2.59961 5.10909V15.2909C2.59961 15.8503 2.82182 16.3867 3.21735 16.7823C3.61288 17.1778 4.14934 17.4 4.7087 17.4H14.8905C15.4499 17.4 15.9863 17.1778 16.3819 16.7823C16.7774 16.3867 16.9996 15.8503 16.9996 15.2909V10.8545C16.9996 10.493 16.7066 10.2 16.3451 10.2C15.9836 10.2 15.6905 10.493 15.6905 10.8545V15.2909C15.6905 15.5031 15.6062 15.7066 15.4562 15.8566C15.3062 16.0066 15.1027 16.0909 14.8905 16.0909H4.7087C4.49653 16.0909 4.29304 16.0066 4.14301 15.8566C3.99299 15.7066 3.9087 15.5031 3.9087 15.2909V5.10909C3.9087 4.89692 3.99299 4.69343 4.14301 4.54341Z" fill="#1F2329" fill-opacity="0.4"/>
<path d="M17.445 6.09783C17.7099 5.85185 17.7252 5.4377 17.4793 5.1728C17.2333 4.90789 16.8191 4.89256 16.5542 5.13854L9.95066 11.2704L8.28136 9.72035C8.01646 9.47437 7.60231 9.48971 7.35633 9.75461C7.11035 10.0195 7.12569 10.4337 7.39059 10.6796L9.50527 12.6433C9.75641 12.8765 10.1449 12.8765 10.396 12.6433L17.445 6.09783Z" fill="#1F2329" fill-opacity="0.4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.1747 3.625C13.1747 3.27982 12.8949 3 12.5497 3C12.2045 3 11.9247 3.27982 11.9247 3.625V4.27551H8.0766V3.625C8.0766 3.27982 7.79678 3 7.4516 3C7.10642 3 6.8266 3.27982 6.8266 3.625V4.27551H5.04347C3.97959 4.27551 3.00203 5.06576 3.00203 6.17531V8.72508V15.0989C3.00203 16.2084 3.97959 16.9987 5.04347 16.9987H14.9586C16.0224 16.9987 17 16.2084 17 15.0989V8.72508V6.17531C17 5.06576 16.0224 4.27551 14.9586 4.27551H13.1747V3.625ZM15.75 9.35008V15.0989C15.75 15.3974 15.4592 15.7487 14.9586 15.7487H5.04347C4.5428 15.7487 4.25203 15.3974 4.25203 15.0989V9.35008H15.75ZM4.25203 8.10008H15.75V6.17531C15.75 5.87674 15.4592 5.52551 14.9586 5.52551H13.1747V6.27889C13.1747 6.62407 12.8949 6.90389 12.5497 6.90389C12.2045 6.90389 11.9247 6.62407 11.9247 6.27889V5.52551H8.0766V6.27889C8.0766 6.62407 7.79678 6.90389 7.4516 6.90389C7.10642 6.90389 6.8266 6.62407 6.8266 6.27889V5.52551H5.04347C4.5428 5.52551 4.25203 5.87674 4.25203 6.17531V8.10008Z" fill="#1F2329" fill-opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,3 @@
<svg width="19" height="12" viewBox="0 0 19 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.75125 4.25H3.75125V11.25H2.60125V5.48L1.19125 5.88L0.91125 4.9L2.75125 4.25ZM4.88945 11.25V10.125L7.93945 7.0125C8.68112 6.27083 9.05195 5.62917 9.05195 5.0875C9.05195 4.6625 8.92279 4.33333 8.66445 4.1C8.41445 3.85833 8.09362 3.7375 7.70195 3.7375C6.96862 3.7375 6.42695 4.1 6.07695 4.825L4.86445 4.1125C5.13945 3.52917 5.52695 3.0875 6.02695 2.7875C6.52695 2.4875 7.08112 2.3375 7.68945 2.3375C8.45612 2.3375 9.11445 2.57917 9.66445 3.0625C10.2145 3.54583 10.4895 4.20417 10.4895 5.0375C10.4895 5.92917 9.99362 6.87917 9.00195 7.8875L7.02695 9.8625H10.652V11.25H4.88945ZM16.1282 5.04C16.8882 5.22 17.5032 5.575 17.9732 6.105C18.4532 6.625 18.6932 7.28 18.6932 8.07C18.6932 9.12 18.3382 9.945 17.6282 10.545C16.9182 11.145 16.0482 11.445 15.0182 11.445C14.2182 11.445 13.4982 11.26 12.8582 10.89C12.2282 10.52 11.7732 9.98 11.4932 9.27L12.9632 8.415C13.2732 9.315 13.9582 9.765 15.0182 9.765C15.6182 9.765 16.0932 9.615 16.4432 9.315C16.7932 9.005 16.9682 8.59 16.9682 8.07C16.9682 7.55 16.7932 7.14 16.4432 6.84C16.0932 6.54 15.6182 6.39 15.0182 6.39H14.6282L13.9382 5.355L16.2032 2.37H11.8082V0.749999H18.2582V2.22L16.1282 5.04Z" fill="#1F2329" fill-opacity="0.4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.70223 11.1046L7.9162 9.31855C7.65162 9.05396 7.83901 8.60156 8.21319 8.60156H11.7852C12.1594 8.60156 12.3468 9.05396 12.0822 9.31855L10.2962 11.1046C10.1322 11.2686 9.86625 11.2686 9.70223 11.1046Z" fill="#1F2329" fill-opacity="0.5"/>
<path d="M10 17C13.866 17 17 13.866 17 10C17 6.13401 13.866 3 10 3C6.13401 3 3 6.13401 3 10C3 13.866 6.13401 17 10 17Z" stroke="#1F2329" stroke-opacity="0.5" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 576 B

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.9875 15.3962L8.12521 12.93H3.35994L2.49766 15.3962H1L4.94837 4.40039H6.53679L10.4852 15.3962H8.9875ZM3.84403 11.5634H7.64112L5.73501 6.14401L3.84403 11.5634Z" fill="#1F2329" fill-opacity="0.5"/>
<path d="M17.6839 7.54205H19V15.3962H17.6839V14.0453C17.0283 15.082 16.0753 15.6004 14.8247 15.6004C13.7658 15.6004 12.8631 15.2024 12.1168 14.4066C11.3705 13.6002 10.9974 12.6211 10.9974 11.4691C10.9974 10.3172 11.3705 9.34326 12.1168 8.54738C12.8631 7.74102 13.7658 7.33784 14.8247 7.33784C16.0753 7.33784 17.0283 7.85621 17.6839 8.89296V7.54205ZM14.9911 14.2809C15.7576 14.2809 16.398 14.0139 16.9124 13.4798C17.4267 12.9352 17.6839 12.265 17.6839 11.4691C17.6839 10.6732 17.4267 10.0082 16.9124 9.47416C16.398 8.92961 15.7576 8.65733 14.9911 8.65733C14.2347 8.65733 13.5994 8.92961 13.085 9.47416C12.5707 10.0082 12.3135 10.6732 12.3135 11.4691C12.3135 12.265 12.5707 12.9352 13.085 13.4798C13.5994 14.0139 14.2347 14.2809 14.9911 14.2809Z" fill="#1F2329" fill-opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.2005 3.00016C12.1798 2.99061 11.2063 3.41373 10.4871 4.16177L10.4808 4.16844L9.38111 5.34588C9.14121 5.60273 9.15496 6.00542 9.41181 6.24531C9.66865 6.4852 10.0713 6.47146 10.3112 6.21461L11.4077 5.0407C11.894 4.53649 12.5343 4.26671 13.1886 4.27283C13.8444 4.27897 14.482 4.56193 14.961 5.07775C15.4414 5.5951 15.7211 6.30419 15.7272 7.0544C15.7332 7.80278 15.4662 8.51578 14.996 9.04219L13.0818 11.1036C12.8196 11.3861 12.5071 11.6013 12.1673 11.7378C11.8277 11.8743 11.4666 11.9299 11.1078 11.9022C10.7489 11.8745 10.3975 11.7639 10.0772 11.5755C9.75665 11.3869 9.47373 11.124 9.24993 10.8018C9.04944 10.5131 8.65291 10.4417 8.36425 10.6422C8.07559 10.8426 8.00412 11.2392 8.20461 11.5278C8.52998 11.9963 8.94768 12.3876 9.43175 12.6724C9.91601 12.9573 10.4543 13.1283 11.0099 13.1711C11.5656 13.214 12.1224 13.1275 12.6417 12.9188C13.1609 12.7103 13.6285 12.3854 14.0145 11.9696L15.9326 9.90396L15.94 9.89582C16.6322 9.12396 17.0084 8.0993 16.9999 7.04413C16.9913 5.98894 16.5987 4.97104 15.8936 4.21173C15.1872 3.4509 14.2212 3.00971 13.2005 3.00016Z" fill="#1F2329" fill-opacity="0.5"/>
<path d="M8.9901 6.82886C8.43442 6.786 7.87763 6.87253 7.35826 7.08117C6.83914 7.28972 6.37154 7.61453 5.98554 8.03035L4.06743 10.096L4.06001 10.1042C3.36777 10.876 2.99163 11.9007 3.00014 12.9559C3.00866 14.0111 3.40131 15.029 4.10637 15.7883C4.81285 16.5491 5.77884 16.9903 6.79948 16.9998C7.8202 17.0094 8.79368 16.5863 9.51285 15.8382L9.52044 15.8302L10.6138 14.6528C10.8529 14.3952 10.838 13.9926 10.5804 13.7534C10.3229 13.5143 9.92025 13.5292 9.68111 13.7867L8.59175 14.9599C8.1055 15.4637 7.46547 15.7333 6.81139 15.7272C6.15563 15.721 5.518 15.4381 5.03903 14.9222C4.55864 14.4049 4.27888 13.6958 4.27283 12.9456C4.26679 12.1972 4.53376 11.4842 5.00403 10.9578L6.9182 8.89638C7.18036 8.61394 7.49286 8.39869 7.8327 8.26216C8.17234 8.12572 8.53342 8.07015 8.89223 8.09782C9.25109 8.1255 9.60253 8.23607 9.92284 8.42453C10.2434 8.61312 10.5263 8.876 10.7501 9.19821C10.9506 9.48687 11.3471 9.55834 11.6357 9.35785C11.9244 9.15736 11.9959 8.76082 11.7954 8.47217C11.47 8.00373 11.0523 7.61241 10.5683 7.32759C10.084 7.04266 9.54572 6.87172 8.9901 6.82886Z" fill="#1F2329" fill-opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#98F4CD"/>
<path d="M38.75 43.5L42.7885 47.25L56.25 34.75M55 44.75V53.2222C55 53.9589 54.7073 54.6655 54.1864 55.1864C53.6655 55.7073 52.9589 56 52.2222 56H32.7778C32.0411 56 31.3345 55.7073 30.8136 55.1864C30.2927 54.6655 30 53.9589 30 53.2222V33.7778C30 33.0411 30.2927 32.3345 30.8136 31.8136C31.3345 31.2927 32.0411 31 32.7778 31H48.0556" stroke="#192432" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 574 B

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#98F4CD"/>
<path d="M43.2629 45.1502C43.2827 45.1686 43.3134 45.1686 43.3332 45.1502L56.3646 33.0497C56.8664 32.5837 57.651 32.6127 58.117 33.1146C58.583 33.6164 58.5539 34.401 58.0521 34.867L44.1418 47.7837C43.6661 48.2254 42.9301 48.2254 42.4543 47.7837L38.2812 43.9087C37.7794 43.4427 37.7503 42.6581 38.2163 42.1562C38.6823 41.6544 39.4669 41.6253 39.9688 42.0913L43.2629 45.1502ZM43 30.0317C35.8378 30.0317 30.0317 35.8378 30.0317 43C30.0317 50.1622 35.8378 55.9683 43 55.9683C50.1622 55.9683 55.9683 50.1622 55.9683 43C55.9683 42.3152 56.5235 41.76 57.2083 41.76C57.8932 41.76 58.4483 42.3152 58.4483 43C58.4483 51.5319 51.5319 58.4483 43 58.4483C34.4681 58.4483 27.5517 51.5319 27.5517 43C27.5517 34.4681 34.4681 27.5517 43 27.5517C45.298 27.5517 47.482 28.0542 49.4453 28.9567C50.0675 29.2427 50.3401 29.979 50.0541 30.6012C49.7681 31.2235 49.0318 31.496 48.4095 31.21C46.7646 30.4539 44.9333 30.0317 43 30.0317Z" fill="#1D2F28" stroke="#B1EEB8" stroke-width="0.103333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#FDEDA7"/>
<path d="M46.75 30.55C46.7776 30.55 46.8 30.5276 46.8 30.5V29.25C46.8 28.5873 47.3373 28.05 48 28.05C48.6627 28.05 49.2 28.5873 49.2 29.25V30.5C49.2 30.5276 49.2224 30.55 49.25 30.55H52.7222C54.7975 30.55 56.7 32.0912 56.7 34.25V51.75C56.7 53.9088 54.7975 55.45 52.7222 55.45H33.2778C31.2025 55.45 29.3 53.9088 29.3 51.75V34.25C29.3 32.0912 31.2025 30.55 33.2778 30.55H36.75C36.7776 30.55 36.8 30.5276 36.8 30.5V29.25C36.8 28.5873 37.3373 28.05 38 28.05C38.6627 28.05 39.2 28.5873 39.2 29.25V30.5C39.2 30.5276 39.2224 30.55 39.25 30.55H46.75ZM54.3 40.5C54.3 40.4724 54.2776 40.45 54.25 40.45H31.75C31.7224 40.45 31.7 40.4724 31.7 40.5V51.75C31.7 52.3509 32.2829 53.05 33.2778 53.05H52.7222C53.7171 53.05 54.3 52.3509 54.3 51.75V40.5ZM31.7 38C31.7 38.0276 31.7224 38.05 31.75 38.05H54.25C54.2776 38.05 54.3 38.0276 54.3 38V34.25C54.3 33.6491 53.7171 32.95 52.7222 32.95H49.25C49.2224 32.95 49.2 32.9724 49.2 33V34.4545C49.2 35.1173 48.6627 35.6545 48 35.6545C47.3373 35.6545 46.8 35.1173 46.8 34.4545V33C46.8 32.9724 46.7776 32.95 46.75 32.95H39.25C39.2224 32.95 39.2 32.9724 39.2 33V34.4545C39.2 35.1173 38.6627 35.6545 38 35.6545C37.3373 35.6545 36.8 35.1173 36.8 34.4545V33C36.8 32.9724 36.7776 32.95 36.75 32.95H33.2778C32.2829 32.95 31.7 33.6491 31.7 34.25V38Z" fill="#2D2017" stroke="#FFEFE3" stroke-width="0.1" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,5 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#91EBF5"/>
<path d="M45.25 30.625V38.5C45.25 39.7426 46.2574 40.75 47.5 40.75H52" stroke="black" stroke-opacity="0.8" stroke-width="2.2"/>
<path d="M32.875 32.875C32.875 31.6324 33.8824 30.625 35.125 30.625H43H44.125C45.5414 30.625 46.8752 31.2919 47.725 32.425L52.225 38.425C52.8092 39.2039 53.125 40.1513 53.125 41.125V43V53.125C53.125 54.3676 52.1176 55.375 50.875 55.375H35.125C33.8824 55.375 32.875 54.3676 32.875 53.125V32.875Z" stroke="black" stroke-opacity="0.8" stroke-width="2.2"/>
</svg>

After

Width:  |  Height:  |  Size: 638 B

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#CABDFF"/>
<path d="M55.6164 48.5837L55.6162 48.5838C54.2773 50.1393 52.4736 50.9218 50.1802 50.9218C49.1723 50.9218 48.3115 50.7288 47.5903 50.3517C46.8827 49.9755 46.3493 49.4392 45.9849 48.7394L45.8256 48.4336L45.6099 48.7026C44.4472 50.1523 42.9386 50.8735 41.065 50.8735C39.3701 50.8735 38.0779 50.2424 37.1593 48.9845C36.2379 47.7228 35.8792 46.04 36.116 43.9082C36.3299 42.1629 36.822 40.6195 37.5889 39.2744C38.3683 37.9176 39.3439 36.8838 40.5136 36.165C41.6844 35.4455 42.9458 35.0868 44.3024 35.0868C45.9947 35.0868 47.4241 35.4343 48.6002 36.1183L49.6168 36.7363L48.7089 45.901C48.5855 46.7745 48.684 47.4913 49.0573 48.0085L49.0573 48.0086L49.0596 48.0117C49.4514 48.5351 50.0591 48.7784 50.8313 48.7784C52.0351 48.7784 53.0272 48.1482 53.805 46.9526L53.8055 46.9518C54.5811 45.7486 54.9974 44.1922 55.071 42.2981C55.2777 38.5125 54.4204 35.5664 52.4599 33.4995C50.5112 31.4215 47.6334 30.4006 43.8683 30.4006C41.5061 30.4006 39.3927 30.9351 37.5343 32.0093C35.6758 33.0836 34.2123 34.6128 33.1446 36.5911C32.0777 38.5572 31.4796 40.808 31.3454 43.3387L31.3454 43.3392C31.1505 47.1789 32.014 50.1828 33.9725 52.3136C35.9334 54.4578 38.8545 55.5114 42.6927 55.5114C43.7084 55.5114 44.7709 55.4079 45.8797 55.2017C46.883 55.0249 47.7669 54.7895 48.5295 54.4938L49.1025 56.562C48.411 56.9363 47.4918 57.2448 46.3369 57.4822L46.3347 57.4827C45.1083 57.7478 43.8703 57.8803 42.6204 57.8803C39.4638 57.8803 36.788 57.3106 34.5844 56.1815L34.5837 56.1811C32.3839 55.0646 30.7431 53.4138 29.6556 51.224C28.5791 49.0429 28.1067 46.4251 28.25 43.3614C28.3931 40.4305 29.1437 37.8085 30.4983 35.4908C31.8523 33.1742 33.6912 31.3888 36.0176 30.1308L36.0179 30.1307C38.3569 28.8617 40.9961 28.225 43.9406 28.225C46.9383 28.225 49.5048 28.7993 51.6481 29.9383L51.6488 29.9387C53.7909 31.0665 55.3905 32.6813 56.454 34.7861C57.5187 36.8933 57.99 39.35 57.8589 42.164C57.728 44.8773 56.9738 47.0099 55.6164 48.5837ZM39.684 43.8568L39.684 43.8568L39.6836 43.8612C39.5493 45.2962 39.6845 46.4295 40.1267 47.2287L40.1273 47.23C40.5815 48.0389 41.3246 48.4401 42.3129 48.4401C42.968 48.4401 43.5793 48.1825 44.1426 47.6922C44.7074 47.2006 45.1652 46.5014 45.5239 45.6091L45.5358 45.5794L45.539 45.5475L46.2986 37.9285L46.317 37.7435L46.1388 37.6906C45.6476 37.5448 45.1437 37.4719 44.6279 37.4719C43.1749 37.4719 42.0262 38.0281 41.2091 39.1424L41.2082 39.1437C40.4167 40.2403 39.9152 41.8193 39.684 43.8568Z" fill="black" fill-opacity="0.8" stroke="#DFC0FF" stroke-width="0.449923"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#91EBF5"/>
<path d="M57 42.1264L43.7622 54.6113C42.1405 56.1407 39.941 57 37.6475 57C35.3541 57 33.1545 56.1407 31.5328 54.6113C29.9111 53.0818 29 51.0073 29 48.8443C29 46.6813 29.9111 44.6068 31.5328 43.0774L44.7706 30.5925C45.8517 29.5728 47.3181 29 48.847 29C50.376 29 51.8424 29.5728 52.9235 30.5925C54.0047 31.6122 54.6121 32.9951 54.6121 34.4371C54.6121 35.8791 54.0047 37.2621 52.9235 38.2818L39.6714 50.7666C39.1308 51.2765 38.3976 51.5629 37.6331 51.5629C36.8686 51.5629 36.1355 51.2765 35.5949 50.7666C35.0543 50.2568 34.7506 49.5653 34.7506 48.8443C34.7506 48.1233 35.0543 47.4318 35.5949 46.922L47.8243 35.4017" stroke="#1F2329" stroke-width="2.2807" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 858 B

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#91EBF5"/>
<path d="M44.234 40.3346V40.4346H44.334H49.6673C50.3485 40.4346 50.9007 40.9868 50.9007 41.668C50.9007 42.3491 50.3485 42.9013 49.6673 42.9013H44.334H44.234V43.0013V50.3346C44.234 53.5976 41.5749 56.2346 38.3209 56.2346C35.0813 56.2346 32.434 53.6092 32.434 50.3607V50.3346C32.434 49.6535 32.9862 49.1013 33.6673 49.1013C34.3485 49.1013 34.9007 49.6535 34.9007 50.3346V50.3607C34.9007 52.2379 36.4346 53.768 38.3209 53.768C40.2216 53.768 41.7673 52.2263 41.7673 50.3346L41.7673 43.0013V42.9013H41.6673H37.6673C36.9862 42.9013 36.434 42.3491 36.434 41.668C36.434 40.9868 36.9862 40.4346 37.6673 40.4346H41.6673H41.7673V40.3346V35.668C41.7673 32.405 44.4264 29.768 47.6804 29.768C50.92 29.768 53.5673 32.3934 53.5673 35.6419V35.668C53.5673 36.3491 53.0151 36.9013 52.334 36.9013C51.6528 36.9013 51.1007 36.3491 51.1007 35.668V35.6419C51.1007 33.7647 49.5667 32.2346 47.6804 32.2346C45.7797 32.2346 44.234 33.7763 44.234 35.668V40.3346Z" fill="black" fill-opacity="0.8" stroke="#92E8FF" stroke-width="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#BAC9FF"/>
<path d="M36.342 32.6719C36.342 31.8452 37.0122 31.175 37.8389 31.175H52.519C53.3457 31.175 54.0159 31.8452 54.0159 32.6719C54.0159 33.4986 53.3457 34.1688 52.519 34.1688H37.8389C37.0122 34.1688 36.342 33.4986 36.342 32.6719ZM36.342 42.4586C36.342 41.6319 37.0122 40.9617 37.8389 40.9617H52.519C53.3457 40.9617 54.0159 41.6319 54.0159 42.4586C54.0159 43.2853 53.3457 43.9554 52.519 43.9554H37.8389C37.0122 43.9554 36.342 43.2853 36.342 42.4586ZM36.342 52.2454C36.342 51.4187 37.0122 50.7486 37.8389 50.7486H52.519C53.3457 50.7486 54.0159 51.4187 54.0159 52.2454C54.0159 53.0721 53.3457 53.7423 52.519 53.7423H37.8389C37.0122 53.7423 36.342 53.0721 36.342 52.2454ZM32.8967 32.672C32.8967 33.32 32.3714 33.8453 31.7233 33.8453C31.0753 33.8453 30.55 33.32 30.55 32.672C30.55 32.0239 31.0753 31.4986 31.7233 31.4986C32.3714 31.4986 32.8967 32.0239 32.8967 32.672ZM32.8967 42.4588C32.8967 43.1068 32.3714 43.6321 31.7233 43.6321C31.0753 43.6321 30.55 43.1068 30.55 42.4588C30.55 41.8107 31.0753 41.2854 31.7233 41.2854C32.3714 41.2854 32.8967 41.8107 32.8967 42.4588ZM32.8967 52.2454C32.8967 52.8934 32.3714 53.4187 31.7233 53.4187C31.0753 53.4187 30.55 52.8934 30.55 52.2454C30.55 51.5974 31.0753 51.0721 31.7233 51.0721C32.3714 51.0721 32.8967 51.5974 32.8967 52.2454Z" fill="#192432" stroke="#DBEAFF" stroke-width="0.1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -0,0 +1,8 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#FFB9EF"/>
<mask id="path-2-inside-1_72_2706" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd" d="M46.837 36.7826C46.837 39.1478 44.9196 41.0652 42.5543 41.0652C40.1891 41.0652 38.2717 39.1478 38.2717 36.7826C38.2717 34.4174 40.1891 32.5 42.5543 32.5C44.9196 32.5 46.837 34.4174 46.837 36.7826ZM45.8011 42.7391C47.9079 41.5883 49.337 39.3523 49.337 36.7826C49.337 33.0367 46.3003 30 42.5543 30C38.8084 30 35.7717 33.0367 35.7717 36.7826C35.7717 39.3523 37.2008 41.5883 39.3076 42.7391C33.9478 44.17 30 49.0588 30 54.8696C30 55.5599 30.5596 56.1196 31.25 56.1196C31.9404 56.1196 32.5 55.5599 32.5 54.8696C32.5 49.3167 37.0015 44.8152 42.5543 44.8152C48.1072 44.8152 52.6087 49.3167 52.6087 54.8696C52.6087 55.5599 53.1683 56.1196 53.8587 56.1196C54.5491 56.1196 55.1087 55.5599 55.1087 54.8696C55.1087 49.0588 51.1609 44.17 45.8011 42.7391Z"/>
</mask>
<path fill-rule="evenodd" clip-rule="evenodd" d="M46.837 36.7826C46.837 39.1478 44.9196 41.0652 42.5543 41.0652C40.1891 41.0652 38.2717 39.1478 38.2717 36.7826C38.2717 34.4174 40.1891 32.5 42.5543 32.5C44.9196 32.5 46.837 34.4174 46.837 36.7826ZM45.8011 42.7391C47.9079 41.5883 49.337 39.3523 49.337 36.7826C49.337 33.0367 46.3003 30 42.5543 30C38.8084 30 35.7717 33.0367 35.7717 36.7826C35.7717 39.3523 37.2008 41.5883 39.3076 42.7391C33.9478 44.17 30 49.0588 30 54.8696C30 55.5599 30.5596 56.1196 31.25 56.1196C31.9404 56.1196 32.5 55.5599 32.5 54.8696C32.5 49.3167 37.0015 44.8152 42.5543 44.8152C48.1072 44.8152 52.6087 49.3167 52.6087 54.8696C52.6087 55.5599 53.1683 56.1196 53.8587 56.1196C54.5491 56.1196 55.1087 55.5599 55.1087 54.8696C55.1087 49.0588 51.1609 44.17 45.8011 42.7391Z" fill="#1F2329"/>
<path d="M45.8011 42.7391L45.7532 42.6513L45.5337 42.7712L45.7753 42.8357L45.8011 42.7391ZM39.3076 42.7391L39.3334 42.8357L39.575 42.7712L39.3555 42.6513L39.3076 42.7391ZM42.5543 41.1652C44.9748 41.1652 46.937 39.2031 46.937 36.7826H46.737C46.737 39.0926 44.8643 40.9652 42.5543 40.9652V41.1652ZM38.1717 36.7826C38.1717 39.2031 40.1339 41.1652 42.5543 41.1652V40.9652C40.2444 40.9652 38.3717 39.0926 38.3717 36.7826H38.1717ZM42.5543 32.4C40.1339 32.4 38.1717 34.3622 38.1717 36.7826H38.3717C38.3717 34.4726 40.2444 32.6 42.5543 32.6V32.4ZM46.937 36.7826C46.937 34.3622 44.9748 32.4 42.5543 32.4V32.6C44.8643 32.6 46.737 34.4726 46.737 36.7826H46.937ZM45.849 42.8269C47.9866 41.6592 49.437 39.3904 49.437 36.7826H49.237C49.237 39.3143 47.8291 41.5174 45.7532 42.6513L45.849 42.8269ZM49.437 36.7826C49.437 32.9814 46.3555 29.9 42.5543 29.9V30.1C46.2451 30.1 49.237 33.0919 49.237 36.7826H49.437ZM42.5543 29.9C38.7532 29.9 35.6717 32.9814 35.6717 36.7826H35.8717C35.8717 33.0919 38.8636 30.1 42.5543 30.1V29.9ZM35.6717 36.7826C35.6717 39.3904 37.1221 41.6592 39.2597 42.8269L39.3555 42.6513C37.2796 41.5174 35.8717 39.3143 35.8717 36.7826H35.6717ZM30.1 54.8696C30.1 49.1052 34.0162 44.2552 39.3334 42.8357L39.2818 42.6425C33.8793 44.0848 29.9 49.0123 29.9 54.8696H30.1ZM31.25 56.0196C30.6149 56.0196 30.1 55.5047 30.1 54.8696H29.9C29.9 55.6152 30.5044 56.2196 31.25 56.2196V56.0196ZM32.4 54.8696C32.4 55.5047 31.8851 56.0196 31.25 56.0196V56.2196C31.9956 56.2196 32.6 55.6152 32.6 54.8696H32.4ZM42.5543 44.7152C36.9463 44.7152 32.4 49.2615 32.4 54.8696H32.6C32.6 49.3719 37.0567 44.9152 42.5543 44.9152V44.7152ZM52.7087 54.8696C52.7087 49.2615 48.1624 44.7152 42.5543 44.7152V44.9152C48.052 44.9152 52.5087 49.3719 52.5087 54.8696H52.7087ZM53.8587 56.0196C53.2236 56.0196 52.7087 55.5047 52.7087 54.8696H52.5087C52.5087 55.6152 53.1131 56.2196 53.8587 56.2196V56.0196ZM55.0087 54.8696C55.0087 55.5047 54.4938 56.0196 53.8587 56.0196V56.2196C54.6043 56.2196 55.2087 55.6152 55.2087 54.8696H55.0087ZM45.7753 42.8357C51.0925 44.2552 55.0087 49.1052 55.0087 54.8696H55.2087C55.2087 49.0123 51.2294 44.0848 45.8269 42.6425L45.7753 42.8357Z" fill="#FFC5E8" mask="url(#path-2-inside-1_72_2706)"/>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#CABDFF"/>
<path d="M38.7237 33.9987C38.7237 33.2947 39.2944 32.7239 39.9985 32.7239H45.9974C46.7015 32.7239 47.2722 33.2947 47.2722 33.9987C47.2722 34.7028 46.7015 35.2735 45.9974 35.2735H39.9985C39.2944 35.2735 38.7237 34.7028 38.7237 33.9987ZM40.2234 51.9956C40.2234 51.2916 40.7942 50.7208 41.4982 50.7208H44.4977C45.2017 50.7208 45.7725 51.2916 45.7725 51.9956C45.7725 52.6997 45.2017 53.2704 44.4977 53.2704H41.4982C40.7942 53.2704 40.2234 52.6997 40.2234 51.9956ZM31.225 32C31.225 29.0867 33.5867 26.725 36.5 26.725H49.5C52.4133 26.725 54.775 29.0867 54.775 32V53.9974C54.775 56.9107 52.4133 59.2724 49.5 59.2724H36.5C33.5867 59.2724 31.225 56.9107 31.225 53.9974V32ZM52.2214 32.4995C52.2214 30.7184 50.7775 29.2745 48.9964 29.2745H36.9995C35.2184 29.2745 33.7745 30.7184 33.7745 32.4995V53.4949C33.7745 55.276 35.2184 56.7198 36.9995 56.7198H48.9964C50.7775 56.7198 52.2214 55.276 52.2214 53.4949V32.4995Z" fill="black" fill-opacity="0.8" stroke="#DFC0FF" stroke-width="0.449923"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -0,0 +1,5 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#BAC9FF"/>
<path d="M42.4064 45.2052L38.8344 41.6332C38.3052 41.104 38.68 40.1992 39.4283 40.1992H46.5725C47.3208 40.1992 47.6956 41.104 47.1664 41.6332L43.5944 45.2052C43.2663 45.5333 42.7345 45.5333 42.4064 45.2052Z" fill="#192432"/>
<path d="M43 57C50.732 57 57 50.732 57 43C57 35.268 50.732 29 43 29C35.268 29 29 35.268 29 43C29 50.732 35.268 57 43 57Z" stroke="#192432" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 589 B

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#BAC9FF"/>
<path d="M36.7312 30.55L44.3714 51.0671H41.5663L39.9016 46.4759L39.8896 46.443H39.8546H30.5888H30.5537L30.5418 46.4759L28.8771 51.0671H26.072L33.7121 30.55H36.7312ZM31.483 43.9136L31.4588 43.9806H31.5301H38.9133H38.9848L38.9603 43.9134L35.2539 33.7522L35.2068 33.6229L35.16 33.7523L31.483 43.9136ZM52.8814 51.45C50.836 51.45 49.0938 50.7094 47.6519 49.2267C46.2101 47.7245 45.4893 45.9012 45.4893 43.7539C45.4893 41.6064 46.2102 39.793 47.6519 38.3105L47.6521 38.3102C49.0941 36.8079 50.8362 36.0577 52.8814 36.0577C55.2971 36.0577 57.1341 37.0219 58.3991 38.951L58.4909 39.091V38.9236V36.4406H60.95V51.0671H58.4909V48.5842V48.4167L58.3991 48.5567C57.1341 50.4858 55.2971 51.45 52.8814 51.45ZM56.9761 47.5592L56.9764 47.5588C57.9861 46.528 58.4909 45.2586 58.4909 43.7539C58.4909 42.2492 57.9862 40.9895 56.9762 39.9782C55.9663 38.9472 54.708 38.4318 53.205 38.4318C51.7213 38.4318 50.4729 38.9473 49.4631 39.9782C48.4532 40.9895 47.9485 42.2492 47.9485 43.7539C47.9485 45.2586 48.4532 46.528 49.4629 47.5588L49.4633 47.5592C50.4732 48.5704 51.7215 49.0759 53.205 49.0759C54.7078 49.0759 55.966 48.5705 56.9761 47.5592Z" fill="#1D2F28" stroke="#A8CBFF" stroke-width="0.1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,4 @@
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="86" height="86" rx="30" fill="#FFB9EF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.0126 30.0003C47.0975 29.9824 45.2718 30.7763 43.9237 32.1785L43.9113 32.1916L41.869 34.3783C41.3978 34.8828 41.4248 35.6738 41.9293 36.145C42.4338 36.6162 43.2248 36.5892 43.696 36.0847L45.7318 33.905C46.6225 32.9818 47.7937 32.489 48.9892 32.5002C50.1875 32.5114 51.3541 33.0284 52.2315 33.9733C53.1116 34.9211 53.6251 36.2214 53.6362 37.5983C53.6473 38.9716 53.1574 40.279 52.296 41.2435L48.7416 45.0714L48.7414 45.0715C48.2612 45.5889 47.6893 45.9826 47.0677 46.2323C46.4466 46.4819 45.7865 46.5834 45.1307 46.5328C44.4748 46.4822 43.8321 46.2801 43.2461 45.9353C42.6596 45.5902 42.1414 45.1089 41.7312 44.5183C41.3374 43.9513 40.5585 43.8109 39.9915 44.2048C39.4245 44.5986 39.2841 45.3775 39.6779 45.9445C40.2876 46.8223 41.0705 47.5559 41.9783 48.09C42.8864 48.6243 43.8961 48.945 44.9385 49.0254C45.981 49.1058 47.0255 48.9435 47.9997 48.5521C48.9734 48.161 49.8501 47.5519 50.5736 46.7725L50.5737 46.7723L54.1358 42.9362L54.1504 42.9202C55.4477 41.4736 56.152 39.5541 56.1361 37.5782C56.1202 35.6022 55.3849 33.6953 54.0634 32.2721C52.7392 30.8461 50.9277 30.0182 49.0126 30.0003ZM41.1979 37.1109C40.1554 37.0305 39.1108 37.1929 38.1367 37.5842C37.163 37.9754 36.2863 38.5845 35.5628 39.3639L35.5626 39.364L32.0006 43.2002L31.986 43.2161C30.6887 44.6627 29.9843 46.5823 30.0003 48.5582C30.0162 50.5342 30.7515 52.4411 32.0729 53.8642C33.3971 55.2903 35.2087 56.1181 37.1237 56.1361C39.0389 56.154 40.8646 55.36 42.2126 53.9579L42.2275 53.9421L44.258 51.7554C44.7277 51.2495 44.6984 50.4586 44.1925 49.9889C43.6867 49.5191 42.8957 49.5484 42.426 50.0543L40.4033 52.2326C39.5128 53.155 38.3421 53.6474 37.1471 53.6362C35.9488 53.625 34.7822 53.1079 33.9049 52.1631C33.0248 51.2153 32.5113 49.9149 32.5002 48.538C32.4891 47.1647 32.979 45.8573 33.8404 44.8929L37.3948 41.065L37.395 41.0648C37.8752 40.5474 38.4471 40.1537 39.0686 39.904C39.6898 39.6545 40.3498 39.553 41.0056 39.6035C41.6616 39.6541 42.3042 39.8562 42.8903 40.2011C43.4768 40.5461 43.995 41.0275 44.4052 41.618C44.799 42.185 45.5779 42.3254 46.1449 41.9316C46.7119 41.5378 46.8523 40.7589 46.4585 40.1919C45.8488 39.3141 45.0658 38.5805 44.1581 38.0464C43.2499 37.512 42.2403 37.1913 41.1979 37.1109Z" fill="#342A40"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -532,6 +532,7 @@
"visibility": "Visibility", "visibility": "Visibility",
"propertyType": "Property type", "propertyType": "Property type",
"addSelectOption": "Add an option", "addSelectOption": "Add an option",
"typeANewOption": "Type a new option",
"optionTitle": "Options", "optionTitle": "Options",
"addOption": "Add option", "addOption": "Add option",
"editProperty": "Edit property", "editProperty": "Edit property",
@ -1131,6 +1132,7 @@
"language": "Language", "language": "Language",
"font": "Font", "font": "Font",
"actions": "Actions", "actions": "Actions",
"date": "Date" "date": "Date",
"addField": "Add field"
} }
} }