chore: improve UI design on Desktop (#5792)

* fix: only show collapse page button when the children of the page is not emtpy

* chore: set minimum sidebar width to 268

* chore: replace space lock icon and pin & unpin icon

* chore: change divider color

* chore: update divider color

* chore: improve create space color

* feat: highlight delete button when hovering

* chore: update translations

* fix: icon align issue

* feat: highlight sidebar resizer when hovering

* feat: add border to popover

* feat: optimize scroll bar

* feat: improve scrollbar hover color

* feat: support creating a new page via cmd+n

* chore: improve scrollbar color

* feat: improve tooltip style

* chore: fix unit test

* chore: bump version 0.6.6
This commit is contained in:
Lucas.Xu 2024-07-26 09:49:13 +08:00 committed by GitHub
parent a2e211555e
commit 29fb4af40a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 793 additions and 386 deletions

View File

@ -26,7 +26,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi" CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi" CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi" LIB_NAME = "dart_ffi"
APPFLOWY_VERSION = "0.6.5" APPFLOWY_VERSION = "0.6.6"
FLUTTER_DESKTOP_FEATURES = "dart" FLUTTER_DESKTOP_FEATURES = "dart"
PRODUCT_NAME = "AppFlowy" PRODUCT_NAME = "AppFlowy"
MACOSX_DEPLOYMENT_TARGET = "11.0" MACOSX_DEPLOYMENT_TARGET = "11.0"

View File

@ -1,16 +1,14 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
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/shared/window_title_bar.dart'; import 'package:appflowy/shared/window_title_bar.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class CocoaWindowChannel { class CocoaWindowChannel {
@ -104,19 +102,17 @@ class MoveWindowDetectorState extends State<MoveWindowDetector> {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
final color = Theme.of(context).isLightMode ? Colors.white : Colors.black;
final textSpan = TextSpan( final textSpan = TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: '${LocaleKeys.sideBar_openSidebar.tr()}\n', text: '${LocaleKeys.sideBar_openSidebar.tr()}\n',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: color), style: context.tooltipTextStyle(),
), ),
TextSpan( TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\', text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',
style: Theme.of(context) style: context
.textTheme .tooltipTextStyle()
.bodyMedium! ?.copyWith(color: Theme.of(context).hintColor),
.copyWith(color: Theme.of(context).hintColor),
), ),
], ],
); );

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/database/application/calculations/calculation_type_ext.dart'; import 'package:appflowy/plugins/database/application/calculations/calculation_type_ext.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart'; import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/application/field/type_option/number_format_bloc.dart'; import 'package:appflowy/plugins/database/application/field/type_option/number_format_bloc.dart';
@ -16,6 +14,7 @@ import 'package:appflowy_popover/appflowy_popover.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:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class CalculateCell extends StatefulWidget { class CalculateCell extends StatefulWidget {
@ -141,11 +140,14 @@ class _CalculateCellState extends State<CalculateCell> {
TextSpan( TextSpan(
text: widget.calculation!.calculationType.shortLabel text: widget.calculation!.calculationType.shortLabel
.toUpperCase(), .toUpperCase(),
style: context.tooltipTextStyle(),
), ),
const TextSpan(text: ' '), const TextSpan(text: ' '),
TextSpan( TextSpan(
text: calculateValue, text: calculateValue,
style: const TextStyle(fontWeight: FontWeight.w500), style: context
.tooltipTextStyle()
?.copyWith(fontWeight: FontWeight.w500),
), ),
], ],
), ),

View File

@ -91,10 +91,8 @@ class _AlignmentButtonsState extends State<_AlignmentButtons> {
margin: const EdgeInsets.all(4), margin: const EdgeInsets.all(4),
direction: PopoverDirection.bottomWithCenterAligned, direction: PopoverDirection.bottomWithCenterAligned,
offset: const Offset(0, 10), offset: const Offset(0, 10),
decoration: BoxDecoration( decorationColor: Theme.of(context).colorScheme.onTertiary,
color: Theme.of(context).colorScheme.onTertiary, borderRadius: const BorderRadius.all(Radius.circular(4)),
borderRadius: const BorderRadius.all(Radius.circular(4)),
),
popupBuilder: (_) { popupBuilder: (_) {
keepEditorFocusNotifier.increase(); keepEditorFocusNotifier.increase();
return _AlignButtons(onAlignChanged: widget.onAlignChanged); return _AlignButtons(onAlignChanged: widget.onAlignChanged);

View File

@ -12,7 +12,6 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/decoration.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -118,10 +117,6 @@ class _SmartEditBlockComponentWidgetState
triggerActions: PopoverTriggerFlags.none, triggerActions: PopoverTriggerFlags.none,
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
constraints: BoxConstraints(maxWidth: width), constraints: BoxConstraints(maxWidth: width),
decoration: FlowyDecoration.decoration(
Colors.transparent,
Colors.transparent,
),
child: const SizedBox( child: const SizedBox(
width: double.infinity, width: double.infinity,
), ),

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart'; import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flutter/material.dart';
class DesktopAppearance extends BaseAppearance { class DesktopAppearance extends BaseAppearance {
@override @override
@ -75,18 +74,12 @@ class DesktopAppearance extends BaseAppearance {
contentTextStyle: TextStyle(color: colorScheme.onSurface), contentTextStyle: TextStyle(color: colorScheme.onSurface),
), ),
scrollbarTheme: ScrollbarThemeData( scrollbarTheme: ScrollbarThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) { thumbColor: WidgetStateProperty.resolveWith(
if (states.any(scrollbarInteractiveStates.contains)) { (states) => states.any(scrollbarInteractiveStates.contains)
return theme.shader3; ? theme.scrollbarHoverColor
} : theme.scrollbarColor,
return theme.shader5; ),
}), thickness: WidgetStateProperty.resolveWith((_) => 4.0),
thickness: WidgetStateProperty.resolveWith((states) {
if (states.any(scrollbarInteractiveStates.contains)) {
return 4;
}
return 3.0;
}),
crossAxisMargin: 0.0, crossAxisMargin: 0.0,
mainAxisMargin: 6.0, mainAxisMargin: 6.0,
radius: Corners.s10Radius, radius: Corners.s10Radius,
@ -147,6 +140,9 @@ class DesktopAppearance extends BaseAppearance {
), ),
onBackground: theme.text, onBackground: theme.text,
background: theme.surface, background: theme.surface,
borderColor: theme.borderColor,
scrollbarColor: theme.scrollbarColor,
scrollbarHoverColor: theme.scrollbarHoverColor,
), ),
], ],
); );

View File

@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
// ThemeData in mobile // ThemeData in mobile
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_menu/_toolbar_theme.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_menu/_toolbar_theme.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart'; import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flutter/material.dart';
class MobileAppearance extends BaseAppearance { class MobileAppearance extends BaseAppearance {
static const _primaryColor = Color(0xFF00BCF0); //primary 100 static const _primaryColor = Color(0xFF00BCF0); //primary 100
@ -276,6 +275,9 @@ class MobileAppearance extends BaseAppearance {
), ),
onBackground: onBackground, onBackground: onBackground,
background: background, background: background,
borderColor: theme.borderColor,
scrollbarColor: theme.scrollbarColor,
scrollbarHoverColor: theme.scrollbarHoverColor,
), ),
ToolbarColorExtension.fromBrightness(brightness), ToolbarColorExtension.fromBrightness(brightness),
], ],

View File

@ -1,6 +1,3 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/blank/blank.dart'; import 'package:appflowy/plugins/blank/blank.dart';
import 'package:appflowy/startup/plugin/plugin.dart'; import 'package:appflowy/startup/plugin/plugin.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
@ -27,12 +24,13 @@ import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart' import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
show UserProfilePB; show UserProfilePB;
import 'package:flowy_infra_ui/style_widget/container.dart'; import 'package:flowy_infra_ui/style_widget/container.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sized_context/sized_context.dart'; import 'package:sized_context/sized_context.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import '../widgets/edit_panel/edit_panel.dart'; import '../widgets/edit_panel/edit_panel.dart';
import '../widgets/sidebar_resizer.dart';
import 'home_layout.dart'; import 'home_layout.dart';
import 'home_stack.dart'; import 'home_stack.dart';
@ -164,7 +162,9 @@ class DesktopHomeScreen extends StatelessWidget {
userProfile: userProfile, userProfile: userProfile,
workspaceSetting: workspaceSetting, workspaceSetting: workspaceSetting,
); );
final homeMenuResizer = _buildHomeMenuResizer(context, layout: layout);
final homeMenuResizer =
layout.showMenu ? const SidebarResizer() : const SizedBox.shrink();
final editPanel = _buildEditPanel(context, layout: layout); final editPanel = _buildEditPanel(context, layout: layout);
return _layoutWidgets( return _layoutWidgets(
@ -218,39 +218,6 @@ class DesktopHomeScreen extends StatelessWidget {
); );
} }
Widget _buildHomeMenuResizer(
BuildContext context, {
required HomeLayout layout,
}) {
if (!layout.showMenu) {
return const SizedBox.shrink();
}
return MouseRegion(
cursor: SystemMouseCursors.resizeLeftRight,
child: GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onHorizontalDragStart: (details) => context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.editPanelResizeStart()),
onHorizontalDragUpdate: (details) => context
.read<HomeSettingBloc>()
.add(HomeSettingEvent.editPanelResized(details.localPosition.dx)),
onHorizontalDragEnd: (details) => context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.editPanelResizeEnd()),
onHorizontalDragCancel: () => context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.editPanelResizeEnd()),
behavior: HitTestBehavior.translucent,
child: SizedBox(
width: 10,
height: MediaQuery.of(context).size.height,
),
),
);
}
Widget _layoutWidgets({ Widget _layoutWidgets({
required HomeLayout layout, required HomeLayout layout,
required Widget sidebar, required Widget sidebar,
@ -296,7 +263,7 @@ class DesktopHomeScreen extends StatelessWidget {
) )
.positioned(left: 0, top: 0, width: layout.menuWidth, bottom: 0), .positioned(left: 0, top: 0, width: layout.menuWidth, bottom: 0),
homeMenuResizer homeMenuResizer
.positioned(left: layout.menuWidth - 5) .positioned(left: layout.menuWidth)
.animate(layout.animDuration, Curves.easeOutQuad), .animate(layout.animDuration, Curves.easeOutQuad),
], ],
); );

View File

