feat: implement new color tokens design (#7684)

* fix: missing AFThemeExtensionV2 on mobile

* feat: add appflowy_ui package
This commit is contained in:
Lucas 2025-04-04 14:41:13 +08:00 committed by Lucas.Xu
parent e870481ef9
commit c34d9c0e1d
91 changed files with 5852 additions and 23 deletions

View file

@ -4,6 +4,7 @@ analyzer:
exclude:
- "**/*.g.dart"
- "**/*.freezed.dart"
- "packages/**/*.dart"
linter:
rules:

View file

@ -181,37 +181,37 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS:
app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0
appflowy_backend: 144c20d8bfb298c4e10fa3fa6701a9f41bf98b88
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
app_links: 3da4c36b46cac3bf24eb897f1a6ce80bda109874
appflowy_backend: 78f6a053f756e6bc29bcc5a2106cbe77b756e97a
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
flowy_infra_ui: 931b73a18b54a392ab6152eebe29a63a30751f53
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
fluttertoast: 76fea30fcf04176325f6864c87306927bd7d2038
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
keyboard_height_plugin: ef70a8181b29f27670e9e2450814ca6b6dc05b05
open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
saver_gallery: 76172dc4bf6b40e66d694948ada9ff402304dd87
saver_gallery: af2d0c762dafda254e0ad025ef0dabd6506cd490
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1
sentry_flutter: a39c2a2d67d5e5b9cb0b94a4985c76dd5b3fc737
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
super_native_extensions: 4916b3c627a9c7fffdc48a23a9eca0b1ac228fa7
sentry_flutter: e24b397f9a61fa5bbefd8279c3b2242ca86faa90
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
webview_flutter_wkwebview: 44d4dee7d7056d5ad185d25b38404436d56c547c
PODFILE CHECKSUM: d0d9b4ff572d8695c38eb3f9b490f55cdfc57eca

View file

@ -4,6 +4,7 @@ import 'package:appflowy/workspace/application/settings/appearance/base_appearan
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/theme_extension_v2.dart';
import 'package:flutter/material.dart';
class MobileAppearance extends BaseAppearance {
@ -29,6 +30,7 @@ class MobileAppearance extends BaseAppearance {
);
final codeFontStyle = getFontStyle(fontFamily: codeFontFamily);
final isLight = brightness == Brightness.light;
final theme = brightness == Brightness.light
? appTheme.lightTheme
@ -283,6 +285,11 @@ class MobileAppearance extends BaseAppearance {
toolbarHoverColor: theme.toolbarHoverColor,
),
ToolbarColorExtension.fromBrightness(brightness),
isLight
? lightAFThemeV2
: darkAFThemeV2.copyWith(
icon_primary: theme.icon,
),
],
);
}

View file

@ -0,0 +1,31 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
build/

View file

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "d8a9f9a52e5af486f80d932e838ee93861ffd863"
channel: "[user-branch]"
project_type: package

View file

@ -0,0 +1,3 @@
## 0.0.1
* TODO: Describe initial release.

View file

@ -0,0 +1 @@
TODO: Add your license here.

View file

@ -0,0 +1,39 @@
# AppFlowy UI
AppFlowy UI is a Flutter package that provides a collection of reusable UI components following the AppFlowy design system. These components are designed to be consistent, accessible, and easy to use.
## Features
- **Design System Components**: Buttons, text fields, and more UI components that follow the AppFlowy design system
- **Theming**: Consistent theming across all components with light and dark mode support
## Installation
Add the following to your *app's* `pubspec.yaml` file:
```yaml
dependencies:
appflowy_ui: ^1.0.0
```
## Supported components
- [x] Button
- [x] TextField
- [ ] Avatar
- [ ] Checkbox
- [ ] Grid
- [ ] Link
- [ ] Loading & Progress Indicator
- [ ] Menu
- [ ] Message Box
- [ ] Navigation Bar
- [ ] Popover
- [ ] Scroll Bar
- [ ] Tab Bar
- [ ] Toggle
- [ ] Tooltip
## Reference
Figma: https://www.figma.com/design/aphWa2OgkqyIragpatdk7a/Design-System

View file

@ -0,0 +1,29 @@
include: package:flutter_lints/flutter.yaml
linter:
rules:
- require_trailing_commas
- prefer_collection_literals
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- sized_box_for_whitespace
- use_decorated_box
- unnecessary_parenthesis
- unnecessary_await_in_return
- unnecessary_raw_strings
- avoid_unnecessary_containers
- avoid_redundant_argument_values
- avoid_unused_constructor_parameters
- always_declare_return_types
- sort_constructors_first
- unawaited_futures
errors:
invalid_annotation_target: ignore

View file

@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

View file

@ -0,0 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "d8a9f9a52e5af486f80d932e838ee93861ffd863"
channel: "[user-branch]"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
- platform: macos
create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View file

@ -0,0 +1,41 @@
# AppFlowy UI Example
This example demonstrates how to use the `appflowy_ui` package in a Flutter application.
## Getting Started
To run this example:
1. Ensure you have Flutter installed and set up on your machine
2. Clone this repository
3. Navigate to the example directory:
```bash
cd example
```
4. Get the dependencies:
```bash
flutter pub get
```
5. Run the example:
```bash
flutter run
```
## Features Demonstrated
- Basic app structure using AppFlowy UI components
- Material 3 design integration
- Responsive layout
## Project Structure
- `lib/main.dart`: The main application file
- `pubspec.yaml`: Project dependencies and configuration
## Additional Resources
For more information about the AppFlowy UI package, please refer to:
- The main package documentation
- [AppFlowy Website](https://appflowy.io)
- [AppFlowy GitHub Repository](https://github.com/AppFlowy-IO/AppFlowy)

View file

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View file

@ -0,0 +1,109 @@
import 'package:appflowy_ui/appflowy_ui.dart';
import 'package:appflowy_ui_example/src/buttons/buttons_page.dart';
import 'package:appflowy_ui_example/src/textfield/textfield_page.dart';
import 'package:flutter/material.dart';
enum ThemeMode {
light,
dark,
}
final themeMode = ValueNotifier(ThemeMode.light);
void main() {
runApp(
const MyApp(),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: themeMode,
builder: (context, themeMode, child) {
return AppFlowyTheme(
data: themeMode == ThemeMode.light
? AppFlowyThemeData.light()
: AppFlowyThemeData.dark(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'AppFlowy UI Example',
theme: themeMode == ThemeMode.light
? ThemeData.light()
: ThemeData.dark(),
home: const MyHomePage(
title: 'AppFlowy UI',
),
),
);
},
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
super.key,
required this.title,
});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final tabs = [
Tab(text: 'Button'),
Tab(text: 'TextField'),
];
@override
Widget build(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return DefaultTabController(
length: tabs.length,
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(
widget.title,
style: theme.textStyle.title.enhanced(
color: theme.textColorScheme.primary,
),
),
actions: [
IconButton(
icon: Icon(
theme.brightness == Brightness.light
? Icons.dark_mode
: Icons.light_mode,
),
onPressed: _toggleTheme,
tooltip: 'Toggle theme',
),
],
),
body: TabBarView(
children: [
ButtonsPage(),
TextFieldPage(),
],
),
bottomNavigationBar: TabBar(
tabs: tabs,
),
floatingActionButton: null,
),
);
}
void _toggleTheme() {
themeMode.value =
themeMode.value == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
}
}

View file

@ -0,0 +1,287 @@
import 'package:appflowy_ui/appflowy_ui.dart';
import 'package:flutter/material.dart';
class ButtonsPage extends StatelessWidget {
const ButtonsPage({super.key});
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSection(
'Filled Text Buttons',
[
AFFilledTextButton.primary(
text: 'Primary Button',
onTap: () {},
),
const SizedBox(width: 16),
AFFilledTextButton.destructive(
text: 'Destructive Button',
onTap: () {},
),
const SizedBox(width: 16),
AFFilledTextButton.disabled(
text: 'Disabled Button',
),
],
),
const SizedBox(height: 32),
_buildSection(
'Filled Icon Text Buttons',
[
AFFilledButton.primary(
onTap: () {},
builder: (context, isHovering, disabled) => Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.add,
size: 20,
color: AppFlowyTheme.of(context).textColorScheme.onFill,
),
const SizedBox(width: 8),
Text(
'Primary Button',
style: TextStyle(
color: AppFlowyTheme.of(context).textColorScheme.onFill,
),
),
],
),
),
const SizedBox(width: 16),
AFFilledButton.destructive(
onTap: () {},
builder: (context, isHovering, disabled) => Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.delete,
size: 20,
color: AppFlowyTheme.of(context).textColorScheme.onFill,
),
const SizedBox(width: 8),
Text(
'Destructive Button',
style: TextStyle(
color: AppFlowyTheme.of(context).textColorScheme.onFill,
),
),
],
),
),
const SizedBox(width: 16),
AFFilledButton.disabled(
builder: (context, isHovering, disabled) => Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.block,
size: 20,
color: AppFlowyTheme.of(context).textColorScheme.tertiary,
),
const SizedBox(width: 8),
Text(
'Disabled Button',
style: TextStyle(
color:
AppFlowyTheme.of(context).textColorScheme.tertiary,
),
),
],
),
),
],
),
const SizedBox(height: 32),
_buildSection(
'Outlined Text Buttons',
[
AFOutlinedTextButton.normal(
text: 'Normal Button',
onTap: () {},
),
const SizedBox(width: 16),
AFOutlinedTextButton.destructive(
text: 'Destructive Button',
onTap: () {},
),
const SizedBox(width: 16),
AFOutlinedTextButton.disabled(
text: 'Disabled Button',
),
],
),
const SizedBox(height: 32),
_buildSection(
'Outlined Icon Text Buttons',
[
AFOutlinedButton.normal(
onTap: () {},
builder: (context, isHovering, disabled) => Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.add,
size: 20,
color: AppFlowyTheme.of(context).textColorScheme.primary,
),
const SizedBox(width: 8),
Text(
'Normal Button',
style: TextStyle(
color:
AppFlowyTheme.of(context).textColorScheme.primary,
),
),
],
),
),
const SizedBox(width: 16),
AFOutlinedButton.destructive(
onTap: () {},
builder: (context, isHovering, disabled) => Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.delete,
size: 20,
color: AppFlowyTheme.of(context).textColorScheme.error,
),
const SizedBox(width: 8),
Text(
'Destructive Button',
style: TextStyle(
color: AppFlowyTheme.of(context).textColorScheme.error,
),
),
],
),
),
const SizedBox(width: 16),
AFOutlinedButton.disabled(
builder: (context, isHovering, disabled) => Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.block,
size: 20,
color: AppFlowyTheme.of(context).textColorScheme.tertiary,
),
const SizedBox(width: 8),
Text(
'Disabled Button',
style: TextStyle(
color:
AppFlowyTheme.of(context).textColorScheme.tertiary,
),
),
],
),
),
],
),
const SizedBox(height: 32),
_buildSection(
'Ghost Buttons',
[
AFGhostTextButton.primary(
text: 'Primary Button',
onTap: () {},
),
const SizedBox(width: 16),
AFGhostTextButton.disabled(
text: 'Disabled Button',
),
],
),
const SizedBox(height: 32),
_buildSection(
'Button with alignment',
[
SizedBox(
width: 200,
child: AFFilledTextButton.primary(
text: 'Left Button',
onTap: () {},
alignment: Alignment.centerLeft,
),
),
const SizedBox(width: 16),
SizedBox(
width: 200,
child: AFFilledTextButton.primary(
text: 'Center Button',
onTap: () {},
alignment: Alignment.center,
),
),
const SizedBox(width: 16),
SizedBox(
width: 200,
child: AFFilledTextButton.primary(
text: 'Right Button',
onTap: () {},
alignment: Alignment.centerRight,
),
),
],
),
const SizedBox(height: 32),
_buildSection(
'Button Sizes',
[
AFFilledTextButton.primary(
text: 'Small Button',
onTap: () {},
size: AFButtonSize.s,
),
const SizedBox(width: 16),
AFFilledTextButton.primary(
text: 'Medium Button',
onTap: () {},
),
const SizedBox(width: 16),
AFFilledTextButton.primary(
text: 'Large Button',
onTap: () {},
size: AFButtonSize.l,
),
const SizedBox(width: 16),
AFFilledTextButton.primary(
text: 'Extra Large Button',
onTap: () {},
size: AFButtonSize.xl,
),
],
),
],
),
);
}
Widget _buildSection(String title, List<Widget> children) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: children,
),
],
);
}
}

View file

