feat(proj): init

This commit is contained in:
vl.arkhangelskii
2026-09-21 04:06:43 +03:00
commit c956b94983
1076 changed files with 50876 additions and 0 deletions
@@ -0,0 +1,73 @@
import 'package:flutter/cupertino.dart';
import 'package:please_pay_me/theme/theme.dart';
import 'package:please_pay_me/ui/ui.dart';
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
import 'package:please_pay_me_widgetbook/support/preview.dart';
import 'package:widgetbook/widgetbook.dart';
WidgetbookComponent dialogsComponent() {
return WidgetbookComponent(
name: 'AppAlert',
useCases: [
WidgetbookUseCase(
name: 'Alert',
builder: (context) {
final message = knobText(
context,
label: 'Message',
initialValue: 'Операция будет удалена без возможности восстановления.',
);
return IosPreview.centered(
child: AppAlert(
title: knobText(context, label: 'Title', initialValue: 'Удалить трату?'),
message: message.isEmpty ? null : message,
confirmLabel: knobText(context, label: 'Confirm', initialValue: 'Удалить'),
cancelLabel: knobBool(context, label: 'Cancel button', initialValue: true)
? 'Отмена'
: null,
destructive: knobBool(context, label: 'Destructive', initialValue: true),
),
);
},
),
WidgetbookUseCase(
name: 'Triggers',
builder: (context) {
return IosPreview(
stretch: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
AppButton(
label: 'Показать alert',
onPressed: () => showAppAlert(
context: context,
title: 'Удалить трату?',
message: 'Действие необратимо.',
confirmLabel: 'Удалить',
cancelLabel: 'Отмена',
destructive: true,
),
),
const SizedBox(height: AppSpacing.s3),
AppButton(
label: 'Показать action sheet',
style: AppButtonStyle.gray,
onPressed: () => showAppActionSheet(
context: context,
title: 'Операция',
actions: const [
AppActionSheetAction(label: 'Редактировать', isDefault: true),
AppActionSheetAction(label: 'Дублировать'),
AppActionSheetAction(label: 'Удалить', destructive: true),
],
),
),
],
),
);
},
),
],
);
}
@@ -0,0 +1,83 @@
import 'package:flutter/cupertino.dart';
import 'package:please_pay_me/theme/theme.dart';
import 'package:please_pay_me/ui/ui.dart';
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
import 'package:widgetbook/widgetbook.dart';
WidgetbookComponent navBarComponent() {
return WidgetbookComponent(
name: 'AppNavBar',
useCases: [
WidgetbookUseCase(
name: 'Playground',
builder: (context) {
final subtitle = knobText(context, label: 'Subtitle', initialValue: 'До 25 сентября');
return CupertinoPageScaffold(
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
navigationBar: AppNavBar(
title: knobText(context, label: 'Title', initialValue: 'Бюджет'),
subtitle: subtitle.isEmpty ? null : subtitle,
previousPageTitle:
knobBool(context, label: 'Back button', initialValue: true) ? 'Назад' : null,
transparent: knobBool(context, label: 'Transparent'),
trailing: knobBool(context, label: 'Trailing action', initialValue: true)
? CupertinoButton(
padding: EdgeInsets.zero,
minimumSize: Size.zero,
onPressed: () {},
child: const AppIcon(
CupertinoIcons.ellipsis_circle,
color: AppColors.accent,
),
)
: null,
),
child: const SafeArea(
child: Padding(
padding: EdgeInsets.all(AppSpacing.s4),
child: AppText.subhead('Контент под навигационной панелью'),
),
),
);
},
),
WidgetbookUseCase(
name: 'Large title',
builder: (context) {
return CupertinoPageScaffold(
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
child: CustomScrollView(
slivers: [
AppLargeNavBar(
title: knobText(context, label: 'Title', initialValue: 'Журнал'),
trailing: CupertinoButton(
padding: EdgeInsets.zero,
minimumSize: Size.zero,
onPressed: () {},
child: const AppIcon(
CupertinoIcons.add_circled,
color: AppColors.accent,
),
),
),
SliverToBoxAdapter(
child: AppListSection(
header: 'Сегодня',
separatorIndent: 60,
children: const [
AppListTile(
leading: AppIconBadge(icon: CupertinoIcons.cart_fill),
title: 'Продукты',
value: '1 840 ₽',
),
],
),
),
],
),
);
},
),
],
);
}
@@ -0,0 +1,93 @@
import 'package:flutter/cupertino.dart';
import 'package:please_pay_me/theme/theme.dart';
import 'package:please_pay_me/ui/ui.dart';
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
import 'package:please_pay_me_widgetbook/support/preview.dart';
import 'package:widgetbook/widgetbook.dart';
WidgetbookComponent segmentedControlComponent() {
return WidgetbookComponent(
name: 'AppSegmentedControl',
useCases: [
WidgetbookUseCase(
name: 'Playground',
builder: (context) {
final labels = knobText(
context,
label: 'Labels (comma separated)',
initialValue: 'Все,Расходы,Доходы',
).split(',').where((e) => e.trim().isNotEmpty).toList();
final safeLabels = labels.isEmpty ? ['Все'] : labels;
return IosPreview(
stretch: true,
child: _StatefulSegments(
labels: safeLabels,
initialIndex: knobInt(
context,
label: 'Initial index',
max: safeLabels.length - 1,
),
),
);
},
),
WidgetbookUseCase(
name: 'In screen header',
builder: (context) {
return CupertinoPageScaffold(
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
navigationBar: const AppNavBar(title: 'Журнал'),
child: SafeArea(
child: Column(
children: [
const SizedBox(height: AppSpacing.s4),
const _StatefulSegments(labels: ['Неделя', 'Месяц', 'Год']),
const SizedBox(height: AppSpacing.s5),
AppListSection(
children: const [
AppListTile(title: 'Итого', value: '45 580 ₽'),
],
),
],
),
),
);
},
),
],
);
}
class _StatefulSegments extends StatefulWidget {
const _StatefulSegments({required this.labels, this.initialIndex = 0});
final List<String> labels;
final int initialIndex;
@override
State<_StatefulSegments> createState() => _StatefulSegmentsState();
}
class _StatefulSegmentsState extends State<_StatefulSegments> {
late int _index = widget.initialIndex;
@override
void didUpdateWidget(_StatefulSegments oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.initialIndex != widget.initialIndex ||
_index >= widget.labels.length) {
_index = widget.initialIndex.clamp(0, widget.labels.length - 1);
}
}
@override
Widget build(BuildContext context) {
return AppSegmentedControl(
labels: widget.labels,
index: _index,
onChanged: (i) => setState(() => _index = i),
);
}
}
@@ -0,0 +1,53 @@
import 'package:flutter/cupertino.dart';
import 'package:please_pay_me/theme/theme.dart';
import 'package:please_pay_me/ui/ui.dart';
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
import 'package:widgetbook/widgetbook.dart';
const _items = [
AppTabItem(icon: CupertinoIcons.list_bullet, label: 'Журнал'),
AppTabItem(icon: CupertinoIcons.chart_pie, label: 'Бюджет'),
AppTabItem(
icon: CupertinoIcons.person,
activeIcon: CupertinoIcons.person_fill,
label: 'Профиль',
),
];
WidgetbookComponent tabBarComponent() {
return WidgetbookComponent(
name: 'AppTabBar',
useCases: [
WidgetbookUseCase(
name: 'Playground',
builder: (context) {
final index = knobInt(context, label: 'Current index', min: 0, max: 2);
return ColoredBox(
color: AppColors.of(context, AppColors.groupedBackground),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
AppTabBar(items: _items, currentIndex: index, onTap: (_) {}),
],
),
);
},
),
WidgetbookUseCase(
name: 'In scaffold',
builder: (context) {
return CupertinoTabScaffold(
tabBar: AppTabBar(items: _items, currentIndex: 0, onTap: (_) {}),
tabBuilder: (context, index) => CupertinoTabView(
builder: (context) => CupertinoPageScaffold(
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
navigationBar: AppNavBar(title: _items[index].label),
child: Center(child: AppText.body(_items[index].label)),
),
),
);
},
),
],
);
}