@ -1,4 +1,5 @@
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'dart:math';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
@ -16,6 +17,8 @@ class HomeLayout {
menuWidth = Sizes.sideBarWidth; menuWidth = Sizes.sideBarWidth;
menuWidth += homeSetting.resizeOffset; menuWidth += homeSetting.resizeOffset;
menuWidth = max(menuWidth, HomeSizes.minimumSidebarWidth);
final screenWidthPx = context.widthPx; final screenWidthPx = context.widthPx;
context context
.read<HomeSettingBloc>() .read<HomeSettingBloc>()

View File

@ -8,6 +8,7 @@ class HomeSizes {
static const double workspaceSectionHeight = 32; static const double workspaceSectionHeight = 32;
static const double searchSectionHeight = 30; static const double searchSectionHeight = 30;
static const double newPageSectionHeight = 30; static const double newPageSectionHeight = 30;
static const double minimumSidebarWidth = 268;
} }
class HomeInsets { class HomeInsets {

View File

@ -1,7 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/app_window_size_manager.dart'; import 'package:appflowy/startup/tasks/app_window_size_manager.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
@ -11,6 +9,7 @@ import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:flutter/material.dart';
import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:scaled_app/scaled_app.dart'; import 'package:scaled_app/scaled_app.dart';
@ -18,6 +17,7 @@ import 'package:scaled_app/scaled_app.dart';
typedef KeyDownHandler = void Function(HotKey hotKey); typedef KeyDownHandler = void Function(HotKey hotKey);
ValueNotifier<int> switchToTheNextSpace = ValueNotifier(0); ValueNotifier<int> switchToTheNextSpace = ValueNotifier(0);
ValueNotifier<int> createNewPageNotifier = ValueNotifier(0);
/// Helper class that utilizes the global [HotKeyManager] to easily /// Helper class that utilizes the global [HotKeyManager] to easily
/// add a [HotKey] with different handlers. /// add a [HotKey] with different handlers.
@ -180,6 +180,16 @@ class _HomeHotKeysState extends State<HomeHotKeys> {
keyDownHandler: (_) => switchToTheNextSpace.value++, keyDownHandler: (_) => switchToTheNextSpace.value++,
), ),
// Create a new page
HotKeyItem(
hotKey: HotKey(
KeyCode.keyN,
modifiers: [Platform.isMacOS ? KeyModifier.meta : KeyModifier.control],
scope: HotKeyScope.inapp,
),
keyDownHandler: (_) => createNewPageNotifier.value++,
),
// Open settings dialog // Open settings dialog
openSettingsHotKey(context, widget.userProfile), openSettingsHotKey(context, widget.userProfile),
]; ];

View File