@ -0,0 +1,77 @@
import 'package:appflowy_ui/appflowy_ui.dart';
import 'package:flutter/material.dart';
class TextFieldPage extends StatelessWidget {
const TextFieldPage({super.key});
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSection(
'TextField with hint text',
[
AFTextField(
hintText: 'Please enter your name',
),
],
),
const SizedBox(height: 32),
_buildSection(
'TextField with initial text',
[
AFTextField(
initialText: 'https://appflowy.com',
),
],
),
const SizedBox(height: 32),
_buildSection(
'TextField with validator ',
[
AFTextField(
validator: (controller) {
if (controller.text.isEmpty) {
return (true, 'This field is required');
}
final emailRegex =
RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(controller.text)) {
return (true, 'Please enter a valid email address');
}
return (false, '');
},
),
],
),
],
),
);
}
Widget _buildSection(String title, List<Widget> children) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: children,
),
],
);
}
}

View file

@ -0,0 +1,7 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/

View file

@ -0,0 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -0,0 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -0,0 +1,705 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC10EC2044A3C60003C045;
remoteInfo = Runner;
};
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* appflowy_ui_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "appflowy_ui_example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
331C80D2294CF70F00263BE5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C80D6294CF71000263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C80D7294CF71000263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
331C80D6294CF71000263BE5 /* RunnerTests */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* appflowy_ui_example.app */,
331C80D5294CF71000263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C80D4294CF70F00263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C80D1294CF70F00263BE5 /* Sources */,
331C80D2294CF70F00263BE5 /* Frameworks */,
331C80D3294CF70F00263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C80DA294CF71000263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* appflowy_ui_example.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C80D4294CF70F00263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 33CC10EC2044A3C60003C045;
};
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
331C80D4294CF70F00263BE5 /* RunnerTests */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C80D3294CF70F00263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C80D1294CF70F00263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C80DA294CF71000263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC10EC2044A3C60003C045 /* Runner */;
targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */;
};
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
331C80DB294CF71000263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.appflowyUiExample.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/appflowy_ui_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/appflowy_ui_example";
};
name = Debug;
};
331C80DC294CF71000263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.appflowyUiExample.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/appflowy_ui_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/appflowy_ui_example";
};
name = Release;
};
331C80DD294CF71000263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.appflowyUiExample.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/appflowy_ui_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/appflowy_ui_example";
};
name = Profile;
};
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C80DB294CF71000263BE5 /* Debug */,
331C80DC294CF71000263BE5 /* Release */,
331C80DD294CF71000263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "appflowy_ui_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "appflowy_ui_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80D4294CF70F00263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "appflowy_ui_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "appflowy_ui_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,13 @@
import Cocoa
import FlutterMacOS
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,343 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
<connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="EPT-qC-fAb">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
</menuItem>
</items>
<point key="canvasLocation" x="142" y="-258"/>
</menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>

View file

@ -0,0 +1,14 @@
// Application-level settings for the Runner target.
//
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
// future. If not, the values below would default to using the project name when this becomes a
// 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = appflowy_ui_example
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.appflowyUiExample
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved.

View file

@ -0,0 +1,2 @@
#include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig"

View file

@ -0,0 +1,2 @@
#include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig"

View file

@ -0,0 +1,13 @@
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
GCC_WARN_UNDECLARED_SELECTOR = YES
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_PRAGMA_PACK = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_COMMA = YES
GCC_WARN_STRICT_SELECTOR_MATCH = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
GCC_WARN_SHADOW = YES
CLANG_WARN_UNREACHABLE_CODE = YES

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View file

@ -0,0 +1,15 @@
import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,12 @@
import Cocoa
import FlutterMacOS
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View file

@ -0,0 +1,24 @@
name: appflowy_ui_example
description: "Example app showcasing AppFlowy UI components and widgets"
publish_to: "none"
version: 1.0.0+1
environment:
flutter: ">=3.27.4"
sdk: ">=3.3.0 <4.0.0"
dependencies:
flutter:
sdk: flutter
appflowy_ui:
path: ../
cupertino_icons: ^1.0.6
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter:
uses-material-design: true

View file

@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:appflowy_ui_example/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}

View file

@ -0,0 +1,4 @@
library;
export 'src/component/component.dart';
export 'src/theme/theme.dart';

View file

@ -0,0 +1,54 @@
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/widgets.dart';
enum AFButtonSize {
s,
m,
l,
xl;
TextStyle buildTextStyle(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return switch (this) {
AFButtonSize.s => theme.textStyle.body.enhanced(),
AFButtonSize.m => theme.textStyle.body.enhanced(),
AFButtonSize.l => theme.textStyle.body.enhanced(),
AFButtonSize.xl => theme.textStyle.title.enhanced(),
};
}
EdgeInsetsGeometry buildPadding(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return switch (this) {
AFButtonSize.s => EdgeInsets.symmetric(
horizontal: theme.spacing.l,
vertical: theme.spacing.xs,
),
AFButtonSize.m => EdgeInsets.symmetric(
horizontal: theme.spacing.l,
vertical: theme.spacing.s,
),
AFButtonSize.l => EdgeInsets.symmetric(
horizontal: theme.spacing.xl,
vertical: 10, // why?
),
AFButtonSize.xl => EdgeInsets.symmetric(
horizontal: theme.spacing.xl,
vertical: 14, // why?
),
};
}
double buildBorderRadius(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return switch (this) {
AFButtonSize.s => theme.borderRadius.m,
AFButtonSize.m => theme.borderRadius.m,
AFButtonSize.l => 10, // why?
AFButtonSize.xl => theme.borderRadius.xl,
};
}
}

View file

@ -0,0 +1,79 @@
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFBaseButtonColorBuilder = Color Function(
BuildContext context,
bool isHovering,
bool disabled,
);
class AFBaseButton extends StatefulWidget {
const AFBaseButton({
super.key,
required this.onTap,
required this.builder,
required this.padding,
required this.borderRadius,
this.borderColor,
this.backgroundColor,
this.disabled = false,
});
final VoidCallback? onTap;
final AFBaseButtonColorBuilder? borderColor;
final AFBaseButtonColorBuilder? backgroundColor;
final EdgeInsetsGeometry padding;
final double borderRadius;
final bool disabled;
final Widget Function(BuildContext context, bool isHovering, bool disabled)
builder;
@override
State<AFBaseButton> createState() => _AFBaseButtonState();
}
class _AFBaseButtonState extends State<AFBaseButton> {
bool isHovering = false;
@override
Widget build(BuildContext context) {
final Color borderColor = _buildBorderColor(context);
final Color backgroundColor = _buildBackgroundColor(context);
return MouseRegion(
cursor:
widget.disabled ? SystemMouseCursors.basic : SystemMouseCursors.click,
onEnter: (_) => setState(() => isHovering = true),
onExit: (_) => setState(() => isHovering = false),
child: GestureDetector(
onTap: widget.disabled ? null : widget.onTap,
child: DecoratedBox(
decoration: BoxDecoration(
color: backgroundColor,
border: Border.all(color: borderColor),
borderRadius: BorderRadius.circular(widget.borderRadius),
),
child: Padding(
padding: widget.padding,
child: widget.builder(context, isHovering, widget.disabled),
),
),
),
);
}
Color _buildBorderColor(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return widget.borderColor?.call(context, isHovering, widget.disabled) ??
theme.borderColorScheme.greyTertiary;
}
Color _buildBackgroundColor(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return widget.backgroundColor?.call(context, isHovering, widget.disabled) ??
theme.fillColorScheme.transparent;
}
}

View file

@ -0,0 +1,51 @@
import 'package:appflowy_ui/appflowy_ui.dart';
import 'package:flutter/material.dart';
class AFBaseTextButton extends StatelessWidget {
const AFBaseTextButton({
super.key,
required this.text,
required this.onTap,
this.disabled = false,
this.size = AFButtonSize.m,
this.padding,
this.borderRadius,
this.textColor,
this.backgroundColor,
this.alignment,
});
/// The text of the button.
final String text;
/// Whether the button is disabled.
final bool disabled;
/// The callback when the button is tapped.
final VoidCallback onTap;
/// The size of the button.
final AFButtonSize size;
/// The padding of the button.
final EdgeInsetsGeometry? padding;
/// The border radius of the button.
final double? borderRadius;
/// The text color of the button.
final AFBaseButtonColorBuilder? textColor;
/// The background color of the button.
final AFBaseButtonColorBuilder? backgroundColor;
/// The alignment of the button.
///
/// If it's null, the button size will be the size of the text with padding.
final Alignment? alignment;
@override
Widget build(BuildContext context) {
throw UnimplementedError();
}
}

View file

@ -0,0 +1,16 @@
// Base button
export 'base_button/base.dart';
export 'base_button/base_button.dart';
export 'base_button/base_text_button.dart';
// Filled buttons
export 'filled_button/filled_button.dart';
export 'filled_button/filled_icon_text_button.dart';
export 'filled_button/filled_text_button.dart';
// Ghost buttons
export 'ghost_button/ghost_button.dart';
export 'ghost_button/ghost_icon_text_button.dart';
export 'ghost_button/ghost_text_button.dart';
// Outlined buttons
export 'outlined_button/outlined_button.dart';
export 'outlined_button/outlined_icon_text_button.dart';
export 'outlined_button/outlined_text_button.dart';

View file

@ -0,0 +1,125 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFFilledButtonWidgetBuilder = Widget Function(
BuildContext context,
bool isHovering,
bool disabled,
);
class AFFilledButton extends StatelessWidget {
const AFFilledButton._({
super.key,
required this.builder,
required this.onTap,
required this.backgroundColor,
this.size = AFButtonSize.m,
this.padding,
this.borderRadius,
this.disabled = false,
});
/// Primary text button.
factory AFFilledButton.primary({
Key? key,
required AFFilledButtonWidgetBuilder builder,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
}) {
return AFFilledButton._(
key: key,
builder: builder,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
backgroundColor: (context, isHovering, disabled) {
if (disabled) {
return AppFlowyTheme.of(context).fillColorScheme.primaryAlpha5;
}
if (isHovering) {
return AppFlowyTheme.of(context).fillColorScheme.themeThickHover;
}
return AppFlowyTheme.of(context).fillColorScheme.themeThick;
},
);
}
/// Destructive text button.
factory AFFilledButton.destructive({
Key? key,
required AFFilledButtonWidgetBuilder builder,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
}) {
return AFFilledButton._(
key: key,
builder: builder,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
backgroundColor: (context, isHovering, disabled) {
if (disabled) {
return AppFlowyTheme.of(context).fillColorScheme.primaryAlpha5;
}
if (isHovering) {
return AppFlowyTheme.of(context).fillColorScheme.errorThickHover;
}
return AppFlowyTheme.of(context).fillColorScheme.errorThick;
},
);
}
/// Disabled text button.
factory AFFilledButton.disabled({
Key? key,
required AFFilledButtonWidgetBuilder builder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFFilledButton._(
key: key,
builder: builder,
onTap: () {},
size: size,
disabled: true,
padding: padding,
borderRadius: borderRadius,
backgroundColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).fillColorScheme.primaryAlpha5,
);
}
final VoidCallback onTap;
final bool disabled;
final AFButtonSize size;
final EdgeInsetsGeometry? padding;
final double? borderRadius;
final AFBaseButtonColorBuilder? backgroundColor;
final AFFilledButtonWidgetBuilder builder;
@override
Widget build(BuildContext context) {
return AFBaseButton(
disabled: disabled,
backgroundColor: backgroundColor,
borderColor: (_, __, ___) => Colors.transparent,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: builder,
);
}
}

View file

