kasy-cli 1.25.0 → 1.26.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.
Files changed (31) hide show
  1. package/lib/commands/new.js +53 -3
  2. package/lib/utils/i18n/messages-en.js +3 -0
  3. package/lib/utils/i18n/messages-es.js +3 -0
  4. package/lib/utils/i18n/messages-pt.js +3 -0
  5. package/package.json +1 -1
  6. package/templates/firebase/lib/components/kasy_app_bar.dart +12 -6
  7. package/templates/firebase/lib/components/kasy_avatar.dart +17 -10
  8. package/templates/firebase/lib/components/kasy_checkbox.dart +24 -15
  9. package/templates/firebase/lib/components/kasy_date_picker.dart +27 -20
  10. package/templates/firebase/lib/components/kasy_otp_verification_bottom_sheet.dart +19 -14
  11. package/templates/firebase/lib/components/kasy_tabs.dart +75 -65
  12. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +103 -3
  13. package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +45 -2
  14. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +9 -4
  15. package/templates/firebase/lib/features/feedbacks/ui/widgets/add_feature_button.dart +1 -0
  16. package/templates/firebase/lib/features/feedbacks/ui/widgets/feature_card.dart +2 -0
  17. package/templates/firebase/lib/features/home/home_feed.dart +21 -5
  18. package/templates/firebase/lib/features/home/home_image_grid.dart +83 -58
  19. package/templates/firebase/lib/features/local_reminders/ui/reminder_page.dart +124 -101
  20. package/templates/firebase/lib/features/notifications/ui/components/notification_tile.dart +1 -0
  21. package/templates/firebase/lib/features/notifications/ui/widgets/notification_tile.dart +85 -85
  22. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +67 -62
  23. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +37 -23
  24. package/templates/firebase/lib/features/settings/ui/widgets/admin_card.dart +14 -6
  25. package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_banner.dart +9 -3
  26. package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_close_button.dart +24 -16
  27. package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_col.dart +29 -22
  28. package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_row.dart +19 -12
  29. package/templates/firebase/lib/i18n/en.i18n.json +2 -1
  30. package/templates/firebase/lib/i18n/es.i18n.json +2 -1
  31. package/templates/firebase/lib/i18n/pt.i18n.json +2 -1
@@ -1,5 +1,6 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:kasy_kit/core/theme/theme.dart';
3
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
3
4
 
4
5
  typedef OnSelectRow = void Function(int index, bool selected);
5
6
 