@ -11,7 +11,6 @@ import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/decoration.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -172,11 +171,6 @@ class FavoriteMoreButton extends StatelessWidget {
constraints: const BoxConstraints( constraints: const BoxConstraints(
minWidth: minWidth, minWidth: minWidth,
), ),
decoration: FlowyDecoration.decoration(
Theme.of(context).cardColor,
Theme.of(context).colorScheme.shadow,
borderRadius: 10.0,
),
popupBuilder: (_) { popupBuilder: (_) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [

View File

@ -137,6 +137,7 @@ class _FavoriteGroups extends StatelessWidget {
state.otherViews, state.otherViews,
LocaleKeys.sideBar_others.tr(), LocaleKeys.sideBar_others.tr(),
); );
return Container( return Container(
width: minWidth - 2 * _kHorizontalPadding, width: minWidth - 2 * _kHorizontalPadding,
constraints: const BoxConstraints( constraints: const BoxConstraints(
@ -149,15 +150,14 @@ class _FavoriteGroups extends StatelessWidget {
children: [ children: [
if (today.isNotEmpty) ...[ if (today.isNotEmpty) ...[
...today, ...today,
const VSpace(8), const FlowyDivider(),
const Divider(height: 1), const VSpace(16),
const VSpace(8),
], ],
if (thisWeek.isNotEmpty) ...[ if (thisWeek.isNotEmpty) ...[
...thisWeek, ...thisWeek,
const VSpace(8), const VSpace(8),
const Divider(height: 1), const FlowyDivider(),
const VSpace(8), const VSpace(16),
], ],
...others.isNotEmpty && (today.isNotEmpty || thisWeek.isNotEmpty) ...others.isNotEmpty && (today.isNotEmpty || thisWeek.isNotEmpty)
? others ? others
@ -182,13 +182,10 @@ class _FavoriteGroups extends StatelessWidget {
return [ return [
if (views.isNotEmpty) ...[ if (views.isNotEmpty) ...[
if (showHeader) if (showHeader)
SizedBox( FlowyText(
height: 24, title,
child: FlowyText( fontSize: 12.0,
title, color: Theme.of(context).hintColor,
fontSize: 12.0,
color: Theme.of(context).hintColor,
),
), ),
const VSpace(2), const VSpace(2),
_FavoriteGroupedViews(views: views), _FavoriteGroupedViews(views: views),

View File

@ -21,8 +21,8 @@ class FavoritePinAction extends StatelessWidget {
: LocaleKeys.favorite_addToSidebar.tr(); : LocaleKeys.favorite_addToSidebar.tr();
final icon = FlowySvg( final icon = FlowySvg(
view.isPinned view.isPinned
? FlowySvgs.favorite_section_pin_s ? FlowySvgs.favorite_section_unpin_s
: FlowySvgs.favorite_section_unpin_s, : FlowySvgs.favorite_section_pin_s,
); );
return FlowyTooltip( return FlowyTooltip(
message: tooltip, message: tooltip,

View File

@ -3,7 +3,6 @@ import 'dart:io' show Platform;
import 'package:appflowy/core/frameless_window.dart'; import 'package:appflowy/core/frameless_window.dart';
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/util/theme_extension.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart'; import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart'; import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
@ -65,20 +64,17 @@ class SidebarTopMenu extends StatelessWidget {
} }
Widget _buildCollapseMenuButton(BuildContext context) { Widget _buildCollapseMenuButton(BuildContext context) {
final color = Theme.of(context).isLightMode ? Colors.white : Colors.black;
final textSpan = TextSpan( final textSpan = TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: '${LocaleKeys.sideBar_closeSidebar.tr()}\n', text: '${LocaleKeys.sideBar_closeSidebar.tr()}\n',
style: style: context.tooltipTextStyle(),
Theme.of(context).tooltipTheme.textStyle!.copyWith(color: color),
), ),
TextSpan( TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\', text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',
style: Theme.of(context) style: context
.tooltipTheme .tooltipTextStyle()
.textStyle! ?.copyWith(color: Theme.of(context).hintColor),
.copyWith(color: Theme.of(context).hintColor),
), ),
], ],
); );

View File

@ -1,3 +1,4 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart'; import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart'; import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_search_bloc.dart'; import 'package:appflowy/workspace/application/sidebar/space/space_search_bloc.dart';
@ -5,9 +6,12 @@ import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart'; import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.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';
@ -123,12 +127,15 @@ class _MovePageMenuState extends State<MovePageMenu> {
expand: true, expand: true,
height: 30, height: 30,
showCreateButton: false, showCreateButton: false,
child: CurrentSpace( child: FlowyTooltip(
onTapBlankArea: () { message: LocaleKeys.space_switchSpace.tr(),
// move the page to current space child: CurrentSpace(
widget.onSelected(space, space); onTapBlankArea: () {
}, // move the page to current space
space: space, widget.onSelected(space, space);
},
space: space,
),
), ),
), ),
Expanded( Expanded(

View File

@ -4,6 +4,7 @@ import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart'; import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart'; import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart'; import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/home/hotkeys.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/rename_view_dialog.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/rename_view_dialog.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -11,18 +12,35 @@ 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';
class SidebarNewPageButton extends StatelessWidget { class SidebarNewPageButton extends StatefulWidget {
const SidebarNewPageButton({ const SidebarNewPageButton({
super.key, super.key,
}); });
@override
State<SidebarNewPageButton> createState() => _SidebarNewPageButtonState();
}
class _SidebarNewPageButtonState extends State<SidebarNewPageButton> {
@override
void initState() {
super.initState();
createNewPageNotifier.addListener(_createNewPage);
}
@override
void dispose() {
createNewPageNotifier.removeListener(_createNewPage);
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
height: HomeSizes.newPageSectionHeight, height: HomeSizes.newPageSectionHeight,
child: FlowyButton( child: FlowyButton(
onTap: () async => _createNewPage(context), onTap: () async => _createNewPage(),
leftIcon: const FlowySvg( leftIcon: const FlowySvg(
FlowySvgs.new_app_m, FlowySvgs.new_app_m,
blendMode: null, blendMode: null,
@ -38,7 +56,7 @@ class SidebarNewPageButton extends StatelessWidget {
); );
} }
Future<void> _createNewPage(BuildContext context) async { Future<void> _createNewPage() async {
return createViewAndShowRenameDialogIfNeeded( return createViewAndShowRenameDialogIfNeeded(
context, context,
LocaleKeys.newPageText.tr(), LocaleKeys.newPageText.tr(),

View File

@ -1,7 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
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/plugins/blank/blank.dart'; import 'package:appflowy/plugins/blank/blank.dart';
@ -35,9 +33,8 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
show UserProfilePB; show UserProfilePB;
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_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flutter/material.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
Loading? _duplicateSpaceLoading; Loading? _duplicateSpaceLoading;
@ -333,10 +330,7 @@ class _SidebarState extends State<_Sidebar> {
child: child, child: child,
); );
}, },
child: const Divider( child: const FlowyDivider(),
color: Color(0x141F2329),
height: 0.5,
),
), ),
), ),
@ -346,7 +340,7 @@ class _SidebarState extends State<_Sidebar> {
Padding( Padding(
padding: menuHorizontalInset + padding: menuHorizontalInset +
const EdgeInsets.symmetric(horizontal: 4.0), const EdgeInsets.symmetric(horizontal: 4.0),
child: const Divider(height: 0.5, color: Color(0x141F2329)), child: const FlowyDivider(),
), ),
const VSpace(8), const VSpace(8),
@ -403,13 +397,16 @@ class _SidebarState extends State<_Sidebar> {
: Expanded( : Expanded(
child: Padding( child: Padding(
padding: menuHorizontalInset - const EdgeInsets.only(right: 6), padding: menuHorizontalInset - const EdgeInsets.only(right: 6),
child: SingleChildScrollView( child: FlowyScrollbar(
padding: const EdgeInsets.only(right: 6),
controller: _scrollController, controller: _scrollController,
physics: const ClampingScrollPhysics(), child: SingleChildScrollView(
child: SidebarSpace( padding: const EdgeInsets.only(right: 6),
userProfile: widget.userProfile, controller: _scrollController,
isHoverEnabled: !_isScrolling, physics: const ClampingScrollPhysics(),
child: SidebarSpace(
userProfile: widget.userProfile,
isHoverEnabled: !_isScrolling,
),
), ),
), ),
), ),

View File

@ -0,0 +1,8 @@
import 'package:appflowy/util/theme_extension.dart';
import 'package:flutter/material.dart';
extension SpacePermissionColorExtension on BuildContext {
Color get enableBorderColor => Theme.of(this).isLightMode
? const Color(0x1E171717)
: const Color(0xFF3A3F49);
}

View File

@ -1,5 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart'; import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/_extension.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon_popup.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon_popup.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -24,19 +25,22 @@ class _CreateSpacePopupState extends State<CreateSpacePopup> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0), padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
width: 500, width: 524,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
FlowyText( FlowyText(
LocaleKeys.space_createNewSpace.tr(), LocaleKeys.space_createNewSpace.tr(),
fontSize: 18.0, fontSize: 18.0,
figmaLineHeight: 24.0,
), ),
const VSpace(6.0), const VSpace(2.0),
FlowyText.regular( FlowyText(
LocaleKeys.space_createSpaceDescription.tr(), LocaleKeys.space_createSpaceDescription.tr(),
fontSize: 14.0, fontSize: 14.0,
fontWeight: FontWeight.w300,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
figmaLineHeight: 18.0,
maxLines: 2, maxLines: 2,
), ),
const VSpace(16.0), const VSpace(16.0),
@ -106,14 +110,16 @@ class _SpaceNameTextField extends StatelessWidget {
LocaleKeys.space_spaceName.tr(), LocaleKeys.space_spaceName.tr(),
fontSize: 14.0, fontSize: 14.0,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
figmaLineHeight: 18.0,
), ),
const VSpace(6.0), const VSpace(6.0),
SizedBox( SizedBox(
height: 40, height: 40,
child: FlowyTextField( child: FlowyTextField(
hintText: LocaleKeys.space_spaceName.tr(), hintText: LocaleKeys.space_spaceNamePlaceholder.tr(),
onChanged: onChanged, onChanged: onChanged,
onSubmitted: onSubmitted, onSubmitted: onSubmitted,
enableBorderColor: context.enableBorderColor,
), ),
), ),
], ],

View File

@ -1,7 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
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/util/theme_extension.dart'; import 'package:appflowy/util/theme_extension.dart';
@ -10,6 +6,7 @@ import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart'; import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart'; import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/_extension.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart'; import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
@ -19,9 +16,11 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/decoration.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class SpacePermissionSwitch extends StatefulWidget { class SpacePermissionSwitch extends StatefulWidget {
@ -55,6 +54,7 @@ class _SpacePermissionSwitchState extends State<SpacePermissionSwitch> {
LocaleKeys.space_permission.tr(), LocaleKeys.space_permission.tr(),
fontSize: 14.0, fontSize: 14.0,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
figmaLineHeight: 18.0,
), ),
const VSpace(6.0), const VSpace(6.0),
AppFlowyPopover( AppFlowyPopover(
@ -63,16 +63,11 @@ class _SpacePermissionSwitchState extends State<SpacePermissionSwitch> {
constraints: const BoxConstraints(maxWidth: 500), constraints: const BoxConstraints(maxWidth: 500),
offset: const Offset(0, 4), offset: const Offset(0, 4),
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
decoration: FlowyDecoration.decoration(
Theme.of(context).cardColor,
Theme.of(context).colorScheme.shadow,
borderRadius: 10,
),
popupBuilder: (_) => _buildPermissionButtons(), popupBuilder: (_) => _buildPermissionButtons(),
child: DecoratedBox( child: DecoratedBox(
decoration: ShapeDecoration( decoration: ShapeDecoration(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide(color: Theme.of(context).colorScheme.outline), side: BorderSide(color: context.enableBorderColor),
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
), ),
@ -148,9 +143,13 @@ class SpacePermissionButton extends StatelessWidget {
radius: BorderRadius.circular(10), radius: BorderRadius.circular(10),
iconPadding: 16.0, iconPadding: 16.0,
leftIcon: FlowySvg(icon), leftIcon: FlowySvg(icon),
leftIconSize: const Size.square(20),
rightIcon: showArrow rightIcon: showArrow
? const FlowySvg(FlowySvgs.space_permission_dropdown_s) ? const FlowySvg(FlowySvgs.space_permission_dropdown_s)
: null, : null,
borderColor: Theme.of(context).isLightMode
? const Color(0x1E171717)
: const Color(0xFF3A3F49),
text: Column( text: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -462,32 +461,29 @@ class CurrentSpace extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final child = FlowyTooltip( final child = Row(
message: LocaleKeys.space_switchSpace.tr(), mainAxisSize: MainAxisSize.min,
child: Row( children: [
mainAxisSize: MainAxisSize.min, SpaceIcon(
children: [ dimension: 20,
SpaceIcon( space: space,
dimension: 20, cornerRadius: 6.0,
space: space, ),
cornerRadius: 6.0, const HSpace(10),
Flexible(
child: FlowyText.medium(
space.name,
fontSize: 14.0,
overflow: TextOverflow.ellipsis,
), ),
const HSpace(10), ),
Flexible( const HSpace(4.0),
child: FlowyText.medium( FlowySvg(
space.name, context.read<SpaceBloc>().state.isExpanded
fontSize: 14.0, ? FlowySvgs.workspace_drop_down_menu_show_s
overflow: TextOverflow.ellipsis, : FlowySvgs.workspace_drop_down_menu_hide_s,
), ),
), ],
const HSpace(4.0),
FlowySvg(
context.read<SpaceBloc>().state.isExpanded
? FlowySvgs.workspace_drop_down_menu_show_s
: FlowySvgs.workspace_drop_down_menu_hide_s,
),
],
),
); );
if (onTapBlankArea != null) { if (onTapBlankArea != null) {

View File

@ -1,7 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart'; import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart'; import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/manage_space_popup.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/manage_space_popup.dart';
@ -105,20 +104,17 @@ class _SidebarSpaceHeaderState extends State<SidebarSpaceHeader> {
} }
Widget _buildChild() { Widget _buildChild() {
final color = Theme.of(context).isLightMode ? Colors.white : Colors.black;
final textSpan = TextSpan( final textSpan = TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: '${LocaleKeys.space_quicklySwitch.tr()}\n', text: '${LocaleKeys.space_quicklySwitch.tr()}\n',
style: style: context.tooltipTextStyle(),
Theme.of(context).tooltipTheme.textStyle!.copyWith(color: color),
), ),
TextSpan( TextSpan(
text: Platform.isMacOS ? '⌘+O' : 'Ctrl+O', text: Platform.isMacOS ? '⌘+O' : 'Ctrl+O',
style: Theme.of(context) style: context
.tooltipTheme .tooltipTextStyle()
.textStyle! ?.copyWith(color: Theme.of(context).hintColor),
.copyWith(color: Theme.of(context).hintColor),
), ),
], ],
); );

View File

@ -40,9 +40,7 @@ class SidebarSpaceMenu extends StatelessWidget {
if (showCreateButton) ...[ if (showCreateButton) ...[
const Padding( const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0), padding: EdgeInsets.symmetric(vertical: 8.0),
child: Divider( child: FlowyDivider(),
height: 0.5,
),
), ),
const SizedBox( const SizedBox(
height: HomeSpaceViewSizes.viewHeight, height: HomeSpaceViewSizes.viewHeight,

View File

@ -36,24 +36,24 @@ extension ViewMoreActionTypeExtension on SpaceMoreActionType {
} }
} }
Widget get leftIcon { FlowySvgData get leftIconSvg {
switch (this) { switch (this) {
case SpaceMoreActionType.delete: case SpaceMoreActionType.delete:
return const FlowySvg(FlowySvgs.trash_s, blendMode: null); return FlowySvgs.trash_s;
case SpaceMoreActionType.rename: case SpaceMoreActionType.rename:
return const FlowySvg(FlowySvgs.view_item_rename_s); return FlowySvgs.view_item_rename_s;
case SpaceMoreActionType.changeIcon: case SpaceMoreActionType.changeIcon:
return const FlowySvg(FlowySvgs.change_icon_s); return FlowySvgs.change_icon_s;
case SpaceMoreActionType.collapseAllPages: case SpaceMoreActionType.collapseAllPages:
return const FlowySvg(FlowySvgs.collapse_all_page_s); return FlowySvgs.collapse_all_page_s;
case SpaceMoreActionType.addNewSpace: case SpaceMoreActionType.addNewSpace:
return const FlowySvg(FlowySvgs.space_add_s); return FlowySvgs.space_add_s;
case SpaceMoreActionType.manage: case SpaceMoreActionType.manage:
return const FlowySvg(FlowySvgs.space_manage_s); return FlowySvgs.space_manage_s;
case SpaceMoreActionType.duplicate: case SpaceMoreActionType.duplicate:
return const FlowySvg(FlowySvgs.duplicate_s); return FlowySvgs.duplicate_s;
case SpaceMoreActionType.divider: case SpaceMoreActionType.divider:
return const SizedBox.shrink(); throw UnsupportedError('Divider does not have an icon');
} }
} }

View File

@ -3,7 +3,6 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/decoration.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
final builtInSpaceColors = [ final builtInSpaceColors = [
@ -59,11 +58,6 @@ class _SpaceIconPopupState extends State<SpaceIconPopup> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AppFlowyPopover( return AppFlowyPopover(
offset: const Offset(0, 4), offset: const Offset(0, 4),
decoration: FlowyDecoration.decoration(
Theme.of(context).cardColor,
Theme.of(context).colorScheme.shadow,
borderRadius: 10,
),
constraints: const BoxConstraints(maxWidth: 220), constraints: const BoxConstraints(maxWidth: 220),
margin: const EdgeInsets.symmetric(horizontal: 14.0, vertical: 12.0), margin: const EdgeInsets.symmetric(horizontal: 14.0, vertical: 12.0),
direction: PopoverDirection.bottomWithCenterAligned, direction: PopoverDirection.bottomWithCenterAligned,

View File

@ -129,7 +129,7 @@ class SpaceMoreActionTypeWrapper extends CustomActionCell {
Widget _buildDivider() { Widget _buildDivider() {
return const Padding( return const Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Divider(height: 1.0), child: FlowyDivider(),
); );
} }
@ -158,22 +158,24 @@ class SpaceMoreActionTypeWrapper extends CustomActionCell {
padding: const EdgeInsets.symmetric(vertical: 2.0), padding: const EdgeInsets.symmetric(vertical: 2.0),
child: Opacity( child: Opacity(
opacity: disable ? 0.3 : 1.0, opacity: disable ? 0.3 : 1.0,
child: FlowyButton( child: FlowyIconTextButton(
disable: disable, disable: disable,
margin: const EdgeInsets.symmetric(horizontal: 6), margin: const EdgeInsets.symmetric(horizontal: 6),
leftIcon: inner.leftIcon,
rightIcon: inner.rightIcon,
iconPadding: 10.0, iconPadding: 10.0,
text: SizedBox(
// height: 16.0,
child: FlowyText.regular(
inner.name,
color: inner == SpaceMoreActionType.delete
? Theme.of(context).colorScheme.error
: null,
),
),
onTap: onTap, onTap: onTap,
leftIconBuilder: (onHover) => FlowySvg(
inner.leftIconSvg,
color: inner == SpaceMoreActionType.delete && onHover
? Theme.of(context).colorScheme.error
: null,
),
rightIconBuilder: (_) => inner.rightIcon,
textBuilder: (onHover) => FlowyText.regular(
inner.name,
color: inner == SpaceMoreActionType.delete && onHover
? Theme.of(context).colorScheme.error
: null,
),
), ),
), ),
); );

View File

@ -49,32 +49,31 @@ extension ViewMoreActionTypeExtension on ViewMoreActionType {
} }
} }
Widget get leftIcon { FlowySvgData get leftIconSvg {
switch (this) { switch (this) {
case ViewMoreActionType.delete: case ViewMoreActionType.delete:
return const FlowySvg(FlowySvgs.trash_s, blendMode: null); return FlowySvgs.trash_s;
case ViewMoreActionType.favorite: case ViewMoreActionType.favorite:
return const FlowySvg(FlowySvgs.favorite_s); return FlowySvgs.favorite_s;
case ViewMoreActionType.unFavorite: case ViewMoreActionType.unFavorite:
return const FlowySvg(FlowySvgs.unfavorite_s); return FlowySvgs.unfavorite_s;
case ViewMoreActionType.duplicate: case ViewMoreActionType.duplicate:
return const FlowySvg(FlowySvgs.duplicate_s); return FlowySvgs.duplicate_s;
case ViewMoreActionType.copyLink:
return const Icon(Icons.copy);
case ViewMoreActionType.rename: case ViewMoreActionType.rename:
return const FlowySvg(FlowySvgs.view_item_rename_s); return FlowySvgs.view_item_rename_s;
case ViewMoreActionType.moveTo: case ViewMoreActionType.moveTo:
return const FlowySvg(FlowySvgs.move_to_s); return FlowySvgs.move_to_s;
case ViewMoreActionType.openInNewTab: case ViewMoreActionType.openInNewTab:
return const FlowySvg(FlowySvgs.view_item_open_in_new_tab_s); return FlowySvgs.view_item_open_in_new_tab_s;
case ViewMoreActionType.changeIcon: case ViewMoreActionType.changeIcon:
return const FlowySvg(FlowySvgs.change_icon_s); return FlowySvgs.change_icon_s;
case ViewMoreActionType.collapseAllPages: case ViewMoreActionType.collapseAllPages:
return const FlowySvg(FlowySvgs.collapse_all_page_s); return FlowySvgs.collapse_all_page_s;
case ViewMoreActionType.divider: case ViewMoreActionType.divider:
case ViewMoreActionType.lastModified: case ViewMoreActionType.lastModified:
case ViewMoreActionType.copyLink:
case ViewMoreActionType.created: case ViewMoreActionType.created:
return const SizedBox.shrink(); throw UnsupportedError('No left icon for $this');
} }
} }

View File

@ -491,6 +491,7 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
final name = FlowyText.regular( final name = FlowyText.regular(
widget.view.name, widget.view.name,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
// figmaLineHeight: 18.0,
); );
final children = [ final children = [
const HSpace(2), const HSpace(2),

View File

@ -101,7 +101,8 @@ class ViewMoreActionButton extends StatelessWidget {
]); ]);
// Chat doesn't change collapse // Chat doesn't change collapse
if (view.layout != ViewLayoutPB.Chat) { // Only show collapse all pages if the view has child views
if (view.layout != ViewLayoutPB.Chat && view.childViews.isNotEmpty) {
actionTypes.add(ViewMoreActionType.collapseAllPages); actionTypes.add(ViewMoreActionType.collapseAllPages);
actionTypes.add(ViewMoreActionType.divider); actionTypes.add(ViewMoreActionType.divider);
} }
@ -204,7 +205,7 @@ class ViewMoreActionTypeWrapper extends CustomActionCell {
Widget _buildDivider() { Widget _buildDivider() {
return const Padding( return const Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Divider(height: 1.0), child: FlowyDivider(),
); );
} }
@ -237,18 +238,24 @@ class ViewMoreActionTypeWrapper extends CustomActionCell {
return Container( return Container(
height: 34, height: 34,
padding: const EdgeInsets.symmetric(vertical: 2.0), padding: const EdgeInsets.symmetric(vertical: 2.0),
child: FlowyButton( child: FlowyIconTextButton(
margin: const EdgeInsets.symmetric(horizontal: 6), margin: const EdgeInsets.symmetric(horizontal: 6),
leftIcon: inner.leftIcon, onTap: onTap,
rightIcon: inner.rightIcon, // show the error color when delete is hovered
iconPadding: 10.0, leftIconBuilder: (onHover) => FlowySvg(
text: FlowyText.regular( inner.leftIconSvg,
inner.name, color: inner == ViewMoreActionType.delete && onHover
color: inner == ViewMoreActionType.delete ? Theme.of(context).colorScheme.error
: null,
),
rightIconBuilder: (_) => inner.rightIcon,
iconPadding: 10.0,
textBuilder: (onHover) => FlowyText.regular(
inner.name,
color: inner == ViewMoreActionType.delete && onHover
? Theme.of(context).colorScheme.error ? Theme.of(context).colorScheme.error
: null, : null,
), ),
onTap: onTap,
), ),
); );
} }

View File

@ -2,7 +2,6 @@ import 'dart:io';
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/util/theme_extension.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_stack.dart'; import 'package:appflowy/workspace/presentation/home/home_stack.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
@ -65,23 +64,17 @@ class FlowyNavigation extends StatelessWidget {
buildWhen: (p, c) => p.isMenuCollapsed != c.isMenuCollapsed, buildWhen: (p, c) => p.isMenuCollapsed != c.isMenuCollapsed,
builder: (context, state) { builder: (context, state) {
if (!PlatformExtension.isWindows && state.isMenuCollapsed) { if (!PlatformExtension.isWindows && state.isMenuCollapsed) {
final color =
Theme.of(context).isLightMode ? Colors.white : Colors.black;
final textSpan = TextSpan( final textSpan = TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: '${LocaleKeys.sideBar_openSidebar.tr()}\n', text: '${LocaleKeys.sideBar_openSidebar.tr()}\n',
style: Theme.of(context) style: context.tooltipTextStyle(),
.tooltipTheme
.textStyle!
.copyWith(color: color),
), ),
TextSpan( TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\', text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',
style: Theme.of(context) style: context
.tooltipTheme .tooltipTextStyle()
.textStyle! ?.copyWith(color: Theme.of(context).hintColor),
.copyWith(color: Theme.of(context).hintColor),
), ),
], ],
); );

View File

@ -1,7 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
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/plugins/document/application/document_appearance_cubit.dart'; import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
@ -45,6 +43,7 @@ import 'package:flowy_infra/theme.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:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -879,16 +878,7 @@ class _FontSelectorDropdownState extends State<_FontSelectorDropdown> {
maxHeight: 150, maxHeight: 150,
maxWidth: constraints.maxWidth - 90, maxWidth: constraints.maxWidth - 90,
), ),
decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(4.0)),
color: Theme.of(context).cardColor,
borderRadius: const BorderRadius.all(Radius.circular(4.0)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.10),
blurRadius: 6,
),
],
),
popupBuilder: (_) => _FontListPopup( popupBuilder: (_) => _FontListPopup(
currentFont: appearance.font, currentFont: appearance.font,
scrollController: _scrollController, scrollController: _scrollController,

View File

@ -1,8 +1,7 @@
import 'package:flutter/material.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
class PopoverActionList<T extends PopoverAction> extends StatefulWidget { class PopoverActionList<T extends PopoverAction> extends StatefulWidget {
@ -54,7 +53,6 @@ class _PopoverActionListState<T extends PopoverAction>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final child = widget.buildChild(popoverController); final child = widget.buildChild(popoverController);
return AppFlowyPopover( return AppFlowyPopover(
asBarrier: widget.asBarrier, asBarrier: widget.asBarrier,
controller: popoverController, controller: popoverController,

View File

@ -0,0 +1,84 @@
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SidebarResizer extends StatefulWidget {
const SidebarResizer({super.key});
@override
State<SidebarResizer> createState() => _SidebarResizerState();
}
class _SidebarResizerState extends State<SidebarResizer> {
final ValueNotifier<bool> isHovered = ValueNotifier(false);
final ValueNotifier<bool> isDragging = ValueNotifier(false);
@override
void dispose() {
isHovered.dispose();
isDragging.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.resizeLeftRight,
onEnter: (_) => isHovered.value = true,
onExit: (_) => isHovered.value = false,
child: GestureDetector(
dragStartBehavior: DragStartBehavior.down,
behavior: HitTestBehavior.translucent,
onHorizontalDragStart: (details) {
isDragging.value = true;
context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.editPanelResizeStart());
},
onHorizontalDragUpdate: (details) {
isDragging.value = true;
context
.read<HomeSettingBloc>()
.add(HomeSettingEvent.editPanelResized(details.localPosition.dx));
},
onHorizontalDragEnd: (details) {
isDragging.value = false;
context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.editPanelResizeEnd());
},
onHorizontalDragCancel: () {
isDragging.value = false;
context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.editPanelResizeEnd());
},
child: ValueListenableBuilder(
valueListenable: isHovered,
builder: (context, isHovered, _) {
return ValueListenableBuilder(
valueListenable: isDragging,
builder: (context, isDragging, _) {
return Container(
width: 2,
// increase the width of the resizer to make it easier to drag
margin: const EdgeInsets.only(right: 2.0),
height: MediaQuery.of(context).size.height,
color: isHovered || isDragging
? const Color(0xFF00B5FF)
: Colors.transparent,
);
},
);
},
),
),
);
}
}

View File

@ -246,6 +246,7 @@ class _ViewTitleState extends State<_ViewTitle> {
opacity: isEditable ? 1.0 : 0.5, opacity: isEditable ? 1.0 : 0.5,
child: FlowyText.regular( child: FlowyText.regular(
state.name, state.name,
fontSize: 14.0,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra/utils/color_converter.dart'; import 'package:flowy_infra/utils/color_converter.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dandelion.dart'; import 'dandelion.dart';
@ -87,6 +86,9 @@ class FlowyColorScheme {
required this.toggleButtonBGColor, required this.toggleButtonBGColor,
required this.calendarWeekendBGColor, required this.calendarWeekendBGColor,
required this.gridRowCountColor, required this.gridRowCountColor,
required this.borderColor,
required this.scrollbarColor,
required this.scrollbarHoverColor,
}); });
final Color surface; final Color surface;
@ -145,6 +147,11 @@ class FlowyColorScheme {
//grid bottom count color //grid bottom count color
final Color gridRowCountColor; final Color gridRowCountColor;
final Color borderColor;
final Color scrollbarColor;
final Color scrollbarHoverColor;
factory FlowyColorScheme.fromJson(Map<String, dynamic> json) => factory FlowyColorScheme.fromJson(Map<String, dynamic> json) =>
_$FlowyColorSchemeFromJson(json); _$FlowyColorSchemeFromJson(json);

View File

@ -1,3 +1,4 @@
import 'package:flowy_infra/colorscheme/default_colorscheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'colorscheme.dart'; import 'colorscheme.dart';
@ -81,6 +82,9 @@ class DandelionColorScheme extends FlowyColorScheme {
toggleButtonBGColor: _lightDandelionYellow, toggleButtonBGColor: _lightDandelionYellow,
calendarWeekendBGColor: const Color(0xFFFBFBFC), calendarWeekendBGColor: const Color(0xFFFBFBFC),
gridRowCountColor: _black, gridRowCountColor: _black,
borderColor: ColorSchemeConstants.lightBorderColor,
scrollbarColor: const Color(0x3F171717),
scrollbarHoverColor: const Color(0x7F171717),
); );
const DandelionColorScheme.dark() const DandelionColorScheme.dark()
@ -135,5 +139,8 @@ class DandelionColorScheme extends FlowyColorScheme {
toggleButtonBGColor: _darkShader1, toggleButtonBGColor: _darkShader1,
calendarWeekendBGColor: const Color(0xff121212), calendarWeekendBGColor: const Color(0xff121212),
gridRowCountColor: _darkMain1, gridRowCountColor: _darkMain1,
borderColor: ColorSchemeConstants.darkBorderColor,
scrollbarColor: const Color(0x40FFFFFF),
scrollbarHoverColor: const Color(0x80FFFFFF),
); );
} }

View File

@ -2,44 +2,48 @@ import 'package:flutter/material.dart';
import 'colorscheme.dart'; import 'colorscheme.dart';
const _white = Color(0xFFFFFFFF); class ColorSchemeConstants {
const _lightHover = Color(0xFFe0f8FF); static const white = Color(0xFFFFFFFF);
const _lightSelector = Color(0xFFf2fcFF); static const lightHover = Color(0xFFe0f8FF);
const _lightBg1 = Color(0xFFf7f8fc); static const lightSelector = Color(0xFFf2fcFF);
const _lightBg2 = Color(0x0F1F2329); static const lightBg1 = Color(0xFFf7f8fc);
const _lightShader1 = Color(0xFF333333); static const lightBg2 = Color(0x0F1F2329);
const _lightShader3 = Color(0xFF828282); static const lightShader1 = Color(0xFF333333);
const _lightShader5 = Color(0xFFe0e0e0); static const lightShader3 = Color(0xFF828282);
const _lightShader6 = Color(0xFFf2f2f2); static const lightShader5 = Color(0xFFe0e0e0);
const _lightMain1 = Color(0xFF00bcf0); static const lightShader6 = Color(0xFFf2f2f2);
const _lightTint9 = Color(0xFFe1fbFF); static const lightMain1 = Color(0xFF00bcf0);
const _darkShader1 = Color(0xFF131720); static const lightTint9 = Color(0xFFe1fbFF);
const _darkShader2 = Color(0xFF1A202C); static const darkShader1 = Color(0xFF131720);
const _darkShader3 = Color(0xFF363D49); static const darkShader2 = Color(0xFF1A202C);
const _darkShader5 = Color(0xFFBBC3CD); static const darkShader3 = Color(0xFF363D49);
const _darkShader6 = Color(0xFFF2F2F2); static const darkShader5 = Color(0xFFBBC3CD);
const _darkMain1 = Color(0xFF00BCF0); static const darkShader6 = Color(0xFFF2F2F2);
const _darkMain2 = Color(0xFF00BCF0); static const darkMain1 = Color(0xFF00BCF0);
const _darkInput = Color(0xFF282E3A); static const darkMain2 = Color(0xFF00BCF0);
static const darkInput = Color(0xFF282E3A);
static const lightBorderColor = Color(0xFFEDEDEE);
static const darkBorderColor = Color(0xFF3A3F49);
}
class DefaultColorScheme extends FlowyColorScheme { class DefaultColorScheme extends FlowyColorScheme {
const DefaultColorScheme.light() const DefaultColorScheme.light()
: super( : super(
surface: _white, surface: ColorSchemeConstants.white,
hover: _lightHover, hover: ColorSchemeConstants.lightHover,
selector: _lightSelector, selector: ColorSchemeConstants.lightSelector,
red: const Color(0xFFfb006d), red: const Color(0xFFfb006d),
yellow: const Color(0xFFFFd667), yellow: const Color(0xFFFFd667),
green: const Color(0xFF66cf80), green: const Color(0xFF66cf80),
shader1: _lightShader1, shader1: ColorSchemeConstants.lightShader1,
shader2: const Color(0xFF4f4f4f), shader2: const Color(0xFF4f4f4f),
shader3: _lightShader3, shader3: ColorSchemeConstants.lightShader3,
shader4: const Color(0xFFbdbdbd), shader4: const Color(0xFFbdbdbd),
shader5: _lightShader5, shader5: ColorSchemeConstants.lightShader5,
shader6: _lightShader6, shader6: ColorSchemeConstants.lightShader6,
shader7: _lightShader1, shader7: ColorSchemeConstants.lightShader1,
bg1: _lightBg1, bg1: ColorSchemeConstants.lightBg1,
bg2: _lightBg2, bg2: ColorSchemeConstants.lightBg2,
bg3: const Color(0xFFe2e4eb), bg3: const Color(0xFFe2e4eb),
bg4: const Color(0xFF2c144b), bg4: const Color(0xFF2c144b),
tint1: const Color(0xFFe8e0FF), tint1: const Color(0xFFe8e0FF),
@ -50,51 +54,54 @@ class DefaultColorScheme extends FlowyColorScheme {
tint6: const Color(0xFFf5FFdc), tint6: const Color(0xFFf5FFdc),
tint7: const Color(0xFFddFFd6), tint7: const Color(0xFFddFFd6),
tint8: const Color(0xFFdeFFf1), tint8: const Color(0xFFdeFFf1),
tint9: _lightTint9, tint9: ColorSchemeConstants.lightTint9,
main1: _lightMain1, main1: ColorSchemeConstants.lightMain1,
main2: const Color(0xFF00b7ea), main2: const Color(0xFF00b7ea),
shadow: const Color.fromRGBO(0, 0, 0, 0.15), shadow: const Color.fromRGBO(0, 0, 0, 0.15),
sidebarBg: _lightBg1, sidebarBg: ColorSchemeConstants.lightBg1,
divider: _lightShader6, divider: ColorSchemeConstants.lightShader6,
topbarBg: _white, topbarBg: ColorSchemeConstants.white,
icon: _lightShader1, icon: ColorSchemeConstants.lightShader1,
text: _lightShader1, text: ColorSchemeConstants.lightShader1,
secondaryText: const Color(0xFF4f4f4f), secondaryText: const Color(0xFF4f4f4f),
strongText: Colors.black, strongText: Colors.black,
input: _white, input: ColorSchemeConstants.white,
hint: _lightShader3, hint: ColorSchemeConstants.lightShader3,
primary: _lightMain1, primary: ColorSchemeConstants.lightMain1,
onPrimary: _white, onPrimary: ColorSchemeConstants.white,
hoverBG1: _lightBg2, hoverBG1: ColorSchemeConstants.lightBg2,
hoverBG2: _lightHover, hoverBG2: ColorSchemeConstants.lightHover,
hoverBG3: _lightShader6, hoverBG3: ColorSchemeConstants.lightShader6,
hoverFG: _lightShader1, hoverFG: ColorSchemeConstants.lightShader1,
questionBubbleBG: _lightSelector, questionBubbleBG: ColorSchemeConstants.lightSelector,
progressBarBGColor: _lightTint9, progressBarBGColor: ColorSchemeConstants.lightTint9,
toolbarColor: _lightShader1, toolbarColor: ColorSchemeConstants.lightShader1,
toggleButtonBGColor: _lightShader5, toggleButtonBGColor: ColorSchemeConstants.lightShader5,
calendarWeekendBGColor: const Color(0xFFFBFBFC), calendarWeekendBGColor: const Color(0xFFFBFBFC),
gridRowCountColor: _lightShader1, gridRowCountColor: ColorSchemeConstants.lightShader1,
borderColor: ColorSchemeConstants.lightBorderColor,
scrollbarColor: const Color(0x3F171717),
scrollbarHoverColor: const Color(0x7F171717),
); );
const DefaultColorScheme.dark() const DefaultColorScheme.dark()
: super( : super(
surface: _darkShader2, surface: ColorSchemeConstants.darkShader2,
hover: _darkMain1, hover: ColorSchemeConstants.darkMain1,
selector: _darkShader2, selector: ColorSchemeConstants.darkShader2,
red: const Color(0xFFfb006d), red: const Color(0xFFfb006d),
yellow: const Color(0xFFF7CF46), yellow: const Color(0xFFF7CF46),
green: const Color(0xFF66CF80), green: const Color(0xFF66CF80),
shader1: _darkShader1, shader1: ColorSchemeConstants.darkShader1,
shader2: _darkShader2, shader2: ColorSchemeConstants.darkShader2,
shader3: _darkShader3, shader3: ColorSchemeConstants.darkShader3,
shader4: const Color(0xFF505469), shader4: const Color(0xFF505469),
shader5: _darkShader5, shader5: ColorSchemeConstants.darkShader5,
shader6: _darkShader6, shader6: ColorSchemeConstants.darkShader6,
shader7: _white, shader7: ColorSchemeConstants.white,
bg1: const Color(0xFF1A202C), bg1: const Color(0xFF1A202C),
bg2: const Color(0xFFEDEEF2), bg2: const Color(0xFFEDEEF2),
bg3: _darkMain1, bg3: ColorSchemeConstants.darkMain1,
bg4: const Color(0xFF2C144B), bg4: const Color(0xFF2C144B),
tint1: const Color(0x4d9327FF), tint1: const Color(0x4d9327FF),
tint2: const Color(0x66FC0088), tint2: const Color(0x66FC0088),
@ -105,29 +112,32 @@ class DefaultColorScheme extends FlowyColorScheme {
tint7: const Color(0x5900BD2A), tint7: const Color(0x5900BD2A),
tint8: const Color(0x80008890), tint8: const Color(0x80008890),
tint9: const Color(0x4d0029FF), tint9: const Color(0x4d0029FF),
main1: _darkMain2, main1: ColorSchemeConstants.darkMain2,
main2: const Color(0xFF00B7EA), main2: const Color(0xFF00B7EA),
shadow: const Color(0xFF0F131C), shadow: const Color(0xFF0F131C),
sidebarBg: const Color(0xFF232B38), sidebarBg: const Color(0xFF232B38),
divider: _darkShader3, divider: ColorSchemeConstants.darkShader3,
topbarBg: _darkShader1, topbarBg: ColorSchemeConstants.darkShader1,
icon: _darkShader5, icon: ColorSchemeConstants.darkShader5,
text: _darkShader5, text: ColorSchemeConstants.darkShader5,
secondaryText: _darkShader5, secondaryText: ColorSchemeConstants.darkShader5,
strongText: Colors.white, strongText: Colors.white,
input: _darkInput, input: ColorSchemeConstants.darkInput,
hint: const Color(0xFF59647a), hint: const Color(0xFF59647a),
primary: _darkMain2, primary: ColorSchemeConstants.darkMain2,
onPrimary: _darkShader1, onPrimary: ColorSchemeConstants.darkShader1,
hoverBG1: const Color(0x1AFFFFFF), hoverBG1: const Color(0x1AFFFFFF),
hoverBG2: _darkMain1, hoverBG2: ColorSchemeConstants.darkMain1,
hoverBG3: _darkShader3, hoverBG3: ColorSchemeConstants.darkShader3,
hoverFG: const Color(0xE5FFFFFF), hoverFG: const Color(0xE5FFFFFF),
questionBubbleBG: _darkShader3, questionBubbleBG: ColorSchemeConstants.darkShader3,
progressBarBGColor: _darkShader3, progressBarBGColor: ColorSchemeConstants.darkShader3,
toolbarColor: _darkInput, toolbarColor: ColorSchemeConstants.darkInput,
toggleButtonBGColor: const Color(0xFF828282), toggleButtonBGColor: const Color(0xFF828282),
calendarWeekendBGColor: _darkShader1, calendarWeekendBGColor: ColorSchemeConstants.darkShader1,
gridRowCountColor: _darkShader5, gridRowCountColor: ColorSchemeConstants.darkShader5,
borderColor: ColorSchemeConstants.darkBorderColor,
scrollbarColor: const Color(0x40FFFFFF),
scrollbarHoverColor: const Color(0x80FFFFFF),
); );
} }

View File

@ -1,3 +1,4 @@
import 'package:flowy_infra/colorscheme/default_colorscheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'colorscheme.dart'; import 'colorscheme.dart';
@ -77,6 +78,9 @@ class LavenderColorScheme extends FlowyColorScheme {
toggleButtonBGColor: _lightSelector, toggleButtonBGColor: _lightSelector,
calendarWeekendBGColor: const Color(0xFFFBFBFC), calendarWeekendBGColor: const Color(0xFFFBFBFC),
gridRowCountColor: _black, gridRowCountColor: _black,
borderColor: ColorSchemeConstants.lightBorderColor,
scrollbarColor: const Color(0x3F171717),
scrollbarHoverColor: const Color(0x7F171717),
); );
const LavenderColorScheme.dark() const LavenderColorScheme.dark()
@ -131,5 +135,8 @@ class LavenderColorScheme extends FlowyColorScheme {
toggleButtonBGColor: _darkShader1, toggleButtonBGColor: _darkShader1,
calendarWeekendBGColor: const Color(0xff121212), calendarWeekendBGColor: const Color(0xff121212),
gridRowCountColor: _darkMain1, gridRowCountColor: _darkMain1,
borderColor: ColorSchemeConstants.darkBorderColor,
scrollbarColor: const Color(0x40FFFFFF),
scrollbarHoverColor: const Color(0x80FFFFFF),
); );
} }

View File

@ -1,3 +1,4 @@
import 'package:flowy_infra/colorscheme/default_colorscheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'colorscheme.dart'; import 'colorscheme.dart';
@ -83,6 +84,9 @@ class LemonadeColorScheme extends FlowyColorScheme {
toggleButtonBGColor: _lightDandelionYellow, toggleButtonBGColor: _lightDandelionYellow,
calendarWeekendBGColor: const Color(0xFFFBFBFC), calendarWeekendBGColor: const Color(0xFFFBFBFC),
gridRowCountColor: _black, gridRowCountColor: _black,
borderColor: ColorSchemeConstants.lightBorderColor,
scrollbarColor: const Color(0x3F171717),
scrollbarHoverColor: const Color(0x7F171717),
); );
const LemonadeColorScheme.dark() const LemonadeColorScheme.dark()
@ -137,5 +141,8 @@ class LemonadeColorScheme extends FlowyColorScheme {
toggleButtonBGColor: _darkShader1, toggleButtonBGColor: _darkShader1,
calendarWeekendBGColor: const Color(0xff121212), calendarWeekendBGColor: const Color(0xff121212),
gridRowCountColor: _darkMain1, gridRowCountColor: _darkMain1,
borderColor: ColorSchemeConstants.darkBorderColor,
scrollbarColor: const Color(0x40FFFFFF),
scrollbarHoverColor: const Color(0x80FFFFFF),
); );
} }

View File

@ -38,6 +38,9 @@ class AFThemeExtension extends ThemeExtension<AFThemeExtension> {
required this.gridRowCountColor, required this.gridRowCountColor,
required this.background, required this.background,
required this.onBackground, required this.onBackground,
required this.borderColor,
required this.scrollbarColor,
required this.scrollbarHoverColor,
}); });
final Color? warning; final Color? warning;
@ -74,6 +77,14 @@ class AFThemeExtension extends ThemeExtension<AFThemeExtension> {
final Color background; final Color background;
final Color onBackground; final Color onBackground;
/// The color of the border of the widget.
///
/// This is used in the divider, outline border, etc.
final Color borderColor;
final Color scrollbarColor;
final Color scrollbarHoverColor;
@override @override
AFThemeExtension copyWith({ AFThemeExtension copyWith({
Color? warning, Color? warning,
@ -105,6 +116,9 @@ class AFThemeExtension extends ThemeExtension<AFThemeExtension> {
TextStyle? caption, TextStyle? caption,
Color? background, Color? background,
Color? onBackground, Color? onBackground,
Color? borderColor,
Color? scrollbarColor,
Color? scrollbarHoverColor,
}) => }) =>
AFThemeExtension( AFThemeExtension(
warning: warning ?? this.warning, warning: warning ?? this.warning,
@ -137,6 +151,9 @@ class AFThemeExtension extends ThemeExtension<AFThemeExtension> {
caption: caption ?? this.caption, caption: caption ?? this.caption,
onBackground: onBackground ?? this.onBackground, onBackground: onBackground ?? this.onBackground,
background: background ?? this.background, background: background ?? this.background,
borderColor: borderColor ?? this.borderColor,
scrollbarColor: scrollbarColor ?? this.scrollbarColor,
scrollbarHoverColor: scrollbarHoverColor ?? this.scrollbarHoverColor,
); );
@override @override
@ -188,6 +205,10 @@ class AFThemeExtension extends ThemeExtension<AFThemeExtension> {
caption: other.caption, caption: other.caption,
onBackground: Color.lerp(onBackground, other.onBackground, t)!, onBackground: Color.lerp(onBackground, other.onBackground, t)!,
background: Color.lerp(background, other.background, t)!, background: Color.lerp(background, other.background, t)!,
borderColor: Color.lerp(borderColor, other.borderColor, t)!,
scrollbarColor: Color.lerp(scrollbarColor, other.scrollbarColor, t)!,
scrollbarHoverColor:
Color.lerp(scrollbarHoverColor, other.scrollbarHoverColor, t)!,
); );
} }
} }