@ -0,0 +1,199 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFFilledIconBuilder = Widget Function(
BuildContext context,
bool isHovering,
bool disabled,
);
class AFFilledIconTextButton extends StatelessWidget {
const AFFilledIconTextButton._({
super.key,
required this.text,
required this.onTap,
required this.iconBuilder,
this.textColor,
this.backgroundColor,
this.size = AFButtonSize.m,
this.padding,
this.borderRadius,
});
/// Primary filled text button.
factory AFFilledIconTextButton.primary({
Key? key,
required String text,
required VoidCallback onTap,
required AFFilledIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFFilledIconTextButton._(
key: key,
text: text,
onTap: onTap,
iconBuilder: iconBuilder,
size: size,
padding: padding,
borderRadius: borderRadius,
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.tertiary;
}
if (isHovering) {
return theme.fillColorScheme.themeThickHover;
}
return theme.fillColorScheme.themeThick;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return theme.textColorScheme.onFill;
},
);
}
/// Destructive filled text button.
factory AFFilledIconTextButton.destructive({
Key? key,
required String text,
required VoidCallback onTap,
required AFFilledIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFFilledIconTextButton._(
key: key,
text: text,
iconBuilder: iconBuilder,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.tertiary;
}
if (isHovering) {
return theme.fillColorScheme.errorThickHover;
}
return theme.fillColorScheme.errorThick;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return theme.textColorScheme.onFill;
},
);
}
/// Disabled filled text button.
factory AFFilledIconTextButton.disabled({
Key? key,
required String text,
required AFFilledIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFFilledIconTextButton._(
key: key,
text: text,
iconBuilder: iconBuilder,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return theme.fillColorScheme.tertiary;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return theme.textColorScheme.onFill;
},
);
}
/// Ghost filled text button with transparent background that shows color on hover.
factory AFFilledIconTextButton.ghost({
Key? key,
required String text,
required VoidCallback onTap,
required AFFilledIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFFilledIconTextButton._(
key: key,
text: text,
iconBuilder: iconBuilder,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return Colors.transparent;
}
if (isHovering) {
return theme.fillColorScheme.themeThickHover;
}
return Colors.transparent;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.textColorScheme.tertiary;
}
return theme.textColorScheme.primary;
},
);
}
final String text;
final VoidCallback onTap;
final AFButtonSize size;
final EdgeInsetsGeometry? padding;
final double? borderRadius;
final AFFilledIconBuilder iconBuilder;
final AFBaseButtonColorBuilder? textColor;
final AFBaseButtonColorBuilder? backgroundColor;
@override
Widget build(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return AFBaseButton(
backgroundColor: backgroundColor,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: (context, isHovering, disabled) {
final textColor = this.textColor?.call(context, isHovering, disabled) ??
theme.textColorScheme.onFill;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
iconBuilder(context, isHovering, disabled),
SizedBox(width: theme.spacing.s),
Text(
text,
style: size.buildTextStyle(context).copyWith(
color: textColor,
),
),
],
);
},
);
}
}

View file

@ -0,0 +1,141 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
class AFFilledTextButton extends AFBaseTextButton {
const AFFilledTextButton({
super.key,
required super.text,
required super.onTap,
required super.backgroundColor,
required super.textColor,
super.size = AFButtonSize.m,
super.padding,
super.borderRadius,
super.disabled = false,
super.alignment,
});
/// Primary text button.
factory AFFilledTextButton.primary({
Key? key,
required String text,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
Alignment? alignment,
}) {
return AFFilledTextButton(
key: key,
text: text,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
alignment: alignment,
textColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).textColorScheme.onFill,
backgroundColor: (context, isHovering, disabled) {
if (disabled) {
return AppFlowyTheme.of(context).fillColorScheme.primaryAlpha5;
}
if (isHovering) {
return AppFlowyTheme.of(context).fillColorScheme.themeThickHover;
}
return AppFlowyTheme.of(context).fillColorScheme.themeThick;
},
);
}
/// Destructive text button.
factory AFFilledTextButton.destructive({
Key? key,
required String text,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
Alignment? alignment,
}) {
return AFFilledTextButton(
key: key,
text: text,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
alignment: alignment,
textColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).textColorScheme.onFill,
backgroundColor: (context, isHovering, disabled) {
if (disabled) {
return AppFlowyTheme.of(context).fillColorScheme.primaryAlpha5;
}
if (isHovering) {
return AppFlowyTheme.of(context).fillColorScheme.errorThickHover;
}
return AppFlowyTheme.of(context).fillColorScheme.errorThick;
},
);
}
/// Disabled text button.
factory AFFilledTextButton.disabled({
Key? key,
required String text,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
Alignment? alignment,
}) {
return AFFilledTextButton(
key: key,
text: text,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: true,
alignment: alignment,
textColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).textColorScheme.tertiary,
backgroundColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).fillColorScheme.primaryAlpha5,
);
}
@override
Widget build(BuildContext context) {
return AFBaseButton(
disabled: disabled,
backgroundColor: backgroundColor,
borderColor: (_, __, ___) => Colors.transparent,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: (context, isHovering, disabled) {
final textColor = this.textColor?.call(context, isHovering, disabled) ??
AppFlowyTheme.of(context).textColorScheme.onFill;
Widget child = Text(
text,
style: size.buildTextStyle(context).copyWith(color: textColor),
);
final alignment = this.alignment;
if (alignment != null) {
child = Align(
alignment: alignment,
child: child,
);
}
return child;
},
);
}
}

View file

@ -0,0 +1,96 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFGhostButtonWidgetBuilder = Widget Function(
BuildContext context,
bool isHovering,
bool disabled,
);
class AFGhostButton extends StatelessWidget {
const AFGhostButton._({
super.key,
required this.onTap,
required this.backgroundColor,
required this.builder,
this.size = AFButtonSize.m,
this.padding,
this.borderRadius,
this.disabled = false,
});
/// Normal ghost button.
factory AFGhostButton.normal({
Key? key,
required VoidCallback onTap,
required AFGhostButtonWidgetBuilder builder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
}) {
return AFGhostButton._(
key: key,
builder: builder,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
);
}
/// Disabled ghost button.
factory AFGhostButton.disabled({
Key? key,
required AFGhostButtonWidgetBuilder builder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFGhostButton._(
key: key,
builder: builder,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: true,
backgroundColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).fillColorScheme.transparent,
);
}
final VoidCallback onTap;
final bool disabled;
final AFButtonSize size;
final EdgeInsetsGeometry? padding;
final double? borderRadius;
final AFBaseButtonColorBuilder? backgroundColor;
final AFGhostButtonWidgetBuilder builder;
@override
Widget build(BuildContext context) {
return AFBaseButton(
disabled: disabled,
backgroundColor: backgroundColor,
borderColor: (_, __, ___) => Colors.transparent,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: builder,
);
}
}

View file

@ -0,0 +1,141 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFGhostIconBuilder = Widget Function(
BuildContext context,
bool isHovering,
bool disabled,
);
class AFGhostIconTextButton extends StatelessWidget {
const AFGhostIconTextButton({
super.key,
required this.text,
required this.onTap,
required this.iconBuilder,
this.textColor,
this.backgroundColor,
this.size = AFButtonSize.m,
this.padding,
this.borderRadius,
this.disabled = false,
});
/// Primary ghost text button.
factory AFGhostIconTextButton.primary({
Key? key,
required String text,
required VoidCallback onTap,
required AFGhostIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
}) {
return AFGhostIconTextButton(
key: key,
text: text,
onTap: onTap,
iconBuilder: iconBuilder,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return Colors.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return Colors.transparent;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.textColorScheme.tertiary;
}
return theme.textColorScheme.primary;
},
);
}
/// Disabled ghost text button.
factory AFGhostIconTextButton.disabled({
Key? key,
required String text,
required AFGhostIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFGhostIconTextButton(
key: key,
text: text,
iconBuilder: iconBuilder,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: true,
backgroundColor: (context, isHovering, disabled) {
return Colors.transparent;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return theme.textColorScheme.tertiary;
},
);
}
final String text;
final bool disabled;
final VoidCallback onTap;
final AFButtonSize size;
final EdgeInsetsGeometry? padding;
final double? borderRadius;
final AFGhostIconBuilder iconBuilder;
final AFBaseButtonColorBuilder? textColor;
final AFBaseButtonColorBuilder? backgroundColor;
@override
Widget build(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return AFBaseButton(
disabled: disabled,
backgroundColor: backgroundColor,
borderColor: (context, isHovering, disabled) {
return Colors.transparent;
},
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: (context, isHovering, disabled) {
final textColor = this.textColor?.call(context, isHovering, disabled) ??
theme.textColorScheme.primary;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
iconBuilder(
context,
isHovering,
disabled,
),
SizedBox(width: theme.spacing.m),
Text(
text,
style: size.buildTextStyle(context).copyWith(
color: textColor,
),
),
],
);
},
);
}
}

View file

@ -0,0 +1,116 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
class AFGhostTextButton extends AFBaseTextButton {
const AFGhostTextButton({
super.key,
required super.text,
required super.onTap,
super.textColor,
super.backgroundColor,
super.size = AFButtonSize.m,
super.padding,
super.borderRadius,
super.disabled = false,
super.alignment,
});
/// Normal ghost text button.
factory AFGhostTextButton.primary({
Key? key,
required String text,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
Alignment? alignment,
}) {
return AFGhostTextButton(
key: key,
text: text,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
alignment: alignment,
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.textColorScheme.tertiary;
}
if (isHovering) {
return theme.textColorScheme.primary;
}
return theme.textColorScheme.primary;
},
);
}
/// Disabled ghost text button.
factory AFGhostTextButton.disabled({
Key? key,
required String text,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
Alignment? alignment,
}) {
return AFGhostTextButton(
key: key,
text: text,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: true,
alignment: alignment,
textColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).textColorScheme.tertiary,
backgroundColor: (context, isHovering, disabled) =>
AppFlowyTheme.of(context).fillColorScheme.transparent,
);
}
@override
Widget build(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return AFBaseButton(
disabled: disabled,
backgroundColor: backgroundColor,
borderColor: (_, __, ___) => Colors.transparent,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: (context, isHovering, disabled) {
final textColor = this.textColor?.call(context, isHovering, disabled) ??
theme.textColorScheme.primary;
Widget child = Text(
text,
style: size.buildTextStyle(context).copyWith(color: textColor),
);
final alignment = this.alignment;
if (alignment != null) {
child = Align(
alignment: alignment,
child: child,
);
}
return child;
},
);
}
}

View file

@ -0,0 +1,168 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFOutlinedButtonWidgetBuilder = Widget Function(
BuildContext context,
bool isHovering,
bool disabled,
);
class AFOutlinedButton extends StatelessWidget {
const AFOutlinedButton._({
super.key,
required this.onTap,
required this.builder,
this.borderColor,
this.backgroundColor,
this.size = AFButtonSize.m,
this.padding,
this.borderRadius,
this.disabled = false,
});
/// Normal outlined button.
factory AFOutlinedButton.normal({
Key? key,
required AFOutlinedButtonWidgetBuilder builder,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
}) {
return AFOutlinedButton._(
key: key,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.borderColorScheme.greyTertiary;
}
if (isHovering) {
return theme.borderColorScheme.greyTertiaryHover;
}
return theme.borderColorScheme.greyTertiary;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
builder: builder,
);
}
/// Destructive outlined button.
factory AFOutlinedButton.destructive({
Key? key,
required AFOutlinedButtonWidgetBuilder builder,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
}) {
return AFOutlinedButton._(
key: key,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.errorThick;
}
if (isHovering) {
return theme.fillColorScheme.errorThickHover;
}
return theme.fillColorScheme.errorThick;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.errorThick;
}
if (isHovering) {
return theme.fillColorScheme.errorSelect;
}
return theme.fillColorScheme.transparent;
},
builder: builder,
);
}
/// Disabled outlined text button.
factory AFOutlinedButton.disabled({
Key? key,
required AFOutlinedButtonWidgetBuilder builder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
}) {
return AFOutlinedButton._(
key: key,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: true,
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.borderColorScheme.greyTertiary;
}
if (isHovering) {
return theme.borderColorScheme.greyTertiaryHover;
}
return theme.borderColorScheme.greyTertiary;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
builder: builder,
);
}
final VoidCallback onTap;
final bool disabled;
final AFButtonSize size;
final EdgeInsetsGeometry? padding;
final double? borderRadius;
final AFBaseButtonColorBuilder? borderColor;
final AFBaseButtonColorBuilder? backgroundColor;
final AFOutlinedButtonWidgetBuilder builder;
@override
Widget build(BuildContext context) {
return AFBaseButton(
disabled: disabled,
backgroundColor: backgroundColor,
borderColor: borderColor,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: builder,
);
}
}

View file