@@ -51,38 +52,50 @@ class _OnboardingSelectableRowGroupState
51
52
  return ListView.separated(
52
53
  physics: widget.physics,
53
54
  shrinkWrap: true,
54
- separatorBuilder: (context, index) => const SizedBox(height: KasySpacing.sm),
55
+ separatorBuilder: (context, index) =>
56
+ const SizedBox(height: KasySpacing.sm),
55
57
  itemCount: widget.options.length,
56
58
  itemBuilder: (context, index) {
57
- final hasOnSelectInfo = widget.onSelectInfoWidget != null &&
59
+ final hasOnSelectInfo =
60
+ widget.onSelectInfoWidget != null &&
58
61
  widget.onSelectInfoWidget!.length > index &&
59
62
  widget.onSelectInfoWidget![index] != null;
63
+ void selectRow() {
64
+ if (_selectedIndex == index) {
65
+ return;
66
+ }
67
+ setState(() {
68
+ _selectedIndex = index;
69
+ });
70
+ widget.onSelect?.call(index, true);
71
+ }
72
+
60
73
  return Column(
61
74
  crossAxisAlignment: CrossAxisAlignment.stretch,
62
75
  children: [
63
- Material(
64
- color: Colors.transparent,
76
+ KasyFocusRing(
77
+ onActivate: selectRow,
65
78
  borderRadius: KasyRadius.lgBorderRadius,
66
- child: InkWell(
79
+ child: Material(
80
+ color: Colors.transparent,
67
81
  borderRadius: KasyRadius.lgBorderRadius,
68
- onTap: () {
69
- if (_selectedIndex == index) {
70
- return;
71
- }
72
- setState(() {
73
- _selectedIndex = index;
74
- });
75
- widget.onSelect?.call(index, true);
76
- },
77
- child: switch (hasOnSelectInfo && _selectedIndex == index) {
78
- false => widget.options[index],
79
- true => widget.options[index],
80
- },
82
+ child: InkWell(
83
+ canRequestFocus: false,
84
+ borderRadius: KasyRadius.lgBorderRadius,
85
+ onTap: selectRow,
86
+ child: switch (hasOnSelectInfo && _selectedIndex == index) {
87
+ false => widget.options[index],
88
+ true => widget.options[index],
89
+ },
90
+ ),
81
91
  ),
82
92
  ),
83
93
  if (hasOnSelectInfo && _selectedIndex == index)
84
94
  Padding(
85
- padding: const EdgeInsets.only(top: KasySpacing.sm, bottom: KasySpacing.md),
95
+ padding: const EdgeInsets.only(
96
+ top: KasySpacing.sm,
97
+ bottom: KasySpacing.md,
98
+ ),
86
99
  child: widget.onSelectInfoWidget![index],
87
100
  ),
88
101
  ],
@@ -126,26 +139,33 @@ class _OnboardingMultiSelectableRowGroupState
126
139
  runSpacing: KasySpacing.sm,
127
140
  children: widget.options.map((option) {
128
141
  final index = widget.options.indexOf(option);
129
- return Material(
130
- color: Colors.transparent,
142
+ void toggleSelection() {
143
+ if (_selectedIndex.contains(index)) {
144
+ _selectedIndex.remove(index);
145
+ widget.onSelect?.call(index, false);
146
+ } else {
147
+ _selectedIndex.add(index);
148
+ widget.onSelect?.call(index, true);
149
+ }
150
+ setState(() {});
151
+ }
152
+
153
+ return KasyFocusRing(
154
+ onActivate: toggleSelection,
131
155
  borderRadius: KasyRadius.mdBorderRadius,
132
- child: InkWell(
133
- splashColor: context.colors.primary.withValues(alpha:.1),
134
- onTap: () {
135
- if (_selectedIndex.contains(index)) {
136
- _selectedIndex.remove(index);
137
- widget.onSelect?.call(index, false);
138
- } else {
139
- _selectedIndex.add(index);
140
- widget.onSelect?.call(index, true);
141
- }
142
- setState(() {});
143
- },
144
- child: SelectableRowTile(
145
- title: option.title,
146
- subtitle: option.subtitle,
147
- selected: _selectedIndex.contains(index),
148
- emoj: option.emoj,
156
+ child: Material(
157
+ color: Colors.transparent,
158
+ borderRadius: KasyRadius.mdBorderRadius,
159
+ child: InkWell(
160
+ canRequestFocus: false,
161
+ splashColor: context.colors.primary.withValues(alpha: .1),
162
+ onTap: toggleSelection,
163
+ child: SelectableRowTile(
164
+ title: option.title,
165
+ subtitle: option.subtitle,
166
+ selected: _selectedIndex.contains(index),
167
+ emoj: option.emoj,
168
+ ),
149
169
  ),
150
170
  ),
151
171
  );
@@ -205,15 +225,11 @@ class _SelectableRowTileState extends State<SelectableRowTile>
205
225
  _opacityAnimation = Tween(
206
226
  begin: 0.0,
207
227
  end: 1.0,
208
- ).animate(
209
- CurvedAnimation(parent: _controller, curve: Curves.ease),
210
- );
228
+ ).animate(CurvedAnimation(parent: _controller, curve: Curves.ease));
211
229
  _iconSizeAnimation = Tween(
212
230
  begin: 0.0,
213
231
  end: 1.0,
214
- ).animate(
215
- CurvedAnimation(parent: _controller, curve: Curves.elasticOut),
216
- );
232
+ ).animate(CurvedAnimation(parent: _controller, curve: Curves.elasticOut));
217
233
  if (widget.selected) {
218
234
  _controller.forward();
219
235
  }
@@ -267,9 +283,7 @@ class _SelectableRowTileState extends State<SelectableRowTile>
267
283
  padding: const EdgeInsets.only(right: KasySpacing.md),
268
284
  child: Text(
269
285
  widget.emoj!,
270
- style: context.textTheme.titleMedium?.copyWith(
271
- fontSize: 28,
272
- ),
286
+ style: context.textTheme.titleMedium?.copyWith(fontSize: 28),
273
287
  ),
274
288
  ),
275
289
  ),
@@ -282,8 +296,9 @@ class _SelectableRowTileState extends State<SelectableRowTile>
282
296
  widget.title!,
283
297
  style: context.textTheme.bodyLarge?.copyWith(
284
298
  color: colors.onSurface,
285
- fontWeight:
286
- widget.selected ? FontWeight.w700 : FontWeight.w600,
299
+ fontWeight: widget.selected
300
+ ? FontWeight.w700
301
+ : FontWeight.w600,
287
302
  ),
288
303
  ),
289
304
  if (widget.subtitle != null)
@@ -301,10 +316,7 @@ class _SelectableRowTileState extends State<SelectableRowTile>
301
316
  ),
302
317
  const SizedBox(width: KasySpacing.sm),
303
318
  if (!widget.selected)
304
- Flexible(
305
- flex: 0,
306
- child: RoundRadioBox.unselected(context),
307
- ),
319
+ Flexible(flex: 0, child: RoundRadioBox.unselected(context)),
308
320
  if (widget.selected)
309
321
  Flexible(
310
322
  flex: 0,
@@ -371,10 +383,7 @@ class RoundRadioBox extends StatelessWidget {
371
383
  decoration: BoxDecoration(
372
384
  color: bgColor,
373
385
  shape: BoxShape.circle,
374
- border: Border.all(
375
- color: borderColor,
376
- width: 2,
377
- ),
386
+ border: Border.all(color: borderColor, width: 2),
378
387
  ),
379
388
  child: Center(
380
389
  child: icon != null
@@ -382,11 +391,7 @@ class RoundRadioBox extends StatelessWidget {
382
391
  opacity: iconOpacity,
383
392
  child: Transform.scale(
384
393
  scale: iconSize,
385
- child: Icon(
386
- icon,
387
- color: context.colors.onPrimary,
388
- size: 15,
389
- ),
394
+ child: Icon(icon, color: context.colors.onPrimary, size: 15),
390
395
  ),
391
396
  )
392
397
  : const SizedBox.shrink(),
@@ -11,6 +11,7 @@ import 'package:kasy_kit/core/data/repositories/user_repository.dart';
11
11
  import 'package:kasy_kit/core/states/models/user_state.dart';
12
12
  import 'package:kasy_kit/core/states/user_state_notifier.dart';
13
13
  import 'package:kasy_kit/core/theme/theme.dart';
14
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
14
15
  import 'package:kasy_kit/features/settings/ui/widgets/avatar_utils.dart';
15
16
  import 'package:kasy_kit/features/settings/ui/widgets/round_progress.dart';
16
17
  import 'package:kasy_kit/i18n/translations.g.dart';
@@ -57,12 +58,18 @@ class _EditableUserAvatarState extends ConsumerState<EditableUserAvatar> {
57
58
  final displayAvatarPath = _optimisticAvatarUrl ?? avatarPath;
58
59
  final double d = widget.diameter ?? KasyAvatarSize.medium.diameter;
59
60
 
60
- return GestureDetector(
61
- behavior: HitTestBehavior.opaque,
62
- onTap: userId != null && !_isUploading
63
- ? () => _onTapAvatar(context, userState, avatarPath)
64
- : null,
65
- child: Padding(
61
+ final VoidCallback? onTapAvatar = userId != null && !_isUploading
62
+ ? () => _onTapAvatar(context, userState, avatarPath)
63
+ : null;
64
+
65
+ return KasyFocusRing(
66
+ enabled: onTapAvatar != null,
67
+ onActivate: onTapAvatar,
68
+ borderRadius: BorderRadius.circular(999),
69
+ child: GestureDetector(
70
+ behavior: HitTestBehavior.opaque,
71
+ onTap: onTapAvatar,
72
+ child: Padding(
66
73
  padding: const EdgeInsets.all(6),
67
74
  child: Stack(
68
75
  clipBehavior: Clip.none,
@@ -103,6 +110,7 @@ class _EditableUserAvatarState extends ConsumerState<EditableUserAvatar> {
103
110
  ),
104
111
  ],
105
112
  ),
113
+ ),
106
114
  ),
107
115
  );
108
116
  }
@@ -313,24 +321,30 @@ class _BottomSheetTile extends StatelessWidget {
313
321
  @override
314
322
  Widget build(BuildContext context) {
315
323
  final Color fg = color ?? context.colors.onSurface;
316
- return InkWell(
317
- onTap: onTap,
318
- child: Padding(
319
- padding: const EdgeInsets.symmetric(
320
- horizontal: KasySpacing.md,
321
- vertical: KasySpacing.smd,
322
- ),
323
- child: Row(
324
- children: [
325
- if (icon != null) ...[
326
- Icon(icon, size: 22, color: fg),
327
- const SizedBox(width: KasySpacing.sm),
324
+ return KasyFocusRing(
325
+ onActivate: onTap,
326
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
327
+ gapColor: context.colors.surface,
328
+ child: InkWell(
329
+ canRequestFocus: false,
330
+ onTap: onTap,
331
+ child: Padding(
332
+ padding: const EdgeInsets.symmetric(
333
+ horizontal: KasySpacing.md,
334
+ vertical: KasySpacing.smd,
335
+ ),
336
+ child: Row(
337
+ children: [
338
+ if (icon != null) ...[
339
+ Icon(icon, size: 22, color: fg),
340
+ const SizedBox(width: KasySpacing.sm),
341
+ ],
342
+ Text(
343
+ label,
344
+ style: context.textTheme.bodyLarge?.copyWith(color: fg),
345
+ ),
328
346
  ],
329
- Text(
330
- label,
331
- style: context.textTheme.bodyLarge?.copyWith(color: fg),
332
- ),
333
- ],
347
+ ),
334
348
  ),
335
349
  ),
336
350
  );
@@ -1,6 +1,7 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
3
3
  import 'package:kasy_kit/core/theme/theme.dart';
4
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
4
5
 
5
6
  /// Here is just a simple content card
6
7
  class AdminPanelCard extends StatelessWidget {
@@ -21,12 +22,18 @@ class AdminPanelCard extends StatelessWidget {
21
22
 
22
23
  @override
23
24
  Widget build(BuildContext context) {
24
- return InkWell(
25
- onTap: () {
26
- KasyHaptics.medium(context);
27
- onTap.call();
28
- },
29
- child: Card(
25
+ void handleActivate() {
26
+ KasyHaptics.medium(context);
27
+ onTap.call();
28
+ }
29
+
30
+ return KasyFocusRing(
31
+ onActivate: handleActivate,
32
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
33
+ child: InkWell(
34
+ canRequestFocus: false,
35
+ onTap: handleActivate,
36
+ child: Card(
30
37
  color: backgroundColor ?? context.colors.primary.withValues(alpha: .15),
31
38
  margin: EdgeInsets.zero,
32
39
  elevation: 0,
@@ -53,6 +60,7 @@ class AdminPanelCard extends StatelessWidget {
53
60
  ],
54
61
  ),
55
62
  ),
63
+ ),
56
64
  ),
57
65
  );
58
66
  }
@@ -1,6 +1,7 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:google_fonts/google_fonts.dart';
3
3
  import 'package:kasy_kit/core/theme/theme.dart';
4
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
4
5
 
5
6
  typedef PremiumWideBannerOnTap = void Function();
6
7
 
@@ -32,9 +33,13 @@ class PremiumWideBanner extends StatelessWidget {
32
33
  color: bgColor,
33
34
  // border: Border.all(color: borderColor),
34
35
  ),
35
- child: InkWell(
36
- onTap: () => onTap(),
37
- child: Row(
36
+ child: KasyFocusRing(
37
+ onActivate: () => onTap(),
38
+ borderRadius: BorderRadius.zero,
39
+ child: InkWell(
40
+ canRequestFocus: false,
41
+ onTap: () => onTap(),
42
+ child: Row(
38
43
  children: [
39
44
  Image.asset(
40
45
  imagePath,
@@ -72,6 +77,7 @@ class PremiumWideBanner extends StatelessWidget {
72
77
  const SizedBox(width: KasySpacing.lg),
73
78
  ],
74
79
  ),
80
+ ),
75
81
  ),
76
82
  ),
77
83
  );
@@ -1,6 +1,7 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:flutter_riverpod/flutter_riverpod.dart';
3
3
  import 'package:kasy_kit/core/theme/theme.dart';
4
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
4
5
 
5
6
  class AppCloseButtonComponent extends ConsumerWidget {
6
7
  final ValueNotifier<bool> showCloseBtn;
@@ -34,24 +35,31 @@ class AppCloseButton extends StatelessWidget {
34
35
 
35
36
  @override
36
37
  Widget build(BuildContext context) {
38
+ final VoidCallback? onClose = onTap;
37
39
  return Material(
38
40
  color: Colors.transparent,
39
- child: InkWell(
40
- onTapUp: (_) {
41
- onTap?.call();
42
- },
43
- child: Ink(
44
- width: 32,
45
- height: 32,
46
- decoration: BoxDecoration(
47
- shape: BoxShape.circle,
48
- color: context.colors.onBackground.withValues(alpha: 0.6),
49
- ),
50
- child: Center(
51
- child: Icon(
52
- KasyIcons.close,
53
- color: context.colors.background,
54
- size: 21,
41
+ child: KasyFocusRing(
42
+ enabled: onClose != null,
43
+ onActivate: onClose,
44
+ borderRadius: BorderRadius.circular(999),
45
+ child: InkWell(
46
+ canRequestFocus: false,
47
+ onTapUp: (_) {
48
+ onClose?.call();
49
+ },
50
+ child: Ink(
51
+ width: 32,
52
+ height: 32,
53
+ decoration: BoxDecoration(
54
+ shape: BoxShape.circle,
55
+ color: context.colors.onBackground.withValues(alpha: 0.6),
56
+ ),
57
+ child: Center(
58
+ child: Icon(
59
+ KasyIcons.close,
60
+ color: context.colors.background,
61
+ size: 21,
62
+ ),
55
63
  ),
56
64
  ),
57
65
  ),
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
4
4
  import 'package:flutter_animate/flutter_animate.dart';
5
5
  import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
6
6
  import 'package:kasy_kit/core/theme/theme.dart';
7
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
7
8
  import 'package:kasy_kit/features/subscriptions/ui/widgets/selectable_row.dart';
8
9
 
9
10
 
@@ -43,6 +44,17 @@ class _SelectableColGroupState<T> extends State<SelectableColGroup<T>> {
43
44
 
44
45
  OnSelectItem<T> get onSelectItem => widget.onSelectItem;
45
46
 
47
+ void _selectIndex(int i) {
48
+ setState(() {
49
+ if (selectedIndex == i) {
50
+ return;
51
+ }
52
+ KasyHaptics.heavy(context);
53
+ selectedIndex = i;
54
+ onSelectItem(widget.items[i].data);
55
+ });
56
+ }
57
+
46
58
  @override
47
59
  Widget build(BuildContext context) {
48
60
  return IntrinsicHeight(
@@ -53,29 +65,24 @@ class _SelectableColGroupState<T> extends State<SelectableColGroup<T>> {
53
65
  children: [
54
66
  for (var i = 0; i < widget.items.length; i++)
55
67
  Expanded(
56
- child: GestureDetector(
57
- onTap: () {
58
- setState(() {
59
- if (selectedIndex == i) {
60
- return;
61
- }
62
- KasyHaptics.heavy(context);
63
- selectedIndex = i;
64
- onSelectItem(widget.items[i].data);
65
- });
66
- },
67
- child: Animate(
68
- effects: [
69
- FadeEffect(
70
- delay: Duration(milliseconds: 100 + 100 * i),
71
- duration: const Duration(milliseconds: 500),
68
+ child: KasyFocusRing(
69
+ onActivate: () => _selectIndex(i),
70
+ borderRadius: KasyRadius.lgBorderRadius,
71
+ child: GestureDetector(
72
+ onTap: () => _selectIndex(i),
73
+ child: Animate(
74
+ effects: [
75
+ FadeEffect(
76
+ delay: Duration(milliseconds: 100 + 100 * i),
77
+ duration: const Duration(milliseconds: 500),
78
+ ),
79
+ ],
80
+ child: SelectableCol.fromOption(
81
+ key: ValueKey('item_$i'),
82
+ widget.items[i],
83
+ selected: selectedIndex == i,
84
+ brightness: widget.brightness,
72
85
  ),
73
- ],
74
- child: SelectableCol.fromOption(
75
- key: ValueKey('item_$i'),
76
- widget.items[i],
77
- selected: selectedIndex == i,
78
- brightness: widget.brightness,
79
86
  ),
80
87
  ),
81
88
  ),
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
2
2
  import 'package:flutter_animate/flutter_animate.dart';
3
3
  import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
4
4
  import 'package:kasy_kit/core/theme/theme.dart';
5
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
5
6
 
6
7
  typedef OnSelectItem<T> = void Function(T data);
7
8
 
@@ -34,23 +35,28 @@ class _SelectableRowGroupState<T> extends State<SelectableRowGroup<T>> {
34
35
 
35
36
  OnSelectItem<T> get onSelectItem => widget.onSelectItem;
36
37
 
38
+ void _selectIndex(int i) {
39
+ setState(() {
40
+ if (selectedIndex == i) {
41
+ return;
42
+ }
43
+ KasyHaptics.heavy(context);
44
+ selectedIndex = i;
45
+ onSelectItem(widget.items[i].data);
46
+ });
47
+ }
48
+
37
49
  @override
38
50
  Widget build(BuildContext context) {
39
51
  return Column(
40
52
  children: [
41
53
  for (var i = 0; i < widget.items.length; i++)
42
- GestureDetector(
43
- onTap: () {
44
- setState(() {
45
- if (selectedIndex == i) {
46
- return;
47
- }
48
- KasyHaptics.heavy(context);
49
- selectedIndex = i;
50
- onSelectItem(widget.items[i].data);
51
- });
52
- },
53
- child: Padding(
54
+ KasyFocusRing(
55
+ onActivate: () => _selectIndex(i),
56
+ borderRadius: KasyRadius.mdBorderRadius,
57
+ child: GestureDetector(
58
+ onTap: () => _selectIndex(i),
59
+ child: Padding(
54
60
  padding: EdgeInsets.only(
55
61
  bottom: i == widget.items.length - 1 ? 0 : KasySpacing.sm,
56
62
  ),
@@ -69,6 +75,7 @@ class _SelectableRowGroupState<T> extends State<SelectableRowGroup<T>> {
69
75
  ),
70
76
  ),
71
77
  ),
78
+ ),
72
79
  ),
73
80
  ],
74
81
  );
@@ -408,7 +408,8 @@
408
408
  "support": "Support",
409
409
  "notifications": "Notifications",
410
410
  "settings": "Config.",
411
- "logout": "Sign out"
411
+ "logout": "Sign out",
412
+ "skip_to_content": "Skip to content"
412
413
  },
413
414
  "reminderPage": {
414
415
  "title": "Reminders",
@@ -408,7 +408,8 @@
408
408
  "support": "Soporte",
409
409
  "notifications": "Notificaciones",
410
410
  "settings": "Config.",
411
- "logout": "Salir"
411
+ "logout": "Salir",
412
+ "skip_to_content": "Saltar al contenido"
412
413
  },
413
414
  "reminderPage": {
414
415
  "title": "Recordatorios",
@@ -408,7 +408,8 @@
408
408
  "support": "Suporte",
409
409
  "notifications": "Notificações",
410
410
  "settings": "Config.",
411
- "logout": "Sair"
411
+ "logout": "Sair",
412
+ "skip_to_content": "Pular para o conteúdo"
412
413
  },
413
414
  "reminderPage": {
414
415
  "title": "Lembretes",