View File

@ -12,7 +12,9 @@ export 'src/flowy_overlay/option_overlay.dart';
export 'src/keyboard/keyboard_visibility_detector.dart'; export 'src/keyboard/keyboard_visibility_detector.dart';
export 'style_widget/button.dart'; export 'style_widget/button.dart';
export 'style_widget/color_picker.dart'; export 'style_widget/color_picker.dart';
export 'style_widget/divider.dart';
export 'style_widget/icon_button.dart'; export 'style_widget/icon_button.dart';
export 'style_widget/scrollbar.dart';
export 'style_widget/scrolling/styled_list.dart'; export 'style_widget/scrolling/styled_list.dart';
export 'style_widget/scrolling/styled_scroll_bar.dart'; export 'style_widget/scrolling/styled_scroll_bar.dart';
export 'style_widget/text.dart'; export 'style_widget/text.dart';

View File

@ -1,5 +1,5 @@
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/style_widget/decoration.dart'; import 'package:flowy_infra/colorscheme/default_colorscheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class AppFlowyPopover extends StatelessWidget { class AppFlowyPopover extends StatelessWidget {
@ -17,7 +17,8 @@ class AppFlowyPopover extends StatelessWidget {
final bool asBarrier; final bool asBarrier;
final EdgeInsets margin; final EdgeInsets margin;
final EdgeInsets windowPadding; final EdgeInsets windowPadding;
final Decoration? decoration; final Color? decorationColor;
final BorderRadius? borderRadius;
/// The widget that will be used to trigger the popover. /// The widget that will be used to trigger the popover.
/// ///
@ -46,9 +47,10 @@ class AppFlowyPopover extends StatelessWidget {
this.asBarrier = false, this.asBarrier = false,
this.margin = const EdgeInsets.all(6), this.margin = const EdgeInsets.all(6),
this.windowPadding = const EdgeInsets.all(8.0), this.windowPadding = const EdgeInsets.all(8.0),
this.decoration,
this.clickHandler = PopoverClickHandler.listener, this.clickHandler = PopoverClickHandler.listener,
this.skipTraversal = false, this.skipTraversal = false,
this.decorationColor,
this.borderRadius,
}); });
@override @override
@ -70,7 +72,8 @@ class AppFlowyPopover extends StatelessWidget {
return _PopoverContainer( return _PopoverContainer(
constraints: constraints, constraints: constraints,
margin: margin, margin: margin,
decoration: decoration, decorationColor: decorationColor,
borderRadius: borderRadius,
child: popupBuilder(context), child: popupBuilder(context),
); );
}, },
@ -81,33 +84,79 @@ class AppFlowyPopover extends StatelessWidget {
class _PopoverContainer extends StatelessWidget { class _PopoverContainer extends StatelessWidget {
const _PopoverContainer({ const _PopoverContainer({
this.decorationColor,
this.borderRadius,
required this.child, required this.child,
required this.margin, required this.margin,
required this.constraints, required this.constraints,
required this.decoration,
}); });
final Widget child; final Widget child;
final BoxConstraints constraints; final BoxConstraints constraints;
final EdgeInsets margin; final EdgeInsets margin;
final Decoration? decoration; final Color? decorationColor;
final BorderRadius? borderRadius;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final decoration = this.decoration ??
FlowyDecoration.decoration(
Theme.of(context).cardColor,
Theme.of(context).colorScheme.shadow,
);
return Material( return Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: Container( child: Container(
padding: margin, padding: margin,
decoration: decoration, decoration: context.getPopoverDecoration(
color: decorationColor,
borderRadius: borderRadius,
),
constraints: constraints, constraints: constraints,
child: child, child: child,
), ),
); );
} }
} }
extension on BuildContext {
/// The decoration of the popover.
///
/// Don't customize the entire decoration of the popover,
/// use the built-in popoverDecoration instead and ask the designer before changing it.
ShapeDecoration getPopoverDecoration({
Color? color,
BorderRadius? borderRadius,
}) {
final borderColor = Theme.of(this).brightness == Brightness.light
? ColorSchemeConstants.lightBorderColor
: ColorSchemeConstants.darkBorderColor;
final shadows = [
const BoxShadow(
color: Color(0x0A1F2329),
blurRadius: 24,
offset: Offset(0, 8),
spreadRadius: 8,
),
const BoxShadow(
color: Color(0x0A1F2329),
blurRadius: 12,
offset: Offset(0, 6),
spreadRadius: 0,
),
const BoxShadow(
color: Color(0x0F1F2329),
blurRadius: 8,
offset: Offset(0, 4),
spreadRadius: -8,
)
];
return ShapeDecoration(
color: color ?? Theme.of(this).cardColor,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
strokeAlign: BorderSide.strokeAlignOutside,
color: borderColor,
),
borderRadius: borderRadius ?? BorderRadius.circular(10),
),
shadows: shadows,
);
}
}