@ -0,0 +1,226 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFOutlinedIconBuilder = Widget Function(
BuildContext context,
bool isHovering,
bool disabled,
);
class AFOutlinedIconTextButton extends StatelessWidget {
const AFOutlinedIconTextButton._({
super.key,
required this.text,
required this.onTap,
required this.iconBuilder,
this.borderColor,
this.textColor,
this.backgroundColor,
this.size = AFButtonSize.m,
this.padding,
this.borderRadius,
this.disabled = false,
this.alignment = MainAxisAlignment.center,
});
/// Normal outlined text button.
factory AFOutlinedIconTextButton.normal({
Key? key,
required String text,
required VoidCallback onTap,
required AFOutlinedIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
MainAxisAlignment alignment = MainAxisAlignment.center,
}) {
return AFOutlinedIconTextButton._(
key: key,
text: text,
onTap: onTap,
iconBuilder: iconBuilder,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
alignment: alignment,
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.borderColorScheme.greyTertiary;
}
if (isHovering) {
return theme.borderColorScheme.greyTertiaryHover;
}
return theme.borderColorScheme.greyTertiary;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.textColorScheme.tertiary;
}
if (isHovering) {
return theme.textColorScheme.primary;
}
return theme.textColorScheme.primary;
},
);
}
/// Destructive outlined text button.
factory AFOutlinedIconTextButton.destructive({
Key? key,
required String text,
required VoidCallback onTap,
required AFOutlinedIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
MainAxisAlignment alignment = MainAxisAlignment.center,
}) {
return AFOutlinedIconTextButton._(
key: key,
text: text,
iconBuilder: iconBuilder,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
alignment: alignment,
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.errorThick;
}
if (isHovering) {
return theme.fillColorScheme.errorThickHover;
}
return theme.fillColorScheme.errorThick;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.errorThick;
}
if (isHovering) {
return theme.fillColorScheme.errorThickHover;
}
return theme.fillColorScheme.errorThick;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return disabled
? theme.textColorScheme.error
: theme.textColorScheme.error;
},
);
}
/// Disabled outlined text button.
factory AFOutlinedIconTextButton.disabled({
Key? key,
required String text,
required AFOutlinedIconBuilder iconBuilder,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
MainAxisAlignment alignment = MainAxisAlignment.center,
}) {
return AFOutlinedIconTextButton._(
key: key,
text: text,
iconBuilder: iconBuilder,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: true,
alignment: alignment,
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return disabled
? theme.textColorScheme.tertiary
: theme.textColorScheme.primary;
},
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.borderColorScheme.greyTertiary;
}
if (isHovering) {
return theme.borderColorScheme.greyTertiaryHover;
}
return theme.borderColorScheme.greyTertiary;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
);
}
final String text;
final bool disabled;
final VoidCallback onTap;
final AFButtonSize size;
final EdgeInsetsGeometry? padding;
final double? borderRadius;
final MainAxisAlignment alignment;
final AFOutlinedIconBuilder iconBuilder;
final AFBaseButtonColorBuilder? textColor;
final AFBaseButtonColorBuilder? borderColor;
final AFBaseButtonColorBuilder? backgroundColor;
@override
Widget build(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return AFBaseButton(
backgroundColor: backgroundColor,
borderColor: borderColor,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
disabled: disabled,
builder: (context, isHovering, disabled) {
final textColor = this.textColor?.call(context, isHovering, disabled) ??
theme.textColorScheme.primary;
return Row(
mainAxisAlignment: alignment,
children: [
iconBuilder(context, isHovering, disabled),
SizedBox(width: theme.spacing.s),
Text(
text,
style: size.buildTextStyle(context).copyWith(
color: textColor,
),
),
],
);
},
);
}
}

View file

@ -0,0 +1,204 @@
import 'package:appflowy_ui/src/component/component.dart';
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
class AFOutlinedTextButton extends AFBaseTextButton {
const AFOutlinedTextButton._({
super.key,
required super.text,
required super.onTap,
this.borderColor,
super.textColor,
super.backgroundColor,
super.size = AFButtonSize.m,
super.padding,
super.borderRadius,
super.disabled = false,
super.alignment,
});
/// Normal outlined text button.
factory AFOutlinedTextButton.normal({
Key? key,
required String text,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
Alignment? alignment,
}) {
return AFOutlinedTextButton._(
key: key,
text: text,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
alignment: alignment,
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.borderColorScheme.greyTertiary;
}
if (isHovering) {
return theme.borderColorScheme.greyTertiaryHover;
}
return theme.borderColorScheme.greyTertiary;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.textColorScheme.tertiary;
}
if (isHovering) {
return theme.textColorScheme.primary;
}
return theme.textColorScheme.primary;
},
);
}
/// Destructive outlined text button.
factory AFOutlinedTextButton.destructive({
Key? key,
required String text,
required VoidCallback onTap,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
bool disabled = false,
Alignment? alignment,
}) {
return AFOutlinedTextButton._(
key: key,
text: text,
onTap: onTap,
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: disabled,
alignment: alignment,
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.errorThick;
}
if (isHovering) {
return theme.fillColorScheme.errorThickHover;
}
return theme.fillColorScheme.errorThick;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.errorThick;
}
if (isHovering) {
return theme.fillColorScheme.errorSelect;
}
return theme.fillColorScheme.transparent;
},
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return disabled
? theme.textColorScheme.error
: theme.textColorScheme.error;
},
);
}
/// Disabled outlined text button.
factory AFOutlinedTextButton.disabled({
Key? key,
required String text,
AFButtonSize size = AFButtonSize.m,
EdgeInsetsGeometry? padding,
double? borderRadius,
Alignment? alignment,
}) {
return AFOutlinedTextButton._(
key: key,
text: text,
onTap: () {},
size: size,
padding: padding,
borderRadius: borderRadius,
disabled: true,
alignment: alignment,
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
return disabled
? theme.textColorScheme.tertiary
: theme.textColorScheme.primary;
},
borderColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.borderColorScheme.greyTertiary;
}
if (isHovering) {
return theme.borderColorScheme.greyTertiaryHover;
}
return theme.borderColorScheme.greyTertiary;
},
backgroundColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (disabled) {
return theme.fillColorScheme.transparent;
}
if (isHovering) {
return theme.fillColorScheme.primaryAlpha5;
}
return theme.fillColorScheme.transparent;
},
);
}
final AFBaseButtonColorBuilder? borderColor;
@override
Widget build(BuildContext context) {
final theme = AppFlowyTheme.of(context);
return AFBaseButton(
disabled: disabled,
backgroundColor: backgroundColor,
borderColor: borderColor,
padding: padding ?? size.buildPadding(context),
borderRadius: borderRadius ?? size.buildBorderRadius(context),
onTap: onTap,
builder: (context, isHovering, disabled) {
final textColor = this.textColor?.call(context, isHovering, disabled) ??
theme.textColorScheme.primary;
Widget child = Text(
text,
style: size.buildTextStyle(context).copyWith(color: textColor),
);
final alignment = this.alignment;
if (alignment != null) {
child = Align(
alignment: alignment,
child: child,
);
}
return child;
},
);
}
}

View file

@ -0,0 +1,2 @@
export 'button/button.dart';
export 'textfield/textfield.dart';

View file

@ -0,0 +1,177 @@
import 'package:appflowy_ui/src/theme/appflowy_theme.dart';
import 'package:flutter/material.dart';
typedef AFTextFieldValidator = (bool result, String errorText) Function(
TextEditingController controller,
);
class AFTextField extends StatefulWidget {
const AFTextField({
super.key,
this.hintText,
this.initialText,
this.keyboardType,
this.radius,
this.validator,
this.controller,
this.onChanged,
this.onSubmitted,
this.autoFocus,
});
/// The hint text to display when the text field is empty.
final String? hintText;
/// The initial text to display in the text field.
final String? initialText;
/// The type of keyboard to display.
final TextInputType? keyboardType;
/// The radius of the text field.
final double? radius;
/// The validator to use for the text field.
final AFTextFieldValidator? validator;
/// The controller to use for the text field.
///
/// If it's not provided, the text field will use a new controller.
final TextEditingController? controller;
/// The callback to call when the text field changes.
final void Function(String)? onChanged;
/// The callback to call when the text field is submitted.
final void Function(String)? onSubmitted;
/// Enable auto focus.
final bool? autoFocus;
@override
State<AFTextField> createState() => _AFTextFieldState();
}
class _AFTextFieldState extends State<AFTextField> {
late final TextEditingController effectiveController;
bool hasError = false;
String errorText = '';
@override
void initState() {
super.initState();
effectiveController = widget.controller ?? TextEditingController();
final initialText = widget.initialText;
if (initialText != null) {
effectiveController.text = initialText;
}
effectiveController.addListener(_validate);
}
@override
void dispose() {
effectiveController.removeListener(_validate);
if (widget.controller == null) {
effectiveController.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = AppFlowyTheme.of(context);
final borderRadius = BorderRadius.circular(
widget.radius ?? theme.borderRadius.l,
);
final errorBorderColor = theme.borderColorScheme.errorThick;
final defaultBorderColor = theme.borderColorScheme.greyTertiary;
Widget child = TextField(
controller: effectiveController,
keyboardType: widget.keyboardType,
style: theme.textStyle.body.standard(
color: theme.textColorScheme.primary,
),
onChanged: widget.onChanged,
onSubmitted: widget.onSubmitted,
autofocus: widget.autoFocus ?? false,
decoration: InputDecoration(
hintText: widget.hintText,
hintStyle: theme.textStyle.body.standard(
color: theme.textColorScheme.tertiary,
),
contentPadding: EdgeInsets.symmetric(
horizontal: theme.spacing.m,
vertical: 10,
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: hasError ? errorBorderColor : defaultBorderColor,
),
borderRadius: borderRadius,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: hasError ? errorBorderColor : defaultBorderColor,
),
borderRadius: borderRadius,
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: hasError
? errorBorderColor
: theme.borderColorScheme.themeThick,
),
borderRadius: borderRadius,
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: errorBorderColor,
),
borderRadius: borderRadius,
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: errorBorderColor,
),
borderRadius: borderRadius,
),
hoverColor: theme.borderColorScheme.greyTertiaryHover,
),
);
if (hasError && errorText.isNotEmpty) {
child = Column(
children: [
child,
SizedBox(height: theme.spacing.xs),
Text(
errorText,
style: theme.textStyle.caption.standard(
color: theme.textColorScheme.error,
),
),
],
);
}
return child;
}
void _validate() {
final validator = widget.validator;
if (validator != null) {
final result = validator(effectiveController);
setState(() {
hasError = result.$1;
errorText = result.$2;
});
}
}
}

View file

@ -0,0 +1,72 @@
import 'package:appflowy_ui/src/theme/data/data.dart';
import 'package:flutter/widgets.dart';
class AppFlowyTheme extends StatelessWidget {
const AppFlowyTheme({
super.key,
required this.data,
required this.child,
});
final AppFlowyThemeData data;
final Widget child;
static AppFlowyThemeData of(BuildContext context, {bool listen = true}) {
final provider = maybeOf(context, listen: listen);
if (provider == null) {
throw FlutterError(
'''
AppFlowyTheme.of() called with a context that does not contain a AppFlowyTheme.\n
No AppFlowyTheme ancestor could be found starting from the context that was passed to AppFlowyTheme.of().
This can happen because you do not have a AppFlowyTheme widget (which introduces a AppFlowyTheme),
or it can happen if the context you use comes from a widget above this widget.\n
The context used was: $context''',
);
}
return provider;
}
static AppFlowyThemeData? maybeOf(
BuildContext context, {
bool listen = true,
}) {
if (listen) {
return context
.dependOnInheritedWidgetOfExactType<AppFlowyInheritedTheme>()
?.theme
.data;
}
final provider = context
.getElementForInheritedWidgetOfExactType<AppFlowyInheritedTheme>()
?.widget;
return (provider as AppFlowyInheritedTheme?)?.theme.data;
}
@override
Widget build(BuildContext context) {
return AppFlowyInheritedTheme(
theme: this,
child: child,
);
}
}
class AppFlowyInheritedTheme extends InheritedTheme {
const AppFlowyInheritedTheme({
super.key,
required this.theme,
required super.child,
});
final AppFlowyTheme theme;
@override
Widget wrap(BuildContext context, Widget child) {
return AppFlowyTheme(data: theme.data, child: child);
}
@override
bool updateShouldNotify(AppFlowyInheritedTheme oldWidget) =>
theme.data != oldWidget.theme.data;
}

View file

@ -0,0 +1,17 @@
class AppFlowyBorderRadius {
const AppFlowyBorderRadius({
required this.xs,
required this.s,
required this.m,
required this.l,
required this.xl,
required this.xxl,
});
final double xs;
final double s;
final double m;
final double l;
final double xl;
final double xxl;
}

View file

@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
class AppFlowyBackgroundColorScheme {
const AppFlowyBackgroundColorScheme({
required this.primary,
required this.secondary,
required this.tertiary,
required this.quaternary,
});
final Color primary;
final Color secondary;
final Color tertiary;
final Color quaternary;
}

View file

@ -0,0 +1,33 @@
import 'package:appflowy_ui/src/theme/color_scheme/base/blue.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/green.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/magenta.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/neutral.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/orange.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/purple.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/red.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/subtle.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/yellow.dart';
class AppFlowyBaseColorScheme {
const AppFlowyBaseColorScheme({
this.blue = const BlueColors(),
this.green = const GreenColors(),
this.yellow = const YellowColors(),
this.red = const RedColors(),
this.orange = const OrangeColors(),
this.magenta = const MagentaColors(),
this.purple = const PurpleColors(),
this.neutral = const NeutralColors(),
this.subtle = const SubtleColors(),
});
final BlueColors blue;
final GreenColors green;
final YellowColors yellow;
final RedColors red;
final OrangeColors orange;
final MagentaColors magenta;
final PurpleColors purple;
final NeutralColors neutral;
final SubtleColors subtle;
}

