kasy-cli 1.21.8 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/add.js +93 -80
- package/lib/commands/configure.js +100 -32
- package/lib/commands/doctor.js +28 -2
- package/lib/commands/new.js +86 -38
- package/lib/commands/notifications.js +1 -1
- package/lib/commands/remove.js +43 -15
- package/lib/commands/run.js +2 -2
- package/lib/commands/update.js +2 -2
- package/lib/scaffold/CHANGELOG.json +14 -0
- package/lib/scaffold/backends/api/generator.js +14 -14
- package/lib/scaffold/backends/api/patch/README.md +83 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +5 -0
- package/lib/scaffold/backends/api/patch/lib/{environnements.dart → environments.dart} +3 -11
- package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_api.dart +108 -0
- package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +51 -0
- package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +5 -5
- package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +71 -38
- package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +2 -2
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +54 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +16 -16
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +100 -0
- package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
- package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +60 -0
- package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/lib/scaffold/backends/api/pubspec.yaml.tpl +4 -5
- package/lib/scaffold/backends/firebase/deploy.js +87 -13
- package/lib/scaffold/backends/firebase/enable-auth-via-cli.js +14 -6
- package/lib/scaffold/backends/firebase/generator.js +5 -5
- package/lib/scaffold/backends/firebase/setup-from-scratch.js +69 -45
- package/lib/scaffold/backends/firebase/tokens.js +4 -4
- package/lib/scaffold/backends/supabase/deploy.js +63 -11
- package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
- package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
- package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
- package/lib/scaffold/backends/supabase/generator.js +17 -17
- package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
- package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
- package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
- package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
- package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
- package/lib/scaffold/backends/supabase/tokens.js +3 -3
- package/lib/scaffold/catalog.js +9 -11
- package/lib/scaffold/generate.js +45 -31
- package/lib/scaffold/shared/generator-utils.js +188 -81
- package/lib/scaffold/shared/sort-imports.js +191 -0
- package/lib/scaffold/shared/template-strings.js +3 -3
- package/lib/utils/checks.js +2 -2
- package/lib/utils/i18n/messages-en.js +50 -35
- package/lib/utils/i18n/messages-es.js +50 -35
- package/lib/utils/i18n/messages-pt.js +52 -37
- package/lib/utils/updates.js +15 -15
- package/package.json +1 -1
- package/templates/firebase/.env.example +2 -2
- package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
- package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
- package/templates/firebase/assets/images/logo_wordmark_dark.png +0 -0
- package/templates/firebase/assets/images/logo_wordmark_light.png +0 -0
- package/templates/firebase/docs/revenuecat-setup.es.md +1 -1
- package/templates/firebase/docs/revenuecat-setup.pt.md +1 -1
- package/templates/firebase/firestore.rules +24 -5
- package/templates/firebase/functions/package-lock.json +22 -1
- package/templates/firebase/functions/package.json +2 -1
- package/templates/firebase/functions/src/admin/functions.ts +113 -0
- package/templates/firebase/functions/src/{llm_chat → ai_chat}/index.ts +16 -16
- package/templates/firebase/functions/src/index.ts +8 -2
- package/templates/firebase/functions/src/notifications/device_triggers.ts +2 -2
- package/templates/firebase/functions/src/notifications/triggers.ts +3 -3
- package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +2 -0
- package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +222 -0
- package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +2 -2
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
- package/templates/firebase/lib/components/components.dart +4 -1
- package/templates/firebase/lib/components/kasy_app_bar.dart +22 -7
- package/templates/firebase/lib/components/kasy_avatar.dart +7 -6
- package/templates/firebase/lib/components/kasy_button.dart +23 -99
- package/templates/firebase/lib/components/kasy_dialog.dart +11 -11
- package/templates/firebase/lib/components/kasy_image_viewer.dart +84 -0
- package/templates/firebase/lib/components/{kasy_sidebar_pro.dart → kasy_sidebar.dart} +692 -425
- package/templates/firebase/lib/components/kasy_status_tag.dart +91 -0
- package/templates/firebase/lib/components/kasy_text_area.dart +1 -3
- package/templates/firebase/lib/components/kasy_text_field.dart +5 -6
- package/templates/firebase/lib/components/kasy_text_field_otp.dart +1 -3
- package/templates/firebase/lib/components/kasy_toast.dart +2 -2
- package/templates/firebase/lib/components/kasy_web_header.dart +209 -0
- package/templates/firebase/lib/core/ads/ads_provider.dart +1 -1
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +57 -4
- package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +19 -91
- package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +196 -96
- package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +41 -0
- package/templates/firebase/lib/core/config/app_env.dart +5 -11
- package/templates/firebase/lib/core/config/features.dart +5 -4
- package/templates/firebase/lib/core/data/api/analytics_api.dart +1 -1
- package/templates/firebase/lib/core/data/api/http_client.dart +1 -1
- package/templates/firebase/lib/core/data/entities/user_entity.dart +3 -0
- package/templates/firebase/lib/core/data/models/entitlement.dart +35 -0
- package/templates/firebase/lib/core/data/models/subscription.dart +13 -186
- package/templates/firebase/lib/core/data/models/user.dart +11 -0
- package/templates/firebase/lib/core/data/repositories/user_repository.dart +1 -1
- package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +1 -1
- package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +1 -1
- package/templates/firebase/lib/core/icons/kasy_icons.dart +31 -1
- package/templates/firebase/lib/core/rating/api/rating_api.dart +2 -2
- package/templates/firebase/lib/core/states/logout_action.dart +25 -0
- package/templates/firebase/lib/core/states/user_state_notifier.dart +3 -3
- package/templates/firebase/lib/core/theme/colors.dart +488 -188
- package/templates/firebase/lib/core/theme/radius.dart +22 -11
- package/templates/firebase/lib/core/theme/shadows.dart +66 -0
- package/templates/firebase/lib/core/theme/texts.dart +75 -41
- package/templates/firebase/lib/core/theme/universal_theme.dart +9 -4
- package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +5 -4
- package/templates/firebase/lib/core/web_viewport_scale.dart +52 -0
- package/templates/firebase/lib/core/widgets/kasy_brand_badge.dart +118 -0
- package/templates/firebase/lib/core/widgets/kasy_brand_logo.dart +40 -0
- package/templates/firebase/lib/core/widgets/kasy_focus_ring.dart +125 -0
- package/templates/firebase/lib/core/widgets/kasy_hover.dart +33 -13
- package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +18 -13
- package/templates/firebase/lib/{environnements.dart → environments.dart} +3 -14
- package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +159 -0
- package/templates/firebase/lib/features/ai_chat/api/ai_chat_api.dart +107 -0
- package/templates/firebase/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +64 -0
- package/templates/firebase/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
- package/templates/firebase/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +73 -38
- package/templates/firebase/lib/features/ai_chat/providers/ai_conversations_notifier.dart +103 -0
- package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_avatars.dart → ai_chat/ui/widgets/ai_chat_avatars.dart} +13 -13
- package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_composer.dart → ai_chat/ui/widgets/ai_chat_composer.dart} +10 -10
- package/templates/firebase/lib/features/{llm_chat/llm_chat_page.dart → ai_chat/ui/widgets/ai_chat_conversation_view.dart} +80 -67
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +285 -0
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +163 -0
- package/templates/firebase/lib/features/authentication/api/authentication_api.dart +52 -13
- package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher.dart +12 -0
- package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher_web.dart +35 -0
- package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +108 -68
- package/templates/firebase/lib/features/authentication/ui/signin_page.dart +38 -51
- package/templates/firebase/lib/features/authentication/ui/signup_page.dart +38 -51
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +118 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +61 -44
- package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +32 -0
- package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +5 -5
- package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +2 -2
- package/templates/firebase/lib/features/home/design_system_page.dart +808 -170
- package/templates/firebase/lib/features/home/home_components_page.dart +6 -3
- package/templates/firebase/lib/features/home/home_components_preview_page.dart +6 -6
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +325 -186
- package/templates/firebase/lib/features/home/home_feed.dart +289 -0
- package/templates/firebase/lib/features/home/home_image_grid.dart +355 -0
- package/templates/firebase/lib/features/home/home_page.dart +11 -250
- package/templates/firebase/lib/features/{local_reminder → local_reminders}/providers/reminder_notifier.dart +1 -1
- package/templates/firebase/lib/features/{local_reminder → local_reminders}/ui/reminder_page.dart +2 -2
- package/templates/firebase/lib/features/notifications/shared/att_permission.dart +1 -1
- package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +25 -61
- package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +117 -0
- package/templates/firebase/lib/features/onboarding/models/user_info.dart +16 -16
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +7 -9
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +71 -48
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +3 -2
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +5 -5
- package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +4 -4
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +4 -2
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +39 -121
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +105 -70
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +639 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +62 -50
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_step_header.dart +75 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +16 -5
- package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +26 -22
- package/templates/firebase/lib/features/settings/settings_page.dart +601 -90
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +1193 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +1 -1
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +2 -3
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +86 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +1215 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +236 -0
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +3 -3
- package/templates/firebase/lib/features/settings/ui/widgets/kasy_user_avatar.dart +77 -0
- package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +1 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +17 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/inapp_subscription_api.dart +67 -46
- package/templates/firebase/lib/features/subscriptions/api/revenuecat_product.dart +189 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +55 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +82 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_product.dart +178 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api.dart +53 -0
- package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api_provider.dart +21 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/providers/premium_page_provider.dart +9 -6
- package/templates/firebase/lib/features/{subscription → subscriptions}/repositories/subscription_repository.dart +26 -30
- package/{lib/scaffold/backends/supabase/patch/lib/features/subscription → templates/firebase/lib/features/subscriptions}/shared/maybeshow_premium.dart +0 -2
- package/templates/firebase/lib/features/subscriptions/shared/subscription_management.dart +45 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/active_premium_content.dart +28 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_minimal.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_row.dart +8 -8
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_with_switch.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_content.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_page_factory.dart +5 -5
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/premium_page.dart +5 -5
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/comparison_table.dart +1 -1
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/paywall_empty_state.dart +4 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_bottom_menu.dart +3 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_col.dart +1 -1
- package/templates/firebase/lib/i18n/en.i18n.json +171 -46
- package/templates/firebase/lib/i18n/es.i18n.json +175 -50
- package/templates/firebase/lib/i18n/pt.i18n.json +166 -41
- package/templates/firebase/lib/main.dart +6 -3
- package/templates/firebase/lib/router.dart +15 -23
- package/templates/firebase/pubspec.yaml +4 -5
- package/templates/firebase/test/core/data/repositories/user_repository_test.dart +3 -3
- package/templates/firebase/test/core/states/user_state_notifier_test.dart +4 -4
- package/templates/firebase/test/core/widgets/focus_ring_shape_test.dart +55 -0
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_inapp_subscription_api.dart +11 -4
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_revenuecat_product.dart +1 -0
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_subscription_api.dart +2 -2
- package/templates/firebase/test/features/{subscription → subscriptions}/subscription_page_test.dart +4 -4
- package/templates/firebase/test/test_utils.dart +6 -6
- package/templates/firebase/web/index.html +5 -2
- package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -58
- package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -86
- package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +0 -22
- package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -47
- package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/img2.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/img3.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/notifications.png +0 -0
- package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
- package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +0 -2021
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +0 -35
- package/templates/firebase/lib/features/home/home_features_page.dart +0 -207
- package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +0 -50
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +0 -316
- package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +0 -85
- /package/templates/firebase/lib/features/{local_reminder → local_reminders}/repositories/reminder_preferences.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/providers/models/premium_state.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/feature_line.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background_gradient.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_banner.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_card.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_close_button.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_feature.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_row.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/trial_switcher.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/unsubscribe_feedback_popup.dart +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import 'dart:ui' show ImageFilter;
|
|
2
|
+
|
|
1
3
|
import 'package:flutter/material.dart';
|
|
2
4
|
import 'package:kasy_kit/components/kasy_app_bar.dart';
|
|
3
5
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
@@ -33,6 +35,10 @@ class DesignSystemPage extends StatelessWidget {
|
|
|
33
35
|
SizedBox(height: KasySpacing.md),
|
|
34
36
|
_TypographySection(),
|
|
35
37
|
SizedBox(height: KasySpacing.xl),
|
|
38
|
+
_SectionHeader('Effect Styles'),
|
|
39
|
+
SizedBox(height: KasySpacing.md),
|
|
40
|
+
_EffectsSection(),
|
|
41
|
+
SizedBox(height: KasySpacing.xl),
|
|
36
42
|
_SectionHeader('Spacing'),
|
|
37
43
|
SizedBox(height: KasySpacing.md),
|
|
38
44
|
_SpacingSection(),
|
|
@@ -90,127 +96,513 @@ class _TokenDivider extends StatelessWidget {
|
|
|
90
96
|
// Colors
|
|
91
97
|
// ---------------------------------------------------------------------------
|
|
92
98
|
|
|
99
|
+
/// Accessor that reads one token from a [KasyColors] theme (light or dark).
|
|
100
|
+
typedef _Pick = Color Function(KasyColors c);
|
|
101
|
+
|
|
102
|
+
class _Variant {
|
|
103
|
+
final String name;
|
|
104
|
+
final _Pick pick;
|
|
105
|
+
|
|
106
|
+
/// Force a hairline border on the swatch (for near-surface / transparent tones).
|
|
107
|
+
final bool border;
|
|
108
|
+
const _Variant(this.name, this.pick, {this.border = false});
|
|
109
|
+
}
|
|
110
|
+
|
|
93
111
|
class _ColorsSection extends StatelessWidget {
|
|
94
112
|
const _ColorsSection();
|
|
95
113
|
|
|
96
114
|
@override
|
|
97
115
|
Widget build(BuildContext context) {
|
|
98
|
-
|
|
116
|
+
return const Column(
|
|
117
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
118
|
+
children: [
|
|
119
|
+
_ColorsIntro(),
|
|
120
|
+
SizedBox(height: KasySpacing.lg),
|
|
99
121
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
122
|
+
// --- Semantic roles (solid + soft preview) ---
|
|
123
|
+
_SemanticCategory(
|
|
124
|
+
name: 'Accent',
|
|
125
|
+
description:
|
|
126
|
+
'The primary brand identity. Used sparingly for key actions, '
|
|
127
|
+
'highlights and moments of emphasis.',
|
|
128
|
+
base: _pickAccent,
|
|
129
|
+
onColor: _pickAccentForeground,
|
|
130
|
+
soft: _pickAccentSoft,
|
|
131
|
+
softForeground: _pickAccentSoftForeground,
|
|
132
|
+
variants: [
|
|
133
|
+
_Variant('accent', _pickAccent),
|
|
134
|
+
_Variant('accent-hover', _pickAccentHover),
|
|
135
|
+
_Variant('accent-foreground', _pickAccentForeground, border: true),
|
|
136
|
+
_Variant('accent-soft', _pickAccentSoft, border: true),
|
|
137
|
+
_Variant('accent-soft-hover', _pickAccentSoftHover, border: true),
|
|
138
|
+
_Variant('accent-soft-foreground', _pickAccentSoftForeground),
|
|
139
|
+
],
|
|
140
|
+
),
|
|
141
|
+
SizedBox(height: KasySpacing.xl),
|
|
142
|
+
_SemanticCategory(
|
|
143
|
+
name: 'Default',
|
|
144
|
+
description:
|
|
145
|
+
'The neutral backbone of the system. Used for most '
|
|
146
|
+
'non-emphasized UI elements.',
|
|
147
|
+
base: _pickNeutral,
|
|
148
|
+
onColor: _pickNeutralForeground,
|
|
149
|
+
variants: [
|
|
150
|
+
_Variant('default', _pickNeutral, border: true),
|
|
151
|
+
_Variant('default-hover', _pickNeutralHover, border: true),
|
|
152
|
+
_Variant('default-foreground', _pickNeutralForeground),
|
|
153
|
+
],
|
|
154
|
+
),
|
|
155
|
+
SizedBox(height: KasySpacing.xl),
|
|
156
|
+
_SemanticCategory(
|
|
157
|
+
name: 'Success',
|
|
158
|
+
description:
|
|
159
|
+
'Communicates positive outcomes, confirmations and completed '
|
|
160
|
+
'states.',
|
|
161
|
+
base: _pickSuccess,
|
|
162
|
+
onColor: _pickSuccessForeground,
|
|
163
|
+
soft: _pickSuccessSoft,
|
|
164
|
+
softForeground: _pickSuccessSoftForeground,
|
|
165
|
+
variants: [
|
|
166
|
+
_Variant('success', _pickSuccess),
|
|
167
|
+
_Variant('success-hover', _pickSuccessHover),
|
|
168
|
+
_Variant('success-foreground', _pickSuccessForeground, border: true),
|
|
169
|
+
_Variant('success-soft', _pickSuccessSoft, border: true),
|
|
170
|
+
_Variant('success-soft-hover', _pickSuccessSoftHover, border: true),
|
|
171
|
+
_Variant('success-soft-foreground', _pickSuccessSoftForeground),
|
|
172
|
+
],
|
|
173
|
+
),
|
|
174
|
+
SizedBox(height: KasySpacing.xl),
|
|
175
|
+
_SemanticCategory(
|
|
176
|
+
name: 'Warning',
|
|
177
|
+
description:
|
|
178
|
+
'Indicates caution or risk that requires attention but is not '
|
|
179
|
+
'destructive.',
|
|
180
|
+
base: _pickWarning,
|
|
181
|
+
onColor: _pickWarningForeground,
|
|
182
|
+
soft: _pickWarningSoft,
|
|
183
|
+
softForeground: _pickWarningSoftForeground,
|
|
184
|
+
variants: [
|
|
185
|
+
_Variant('warning', _pickWarning),
|
|
186
|
+
_Variant('warning-hover', _pickWarningHover),
|
|
187
|
+
_Variant('warning-foreground', _pickWarningForeground, border: true),
|
|
188
|
+
_Variant('warning-soft', _pickWarningSoft, border: true),
|
|
189
|
+
_Variant('warning-soft-hover', _pickWarningSoftHover, border: true),
|
|
190
|
+
_Variant('warning-soft-foreground', _pickWarningSoftForeground),
|
|
191
|
+
],
|
|
192
|
+
),
|
|
193
|
+
SizedBox(height: KasySpacing.xl),
|
|
194
|
+
_SemanticCategory(
|
|
195
|
+
name: 'Danger',
|
|
196
|
+
description:
|
|
197
|
+
'Represents destructive, irreversible or critical actions and '
|
|
198
|
+
'states.',
|
|
199
|
+
base: _pickDanger,
|
|
200
|
+
onColor: _pickDangerForeground,
|
|
201
|
+
soft: _pickDangerSoft,
|
|
202
|
+
softForeground: _pickDangerSoftForeground,
|
|
203
|
+
variants: [
|
|
204
|
+
_Variant('danger', _pickDanger),
|
|
205
|
+
_Variant('danger-hover', _pickDangerHover),
|
|
206
|
+
_Variant('danger-foreground', _pickDangerForeground, border: true),
|
|
207
|
+
_Variant('danger-soft', _pickDangerSoft, border: true),
|
|
208
|
+
_Variant('danger-soft-hover', _pickDangerSoftHover, border: true),
|
|
209
|
+
_Variant('danger-soft-foreground', _pickDangerSoftForeground),
|
|
210
|
+
],
|
|
211
|
+
),
|
|
212
|
+
SizedBox(height: KasySpacing.xl),
|
|
145
213
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
214
|
+
// --- Neutral swatch roles ---
|
|
215
|
+
_SwatchCategory(
|
|
216
|
+
name: 'Foreground',
|
|
217
|
+
description:
|
|
218
|
+
'Primary content such as text and icons. Adapts automatically to '
|
|
219
|
+
'background and surface contexts.',
|
|
220
|
+
variants: [
|
|
221
|
+
_Variant('foreground', _pickForeground),
|
|
222
|
+
_Variant('muted', _pickForegroundMuted),
|
|
223
|
+
_Variant('segment', _pickForegroundSegment),
|
|
224
|
+
_Variant('overlay', _pickForegroundOverlay),
|
|
225
|
+
_Variant('link', _pickForegroundLink),
|
|
226
|
+
_Variant('inverse', _pickForegroundInverse, border: true),
|
|
227
|
+
],
|
|
228
|
+
),
|
|
229
|
+
SizedBox(height: KasySpacing.xl),
|
|
230
|
+
_SwatchCategory(
|
|
231
|
+
name: 'Background',
|
|
232
|
+
description:
|
|
233
|
+
'The base canvas of the interface. Establishes overall contrast '
|
|
234
|
+
'and mood while staying visually quiet.',
|
|
235
|
+
variants: [
|
|
236
|
+
_Variant('background', _pickBackground, border: true),
|
|
237
|
+
_Variant('background-secondary', _pickBackgroundSecondary, border: true),
|
|
238
|
+
_Variant('background-tertiary', _pickBackgroundTertiary, border: true),
|
|
239
|
+
_Variant('background-inverse', _pickBackgroundInverse),
|
|
240
|
+
],
|
|
241
|
+
),
|
|
242
|
+
SizedBox(height: KasySpacing.xl),
|
|
243
|
+
_SwatchCategory(
|
|
244
|
+
name: 'Surface',
|
|
245
|
+
description:
|
|
246
|
+
'Containers such as cards, panels, modals and dropdowns. Create '
|
|
247
|
+
'separation through elevation and layering.',
|
|
248
|
+
variants: [
|
|
249
|
+
_Variant('surface', _pickSurface, border: true),
|
|
250
|
+
_Variant('surface-secondary', _pickSurfaceSecondary, border: true),
|
|
251
|
+
_Variant('surface-tertiary', _pickSurfaceTertiary, border: true),
|
|
252
|
+
_Variant('surface-transparent', _pickSurfaceTransparent, border: true),
|
|
253
|
+
],
|
|
254
|
+
),
|
|
255
|
+
SizedBox(height: KasySpacing.xl),
|
|
256
|
+
_SwatchCategory(
|
|
257
|
+
name: 'Form field',
|
|
258
|
+
description:
|
|
259
|
+
'Specialized tokens for inputs and controls, accounting for '
|
|
260
|
+
'default, hover and focus states.',
|
|
261
|
+
variants: [
|
|
262
|
+
_Variant('field-background', _pickFieldBackground, border: true),
|
|
263
|
+
_Variant('field-background-hover', _pickFieldBackgroundHover, border: true),
|
|
264
|
+
_Variant('field-background-focus', _pickFieldBackgroundFocus, border: true),
|
|
265
|
+
_Variant('field-placeholder', _pickFieldPlaceholder),
|
|
266
|
+
_Variant('field-foreground', _pickFieldForeground),
|
|
267
|
+
_Variant('field-border', _pickFieldBorder, border: true),
|
|
268
|
+
_Variant('field-border-hover', _pickFieldBorderHover, border: true),
|
|
269
|
+
],
|
|
270
|
+
),
|
|
271
|
+
SizedBox(height: KasySpacing.xl),
|
|
272
|
+
_SwatchCategory(
|
|
273
|
+
name: 'Separator',
|
|
274
|
+
description:
|
|
275
|
+
'Dividers, outlines and subtle boundaries. Low contrast and '
|
|
276
|
+
'unobtrusive by design.',
|
|
277
|
+
variants: [
|
|
278
|
+
_Variant('separator', _pickSeparator, border: true),
|
|
279
|
+
_Variant('separator-secondary', _pickSeparatorSecondary, border: true),
|
|
280
|
+
_Variant('separator-tertiary', _pickSeparatorTertiary, border: true),
|
|
281
|
+
],
|
|
282
|
+
),
|
|
283
|
+
SizedBox(height: KasySpacing.xl),
|
|
284
|
+
_SwatchCategory(
|
|
285
|
+
name: 'Other',
|
|
286
|
+
description:
|
|
287
|
+
'Shared utility tokens used for borders, overlays, segmented '
|
|
288
|
+
'controls and backdrops.',
|
|
289
|
+
variants: [
|
|
290
|
+
_Variant('border', _pickBorder, border: true),
|
|
291
|
+
_Variant('overlay', _pickOverlay, border: true),
|
|
292
|
+
_Variant('segment', _pickSegment, border: true),
|
|
293
|
+
_Variant('backdrop', _pickBackdrop, border: true),
|
|
294
|
+
],
|
|
295
|
+
),
|
|
171
296
|
],
|
|
172
297
|
);
|
|
173
298
|
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// --- Token accessors (kept top-level so the section tree stays const) ---
|
|
302
|
+
Color _pickAccent(KasyColors c) => c.accent;
|
|
303
|
+
Color _pickAccentHover(KasyColors c) => c.accentHover;
|
|
304
|
+
Color _pickAccentForeground(KasyColors c) => c.accentForeground;
|
|
305
|
+
Color _pickAccentSoft(KasyColors c) => c.accentSoft;
|
|
306
|
+
Color _pickAccentSoftHover(KasyColors c) => c.accentSoftHover;
|
|
307
|
+
Color _pickAccentSoftForeground(KasyColors c) => c.accentSoftForeground;
|
|
308
|
+
Color _pickNeutral(KasyColors c) => c.neutral;
|
|
309
|
+
Color _pickNeutralHover(KasyColors c) => c.neutralHover;
|
|
310
|
+
Color _pickNeutralForeground(KasyColors c) => c.neutralForeground;
|
|
311
|
+
Color _pickSuccess(KasyColors c) => c.success;
|
|
312
|
+
Color _pickSuccessHover(KasyColors c) => c.successHover;
|
|
313
|
+
Color _pickSuccessForeground(KasyColors c) => c.successForeground;
|
|
314
|
+
Color _pickSuccessSoft(KasyColors c) => c.successSoft;
|
|
315
|
+
Color _pickSuccessSoftHover(KasyColors c) => c.successSoftHover;
|
|
316
|
+
Color _pickSuccessSoftForeground(KasyColors c) => c.successSoftForeground;
|
|
317
|
+
Color _pickWarning(KasyColors c) => c.warning;
|
|
318
|
+
Color _pickWarningHover(KasyColors c) => c.warningHover;
|
|
319
|
+
Color _pickWarningForeground(KasyColors c) => c.warningForeground;
|
|
320
|
+
Color _pickWarningSoft(KasyColors c) => c.warningSoft;
|
|
321
|
+
Color _pickWarningSoftHover(KasyColors c) => c.warningSoftHover;
|
|
322
|
+
Color _pickWarningSoftForeground(KasyColors c) => c.warningSoftForeground;
|
|
323
|
+
Color _pickDanger(KasyColors c) => c.danger;
|
|
324
|
+
Color _pickDangerHover(KasyColors c) => c.dangerHover;
|
|
325
|
+
Color _pickDangerForeground(KasyColors c) => c.dangerForeground;
|
|
326
|
+
Color _pickDangerSoft(KasyColors c) => c.dangerSoft;
|
|
327
|
+
Color _pickDangerSoftHover(KasyColors c) => c.dangerSoftHover;
|
|
328
|
+
Color _pickDangerSoftForeground(KasyColors c) => c.dangerSoftForeground;
|
|
329
|
+
Color _pickForeground(KasyColors c) => c.foreground;
|
|
330
|
+
Color _pickForegroundMuted(KasyColors c) => c.foregroundMuted;
|
|
331
|
+
Color _pickForegroundSegment(KasyColors c) => c.foregroundSegment;
|
|
332
|
+
Color _pickForegroundOverlay(KasyColors c) => c.foregroundOverlay;
|
|
333
|
+
Color _pickForegroundLink(KasyColors c) => c.foregroundLink;
|
|
334
|
+
Color _pickForegroundInverse(KasyColors c) => c.foregroundInverse;
|
|
335
|
+
Color _pickBackground(KasyColors c) => c.background;
|
|
336
|
+
Color _pickBackgroundSecondary(KasyColors c) => c.backgroundSecondary;
|
|
337
|
+
Color _pickBackgroundTertiary(KasyColors c) => c.backgroundTertiary;
|
|
338
|
+
Color _pickBackgroundInverse(KasyColors c) => c.backgroundInverse;
|
|
339
|
+
Color _pickSurface(KasyColors c) => c.surface;
|
|
340
|
+
Color _pickSurfaceSecondary(KasyColors c) => c.surfaceSecondary;
|
|
341
|
+
Color _pickSurfaceTertiary(KasyColors c) => c.surfaceTertiary;
|
|
342
|
+
Color _pickSurfaceTransparent(KasyColors c) => c.surfaceTransparent;
|
|
343
|
+
Color _pickFieldBackground(KasyColors c) => c.fieldBackground;
|
|
344
|
+
Color _pickFieldBackgroundHover(KasyColors c) => c.fieldBackgroundHover;
|
|
345
|
+
Color _pickFieldBackgroundFocus(KasyColors c) => c.fieldBackgroundFocus;
|
|
346
|
+
Color _pickFieldPlaceholder(KasyColors c) => c.fieldPlaceholder;
|
|
347
|
+
Color _pickFieldForeground(KasyColors c) => c.fieldForeground;
|
|
348
|
+
Color _pickFieldBorder(KasyColors c) => c.fieldBorder;
|
|
349
|
+
Color _pickFieldBorderHover(KasyColors c) => c.fieldBorderHover;
|
|
350
|
+
Color _pickSeparator(KasyColors c) => c.separator;
|
|
351
|
+
Color _pickSeparatorSecondary(KasyColors c) => c.separatorSecondary;
|
|
352
|
+
Color _pickSeparatorTertiary(KasyColors c) => c.separatorTertiary;
|
|
353
|
+
Color _pickBorder(KasyColors c) => c.border;
|
|
354
|
+
Color _pickOverlay(KasyColors c) => c.overlay;
|
|
355
|
+
Color _pickSegment(KasyColors c) => c.segment;
|
|
356
|
+
Color _pickBackdrop(KasyColors c) => c.backdrop;
|
|
357
|
+
|
|
358
|
+
String _hexOf(Color color) {
|
|
359
|
+
final int v = color.toARGB32();
|
|
360
|
+
final int a = (v >> 24) & 0xFF;
|
|
361
|
+
final int r = (v >> 16) & 0xFF;
|
|
362
|
+
final int g = (v >> 8) & 0xFF;
|
|
363
|
+
final int b = v & 0xFF;
|
|
364
|
+
String two(int x) => x.toRadixString(16).padLeft(2, '0').toUpperCase();
|
|
365
|
+
final String rgb = '${two(r)}${two(g)}${two(b)}';
|
|
366
|
+
return a == 0xFF ? '#$rgb' : '#$rgb${two(a)}';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// ---------------------------------------------------------------------------
|
|
370
|
+
// Colors — intro
|
|
371
|
+
// ---------------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
class _ColorsIntro extends StatelessWidget {
|
|
374
|
+
const _ColorsIntro();
|
|
174
375
|
|
|
175
|
-
|
|
176
|
-
|
|
376
|
+
@override
|
|
377
|
+
Widget build(BuildContext context) {
|
|
378
|
+
return Text(
|
|
379
|
+
'Built around semantic intent, not raw palettes. A small set of color '
|
|
380
|
+
'roles covers most interface needs, each resolving to a light and a dark '
|
|
381
|
+
'theme shown side by side.',
|
|
382
|
+
style: context.textTheme.bodyMedium?.copyWith(
|
|
383
|
+
color: context.colors.muted,
|
|
384
|
+
height: 1.5,
|
|
385
|
+
),
|
|
386
|
+
);
|
|
177
387
|
}
|
|
178
388
|
}
|
|
179
389
|
|
|
180
|
-
|
|
390
|
+
// ---------------------------------------------------------------------------
|
|
391
|
+
// Category heading (name + description)
|
|
392
|
+
// ---------------------------------------------------------------------------
|
|
393
|
+
|
|
394
|
+
class _CategoryHeading extends StatelessWidget {
|
|
181
395
|
final String name;
|
|
182
|
-
final
|
|
183
|
-
|
|
184
|
-
|
|
396
|
+
final String description;
|
|
397
|
+
const _CategoryHeading({required this.name, required this.description});
|
|
398
|
+
|
|
399
|
+
@override
|
|
400
|
+
Widget build(BuildContext context) {
|
|
401
|
+
return Column(
|
|
402
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
403
|
+
children: [
|
|
404
|
+
Text(
|
|
405
|
+
name,
|
|
406
|
+
style: context.textTheme.titleMedium?.copyWith(
|
|
407
|
+
color: context.colors.onSurface,
|
|
408
|
+
fontWeight: FontWeight.w700,
|
|
409
|
+
),
|
|
410
|
+
),
|
|
411
|
+
const SizedBox(height: KasySpacing.xs),
|
|
412
|
+
Text(
|
|
413
|
+
description,
|
|
414
|
+
style: context.textTheme.bodySmall?.copyWith(
|
|
415
|
+
color: context.colors.muted,
|
|
416
|
+
height: 1.45,
|
|
417
|
+
),
|
|
418
|
+
),
|
|
419
|
+
const SizedBox(height: KasySpacing.smd),
|
|
420
|
+
],
|
|
421
|
+
);
|
|
422
|
+
}
|
|
185
423
|
}
|
|
186
424
|
|
|
187
|
-
|
|
425
|
+
// ---------------------------------------------------------------------------
|
|
426
|
+
// Semantic category: heading + Light/Dark solid+soft preview + variant list
|
|
427
|
+
// ---------------------------------------------------------------------------
|
|
428
|
+
|
|
429
|
+
class _SemanticCategory extends StatelessWidget {
|
|
430
|
+
final String name;
|
|
431
|
+
final String description;
|
|
432
|
+
final _Pick base;
|
|
433
|
+
final _Pick onColor;
|
|
434
|
+
final _Pick? soft;
|
|
435
|
+
final _Pick? softForeground;
|
|
436
|
+
final List<_Variant> variants;
|
|
437
|
+
|
|
438
|
+
const _SemanticCategory({
|
|
439
|
+
required this.name,
|
|
440
|
+
required this.description,
|
|
441
|
+
required this.base,
|
|
442
|
+
required this.onColor,
|
|
443
|
+
required this.variants,
|
|
444
|
+
this.soft,
|
|
445
|
+
this.softForeground,
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
@override
|
|
449
|
+
Widget build(BuildContext context) {
|
|
450
|
+
return Column(
|
|
451
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
452
|
+
children: [
|
|
453
|
+
_CategoryHeading(name: name, description: description),
|
|
454
|
+
Row(
|
|
455
|
+
children: [
|
|
456
|
+
Expanded(child: _SemanticPreview(theme: KasyColors.light(), label: 'Light', base: base, onColor: onColor, soft: soft, softForeground: softForeground)),
|
|
457
|
+
const SizedBox(width: KasySpacing.smd),
|
|
458
|
+
Expanded(child: _SemanticPreview(theme: KasyColors.dark(), label: 'Dark', base: base, onColor: onColor, soft: soft, softForeground: softForeground)),
|
|
459
|
+
],
|
|
460
|
+
),
|
|
461
|
+
const SizedBox(height: KasySpacing.smd),
|
|
462
|
+
_VariantList(variants: variants),
|
|
463
|
+
],
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
class _SemanticPreview extends StatelessWidget {
|
|
469
|
+
final KasyColors theme;
|
|
188
470
|
final String label;
|
|
189
|
-
|
|
471
|
+
final _Pick base;
|
|
472
|
+
final _Pick onColor;
|
|
473
|
+
final _Pick? soft;
|
|
474
|
+
final _Pick? softForeground;
|
|
475
|
+
|
|
476
|
+
const _SemanticPreview({
|
|
477
|
+
required this.theme,
|
|
478
|
+
required this.label,
|
|
479
|
+
required this.base,
|
|
480
|
+
required this.onColor,
|
|
481
|
+
required this.soft,
|
|
482
|
+
required this.softForeground,
|
|
483
|
+
});
|
|
190
484
|
|
|
191
485
|
@override
|
|
192
486
|
Widget build(BuildContext context) {
|
|
193
|
-
return
|
|
194
|
-
padding: const EdgeInsets.
|
|
487
|
+
return Container(
|
|
488
|
+
padding: const EdgeInsets.all(KasySpacing.smd),
|
|
489
|
+
decoration: BoxDecoration(
|
|
490
|
+
color: theme.surface,
|
|
491
|
+
borderRadius: BorderRadius.circular(KasyRadius.md),
|
|
492
|
+
border: Border.all(color: theme.border),
|
|
493
|
+
),
|
|
494
|
+
child: Column(
|
|
495
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
496
|
+
children: [
|
|
497
|
+
Text(
|
|
498
|
+
label,
|
|
499
|
+
style: context.textTheme.labelSmall?.copyWith(
|
|
500
|
+
color: theme.foregroundMuted,
|
|
501
|
+
letterSpacing: 0.6,
|
|
502
|
+
),
|
|
503
|
+
),
|
|
504
|
+
const SizedBox(height: KasySpacing.sm),
|
|
505
|
+
_PreviewPill(bg: base(theme), fg: onColor(theme), text: 'Solid'),
|
|
506
|
+
if (soft != null && softForeground != null) ...[
|
|
507
|
+
const SizedBox(height: KasySpacing.sm),
|
|
508
|
+
_PreviewPill(bg: soft!(theme), fg: softForeground!(theme), text: 'Soft'),
|
|
509
|
+
],
|
|
510
|
+
],
|
|
511
|
+
),
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
class _PreviewPill extends StatelessWidget {
|
|
517
|
+
final Color bg;
|
|
518
|
+
final Color fg;
|
|
519
|
+
final String text;
|
|
520
|
+
const _PreviewPill({required this.bg, required this.fg, required this.text});
|
|
521
|
+
|
|
522
|
+
@override
|
|
523
|
+
Widget build(BuildContext context) {
|
|
524
|
+
return Container(
|
|
525
|
+
height: 36,
|
|
526
|
+
alignment: Alignment.center,
|
|
527
|
+
decoration: BoxDecoration(
|
|
528
|
+
color: bg,
|
|
529
|
+
borderRadius: BorderRadius.circular(KasyRadius.sm),
|
|
530
|
+
),
|
|
195
531
|
child: Text(
|
|
196
|
-
|
|
197
|
-
style: context.textTheme.
|
|
198
|
-
color:
|
|
199
|
-
|
|
532
|
+
text,
|
|
533
|
+
style: context.textTheme.labelMedium?.copyWith(
|
|
534
|
+
color: fg,
|
|
535
|
+
fontWeight: FontWeight.w600,
|
|
200
536
|
),
|
|
201
537
|
),
|
|
202
538
|
);
|
|
203
539
|
}
|
|
204
540
|
}
|
|
205
541
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
542
|
+
// ---------------------------------------------------------------------------
|
|
543
|
+
// Swatch category: heading + variant list (Light/Dark chips)
|
|
544
|
+
// ---------------------------------------------------------------------------
|
|
545
|
+
|
|
546
|
+
class _SwatchCategory extends StatelessWidget {
|
|
547
|
+
final String name;
|
|
548
|
+
final String description;
|
|
549
|
+
final List<_Variant> variants;
|
|
550
|
+
|
|
551
|
+
const _SwatchCategory({
|
|
552
|
+
required this.name,
|
|
553
|
+
required this.description,
|
|
554
|
+
required this.variants,
|
|
555
|
+
});
|
|
209
556
|
|
|
210
557
|
@override
|
|
211
558
|
Widget build(BuildContext context) {
|
|
212
|
-
|
|
213
|
-
|
|
559
|
+
return Column(
|
|
560
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
561
|
+
children: [
|
|
562
|
+
_CategoryHeading(name: name, description: description),
|
|
563
|
+
_VariantList(variants: variants),
|
|
564
|
+
],
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// ---------------------------------------------------------------------------
|
|
570
|
+
// Variant list (one row per token: Light chip, Dark chip, name, hex pair)
|
|
571
|
+
// ---------------------------------------------------------------------------
|
|
572
|
+
|
|
573
|
+
class _VariantList extends StatelessWidget {
|
|
574
|
+
final List<_Variant> variants;
|
|
575
|
+
const _VariantList({required this.variants});
|
|
576
|
+
|
|
577
|
+
@override
|
|
578
|
+
Widget build(BuildContext context) {
|
|
579
|
+
final KasyColors light = KasyColors.light();
|
|
580
|
+
final KasyColors dark = KasyColors.dark();
|
|
581
|
+
return _TokenCard(
|
|
582
|
+
children: [
|
|
583
|
+
for (int i = 0; i < variants.length; i++) ...[
|
|
584
|
+
_VariantRow(variant: variants[i], light: light, dark: dark),
|
|
585
|
+
if (i < variants.length - 1) const _TokenDivider(),
|
|
586
|
+
],
|
|
587
|
+
],
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
class _VariantRow extends StatelessWidget {
|
|
593
|
+
final _Variant variant;
|
|
594
|
+
final KasyColors light;
|
|
595
|
+
final KasyColors dark;
|
|
596
|
+
const _VariantRow({
|
|
597
|
+
required this.variant,
|
|
598
|
+
required this.light,
|
|
599
|
+
required this.dark,
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
@override
|
|
603
|
+
Widget build(BuildContext context) {
|
|
604
|
+
final Color lightColor = variant.pick(light);
|
|
605
|
+
final Color darkColor = variant.pick(dark);
|
|
214
606
|
return Padding(
|
|
215
607
|
padding: const EdgeInsets.symmetric(
|
|
216
608
|
horizontal: KasySpacing.md,
|
|
@@ -218,33 +610,29 @@ class _ColorRow extends StatelessWidget {
|
|
|
218
610
|
),
|
|
219
611
|
child: Row(
|
|
220
612
|
children: [
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
decoration: BoxDecoration(
|
|
225
|
-
color: token.color,
|
|
226
|
-
borderRadius: BorderRadius.circular(KasyRadius.xs),
|
|
227
|
-
border: token.border
|
|
228
|
-
? Border.all(
|
|
229
|
-
color: context.colors.outline.withValues(alpha: 0.5),
|
|
230
|
-
)
|
|
231
|
-
: null,
|
|
232
|
-
),
|
|
233
|
-
),
|
|
613
|
+
_ThemeChip(surface: light.surface, token: lightColor, border: variant.border),
|
|
614
|
+
const SizedBox(width: KasySpacing.xs),
|
|
615
|
+
_ThemeChip(surface: dark.surface, token: darkColor, border: variant.border),
|
|
234
616
|
const SizedBox(width: KasySpacing.smd),
|
|
235
617
|
Expanded(
|
|
236
|
-
child:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
618
|
+
child: Column(
|
|
619
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
620
|
+
children: [
|
|
621
|
+
Text(
|
|
622
|
+
variant.name,
|
|
623
|
+
style: context.textTheme.bodyMedium?.copyWith(
|
|
624
|
+
color: context.colors.onSurface,
|
|
625
|
+
),
|
|
626
|
+
),
|
|
627
|
+
const SizedBox(height: 2),
|
|
628
|
+
Text(
|
|
629
|
+
'${_hexOf(lightColor)} · ${_hexOf(darkColor)}',
|
|
630
|
+
style: context.textTheme.bodySmall?.copyWith(
|
|
631
|
+
color: context.colors.muted,
|
|
632
|
+
fontFeatures: const [FontFeature.tabularFigures()],
|
|
633
|
+
),
|
|
634
|
+
),
|
|
635
|
+
],
|
|
248
636
|
),
|
|
249
637
|
),
|
|
250
638
|
],
|
|
@@ -253,6 +641,40 @@ class _ColorRow extends StatelessWidget {
|
|
|
253
641
|
}
|
|
254
642
|
}
|
|
255
643
|
|
|
644
|
+
class _ThemeChip extends StatelessWidget {
|
|
645
|
+
final Color surface;
|
|
646
|
+
final Color token;
|
|
647
|
+
final bool border;
|
|
648
|
+
const _ThemeChip({
|
|
649
|
+
required this.surface,
|
|
650
|
+
required this.token,
|
|
651
|
+
this.border = false,
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
@override
|
|
655
|
+
Widget build(BuildContext context) {
|
|
656
|
+
return Container(
|
|
657
|
+
width: 28,
|
|
658
|
+
height: 28,
|
|
659
|
+
padding: const EdgeInsets.all(3),
|
|
660
|
+
decoration: BoxDecoration(
|
|
661
|
+
color: surface,
|
|
662
|
+
borderRadius: BorderRadius.circular(KasyRadius.xs),
|
|
663
|
+
border: Border.all(color: context.colors.outline.withValues(alpha: 0.5)),
|
|
664
|
+
),
|
|
665
|
+
child: DecoratedBox(
|
|
666
|
+
decoration: BoxDecoration(
|
|
667
|
+
color: token,
|
|
668
|
+
borderRadius: BorderRadius.circular(KasyRadius.xs - 1),
|
|
669
|
+
border: border
|
|
670
|
+
? Border.all(color: context.colors.outline.withValues(alpha: 0.5))
|
|
671
|
+
: null,
|
|
672
|
+
),
|
|
673
|
+
),
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
256
678
|
// ---------------------------------------------------------------------------
|
|
257
679
|
// Typography
|
|
258
680
|
// ---------------------------------------------------------------------------
|
|
@@ -262,76 +684,82 @@ class _TypographySection extends StatelessWidget {
|
|
|
262
684
|
|
|
263
685
|
@override
|
|
264
686
|
Widget build(BuildContext context) {
|
|
265
|
-
final
|
|
266
|
-
final
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
_TypeToken('labelSmall', tt.labelSmall, ktt.labelSmall),
|
|
687
|
+
final Color fg = context.colors.onSurface;
|
|
688
|
+
final List<_TypeRole> roles = [
|
|
689
|
+
_TypeRole('Heading 1', KasyTextTheme.heading1, 'ExtraBold · 36/40'),
|
|
690
|
+
_TypeRole('Heading 2', KasyTextTheme.heading2, 'Bold · 24/32'),
|
|
691
|
+
_TypeRole('Heading 3', KasyTextTheme.heading3, 'SemiBold · 20/28'),
|
|
692
|
+
_TypeRole('Heading 4', KasyTextTheme.heading4, 'SemiBold · 16/24'),
|
|
693
|
+
_TypeRole('Body base', KasyTextTheme.bodyBase, 'Regular · 16/24'),
|
|
694
|
+
_TypeRole('Body base medium', KasyTextTheme.bodyBaseMedium, 'Medium · 16/24'),
|
|
695
|
+
_TypeRole('Body sm', KasyTextTheme.bodySm, 'Regular · 14/20'),
|
|
696
|
+
_TypeRole('Body sm medium', KasyTextTheme.bodySmMedium, 'Medium · 14/20'),
|
|
697
|
+
_TypeRole('Body xs', KasyTextTheme.bodyXs, 'Regular · 12/16'),
|
|
698
|
+
_TypeRole('Body xs medium', KasyTextTheme.bodyXsMedium, 'Medium · 12/16'),
|
|
699
|
+
_TypeRole('Link base', KasyTextTheme.linkBase, 'Medium · 16/24 · Underlined'),
|
|
700
|
+
_TypeRole('Link sm', KasyTextTheme.linkSm, 'Medium · 14/20 · Underlined'),
|
|
701
|
+
_TypeRole('Text field base', KasyTextTheme.textFieldBase, 'Regular · 16/24'),
|
|
702
|
+
_TypeRole('Text field sm', KasyTextTheme.textFieldSm, 'Regular · 14/20'),
|
|
703
|
+
_TypeRole('Button base', KasyTextTheme.buttonBase, 'Medium · 16/24'),
|
|
704
|
+
_TypeRole('Button sm', KasyTextTheme.buttonSm, 'Medium · 14/20'),
|
|
284
705
|
];
|
|
285
706
|
|
|
286
|
-
return
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
707
|
+
return Column(
|
|
708
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
709
|
+
children: [
|
|
710
|
+
Text(
|
|
711
|
+
"Based on Tailwind's scale: Inter, neutral tracking and predictable "
|
|
712
|
+
'rhythm. Functional and scalable rather than decorative.',
|
|
713
|
+
style: context.textTheme.bodyMedium?.copyWith(
|
|
714
|
+
color: context.colors.muted,
|
|
715
|
+
height: 1.5,
|
|
716
|
+
),
|
|
717
|
+
),
|
|
718
|
+
const SizedBox(height: KasySpacing.md),
|
|
719
|
+
_TokenCard(
|
|
720
|
+
children: [
|
|
721
|
+
for (int i = 0; i < roles.length; i++) ...[
|
|
722
|
+
_TypeRow(role: roles[i], foreground: fg),
|
|
723
|
+
if (i < roles.length - 1) const _TokenDivider(),
|
|
724
|
+
],
|
|
725
|
+
],
|
|
726
|
+
),
|
|
727
|
+
],
|
|
298
728
|
);
|
|
299
729
|
}
|
|
300
730
|
}
|
|
301
731
|
|
|
302
|
-
class
|
|
732
|
+
class _TypeRole {
|
|
303
733
|
final String name;
|
|
304
|
-
final TextStyle
|
|
305
|
-
final
|
|
306
|
-
const
|
|
734
|
+
final TextStyle style;
|
|
735
|
+
final String spec;
|
|
736
|
+
const _TypeRole(this.name, this.style, this.spec);
|
|
307
737
|
}
|
|
308
738
|
|
|
309
739
|
class _TypeRow extends StatelessWidget {
|
|
310
|
-
final
|
|
311
|
-
|
|
740
|
+
final _TypeRole role;
|
|
741
|
+
final Color foreground;
|
|
742
|
+
const _TypeRow({required this.role, required this.foreground});
|
|
312
743
|
|
|
313
744
|
@override
|
|
314
745
|
Widget build(BuildContext context) {
|
|
315
|
-
final double size = token.raw.fontSize ?? 14;
|
|
316
|
-
final int weight = token.raw.fontWeight?.value ?? 400;
|
|
317
746
|
return Padding(
|
|
318
747
|
padding: const EdgeInsets.symmetric(
|
|
319
748
|
horizontal: KasySpacing.md,
|
|
320
749
|
vertical: KasySpacing.smd,
|
|
321
750
|
),
|
|
322
|
-
child:
|
|
751
|
+
child: Column(
|
|
752
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
323
753
|
children: [
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
overflow: TextOverflow.ellipsis,
|
|
330
|
-
),
|
|
754
|
+
Text(
|
|
755
|
+
role.name,
|
|
756
|
+
style: role.style.copyWith(color: foreground),
|
|
757
|
+
maxLines: 1,
|
|
758
|
+
overflow: TextOverflow.ellipsis,
|
|
331
759
|
),
|
|
332
|
-
const SizedBox(
|
|
760
|
+
const SizedBox(height: 4),
|
|
333
761
|
Text(
|
|
334
|
-
'${
|
|
762
|
+
'Inter · ${role.spec}',
|
|
335
763
|
style: context.textTheme.bodySmall?.copyWith(
|
|
336
764
|
color: context.colors.muted,
|
|
337
765
|
fontFeatures: const [FontFeature.tabularFigures()],
|
|
@@ -436,12 +864,17 @@ class _RadiusSection extends StatelessWidget {
|
|
|
436
864
|
const _RadiusSection();
|
|
437
865
|
|
|
438
866
|
static const List<({String name, double value})> _tokens = [
|
|
439
|
-
(name: '
|
|
440
|
-
(name: '
|
|
441
|
-
(name: '
|
|
442
|
-
(name: '
|
|
443
|
-
(name: '
|
|
444
|
-
(name: '
|
|
867
|
+
(name: 'none', value: KasyRadius.roundedNone),
|
|
868
|
+
(name: 'xs', value: KasyRadius.roundedXs),
|
|
869
|
+
(name: 'sm', value: KasyRadius.roundedSm),
|
|
870
|
+
(name: 'md', value: KasyRadius.roundedMd),
|
|
871
|
+
(name: 'lg', value: KasyRadius.roundedLg),
|
|
872
|
+
(name: 'xl', value: KasyRadius.roundedXl),
|
|
873
|
+
(name: '2xl', value: KasyRadius.rounded2xl),
|
|
874
|
+
(name: '2.5xl', value: KasyRadius.rounded2_5xl),
|
|
875
|
+
(name: '3xl', value: KasyRadius.rounded3xl),
|
|
876
|
+
(name: '4xl', value: KasyRadius.rounded4xl),
|
|
877
|
+
(name: 'full', value: KasyRadius.roundedFull),
|
|
445
878
|
];
|
|
446
879
|
|
|
447
880
|
@override
|
|
@@ -550,3 +983,208 @@ class _TokenCard extends StatelessWidget {
|
|
|
550
983
|
);
|
|
551
984
|
}
|
|
552
985
|
}
|
|
986
|
+
|
|
987
|
+
// ---------------------------------------------------------------------------
|
|
988
|
+
// Effect Styles — Shadows, Blur, Focus Rings
|
|
989
|
+
// ---------------------------------------------------------------------------
|
|
990
|
+
|
|
991
|
+
class _EffectsSection extends StatelessWidget {
|
|
992
|
+
const _EffectsSection();
|
|
993
|
+
|
|
994
|
+
@override
|
|
995
|
+
Widget build(BuildContext context) {
|
|
996
|
+
return Column(
|
|
997
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
998
|
+
children: [
|
|
999
|
+
Text(
|
|
1000
|
+
'How depth, separation and focus are expressed. Applied consistently '
|
|
1001
|
+
'to communicate hierarchy without relying on color alone.',
|
|
1002
|
+
style: context.textTheme.bodyMedium?.copyWith(
|
|
1003
|
+
color: context.colors.muted,
|
|
1004
|
+
height: 1.5,
|
|
1005
|
+
),
|
|
1006
|
+
),
|
|
1007
|
+
const SizedBox(height: KasySpacing.lg),
|
|
1008
|
+
const _EffectGroupLabel('Shadows'),
|
|
1009
|
+
const SizedBox(height: KasySpacing.smd),
|
|
1010
|
+
const Wrap(
|
|
1011
|
+
spacing: KasySpacing.md,
|
|
1012
|
+
runSpacing: KasySpacing.md,
|
|
1013
|
+
children: [
|
|
1014
|
+
_ShadowTile(label: 'Inner', shadows: [], inner: true),
|
|
1015
|
+
_ShadowTile(label: 'Surface', shadows: KasyShadows.surface),
|
|
1016
|
+
_ShadowTile(label: 'Field', shadows: KasyShadows.field),
|
|
1017
|
+
_ShadowTile(label: 'Switch', shadows: KasyShadows.switchControl),
|
|
1018
|
+
_ShadowTile(label: 'Tab', shadows: KasyShadows.tab),
|
|
1019
|
+
_ShadowTile(label: 'Overlay', shadows: KasyShadows.overlay),
|
|
1020
|
+
],
|
|
1021
|
+
),
|
|
1022
|
+
const SizedBox(height: KasySpacing.lg),
|
|
1023
|
+
const _EffectGroupLabel('Blur'),
|
|
1024
|
+
const SizedBox(height: KasySpacing.smd),
|
|
1025
|
+
const Wrap(
|
|
1026
|
+
spacing: KasySpacing.md,
|
|
1027
|
+
runSpacing: KasySpacing.md,
|
|
1028
|
+
children: [
|
|
1029
|
+
_BlurTile(label: 'Blur', sigma: 8),
|
|
1030
|
+
_BlurTile(label: 'Backdrop', sigma: 3),
|
|
1031
|
+
],
|
|
1032
|
+
),
|
|
1033
|
+
const SizedBox(height: KasySpacing.lg),
|
|
1034
|
+
const _EffectGroupLabel('Focus Rings'),
|
|
1035
|
+
const SizedBox(height: KasySpacing.smd),
|
|
1036
|
+
const Wrap(
|
|
1037
|
+
spacing: KasySpacing.lg,
|
|
1038
|
+
runSpacing: KasySpacing.md,
|
|
1039
|
+
children: [
|
|
1040
|
+
_FocusTile(label: 'Focus Ring', field: false),
|
|
1041
|
+
_FocusTile(label: 'Focus Ring Field', field: true),
|
|
1042
|
+
],
|
|
1043
|
+
),
|
|
1044
|
+
],
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
class _EffectGroupLabel extends StatelessWidget {
|
|
1050
|
+
final String label;
|
|
1051
|
+
const _EffectGroupLabel(this.label);
|
|
1052
|
+
|
|
1053
|
+
@override
|
|
1054
|
+
Widget build(BuildContext context) {
|
|
1055
|
+
return Text(
|
|
1056
|
+
label,
|
|
1057
|
+
style: context.textTheme.titleSmall?.copyWith(
|
|
1058
|
+
color: context.colors.onSurface,
|
|
1059
|
+
fontWeight: FontWeight.w700,
|
|
1060
|
+
),
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/// 72×72 labeled sample tile shared by the effect groups.
|
|
1066
|
+
class _EffectTile extends StatelessWidget {
|
|
1067
|
+
final String label;
|
|
1068
|
+
final Widget box;
|
|
1069
|
+
const _EffectTile({required this.label, required this.box});
|
|
1070
|
+
|
|
1071
|
+
@override
|
|
1072
|
+
Widget build(BuildContext context) {
|
|
1073
|
+
return Column(
|
|
1074
|
+
mainAxisSize: MainAxisSize.min,
|
|
1075
|
+
children: [
|
|
1076
|
+
box,
|
|
1077
|
+
const SizedBox(height: KasySpacing.sm),
|
|
1078
|
+
Text(
|
|
1079
|
+
label,
|
|
1080
|
+
style: context.textTheme.bodySmall?.copyWith(
|
|
1081
|
+
color: context.colors.muted,
|
|
1082
|
+
),
|
|
1083
|
+
),
|
|
1084
|
+
],
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
class _ShadowTile extends StatelessWidget {
|
|
1090
|
+
final String label;
|
|
1091
|
+
final List<BoxShadow> shadows;
|
|
1092
|
+
final bool inner;
|
|
1093
|
+
const _ShadowTile({
|
|
1094
|
+
required this.label,
|
|
1095
|
+
required this.shadows,
|
|
1096
|
+
this.inner = false,
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
@override
|
|
1100
|
+
Widget build(BuildContext context) {
|
|
1101
|
+
final c = context.colors;
|
|
1102
|
+
return _EffectTile(
|
|
1103
|
+
label: label,
|
|
1104
|
+
box: Container(
|
|
1105
|
+
width: 72,
|
|
1106
|
+
height: 72,
|
|
1107
|
+
decoration: BoxDecoration(
|
|
1108
|
+
color: c.surface,
|
|
1109
|
+
borderRadius: BorderRadius.circular(KasyRadius.md),
|
|
1110
|
+
border: Border.all(color: c.separator),
|
|
1111
|
+
boxShadow: inner ? null : shadows,
|
|
1112
|
+
gradient: inner
|
|
1113
|
+
? LinearGradient(
|
|
1114
|
+
begin: Alignment.topCenter,
|
|
1115
|
+
end: Alignment.center,
|
|
1116
|
+
colors: [KasyShadows.inner, c.surface],
|
|
1117
|
+
)
|
|
1118
|
+
: null,
|
|
1119
|
+
),
|
|
1120
|
+
),
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
class _BlurTile extends StatelessWidget {
|
|
1126
|
+
final String label;
|
|
1127
|
+
final double sigma;
|
|
1128
|
+
const _BlurTile({required this.label, required this.sigma});
|
|
1129
|
+
|
|
1130
|
+
@override
|
|
1131
|
+
Widget build(BuildContext context) {
|
|
1132
|
+
final c = context.colors;
|
|
1133
|
+
return _EffectTile(
|
|
1134
|
+
label: label,
|
|
1135
|
+
box: ClipRRect(
|
|
1136
|
+
borderRadius: BorderRadius.circular(KasyRadius.md),
|
|
1137
|
+
child: SizedBox(
|
|
1138
|
+
width: 72,
|
|
1139
|
+
height: 72,
|
|
1140
|
+
child: Stack(
|
|
1141
|
+
fit: StackFit.expand,
|
|
1142
|
+
children: [
|
|
1143
|
+
DecoratedBox(
|
|
1144
|
+
decoration: BoxDecoration(
|
|
1145
|
+
gradient: LinearGradient(
|
|
1146
|
+
begin: Alignment.topLeft,
|
|
1147
|
+
end: Alignment.bottomRight,
|
|
1148
|
+
colors: [c.accent, c.success, c.warning, c.danger],
|
|
1149
|
+
),
|
|
1150
|
+
),
|
|
1151
|
+
),
|
|
1152
|
+
BackdropFilter(
|
|
1153
|
+
filter: ImageFilter.blur(sigmaX: sigma, sigmaY: sigma),
|
|
1154
|
+
child: ColoredBox(
|
|
1155
|
+
color: c.surface.withValues(alpha: 0.10),
|
|
1156
|
+
),
|
|
1157
|
+
),
|
|
1158
|
+
],
|
|
1159
|
+
),
|
|
1160
|
+
),
|
|
1161
|
+
),
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
class _FocusTile extends StatelessWidget {
|
|
1167
|
+
final String label;
|
|
1168
|
+
final bool field;
|
|
1169
|
+
const _FocusTile({required this.label, required this.field});
|
|
1170
|
+
|
|
1171
|
+
@override
|
|
1172
|
+
Widget build(BuildContext context) {
|
|
1173
|
+
final c = context.colors;
|
|
1174
|
+
return _EffectTile(
|
|
1175
|
+
label: label,
|
|
1176
|
+
box: Container(
|
|
1177
|
+
width: 72,
|
|
1178
|
+
height: 72,
|
|
1179
|
+
decoration: BoxDecoration(
|
|
1180
|
+
color: c.surface,
|
|
1181
|
+
borderRadius: BorderRadius.circular(KasyRadius.md),
|
|
1182
|
+
border: Border.all(color: c.separator),
|
|
1183
|
+
boxShadow: field
|
|
1184
|
+
? KasyShadows.focusRingField(ring: c.accent)
|
|
1185
|
+
: KasyShadows.focusRing(ring: c.accent, gap: c.background),
|
|
1186
|
+
),
|
|
1187
|
+
),
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
}
|