View File

@ -1,13 +1,141 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flowy_infra_ui/widget/ignore_parent_gesture.dart'; import 'package:flowy_infra_ui/widget/ignore_parent_gesture.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
class FlowyIconTextButton extends StatelessWidget {
final Widget Function(bool onHover) textBuilder;
final VoidCallback? onTap;
final VoidCallback? onSecondaryTap;
final void Function(bool)? onHover;
final EdgeInsets? margin;
final Widget Function(bool onHover)? leftIconBuilder;
final Widget Function(bool onHover)? rightIconBuilder;
final Color? hoverColor;
final bool isSelected;
final BorderRadius? radius;
final BoxDecoration? decoration;
final bool useIntrinsicWidth;
final bool disable;
final double disableOpacity;
final Size? leftIconSize;
final bool expandText;
final MainAxisAlignment mainAxisAlignment;
final bool showDefaultBoxDecorationOnMobile;
final double iconPadding;
final bool expand;
final Color? borderColor;
const FlowyIconTextButton({
super.key,
required this.textBuilder,
this.onTap,
this.onSecondaryTap,
this.onHover,
this.margin,
this.leftIconBuilder,
this.rightIconBuilder,
this.hoverColor,
this.isSelected = false,
this.radius,
this.decoration,
this.useIntrinsicWidth = false,
this.disable = false,
this.disableOpacity = 0.5,
this.leftIconSize = const Size.square(16),
this.expandText = true,
this.mainAxisAlignment = MainAxisAlignment.center,
this.showDefaultBoxDecorationOnMobile = false,
this.iconPadding = 6,
this.expand = false,
this.borderColor,
});
@override
Widget build(BuildContext context) {
final color = hoverColor ?? Theme.of(context).colorScheme.secondary;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: disable ? null : onTap,
onSecondaryTap: disable ? null : onSecondaryTap,
child: FlowyHover(
cursor:
disable ? SystemMouseCursors.forbidden : SystemMouseCursors.click,
style: HoverStyle(
borderRadius: radius ?? Corners.s6Border,
hoverColor: color,
borderColor: borderColor ?? Colors.transparent,
),
onHover: disable ? null : onHover,
isSelected: () => isSelected,
builder: (context, onHover) => _render(context, onHover),
),
);
}
Widget _render(BuildContext context, bool onHover) {
final List<Widget> children = [];
if (leftIconBuilder != null) {
children.add(
SizedBox.fromSize(
size: leftIconSize,
child: leftIconBuilder!(onHover),
),
);
children.add(HSpace(iconPadding));
}
if (expandText) {
children.add(Expanded(child: textBuilder(onHover)));
} else {
children.add(textBuilder(onHover));
}
if (rightIconBuilder != null) {
children.add(HSpace(iconPadding));
// No need to define the size of rightIcon. Just use its intrinsic width
children.add(rightIconBuilder!(onHover));
}
Widget child = Row(
mainAxisAlignment: mainAxisAlignment,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: expand ? MainAxisSize.max : MainAxisSize.min,
children: children,
);
if (useIntrinsicWidth) {
child = IntrinsicWidth(child: child);
}
final decoration = this.decoration ??
(showDefaultBoxDecorationOnMobile &&
(Platform.isIOS || Platform.isAndroid)
? BoxDecoration(
border: Border.all(
color: borderColor ??
Theme.of(context).colorScheme.surfaceContainerHighest,
width: 1.0,
))
: null);
return Container(
decoration: decoration,
child: Padding(
padding:
margin ?? const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
child: child,
),
);
}
}
class FlowyButton extends StatelessWidget { class FlowyButton extends StatelessWidget {
final Widget text; final Widget text;
@ -30,6 +158,7 @@ class FlowyButton extends StatelessWidget {
final bool showDefaultBoxDecorationOnMobile; final bool showDefaultBoxDecorationOnMobile;
final double iconPadding; final double iconPadding;
final bool expand; final bool expand;
final Color? borderColor;
const FlowyButton({ const FlowyButton({
super.key, super.key,
@ -53,6 +182,7 @@ class FlowyButton extends StatelessWidget {
this.showDefaultBoxDecorationOnMobile = false, this.showDefaultBoxDecorationOnMobile = false,
this.iconPadding = 6, this.iconPadding = 6,
this.expand = false, this.expand = false,
this.borderColor,
}); });
@override @override
@ -80,6 +210,7 @@ class FlowyButton extends StatelessWidget {
style: HoverStyle( style: HoverStyle(
borderRadius: radius ?? Corners.s6Border, borderRadius: radius ?? Corners.s6Border,
hoverColor: color, hoverColor: color,
borderColor: borderColor ?? Colors.transparent,
), ),
onHover: disable ? null : onHover, onHover: disable ? null : onHover,
isSelected: () => isSelected, isSelected: () => isSelected,
@ -129,7 +260,8 @@ class FlowyButton extends StatelessWidget {
(Platform.isIOS || Platform.isAndroid) (Platform.isIOS || Platform.isAndroid)
? BoxDecoration( ? BoxDecoration(
border: Border.all( border: Border.all(
color: Theme.of(context).colorScheme.surfaceContainerHighest, color: borderColor ??
Theme.of(context).colorScheme.surfaceContainerHighest,
width: 1.0, width: 1.0,
)) ))
: null); : null);

View File

@ -8,6 +8,7 @@ class FlowyDecoration {
double blurRadius = 20, double blurRadius = 20,
Offset offset = Offset.zero, Offset offset = Offset.zero,
double borderRadius = 6, double borderRadius = 6,
BoxBorder? border,
}) { }) {
return BoxDecoration( return BoxDecoration(
color: boxColor, color: boxColor,
@ -20,6 +21,7 @@ class FlowyDecoration {
offset: offset, offset: offset,
), ),
], ],
border: border,
); );
} }
} }