View file

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class BlueColors {
const BlueColors();
Color get blue100 => const Color(0xFFE3F6FF);
Color get blue200 => const Color(0xFFA9E2FF);
Color get blue300 => const Color(0xFF80D2FF);
Color get blue400 => const Color(0xFF4EC1FF);
Color get blue500 => const Color(0xFF00B5FF);
Color get blue600 => const Color(0xFF0092D6);
Color get blue700 => const Color(0xFF0078C0);
Color get blue800 => const Color(0xFF0065A9);
Color get blue900 => const Color(0xFF00508F);
Color get blue1000 => const Color(0xFF003C77);
Color get alphaBlue50015 => const Color(0x2600B5FF);
}

View file

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
class GreenColors {
const GreenColors();
Color get green100 => const Color(0xFFECF9F5);
Color get green200 => const Color(0xFFC3E5D8);
Color get green300 => const Color(0xFF9AD1BC);
Color get green400 => const Color(0xFF71BD9F);
Color get green500 => const Color(0xFF48A982);
Color get green600 => const Color(0xFF248569);
Color get green700 => const Color(0xFF29725D);
Color get green800 => const Color(0xFF2E6050);
Color get green900 => const Color(0xFF305548);
Color get green1000 => const Color(0xFF305244);
}

View file

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
class MagentaColors {
const MagentaColors();
Color get magenta100 => const Color(0xFFFFE5EF);
Color get magenta200 => const Color(0xFFFFB8D1);
Color get magenta300 => const Color(0xFFFF8AB2);
Color get magenta400 => const Color(0xFFFF5C93);
Color get magenta500 => const Color(0xFFFB006D);
Color get magenta600 => const Color(0xFFD2005F);
Color get magenta700 => const Color(0xFFD2005F);
Color get magenta800 => const Color(0xFF850040);
Color get magenta900 => const Color(0xFF610031);
Color get magenta1000 => const Color(0xFF400022);
}

View file

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
class NeutralColors {
const NeutralColors();
Color get neutral100 => const Color(0xFFF8FAFF);
Color get neutral200 => const Color(0xFFE4E8F5);
Color get neutral300 => const Color(0xFFCED3E6);
Color get neutral400 => const Color(0xFFB5BBD3);
Color get neutral500 => const Color(0xFF989EB7);
Color get neutral600 => const Color(0xFF6F748C);
Color get neutral700 => const Color(0xFF54596E);
Color get neutral800 => const Color(0xFF3C3F4E);
Color get neutral900 => const Color(0xFF272930);
Color get neutral1000 => const Color(0xFF21232A);
Color get black => const Color(0xFF000000);
Color get alphaBlack60 => const Color(0x99000000);
Color get white => const Color(0xFFFFFFFF);
Color get alphaWhite0 => const Color(0x00FFFFFF);
Color get alphaWhite20 => const Color(0x33FFFFFF);
Color get alphaWhite30 => const Color(0x4DFFFFFF);
Color get alphaGrey10005 => const Color(0x0DF9FAFD);
Color get alphaGrey10010 => const Color(0x1AF9FAFD);
Color get alphaGrey100005 => const Color(0x0D1F2329);
Color get alphaGrey100010 => const Color(0x1A1F2329);
Color get alphaGrey100070 => const Color(0xB21F2329);
Color get alphaGrey100080 => const Color(0xCC1F2329);
}

View file

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
class OrangeColors {
const OrangeColors();
Color get orange100 => const Color(0xFFFFF3D5);
Color get orange200 => const Color(0xFFFFE4AB);
Color get orange300 => const Color(0xFFFFD181);
Color get orange400 => const Color(0xFFFFBE62);
Color get orange500 => const Color(0xFFFFA02E);
Color get orange600 => const Color(0xFFDB7E21);
Color get orange700 => const Color(0xFFB75F17);
Color get orange800 => const Color(0xFF93450E);
Color get orange900 => const Color(0xFF7A3108);
Color get orange1000 => const Color(0xFF602706);
}

View file

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
class PurpleColors {
const PurpleColors();
Color get purple100 => const Color(0xFFF1E0FF);
Color get purple200 => const Color(0xFFE1B3FF);
Color get purple300 => const Color(0xFFD185FF);
Color get purple400 => const Color(0xFFBC58FF);
Color get purple500 => const Color(0xFF9327FF);
Color get purple600 => const Color(0xFF7A1DCC);
Color get purple700 => const Color(0xFF6617B3);
Color get purple800 => const Color(0xFF55138F);
Color get purple900 => const Color(0xFF470C72);
Color get purple1000 => const Color(0xFF380758);
}

View file

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class RedColors {
const RedColors();
Color get red100 => const Color(0xFFFFD2DD);
Color get red200 => const Color(0xFFFFA5B4);
Color get red300 => const Color(0xFFFF7D87);
Color get red400 => const Color(0xFFFF5050);
Color get red500 => const Color(0xFFF33641);
Color get red600 => const Color(0xFFE71D32);
Color get red700 => const Color(0xFFAD1625);
Color get red800 => const Color(0xFF8C101C);
Color get red900 => const Color(0xFF6E0A1E);
Color get red1000 => const Color(0xFF4C0A17);
Color get alphaRed50010 => const Color(0x1AF33641);
}

View file

@ -0,0 +1,265 @@
import 'package:flutter/material.dart';
class SubtleColors {
const SubtleColors();
// Rose colors
Color get rose100 => const Color(0xFFFCF2F2);
Color get rose200 => const Color(0xFFFAE3E3);
Color get rose300 => const Color(0xFFFAD9D9);
Color get rose400 => const Color(0xFFEDADAD);
Color get rose500 => const Color(0xFFCC4E4E);
Color get rose600 => const Color(0xFF702828);
// Papaya colors
Color get papaya100 => const Color(0xFFFCF4F0);
Color get papaya200 => const Color(0xFFFAE8DE);
Color get papaya300 => const Color(0xFFFADFD2);
Color get papaya400 => const Color(0xFFF0BDA3);
Color get papaya500 => const Color(0xFFD67240);
Color get papaya600 => const Color(0xFF6B3215);
// Tangerine colors
Color get tangerine100 => const Color(0xFFFFF7ED);
Color get tangerine200 => const Color(0xFFFCEDD9);
Color get tangerine300 => const Color(0xFFFAE5CA);
Color get tangerine400 => const Color(0xFFF2CB99);
Color get tangerine500 => const Color(0xFFDB8F2C);
Color get tangerine600 => const Color(0xFF613B0A);
// Mango colors
Color get mango100 => const Color(0xFFFFF9EC);
Color get mango200 => const Color(0xFFFCF1D7);
Color get mango300 => const Color(0xFFFAE9C3);
Color get mango400 => const Color(0xFFF5D68E);
Color get mango500 => const Color(0xFFE0A416);
Color get mango600 => const Color(0xFF5C4102);
// Lemon colors
Color get lemon100 => const Color(0xFFFFFBE8);
Color get lemon200 => const Color(0xFFFCF5CF);
Color get lemon300 => const Color(0xFFFAEFB9);
Color get lemon400 => const Color(0xFFF5E282);
Color get lemon500 => const Color(0xFFE0BB00);
Color get lemon600 => const Color(0xFF574800);
// Olive colors
Color get olive100 => const Color(0xFFF9FAE6);
Color get olive200 => const Color(0xFFF6F7D0);
Color get olive300 => const Color(0xFFF0F2B3);
Color get olive400 => const Color(0xFFDBDE83);
Color get olive500 => const Color(0xFFADB204);
Color get olive600 => const Color(0xFF4A4C03);
// Lime colors
Color get lime100 => const Color(0xFFF6F9E6);
Color get lime200 => const Color(0xFFEEF5CE);
Color get lime300 => const Color(0xFFE7F0BB);
Color get lime400 => const Color(0xFFCFDB91);
Color get lime500 => const Color(0xFF92A822);
Color get lime600 => const Color(0xFF414D05);
// Grass colors
Color get grass100 => const Color(0xFFF4FAEB);
Color get grass200 => const Color(0xFFE9F5D7);
Color get grass300 => const Color(0xFFDEF0C5);
Color get grass400 => const Color(0xFFBFD998);
Color get grass500 => const Color(0xFF75A828);
Color get grass600 => const Color(0xFF334D0C);
// Forest colors
Color get forest100 => const Color(0xFFF1FAF0);
Color get forest200 => const Color(0xFFE2F5DF);
Color get forest300 => const Color(0xFFD7F0D3);
Color get forest400 => const Color(0xFFA8D6A1);
Color get forest500 => const Color(0xFF49A33B);
Color get forest600 => const Color(0xFF1E4F16);
// Jade colors
Color get jade100 => const Color(0xFFF0FAF6);
Color get jade200 => const Color(0xFFDFF5EB);
Color get jade300 => const Color(0xFFCEF0E1);
Color get jade400 => const Color(0xFF90D1B5);
Color get jade500 => const Color(0xFF1C9963);
Color get jade600 => const Color(0xFF075231);
// Aqua colors
Color get aqua100 => const Color(0xFFF0F9FA);
Color get aqua200 => const Color(0xFFDFF3F5);
Color get aqua300 => const Color(0xFFCCECF0);
Color get aqua400 => const Color(0xFF83CCD4);
Color get aqua500 => const Color(0xFF008E9E);
Color get aqua600 => const Color(0xFF004E57);
// Azure colors
Color get azure100 => const Color(0xFFF0F6FA);
Color get azure200 => const Color(0xFFE1EEF7);
Color get azure300 => const Color(0xFFD3E6F5);
Color get azure400 => const Color(0xFF88C0EB);
Color get azure500 => const Color(0xFF0877CC);
Color get azure600 => const Color(0xFF154469);
// Denim colors
Color get denim100 => const Color(0xFFF0F3FA);
Color get denim200 => const Color(0xFFE3EBFA);
Color get denim300 => const Color(0xFFD7E2F7);
Color get denim400 => const Color(0xFF9AB6ED);
Color get denim500 => const Color(0xFF3267D1);
Color get denim600 => const Color(0xFF223C70);
// Mauve colors
Color get mauve100 => const Color(0xFFF2F2FC);
Color get mauve200 => const Color(0xFFE6E6FA);
Color get mauve300 => const Color(0xFFDCDCF7);
Color get mauve400 => const Color(0xFFAEAEF5);
Color get mauve500 => const Color(0xFF5555E0);
Color get mauve600 => const Color(0xFF36366B);
// Lavender colors
Color get lavender100 => const Color(0xFFF6F3FC);
Color get lavender200 => const Color(0xFFEBE3FA);
Color get lavender300 => const Color(0xFFE4DAF7);
Color get lavender400 => const Color(0xFFC1AAF0);
Color get lavender500 => const Color(0xFF8153DB);
Color get lavender600 => const Color(0xFF462F75);
// Lilac colors
Color get lilac100 => const Color(0xFFF7F0FA);
Color get lilac200 => const Color(0xFFF0E1F7);
Color get lilac300 => const Color(0xFFEDD7F7);
Color get lilac400 => const Color(0xFFD3A9E8);
Color get lilac500 => const Color(0xFF9E4CC7);
Color get lilac600 => const Color(0xFF562D6B);
// Mallow colors
Color get mallow100 => const Color(0xFFFAF0FA);
Color get mallow200 => const Color(0xFFF5E1F4);
Color get mallow300 => const Color(0xFFF5D7F4);
Color get mallow400 => const Color(0xFFDEA4DC);
Color get mallow500 => const Color(0xFFB240AF);
Color get mallow600 => const Color(0xFF632861);
// Camellia colors
Color get camellia100 => const Color(0xFFF9EFF3);
Color get camellia200 => const Color(0xFFF7E1EB);
Color get camellia300 => const Color(0xFFF7D7E5);
Color get camellia400 => const Color(0xFFE5A3C0);
Color get camellia500 => const Color(0xFFC24279);
Color get camellia600 => const Color(0xFF6E2343);
// Smoke colors
Color get smoke100 => const Color(0xFFF5F5F5);
Color get smoke200 => const Color(0xFFE8E8E8);
Color get smoke300 => const Color(0xFFDEDEDE);
Color get smoke400 => const Color(0xFFB8B8B8);
Color get smoke500 => const Color(0xFF6E6E6E);
Color get smoke600 => const Color(0xFF404040);
// Iron colors
Color get iron100 => const Color(0xFFF2F4F7);
Color get iron200 => const Color(0xFFE6E9F0);
Color get iron300 => const Color(0xFFDADEE5);
Color get iron400 => const Color(0xFFB0B5BF);
Color get iron500 => const Color(0xFF666F80);
Color get iron600 => const Color(0xFF394152);
}