View File

@ -0,0 +1,17 @@
import 'package:flowy_infra/theme_extension.dart';
import 'package:flutter/material.dart';
class FlowyDivider extends StatelessWidget {
const FlowyDivider({
super.key,
});
@override
Widget build(BuildContext context) {
return Divider(
height: 1.0,
thickness: 1.0,
color: AFThemeExtension.of(context).borderColor,
);
}
}

View File

@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
class FlowyScrollbar extends StatefulWidget {
const FlowyScrollbar({
super.key,
this.controller,
required this.child,
});
final ScrollController? controller;
final Widget child;
@override
State<FlowyScrollbar> createState() => _FlowyScrollbarState();
}
class _FlowyScrollbarState extends State<FlowyScrollbar> {
final ValueNotifier<bool> isHovered = ValueNotifier(false);
@override
void dispose() {
isHovered.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (_) => isHovered.value = true,
onExit: (_) => isHovered.value = false,
child: ValueListenableBuilder(
valueListenable: isHovered,
builder: (context, isHovered, child) {
return Scrollbar(
thumbVisibility: isHovered,
// the radius should be fixed to 12
radius: const Radius.circular(12),
controller: widget.controller,
child: ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(
scrollbars: false,
),
child: child!,
),
);
},
child: widget.child,
),
);
}
}

View File

@ -1,12 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart';
import 'package:async/async.dart'; import 'package:async/async.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/widget/mouse_hover_builder.dart'; import 'package:flowy_infra_ui/widget/mouse_hover_builder.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
class StyledScrollbar extends StatefulWidget { class StyledScrollbar extends StatefulWidget {
@ -120,11 +119,6 @@ class ScrollbarState extends State<StyledScrollbar> {
? false ? false
: contentExtent > _viewExtent && contentExtent > 0; : contentExtent > _viewExtent && contentExtent > 0;
// Handle color
var handleColor = widget.handleColor ??
(Theme.of(context).brightness == Brightness.dark
? AFThemeExtension.of(context).lightGreyHover
: AFThemeExtension.of(context).greyHover);
// Track color // Track color
var trackColor = widget.trackColor ?? var trackColor = widget.trackColor ??
(Theme.of(context).brightness == Brightness.dark (Theme.of(context).brightness == Brightness.dark
@ -161,18 +155,24 @@ class ScrollbarState extends State<StyledScrollbar> {
onHorizontalDragUpdate: _handleHorizontalDrag, onHorizontalDragUpdate: _handleHorizontalDrag,
// HANDLE SHAPE // HANDLE SHAPE
child: MouseHoverBuilder( child: MouseHoverBuilder(
builder: (_, isHovered) => Container( builder: (_, isHovered) {
width: widget.axis == Axis.vertical final handleColor =
? widget.size Theme.of(context).scrollbarTheme.thumbColor?.resolve(
: handleExtent, isHovered ? {WidgetState.dragged} : {},
height: widget.axis == Axis.horizontal );
? widget.size return Container(
: handleExtent, width: widget.axis == Axis.vertical
decoration: BoxDecoration( ? widget.size
color: handleColor.withOpacity(isHovered ? 1 : .85), : handleExtent,
borderRadius: Corners.s3Border, height: widget.axis == Axis.horizontal
), ? widget.size
), : handleExtent,
decoration: BoxDecoration(
color: handleColor,
borderRadius: Corners.s3Border,
),
);
},
), ),
), ),
) )

View File

@ -1,7 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
class FlowyText extends StatelessWidget { class FlowyText extends StatelessWidget {
@ -20,6 +19,7 @@ class FlowyText extends StatelessWidget {
final bool withTooltip; final bool withTooltip;
final StrutStyle? strutStyle; final StrutStyle? strutStyle;
final bool isEmoji; final bool isEmoji;
final double? figmaLineHeight;
const FlowyText( const FlowyText(
this.text, { this.text, {
@ -38,6 +38,7 @@ class FlowyText extends StatelessWidget {
this.withTooltip = false, this.withTooltip = false,
this.isEmoji = false, this.isEmoji = false,
this.strutStyle, this.strutStyle,
this.figmaLineHeight,
}); });
FlowyText.small( FlowyText.small(
@ -55,6 +56,7 @@ class FlowyText extends StatelessWidget {
this.withTooltip = false, this.withTooltip = false,
this.isEmoji = false, this.isEmoji = false,
this.strutStyle, this.strutStyle,
this.figmaLineHeight,
}) : fontWeight = FontWeight.w400, }) : fontWeight = FontWeight.w400,
fontSize = (Platform.isIOS || Platform.isAndroid) ? 14 : 12; fontSize = (Platform.isIOS || Platform.isAndroid) ? 14 : 12;
@ -74,6 +76,7 @@ class FlowyText extends StatelessWidget {
this.withTooltip = false, this.withTooltip = false,
this.isEmoji = false, this.isEmoji = false,
this.strutStyle, this.strutStyle,
this.figmaLineHeight,
}) : fontWeight = FontWeight.w400; }) : fontWeight = FontWeight.w400;
const FlowyText.medium( const FlowyText.medium(
@ -92,6 +95,7 @@ class FlowyText extends StatelessWidget {
this.withTooltip = false, this.withTooltip = false,
this.isEmoji = false, this.isEmoji = false,
this.strutStyle, this.strutStyle,
this.figmaLineHeight,
}) : fontWeight = FontWeight.w500; }) : fontWeight = FontWeight.w500;
const FlowyText.semibold( const FlowyText.semibold(
@ -110,6 +114,7 @@ class FlowyText extends StatelessWidget {
this.withTooltip = false, this.withTooltip = false,
this.isEmoji = false, this.isEmoji = false,
this.strutStyle, this.strutStyle,
this.figmaLineHeight,
}) : fontWeight = FontWeight.w600; }) : fontWeight = FontWeight.w600;
// Some emojis are not supported on Linux and Android, fallback to noto color emoji // Some emojis are not supported on Linux and Android, fallback to noto color emoji
@ -128,6 +133,7 @@ class FlowyText extends StatelessWidget {
this.strutStyle = const StrutStyle(forceStrutHeight: true), this.strutStyle = const StrutStyle(forceStrutHeight: true),
this.isEmoji = true, this.isEmoji = true,
this.fontFamily, this.fontFamily,
this.figmaLineHeight,
}) : fontWeight = FontWeight.w400, }) : fontWeight = FontWeight.w400,
fallbackFontFamily = null; fallbackFontFamily = null;
@ -150,6 +156,13 @@ class FlowyText extends StatelessWidget {
fontSize = fontSize * 0.8; fontSize = fontSize * 0.8;
} }
double? lineHeight;
if (this.lineHeight != null) {
lineHeight = this.lineHeight!;
} else if (figmaLineHeight != null) {
lineHeight = figmaLineHeight! / fontSize;
}
final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith( final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: fontSize, fontSize: fontSize,
fontWeight: fontWeight, fontWeight: fontWeight,

View File

@ -26,21 +26,47 @@ class FlowyTooltip extends StatelessWidget {
return child ?? const SizedBox.shrink(); return child ?? const SizedBox.shrink();
} }
final isLightMode = Theme.of(context).brightness == Brightness.light;
return Tooltip( return Tooltip(
margin: margin, margin: margin,
verticalOffset: 16.0, verticalOffset: 16.0,
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), padding: const EdgeInsets.only(
left: 12.0,
right: 12.0,
top: 5.0,
bottom: 8.0,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isLightMode ? const Color(0xE5171717) : const Color(0xE5E5E5E5), color: context.tooltipBackgroundColor(),
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(12.0),
), ),
waitDuration: _tooltipWaitDuration, waitDuration: _tooltipWaitDuration,
message: message, message: message,
textStyle: message != null ? context.tooltipTextStyle() : null,
richMessage: richMessage, richMessage: richMessage,
showDuration: showDuration,
preferBelow: preferBelow, preferBelow: preferBelow,
child: child, child: child,
); );
} }
} }
extension FlowyToolTipExtension on BuildContext {
double tooltipFontSize() => 13.0;
double tooltipHeight() => 18.0 / tooltipFontSize();
Color tooltipFontColor() => Theme.of(this).brightness == Brightness.light
? Colors.white
: Colors.black;
TextStyle? tooltipTextStyle({Color? fontColor}) {
return Theme.of(this).textTheme.bodyMedium?.copyWith(
color: fontColor ?? tooltipFontColor(),
fontSize: tooltipFontSize(),
fontWeight: FontWeight.w400,
height: tooltipHeight(),
);
}
Color tooltipBackgroundColor() =>
Theme.of(this).brightness == Brightness.light
? const Color(0xFF1D2129)
: const Color(0xE5E5E5E5);
}