View file

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
class YellowColors {
const YellowColors();
Color get yellow100 => const Color(0xFFFFF9B2);
Color get yellow200 => const Color(0xFFFFEC66);
Color get yellow300 => const Color(0xFFFFDF1A);
Color get yellow400 => const Color(0xFFFFCC00);
Color get yellow500 => const Color(0xFFFFCE00);
Color get yellow600 => const Color(0xFFE6B800);
Color get yellow700 => const Color(0xFFCC9F00);
Color get yellow800 => const Color(0xFFB38A00);
Color get yellow900 => const Color(0xFF9A7500);
Color get yellow1000 => const Color(0xFF7F6200);
}

View file

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
class AppFlowyBorderColorScheme {
const AppFlowyBorderColorScheme({
required this.greyPrimary,
required this.greyPrimaryHover,
required this.greySecondary,
required this.greySecondaryHover,
required this.greyTertiary,
required this.greyTertiaryHover,
required this.greyQuaternary,
required this.greyQuaternaryHover,
required this.transparent,
required this.themeThick,
required this.themeThickHover,
required this.infoThick,
required this.infoThickHover,
required this.successThick,
required this.successThickHover,
required this.warningThick,
required this.warningThickHover,
required this.errorThick,
required this.errorThickHover,
required this.purpleThick,
required this.purpleThickHover,
});
final Color greyPrimary;
final Color greyPrimaryHover;
final Color greySecondary;
final Color greySecondaryHover;
final Color greyTertiary;
final Color greyTertiaryHover;
final Color greyQuaternary;
final Color greyQuaternaryHover;
final Color transparent;
final Color themeThick;
final Color themeThickHover;
final Color infoThick;
final Color infoThickHover;
final Color successThick;
final Color successThickHover;
final Color warningThick;
final Color warningThickHover;
final Color errorThick;
final Color errorThickHover;
final Color purpleThick;
final Color purpleThickHover;
}

View file

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
class AppFlowyBorderColorScheme {
const AppFlowyBorderColorScheme({
required this.greyPrimary,
required this.greyPrimaryHover,
required this.greySecondary,
required this.greySecondaryHover,
required this.greyTertiary,
required this.greyTertiaryHover,
required this.greyQuaternary,
required this.greyQuaternaryHover,
required this.transparent,
required this.themeThick,
required this.themeThickHover,
required this.infoThick,
required this.infoThickHover,
required this.successThick,
required this.successThickHover,
required this.warningThick,
required this.warningThickHover,
required this.errorThick,
required this.errorThickHover,
required this.purpleThick,
required this.purpleThickHover,
});
final Color greyPrimary;
final Color greyPrimaryHover;
final Color greySecondary;
final Color greySecondaryHover;
final Color greyTertiary;
final Color greyTertiaryHover;
final Color greyQuaternary;
final Color greyQuaternaryHover;
final Color transparent;
final Color themeThick;
final Color themeThickHover;
final Color infoThick;
final Color infoThickHover;
final Color successThick;
final Color successThickHover;
final Color warningThick;
final Color warningThickHover;
final Color errorThick;
final Color errorThickHover;
final Color purpleThick;
final Color purpleThickHover;
}

View file

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
class AppFlowyBrandColorScheme {
const AppFlowyBrandColorScheme({
required this.skyline,
required this.aqua,
required this.violet,
required this.amethyst,
required this.berry,
required this.coral,
required this.golden,
required this.amber,
required this.lemon,
});
final Color skyline;
final Color aqua;
final Color violet;
final Color amethyst;
final Color berry;
final Color coral;
final Color golden;
final Color amber;
final Color lemon;
}

View file

@ -0,0 +1,8 @@
export 'background/background_color_scheme.dart';
export 'base/base_scheme.dart';
export 'border/border_color_scheme.dart';
export 'brand/brand_color_scheme.dart';
export 'fill/fill_color_scheme.dart';
export 'icon/icon_color_theme.dart';
export 'surface/surface_color_scheme.dart';
export 'text/text_color_scheme.dart';

View file

@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
class AppFlowyFillColorScheme {
const AppFlowyFillColorScheme({
required this.primary,
required this.primaryHover,
required this.secondary,
required this.secondaryHover,
required this.tertiary,
required this.tertiaryHover,
required this.quaternary,
required this.quaternaryHover,
required this.transparent,
required this.primaryAlpha5,
required this.primaryAlpha5Hover,
required this.primaryAlpha80,
required this.primaryAlpha80Hover,
required this.white,
required this.whiteAlpha,
required this.whiteAlphaHover,
required this.black,
required this.themeLight,
required this.themeLightHover,
required this.themeThick,
required this.themeThickHover,
required this.themeSelect,
required this.infoLight,
required this.infoLightHover,
required this.infoThick,
required this.infoThickHover,
required this.successLight,
required this.successLightHover,
required this.successThick,
required this.successThickHover,
required this.warningLight,
required this.warningLightHover,
required this.warningThick,
required this.warningThickHover,
required this.errorLight,
required this.errorLightHover,
required this.errorThick,
required this.errorThickHover,
required this.errorSelect,
required this.purpleLight,
required this.purpleLightHover,
required this.purpleThick,
required this.purpleThickHover,
});
final Color primary;
final Color primaryHover;
final Color secondary;
final Color secondaryHover;
final Color tertiary;
final Color tertiaryHover;
final Color quaternary;
final Color quaternaryHover;
final Color transparent;
final Color primaryAlpha5;
final Color primaryAlpha5Hover;
final Color primaryAlpha80;
final Color primaryAlpha80Hover;
final Color white;
final Color whiteAlpha;
final Color whiteAlphaHover;
final Color black;
final Color themeLight;
final Color themeLightHover;
final Color themeThick;
final Color themeThickHover;
final Color themeSelect;
final Color infoLight;
final Color infoLightHover;
final Color infoThick;
final Color infoThickHover;
final Color successLight;
final Color successLightHover;
final Color successThick;
final Color successThickHover;
final Color warningLight;
final Color warningLightHover;
final Color warningThick;
final Color warningThickHover;
final Color errorLight;
final Color errorLightHover;
final Color errorThick;
final Color errorThickHover;
final Color errorSelect;
final Color purpleLight;
final Color purpleLightHover;
final Color purpleThick;
final Color purpleThickHover;
}

View file

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
class AppFlowyIconColorTheme {
const AppFlowyIconColorTheme({
required this.primary,
required this.secondary,
required this.tertiary,
required this.quaternary,
required this.white,
required this.purpleThick,
required this.purpleThickHover,
});
final Color primary;
final Color secondary;
final Color tertiary;
final Color quaternary;
final Color white;
final Color purpleThick;
final Color purpleThickHover;
}

View file

@ -0,0 +1,11 @@
import 'package:flutter/material.dart';
class AppFlowySurfaceColorScheme {
const AppFlowySurfaceColorScheme({
required this.primary,
required this.overlay,
});
final Color primary;
final Color overlay;
}

View file

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
class AppFlowyTextColorScheme {
const AppFlowyTextColorScheme({
required this.primary,
required this.secondary,
required this.tertiary,
required this.quaternary,
required this.inverse,
required this.onFill,
required this.theme,
required this.themeHover,
required this.action,
required this.actionHover,
required this.info,
required this.infoHover,
required this.success,
required this.successHover,
required this.warning,
required this.warningHover,
required this.error,
required this.errorHover,
required this.purple,
required this.purpleHover,
});
final Color primary;
final Color secondary;
final Color tertiary;
final Color quaternary;
final Color inverse;
final Color onFill;
final Color theme;
final Color themeHover;
final Color action;
final Color actionHover;
final Color info;
final Color infoHover;
final Color success;
final Color successHover;
final Color warning;
final Color warningHover;
final Color error;
final Color errorHover;
final Color purple;
final Color purpleHover;
}

View file

@ -0,0 +1,324 @@
import 'package:appflowy_ui/src/theme/border_radius/border_radius.dart';
import 'package:appflowy_ui/src/theme/color_scheme/background/background_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/base_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/border/border.dart';
import 'package:appflowy_ui/src/theme/color_scheme/brand/brand_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/fill/fill_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/icon/icon_color_theme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/surface/surface_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/text/text_color_scheme.dart';
import 'package:appflowy_ui/src/theme/dimensions.dart';
import 'package:appflowy_ui/src/theme/spacing/spacing.dart';
import 'package:flutter/material.dart';
class AppFlowyThemeBuilder {
const AppFlowyThemeBuilder();
AppFlowyTextColorScheme buildTextColorScheme(
AppFlowyBaseColorScheme colorScheme,
Brightness brightness,
) {
return switch (brightness) {
Brightness.light => AppFlowyTextColorScheme(
primary: colorScheme.neutral.neutral1000,
secondary: colorScheme.neutral.neutral600,
tertiary: colorScheme.neutral.neutral400,
quaternary: colorScheme.neutral.neutral200,
inverse: colorScheme.neutral.white,
onFill: colorScheme.neutral.white,
theme: colorScheme.blue.blue500,
themeHover: colorScheme.blue.blue600,
action: colorScheme.blue.blue500,
actionHover: colorScheme.blue.blue600,
info: colorScheme.blue.blue500,
infoHover: colorScheme.blue.blue600,
success: colorScheme.green.green600,
successHover: colorScheme.green.green700,
warning: colorScheme.orange.orange600,
warningHover: colorScheme.orange.orange700,
error: colorScheme.red.red600,
errorHover: colorScheme.red.red700,
purple: colorScheme.purple.purple500,
purpleHover: colorScheme.purple.purple600,
),
Brightness.dark => AppFlowyTextColorScheme(
primary: colorScheme.neutral.neutral200,
secondary: colorScheme.neutral.neutral400,
tertiary: colorScheme.neutral.neutral600,
quaternary: colorScheme.neutral.neutral1000,
inverse: colorScheme.neutral.neutral1000,
onFill: colorScheme.neutral.white,
theme: colorScheme.blue.blue500,
themeHover: colorScheme.blue.blue600,
action: colorScheme.blue.blue500,
actionHover: colorScheme.blue.blue600,
info: colorScheme.blue.blue500,
infoHover: colorScheme.blue.blue600,
success: colorScheme.green.green600,
successHover: colorScheme.green.green700,
warning: colorScheme.orange.orange600,
warningHover: colorScheme.orange.orange700,
error: colorScheme.red.red500,
errorHover: colorScheme.red.red400,
purple: colorScheme.purple.purple500,
purpleHover: colorScheme.purple.purple600,
),
};
}
AppFlowyIconColorTheme buildIconColorTheme(
AppFlowyBaseColorScheme colorScheme,
Brightness brightness,
) {
return switch (brightness) {
Brightness.light => AppFlowyIconColorTheme(
primary: colorScheme.neutral.neutral1000,
secondary: colorScheme.neutral.neutral600,
tertiary: colorScheme.neutral.neutral400,
quaternary: colorScheme.neutral.neutral200,
white: colorScheme.neutral.white,
purpleThick: colorScheme.purple.purple500,
purpleThickHover: colorScheme.purple.purple600,
),
Brightness.dark => AppFlowyIconColorTheme(
primary: colorScheme.neutral.neutral200,
secondary: colorScheme.neutral.neutral400,
tertiary: colorScheme.neutral.neutral600,
quaternary: colorScheme.neutral.neutral1000,
white: colorScheme.neutral.white,
purpleThick: const Color(0xFFFFFFFF),
purpleThickHover: const Color(0xFFFFFFFF),
),
};
}
AppFlowyBorderColorScheme buildBorderColorScheme(
AppFlowyBaseColorScheme colorScheme,
Brightness brightness,
) {
return switch (brightness) {
Brightness.light => AppFlowyBorderColorScheme(
greyPrimary: colorScheme.neutral.neutral1000,
greyPrimaryHover: colorScheme.neutral.neutral900,
greySecondary: colorScheme.neutral.neutral800,
greySecondaryHover: colorScheme.neutral.neutral700,
greyTertiary: colorScheme.neutral.neutral300,
greyTertiaryHover: colorScheme.neutral.neutral400,
greyQuaternary: colorScheme.neutral.neutral100,
greyQuaternaryHover: colorScheme.neutral.neutral200,
transparent: colorScheme.neutral.alphaWhite0,
themeThick: colorScheme.blue.blue500,
themeThickHover: colorScheme.blue.blue600,
infoThick: colorScheme.blue.blue500,
infoThickHover: colorScheme.blue.blue600,
successThick: colorScheme.green.green600,
successThickHover: colorScheme.green.green700,
warningThick: colorScheme.orange.orange600,
warningThickHover: colorScheme.orange.orange700,
errorThick: colorScheme.red.red600,
errorThickHover: colorScheme.red.red700,
purpleThick: colorScheme.purple.purple500,
purpleThickHover: colorScheme.purple.purple600,
),
Brightness.dark => AppFlowyBorderColorScheme(
greyPrimary: colorScheme.neutral.neutral100,
greyPrimaryHover: colorScheme.neutral.neutral200,
greySecondary: colorScheme.neutral.neutral300,
greySecondaryHover: colorScheme.neutral.neutral400,
greyTertiary: colorScheme.neutral.neutral800,
greyTertiaryHover: colorScheme.neutral.neutral700,
greyQuaternary: colorScheme.neutral.neutral1000,
greyQuaternaryHover: colorScheme.neutral.neutral900,
transparent: colorScheme.neutral.alphaWhite0,
themeThick: colorScheme.blue.blue500,
themeThickHover: colorScheme.blue.blue600,
infoThick: colorScheme.blue.blue500,
infoThickHover: colorScheme.blue.blue600,
successThick: colorScheme.green.green600,
successThickHover: colorScheme.green.green700,
warningThick: colorScheme.orange.orange600,
warningThickHover: colorScheme.orange.orange700,
errorThick: colorScheme.red.red500,
errorThickHover: colorScheme.red.red400,
purpleThick: colorScheme.purple.purple500,
purpleThickHover: colorScheme.purple.purple600,
),
};
}
AppFlowyFillColorScheme buildFillColorScheme(
AppFlowyBaseColorScheme colorScheme,
Brightness brightness,
) {
return switch (brightness) {
Brightness.light => AppFlowyFillColorScheme(
primary: colorScheme.neutral.neutral100,
primaryHover: colorScheme.neutral.neutral200,
secondary: colorScheme.neutral.neutral300,
secondaryHover: colorScheme.neutral.neutral400,
tertiary: colorScheme.neutral.neutral600,
tertiaryHover: colorScheme.neutral.neutral500,
quaternary: colorScheme.neutral.neutral1000,
quaternaryHover: colorScheme.neutral.neutral900,
transparent: colorScheme.neutral.alphaWhite0,
primaryAlpha5: colorScheme.neutral.alphaGrey100005,
primaryAlpha5Hover: colorScheme.neutral.alphaGrey10010,
primaryAlpha80: colorScheme.neutral.alphaGrey100080,
primaryAlpha80Hover: colorScheme.neutral.alphaGrey100070,
white: colorScheme.neutral.white,
whiteAlpha: colorScheme.neutral.alphaWhite20,
whiteAlphaHover: colorScheme.neutral.alphaWhite30,
black: colorScheme.neutral.black,
themeLight: colorScheme.blue.blue100,
themeLightHover: colorScheme.blue.blue200,
themeThick: colorScheme.blue.blue500,
themeThickHover: colorScheme.blue.blue600,
themeSelect: colorScheme.blue.alphaBlue50015,
infoLight: colorScheme.blue.blue100,
infoLightHover: colorScheme.blue.blue200,
infoThick: colorScheme.blue.blue500,
infoThickHover: colorScheme.blue.blue600,
successLight: colorScheme.green.green100,
successLightHover: colorScheme.green.green200,
successThick: colorScheme.green.green600,
successThickHover: colorScheme.green.green700,
warningLight: colorScheme.orange.orange100,
warningLightHover: colorScheme.orange.orange200,
warningThick: colorScheme.orange.orange600,
warningThickHover: colorScheme.orange.orange700,
errorLight: colorScheme.red.red100,
errorLightHover: colorScheme.red.red200,
errorThick: colorScheme.red.red600,
errorThickHover: colorScheme.red.red700,
errorSelect: colorScheme.red.alphaRed50010,
purpleLight: colorScheme.purple.purple100,
purpleLightHover: colorScheme.purple.purple200,
purpleThick: colorScheme.purple.purple500,
purpleThickHover: colorScheme.purple.purple600,
),
Brightness.dark => AppFlowyFillColorScheme(
primary: colorScheme.neutral.neutral1000,
primaryHover: colorScheme.neutral.neutral900,
secondary: colorScheme.neutral.neutral600,
secondaryHover: colorScheme.neutral.neutral500,
tertiary: colorScheme.neutral.neutral300,
tertiaryHover: colorScheme.neutral.neutral400,
quaternary: colorScheme.neutral.neutral100,
quaternaryHover: colorScheme.neutral.neutral200,
transparent: colorScheme.neutral.alphaWhite0,
primaryAlpha5: colorScheme.neutral.alphaGrey100005,
primaryAlpha5Hover: colorScheme.neutral.alphaGrey100010,
primaryAlpha80: colorScheme.neutral.alphaGrey100080,
primaryAlpha80Hover: colorScheme.neutral.alphaGrey100070,
white: colorScheme.neutral.white,
whiteAlpha: colorScheme.neutral.alphaWhite20,
whiteAlphaHover: colorScheme.neutral.alphaWhite30,
black: colorScheme.neutral.black,
themeLight: colorScheme.blue.blue100,
themeLightHover: colorScheme.blue.blue200,
themeThick: colorScheme.blue.blue500,
themeThickHover: colorScheme.blue.blue600,
themeSelect: colorScheme.blue.alphaBlue50015,
infoLight: colorScheme.blue.blue100,
infoLightHover: colorScheme.blue.blue200,
infoThick: colorScheme.blue.blue500,
infoThickHover: colorScheme.blue.blue600,
successLight: colorScheme.green.green100,
successLightHover: colorScheme.green.green200,
successThick: colorScheme.green.green600,
successThickHover: colorScheme.green.green700,
warningLight: colorScheme.orange.orange100,
warningLightHover: colorScheme.orange.orange200,
warningThick: colorScheme.orange.orange600,
warningThickHover: colorScheme.orange.orange700,
errorLight: colorScheme.red.red100,
errorLightHover: colorScheme.red.red200,
errorThick: colorScheme.red.red600,
errorThickHover: colorScheme.red.red700,
errorSelect: colorScheme.red.alphaRed50010,
purpleLight: colorScheme.purple.purple100,
purpleLightHover: colorScheme.purple.purple200,
purpleThick: colorScheme.purple.purple500,
purpleThickHover: colorScheme.purple.purple600,
),
};
}
AppFlowySurfaceColorScheme buildSurfaceColorScheme(
AppFlowyBaseColorScheme colorScheme,
Brightness brightness,
) {
return switch (brightness) {
Brightness.light => AppFlowySurfaceColorScheme(
primary: colorScheme.neutral.white,
overlay: colorScheme.neutral.alphaBlack60,
),
Brightness.dark => AppFlowySurfaceColorScheme(
primary: colorScheme.neutral.neutral900,
overlay: colorScheme.neutral.alphaBlack60,
),
};
}
AppFlowyBackgroundColorScheme buildBackgroundColorScheme(
AppFlowyBaseColorScheme colorScheme,
Brightness brightness,
) {
return switch (brightness) {
Brightness.light => AppFlowyBackgroundColorScheme(
primary: colorScheme.neutral.white,
secondary: colorScheme.neutral.neutral100,
tertiary: colorScheme.neutral.neutral200,
quaternary: colorScheme.neutral.neutral300,
),
Brightness.dark => AppFlowyBackgroundColorScheme(
primary: colorScheme.neutral.neutral1000,
secondary: colorScheme.neutral.neutral900,
tertiary: colorScheme.neutral.neutral800,
quaternary: colorScheme.neutral.neutral700,
),
};
}
AppFlowyBrandColorScheme buildBrandColorScheme(
AppFlowyBaseColorScheme colorScheme,
) {
return AppFlowyBrandColorScheme(
skyline: const Color(0xFF00B5FF),
aqua: const Color(0xFF00C8FF),
violet: const Color(0xFF9327FF),
amethyst: const Color(0xFF8427E0),
berry: const Color(0xFFE3006D),
coral: const Color(0xFFFB006D),
golden: const Color(0xFFF7931E),
amber: const Color(0xFFFFBD00),
lemon: const Color(0xFFFFCE00),
);
}
AppFlowyBorderRadius buildBorderRadius(
AppFlowyBaseColorScheme colorScheme,
) {
return AppFlowyBorderRadius(
xs: AppFlowyBorderRadiusConstant.radius100,
s: AppFlowyBorderRadiusConstant.radius200,
m: AppFlowyBorderRadiusConstant.radius300,
l: AppFlowyBorderRadiusConstant.radius400,
xl: AppFlowyBorderRadiusConstant.radius500,
xxl: AppFlowyBorderRadiusConstant.radius600,
);
}
AppFlowySpacing buildSpacing(
AppFlowyBaseColorScheme colorScheme,
) {
return AppFlowySpacing(
xs: AppFlowySpacingConstant.spacing100,
s: AppFlowySpacingConstant.spacing200,
m: AppFlowySpacingConstant.spacing300,
l: AppFlowySpacingConstant.spacing400,
xl: AppFlowySpacingConstant.spacing500,
xxl: AppFlowySpacingConstant.spacing600,
);
}
}

View file