View File

@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.6.5 version: 0.6.6
environment: environment:
flutter: ">=3.22.0" flutter: ">=3.22.0"

View File

@ -1,5 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5"> <g opacity="0.5">
<path d="M8.38274 2.1912C8.61919 1.95467 8.99451 1.91977 9.2623 2.18766L14.145 7.07205C14.3765 7.30363 14.411 7.68431 14.1468 7.94865C13.9854 8.11011 13.5919 8.23414 13.2876 7.92972L12.5611 7.20735L10.6204 9.1481C10.5628 9.20571 10.5477 9.30158 10.5477 9.38042L10.2799 13.2031C10.2799 13.285 10.2475 13.3638 10.1899 13.4214L9.84485 13.7657C9.60524 14.0063 9.21857 14.0071 8.98279 13.7713L6.20394 10.9936L3.37596 13.8224C3.1392 14.0592 2.75536 14.0592 2.51861 13.8224L2.5096 13.8134C2.27301 13.5767 2.27282 13.193 2.50916 12.9561L5.33522 10.1233L2.5568 7.34311C2.31101 7.09723 2.31763 6.71613 2.55769 6.47598L2.90214 6.13221C2.95976 6.07459 3.03787 6.04124 3.11932 6.04124L6.94541 5.77806C7.02695 5.77806 7.13094 5.77049 7.18854 5.71288L9.12891 3.77213L8.40493 3.04532C8.17437 2.81725 8.15367 2.42036 8.38274 2.1912Z" fill="#171717"/> <path d="M4.21594 1C3.79948 1 3.53477 1.31897 3.53477 1.68668C3.53477 2.04293 3.85938 2.33534 4.21594 2.33333L5.34384 2.33534L5.3436 5.35268C5.3436 5.44225 5.26862 5.52899 5.20522 5.59239L2.43472 8.77204C2.37139 8.83537 2.33657 8.92204 2.33655 9.01163L2.33594 9.54668C2.33594 9.92001 2.62702 10.2214 3.00927 10.2214L7.33078 10.2221L7.33526 14.4C7.33563 14.7679 7.634 15 8.00193 15H8.01594C8.38412 15 8.68259 14.7682 8.6826 14.4L8.68275 10.223L13.0026 10.2213C13.3693 10.2213 13.6693 9.92001 13.6686 9.54668L13.6693 9.01078C13.6693 8.92122 13.6332 8.83471 13.5696 8.77107L10.8064 5.59145C10.7452 5.53017 10.6824 5.4439 10.6824 5.35433L10.6829 2.33676L11.8093 2.33334C12.2825 2.33334 12.492 1.93102 12.492 1.68001C12.492 1.26906 12.1693 1.00001 11.8093 1H4.21594ZM6.70711 2.33483L9.37687 2.33333L9.38048 5.94579L11.9314 8.89026L4.13249 8.88794L6.70923 5.93339L6.70711 2.33483Z" fill="#2B2F36"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 960 B

After

Width:  |  Height:  |  Size: 1019 B

View File

@ -1,5 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5"> <g opacity="0.5">
<path d="M9.2623 2.18766C8.99451 1.91977 8.61919 1.95467 8.38274 2.1912C8.15367 2.42036 8.17437 2.81725 8.40493 3.04532L9.12891 3.77213L7.18854 5.71288C7.13094 5.77049 7.02695 5.77806 6.94541 5.77806L3.11932 6.04124C3.03787 6.04124 2.95976 6.07459 2.90214 6.13221L2.55769 6.47598C2.31763 6.71613 2.31101 7.09723 2.5568 7.34311L5.33522 10.1233L2.50916 12.9561C2.27282 13.193 2.27301 13.5767 2.5096 13.8134L2.51861 13.8224C2.75536 14.0592 3.1392 14.0592 3.37596 13.8224L6.20394 10.9936L8.98279 13.7713C9.21857 14.0071 9.60524 14.0063 9.84485 13.7657L10.1899 13.4214C10.2475 13.3638 10.2799 13.285 10.2799 13.2031L10.5477 9.38042C10.5477 9.30159 10.5628 9.20571 10.6204 9.1481L12.5611 7.20735L13.2876 7.92972C13.5919 8.23414 13.9854 8.11011 14.1468 7.94865C14.411 7.68431 14.3765 7.30363 14.145 7.07205L9.2623 2.18766ZM10.0059 4.64872L11.7235 6.36508L9.40296 8.69111L9.14988 12.226L4.1365 7.20788L7.69325 6.96485L10.0059 4.64872Z" fill="#171717"/> <path d="M2.42691 8.77204L4.58617 6.2939L5.54809 7.25582L4.12467 8.88794L7.18111 8.88885L8.67493 10.3827L8.67479 14.6208C8.67478 14.989 8.37631 15.2875 8.00813 15.2875H7.99411C7.62619 15.2875 7.32782 14.9894 7.32745 14.6215L7.32297 10.2221L3.00146 10.2214C2.61921 10.2214 2.32812 9.92001 2.32812 9.54668L2.32874 9.01163C2.32876 8.92204 2.36357 8.83537 2.42691 8.77204Z" fill="#171717"/>
<path d="M11.9236 8.89026L11.9012 8.89025L13.1997 10.1888C13.4669 10.1012 13.6613 9.8473 13.6608 9.54668L13.6615 9.01078C13.6615 8.92122 13.6254 8.83471 13.5618 8.77107L10.7986 5.59145C10.7374 5.53017 10.6746 5.4439 10.6746 5.35433L10.675 2.33675L11.8015 2.33334C12.2747 2.33334 12.4842 1.93102 12.4842 1.68001C12.4842 1.26906 12.1615 1.00001 11.8015 1H4.20813C4.14572 1 4.08673 1.00716 4.03152 1.02058L6.70009 3.68915L6.6993 2.33483L9.36906 2.33333L9.37267 5.94579L11.9236 8.89026Z" fill="#171717"/>
</g> </g>
<path opacity="0.5" d="M1.79688 1.2002L14.1712 13.5746" stroke="#171717" stroke-width="1.2" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,3 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.4" fill-rule="evenodd" clip-rule="evenodd" d="M8.78714 4.75039V4.16515C8.78714 3.42984 8.6 1.25 5.99904 1.25C3.3 1.25 3.21094 3.42984 3.21094 4.16515V4.75039L3.38817 4.73529L3.2119 4.75123C2.30484 4.99873 2 5.7229 2 7.29041V8.20709C2 10.2238 2.50558 10.9996 4.14127 10.9996H7.85873C9.49442 10.9996 10 10.2238 10 8.20709V7.29041C10 5.7229 9.69516 4.99873 8.7881 4.75123L8.64331 4.73813L8.78714 4.75039ZM4.32618 4.16515V4.65048L7.6719 4.65039V4.16515C7.6719 3.0108 7.3 2.3002 5.99904 2.3002C4.65 2.3002 4.32618 3.0108 4.32618 4.16515ZM6.00078 8.95078C6.66352 8.95078 7.20078 8.41352 7.20078 7.75078C7.20078 7.08804 6.66352 6.55078 6.00078 6.55078C5.33804 6.55078 4.80078 7.08804 4.80078 7.75078C4.80078 8.41352 5.33804 8.95078 6.00078 8.95078Z" fill="#171717"/> <path opacity="0.4" fill-rule="evenodd" clip-rule="evenodd" d="M10.2465 5.5418V4.85902C10.2465 4.00116 10.0281 1.45801 6.99367 1.45801C3.84479 1.45801 3.74089 4.00116 3.74089 4.85902V5.5418L3.94766 5.52418L3.74201 5.54277C2.68377 5.83152 2.32812 6.67639 2.32812 8.50516V9.57461C2.32812 11.9274 2.91797 12.8326 4.82627 12.8326H9.16331C11.0716 12.8326 11.6615 11.9274 11.6615 9.57461V8.50516C11.6615 6.67639 11.3058 5.83152 10.2476 5.54277L10.0787 5.5275L10.2465 5.5418ZM5.042 4.85902V5.42523L8.94534 5.42513V4.85902C8.94534 3.51227 8.51146 2.68324 6.99367 2.68324C5.41979 2.68324 5.042 3.51227 5.042 4.85902ZM6.99115 10.4423C7.76434 10.4423 8.39115 9.81545 8.39115 9.04225C8.39115 8.26905 7.76434 7.64225 6.99115 7.64225C6.21795 7.64225 5.59115 8.26905 5.59115 9.04225C5.59115 9.81545 6.21795 10.4423 6.99115 10.4423Z" fill="#171717"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 880 B

After

Width:  |  Height:  |  Size: 937 B

View File

@ -272,7 +272,7 @@
"recent": "Recent", "recent": "Recent",
"today": "Today", "today": "Today",
"thisWeek": "This week", "thisWeek": "This week",
"others": "Other favorites", "others": "Earlier favorites",
"justNow": "just now", "justNow": "just now",
"minutesAgo": "{count} minutes ago", "minutesAgo": "{count} minutes ago",
"lastViewed": "Last viewed", "lastViewed": "Last viewed",
@ -2159,6 +2159,7 @@
"createNewSpace": "Create a new space", "createNewSpace": "Create a new space",
"createSpaceDescription": "Create multiple public and private spaces to better organize your work.", "createSpaceDescription": "Create multiple public and private spaces to better organize your work.",
"spaceName": "Space name", "spaceName": "Space name",
"spaceNamePlaceholder": "e.g. Marketing, Engineering, HR",
"permission": "Permission", "permission": "Permission",
"publicPermission": "Public", "publicPermission": "Public",
"publicPermissionDescription": "All workspace members with full access", "publicPermissionDescription": "All workspace members with full access",