@ -0,0 +1,238 @@
import 'package:appflowy_ui/src/theme/border_radius/border_radius.dart';
import 'package:appflowy_ui/src/theme/color_scheme/background/background_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/base/base_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/border/border.dart';
import 'package:appflowy_ui/src/theme/color_scheme/brand/brand_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/fill/fill_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/icon/icon_color_theme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/surface/surface_color_scheme.dart';
import 'package:appflowy_ui/src/theme/color_scheme/text/text_color_scheme.dart';
import 'package:appflowy_ui/src/theme/data/builder.dart';
import 'package:appflowy_ui/src/theme/spacing/spacing.dart';
import 'package:appflowy_ui/src/theme/text_style/text_style.dart';
import 'package:flutter/material.dart';
abstract class AppFlowyBaseTheme {
const AppFlowyBaseTheme();
AppFlowyBaseColorScheme get colorScheme;
AppFlowyTextColorScheme get textColorScheme;
AppFlowyBaseTextStyle get textStyle;
AppFlowyIconColorTheme get iconColorTheme;
AppFlowyBorderColorScheme get borderColorScheme;
AppFlowyBackgroundColorScheme get backgroundColorScheme;
AppFlowyFillColorScheme get fillColorScheme;
AppFlowySurfaceColorScheme get surfaceColorScheme;
AppFlowyBorderRadius get borderRadius;
AppFlowySpacing get spacing;
AppFlowyBrandColorScheme get brandColorScheme;
}
class AppFlowyThemeData extends AppFlowyBaseTheme {
factory AppFlowyThemeData.light() {
final colorScheme = AppFlowyBaseColorScheme();
final textStyle = AppFlowyBaseTextStyle();
final textColorScheme = themeBuilder.buildTextColorScheme(
colorScheme,
Brightness.light,
);
final borderColorScheme = themeBuilder.buildBorderColorScheme(
colorScheme,
Brightness.light,
);
final fillColorScheme = themeBuilder.buildFillColorScheme(
colorScheme,
Brightness.light,
);
final surfaceColorScheme = themeBuilder.buildSurfaceColorScheme(
colorScheme,
Brightness.light,
);
final backgroundColorScheme = themeBuilder.buildBackgroundColorScheme(
colorScheme,
Brightness.light,
);
final iconColorTheme = themeBuilder.buildIconColorTheme(
colorScheme,
Brightness.light,
);
final brandColorScheme = themeBuilder.buildBrandColorScheme(colorScheme);
final borderRadius = themeBuilder.buildBorderRadius(colorScheme);
final spacing = themeBuilder.buildSpacing(colorScheme);
return AppFlowyThemeData(
colorScheme: colorScheme,
textColorScheme: textColorScheme,
textStyle: textStyle,
iconColorTheme: iconColorTheme,
backgroundColorScheme: backgroundColorScheme,
borderColorScheme: borderColorScheme,
fillColorScheme: fillColorScheme,
surfaceColorScheme: surfaceColorScheme,
borderRadius: borderRadius,
spacing: spacing,
brandColorScheme: brandColorScheme,
);
}
factory AppFlowyThemeData.dark() {
final colorScheme = AppFlowyBaseColorScheme();
final textStyle = AppFlowyBaseTextStyle();
final textColorScheme = themeBuilder.buildTextColorScheme(
colorScheme,
Brightness.dark,
);
final borderColorScheme = themeBuilder.buildBorderColorScheme(
colorScheme,
Brightness.dark,
);
final fillColorScheme = themeBuilder.buildFillColorScheme(
colorScheme,
Brightness.dark,
);
final surfaceColorScheme = themeBuilder.buildSurfaceColorScheme(
colorScheme,
Brightness.dark,
);
final backgroundColorScheme = themeBuilder.buildBackgroundColorScheme(
colorScheme,
Brightness.dark,
);
final iconColorTheme = themeBuilder.buildIconColorTheme(
colorScheme,
Brightness.dark,
);
final brandColorScheme = themeBuilder.buildBrandColorScheme(colorScheme);
final borderRadius = themeBuilder.buildBorderRadius(colorScheme);
final spacing = themeBuilder.buildSpacing(colorScheme);
return AppFlowyThemeData(
colorScheme: colorScheme,
textColorScheme: textColorScheme,
textStyle: textStyle,
iconColorTheme: iconColorTheme,
backgroundColorScheme: backgroundColorScheme,
borderColorScheme: borderColorScheme,
fillColorScheme: fillColorScheme,
surfaceColorScheme: surfaceColorScheme,
borderRadius: borderRadius,
spacing: spacing,
brandColorScheme: brandColorScheme,
);
}
const AppFlowyThemeData({
required this.colorScheme,
required this.textStyle,
required this.textColorScheme,
required this.borderColorScheme,
required this.fillColorScheme,
required this.surfaceColorScheme,
required this.borderRadius,
required this.spacing,
required this.brandColorScheme,
required this.iconColorTheme,
required this.backgroundColorScheme,
this.brightness = Brightness.light,
});
static const AppFlowyThemeBuilder themeBuilder = AppFlowyThemeBuilder();
final Brightness brightness;
@override
final AppFlowyBaseColorScheme colorScheme;
@override
final AppFlowyBaseTextStyle textStyle;
@override
final AppFlowyTextColorScheme textColorScheme;
@override
final AppFlowyBorderColorScheme borderColorScheme;
@override
final AppFlowyFillColorScheme fillColorScheme;
@override
final AppFlowySurfaceColorScheme surfaceColorScheme;
@override
final AppFlowyBorderRadius borderRadius;
@override
final AppFlowySpacing spacing;
@override
final AppFlowyBrandColorScheme brandColorScheme;
@override
final AppFlowyIconColorTheme iconColorTheme;
@override
final AppFlowyBackgroundColorScheme backgroundColorScheme;
static AppFlowyTextColorScheme buildTextColorScheme(
AppFlowyBaseColorScheme colorScheme,
Brightness brightness,
) {
return switch (brightness) {
Brightness.light => AppFlowyTextColorScheme(
primary: colorScheme.neutral.neutral1000,
secondary: colorScheme.neutral.neutral600,
tertiary: colorScheme.neutral.neutral400,
quaternary: colorScheme.neutral.neutral200,
inverse: colorScheme.neutral.white,
onFill: colorScheme.neutral.white,
theme: colorScheme.blue.blue500,
themeHover: colorScheme.blue.blue600,
action: colorScheme.blue.blue500,
actionHover: colorScheme.blue.blue600,
info: colorScheme.blue.blue500,
infoHover: colorScheme.blue.blue600,
success: colorScheme.green.green600,
successHover: colorScheme.green.green700,
warning: colorScheme.orange.orange600,
warningHover: colorScheme.orange.orange700,
error: colorScheme.red.red600,
errorHover: colorScheme.red.red700,
purple: colorScheme.purple.purple500,
purpleHover: colorScheme.purple.purple600,
),
Brightness.dark => AppFlowyTextColorScheme(
primary: colorScheme.neutral.neutral200,
secondary: colorScheme.neutral.neutral400,
tertiary: colorScheme.neutral.neutral600,
quaternary: colorScheme.neutral.neutral1000,
inverse: colorScheme.neutral.neutral1000,
onFill: colorScheme.neutral.white,
theme: colorScheme.blue.blue500,
themeHover: colorScheme.blue.blue600,
action: colorScheme.blue.blue500,
actionHover: colorScheme.blue.blue600,
info: colorScheme.blue.blue500,
infoHover: colorScheme.blue.blue600,
success: colorScheme.green.green600,
successHover: colorScheme.green.green700,
warning: colorScheme.orange.orange600,
warningHover: colorScheme.orange.orange700,
error: colorScheme.red.red500,
errorHover: colorScheme.red.red400,
purple: colorScheme.purple.purple500,
purpleHover: colorScheme.purple.purple600,
),
};
}
}

View file

@ -0,0 +1,17 @@
class AppFlowySpacingConstant {
static const double spacing100 = 4;
static const double spacing200 = 6;
static const double spacing300 = 8;
static const double spacing400 = 12;
static const double spacing500 = 16;
static const double spacing600 = 20;
}
class AppFlowyBorderRadiusConstant {
static const double radius100 = 4;
static const double radius200 = 6;
static const double radius300 = 8;
static const double radius400 = 12;
static const double radius500 = 16;
static const double radius600 = 20;
}

View file

@ -0,0 +1,17 @@
class AppFlowySpacing {
const AppFlowySpacing({
required this.xs,
required this.s,
required this.m,
required this.l,
required this.xl,
required this.xxl,
});
final double xs;
final double s;
final double m;
final double l;
final double xl;
final double xxl;
}

View file

@ -0,0 +1,298 @@
import 'package:flutter/widgets.dart';
abstract class TextThemeType {
const TextThemeType();
TextStyle standard({
String family = '',
Color? color,
});
TextStyle enhanced({
String family = '',
Color? color,
});
TextStyle prominent({
String family = '',
Color? color,
});
TextStyle underline({
String family = '',
Color? color,
});
}
class TextThemeHeading {
const TextThemeHeading();
TextStyle h1({
String family = '',
Color? color,
}) =>
_defaultTextStyle(
family: family,
fontSize: 36,
height: 40 / 36,
color: color,
);
TextStyle h2({
String family = '',
Color? color,
}) =>
_defaultTextStyle(
family: family,
fontSize: 24,
height: 32 / 24,
color: color,
);
TextStyle h3({
String family = '',
Color? color,
}) =>
_defaultTextStyle(
family: family,
fontSize: 20,
height: 28 / 20,
color: color,
);
TextStyle h4({
String family = '',
Color? color,
}) =>
_defaultTextStyle(
family: family,
fontSize: 16,
height: 22 / 16,
color: color,
);
static TextStyle _defaultTextStyle({
required String family,
required double fontSize,
required double height,
TextDecoration decoration = TextDecoration.none,
Color? color,
}) =>
TextStyle(
inherit: false,
fontSize: fontSize,
decoration: decoration,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
height: height,
fontFamily: family,
color: color,
textBaseline: TextBaseline.alphabetic,
leadingDistribution: TextLeadingDistribution.even,
);
}
class TextThemeHeadline extends TextThemeType {
const TextThemeHeadline();
@override
TextStyle standard({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
);
@override
TextStyle enhanced({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.w600,
);
@override
TextStyle prominent({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.bold,
);
@override
TextStyle underline({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
decoration: TextDecoration.underline,
);
static TextStyle _defaultTextStyle({
required String family,
double fontSize = 24,
double height = 36 / 24,
FontWeight weight = FontWeight.normal,
TextDecoration decoration = TextDecoration.none,
Color? color,
}) =>
TextStyle(
inherit: false,
fontSize: fontSize,
decoration: decoration,
fontStyle: FontStyle.normal,
fontWeight: weight,
height: height,
fontFamily: family,
textBaseline: TextBaseline.alphabetic,
leadingDistribution: TextLeadingDistribution.even,
color: color,
);
}
class TextThemeTitle extends TextThemeType {
const TextThemeTitle();
@override
TextStyle standard({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
);
@override
TextStyle enhanced({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.w600,
);
@override
TextStyle prominent({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.bold,
);
@override
TextStyle underline({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
decoration: TextDecoration.underline,
);
static TextStyle _defaultTextStyle({
required String family,
double fontSize = 20,
double height = 28 / 20,
FontWeight weight = FontWeight.normal,
TextDecoration decoration = TextDecoration.none,
Color? color,
}) =>
TextStyle(
inherit: false,
fontSize: fontSize,
decoration: decoration,
fontStyle: FontStyle.normal,
fontWeight: weight,
height: height,
fontFamily: family,
textBaseline: TextBaseline.alphabetic,
leadingDistribution: TextLeadingDistribution.even,
color: color,
);
}
class TextThemeBody extends TextThemeType {
const TextThemeBody();
@override
TextStyle standard({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
);
@override
TextStyle enhanced({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.w600,
);
@override
TextStyle prominent({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.bold,
);
@override
TextStyle underline({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
decoration: TextDecoration.underline,
);
static TextStyle _defaultTextStyle({
required String family,
double fontSize = 14,
double height = 20 / 14,
FontWeight weight = FontWeight.normal,
TextDecoration decoration = TextDecoration.none,
Color? color,
}) =>
TextStyle(
inherit: false,
fontSize: fontSize,
decoration: decoration,
fontStyle: FontStyle.normal,
fontWeight: weight,
height: height,
fontFamily: family,
textBaseline: TextBaseline.alphabetic,
leadingDistribution: TextLeadingDistribution.even,
color: color,
);
}
class TextThemeCaption extends TextThemeType {
const TextThemeCaption();
@override
TextStyle standard({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
);
@override
TextStyle enhanced({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.w600,
);
@override
TextStyle prominent({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
weight: FontWeight.bold,
);
@override
TextStyle underline({String family = '', Color? color}) => _defaultTextStyle(
family: family,
color: color,
decoration: TextDecoration.underline,
);
static TextStyle _defaultTextStyle({
required String family,
double fontSize = 12,
double height = 16 / 12,
FontWeight weight = FontWeight.normal,
TextDecoration decoration = TextDecoration.none,
Color? color,
}) =>
TextStyle(
inherit: false,
fontSize: fontSize,
decoration: decoration,
fontStyle: FontStyle.normal,
fontWeight: weight,
height: height,
fontFamily: family,
textBaseline: TextBaseline.alphabetic,
leadingDistribution: TextLeadingDistribution.even,
color: color,
);
}

View file

@ -0,0 +1,17 @@
import 'package:appflowy_ui/src/theme/text_style/base/default_text_style.dart';
class AppFlowyBaseTextStyle {
const AppFlowyBaseTextStyle({
this.heading = const TextThemeHeading(),
this.headline = const TextThemeHeadline(),
this.title = const TextThemeTitle(),
this.body = const TextThemeBody(),
this.caption = const TextThemeCaption(),
});
final TextThemeHeading heading;
final TextThemeType headline;
final TextThemeType title;
final TextThemeType body;
final TextThemeType caption;
}

View file

@ -0,0 +1,7 @@
export 'appflowy_theme.dart';
export 'border_radius/border_radius.dart';
export 'color_scheme/color_scheme.dart';
export 'data/data.dart';
export 'dimensions.dart';
export 'spacing/spacing.dart';
export 'text_style/text_style.dart';

View file

@ -0,0 +1,17 @@
name: appflowy_ui
description: "A Flutter package for AppFlowy UI components and widgets"
version: 1.0.0
homepage: https://github.com/appflowy-io/appflowy
environment:
sdk: ^3.6.2
flutter: ">=1.17.0"
dependencies:
flutter:
sdk: flutter
flutter_lints: ^5.0.0
dev_dependencies:
flutter_test:
sdk: flutter

View file

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.6 14.0002C11.6 15.5466 12.8536 16.8002 14.4 16.8002C15.9464 16.8002 17.2 15.5466 17.2 14.0002C17.2 12.4538 15.9464 11.2002 14.4 11.2002C12.8536 11.2002 11.6 12.4538 11.6 14.0002ZM11.6 14.0002L11.0733 13.7368C10.3977 13.399 9.60232 13.399 8.92672 13.7368L8.4 14.0002M2 8.8002H18M3.6 8.8002L4.09104 6.83603C4.52758 5.08988 4.74585 4.21681 5.39687 3.7085C6.0479 3.2002 6.94784 3.2002 8.74776 3.2002H11.2522C13.0522 3.2002 13.9521 3.2002 14.6031 3.7085C15.2542 4.21681 15.4724 5.08988 15.909 6.83603L16.4 8.8002M8.4 14.0002C8.4 15.5466 7.1464 16.8002 5.6 16.8002C4.0536 16.8002 2.8 15.5466 2.8 14.0002C2.8 12.4538 4.0536 11.2002 5.6 11.2002C7.1464 11.2002 8.4 12.4538 8.4 14.0002Z" stroke="#6F748C" stroke-width="1.25" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 856 B