@djangocfg/layouts 2.1.110 → 2.1.112

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.
@@ -11,6 +11,7 @@
11
11
  import { ArrowDownToLine, Check, Menu, Monitor, Plus, Search } from 'lucide-react';
12
12
  import React, { useMemo } from 'react';
13
13
 
14
+ import { useTypedT, type I18nTranslations } from '@djangocfg/i18n';
14
15
  import {
15
16
  Button, Card, CardContent, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader,
16
17
  DialogTitle
@@ -32,28 +33,29 @@ function getBrowserCategory(browser: {
32
33
  return 'unknown';
33
34
  }
34
35
 
35
- function getBrowserSteps(category: BrowserCategory, browserName: string): InstallStep[] {
36
+ type TranslationFn = (key: string) => string;
37
+
38
+ function getBrowserSteps(category: BrowserCategory, t: TranslationFn): InstallStep[] {
36
39
  switch (category) {
37
40
  case 'chromium':
38
- // Chrome, Edge, Brave, Arc, Vivaldi, Opera, Yandex, etc.
39
41
  return [
40
42
  {
41
43
  number: 1,
42
- title: 'Find Install Icon',
44
+ title: t('layouts.pwa.chromiumStep1Title'),
43
45
  icon: ArrowDownToLine,
44
- description: 'Look for install icon in address bar (right side)',
46
+ description: t('layouts.pwa.chromiumStep1Desc'),
45
47
  },
46
48
  {
47
49
  number: 2,
48
- title: 'Click Install',
50
+ title: t('layouts.pwa.chromiumStep2Title'),
49
51
  icon: Plus,
50
- description: 'Click the icon and select "Install"',
52
+ description: t('layouts.pwa.chromiumStep2Desc'),
51
53
  },
52
54
  {
53
55
  number: 3,
54
- title: 'Confirm',
56
+ title: t('layouts.pwa.chromiumStep3Title'),
55
57
  icon: Check,
56
- description: 'Click "Install" in the popup dialog',
58
+ description: t('layouts.pwa.chromiumStep3Desc'),
57
59
  },
58
60
  ];
59
61
 
@@ -61,21 +63,21 @@ function getBrowserSteps(category: BrowserCategory, browserName: string): Instal
61
63
  return [
62
64
  {
63
65
  number: 1,
64
- title: 'Open Menu',
66
+ title: t('layouts.pwa.firefoxStep1Title'),
65
67
  icon: Menu,
66
- description: 'Click the menu button (three lines)',
68
+ description: t('layouts.pwa.firefoxStep1Desc'),
67
69
  },
68
70
  {
69
71
  number: 2,
70
- title: 'Find Install Option',
72
+ title: t('layouts.pwa.firefoxStep2Title'),
71
73
  icon: Search,
72
- description: 'Look for "Install" or "Add to Home Screen"',
74
+ description: t('layouts.pwa.firefoxStep2Desc'),
73
75
  },
74
76
  {
75
77
  number: 3,
76
- title: 'Confirm',
78
+ title: t('layouts.pwa.firefoxStep3Title'),
77
79
  icon: Check,
78
- description: 'Follow the installation prompts',
80
+ description: t('layouts.pwa.firefoxStep3Desc'),
79
81
  },
80
82
  ];
81
83
 
@@ -83,15 +85,15 @@ function getBrowserSteps(category: BrowserCategory, browserName: string): Instal
83
85
  return [
84
86
  {
85
87
  number: 1,
86
- title: 'Limited Support',
88
+ title: t('layouts.pwa.safariStep1Title'),
87
89
  icon: Monitor,
88
- description: 'Safari on macOS has limited PWA support',
90
+ description: t('layouts.pwa.safariStep1Desc'),
89
91
  },
90
92
  {
91
93
  number: 2,
92
- title: 'Use Chromium Browser',
94
+ title: t('layouts.pwa.safariStep2Title'),
93
95
  icon: ArrowDownToLine,
94
- description: 'Consider using Chrome, Edge, or Brave for full PWA experience',
96
+ description: t('layouts.pwa.safariStep2Desc'),
95
97
  },
96
98
  ];
97
99
 
@@ -99,21 +101,21 @@ function getBrowserSteps(category: BrowserCategory, browserName: string): Instal
99
101
  return [
100
102
  {
101
103
  number: 1,
102
- title: 'Check Address Bar',
104
+ title: t('layouts.pwa.unknownStep1Title'),
103
105
  icon: ArrowDownToLine,
104
- description: 'Look for an install or download icon',
106
+ description: t('layouts.pwa.unknownStep1Desc'),
105
107
  },
106
108
  {
107
109
  number: 2,
108
- title: 'Or Use Menu',
110
+ title: t('layouts.pwa.unknownStep2Title'),
109
111
  icon: Menu,
110
- description: 'Check browser menu for install option',
112
+ description: t('layouts.pwa.unknownStep2Desc'),
111
113
  },
112
114
  {
113
115
  number: 3,
114
- title: 'Confirm',
116
+ title: t('layouts.pwa.unknownStep3Title'),
115
117
  icon: Check,
116
- description: 'Follow the installation prompts',
118
+ description: t('layouts.pwa.unknownStep3Desc'),
117
119
  },
118
120
  ];
119
121
  }
@@ -157,15 +159,25 @@ export function DesktopGuide({ onDismiss, open = true }: IOSGuideModalProps) {
157
159
  isOpera,
158
160
  isYandex,
159
161
  } = useInstall();
162
+ const t = useTypedT<I18nTranslations>();
163
+
164
+ const labels = useMemo(() => ({
165
+ title: t('layouts.pwa.desktopTitle'),
166
+ description: t('layouts.pwa.desktopDescription'),
167
+ descSafari: t('layouts.pwa.desktopDescSafari'),
168
+ tip: t('layouts.pwa.desktopTip'),
169
+ firefoxNote: t('layouts.pwa.desktopFirefoxNote'),
170
+ gotIt: t('layouts.pwa.gotIt'),
171
+ }), [t]);
160
172
 
161
173
  const category = useMemo(
162
174
  () => getBrowserCategory({ isChromium, isFirefox, isSafari }),
163
175
  [isChromium, isFirefox, isSafari]
164
176
  );
165
177
 
166
- const steps = useMemo(() => getBrowserSteps(category, browserName), [category, browserName]);
178
+ const steps = useMemo(() => getBrowserSteps(category, t), [category, t]);
167
179
 
168
- // Get specific browser display name with emoji
180
+ // Get specific browser display name
169
181
  const displayName = useMemo(() => {
170
182
  if (isEdge) return 'Edge';
171
183
  if (isBrave) return 'Brave';
@@ -182,12 +194,12 @@ export function DesktopGuide({ onDismiss, open = true }: IOSGuideModalProps) {
182
194
  <DialogHeader className="text-left">
183
195
  <DialogTitle className="flex items-center gap-2">
184
196
  <Monitor className="w-5 h-5 text-primary" />
185
- Install App on Desktop
197
+ {labels.title}
186
198
  </DialogTitle>
187
199
  <DialogDescription className="text-left">
188
200
  {isSafari
189
- ? 'Safari on macOS has limited PWA support. For the best experience, use Chrome, Edge, or Brave.'
190
- : `Install this app on ${displayName} for quick access from your desktop`
201
+ ? labels.descSafari
202
+ : labels.description.replace('{browser}', displayName)
191
203
  }
192
204
  </DialogDescription>
193
205
  </DialogHeader>
@@ -200,20 +212,20 @@ export function DesktopGuide({ onDismiss, open = true }: IOSGuideModalProps) {
200
212
 
201
213
  {category === 'chromium' && (
202
214
  <div className="p-3 bg-muted/30 rounded-lg text-xs text-muted-foreground">
203
- 💡 Tip: You can also right-click the page and look for "Install" option in {displayName}
215
+ 💡 {labels.tip.replace('{browser}', displayName)}
204
216
  </div>
205
217
  )}
206
218
 
207
219
  {category === 'firefox' && (
208
220
  <div className="p-3 bg-amber-500/10 rounded-lg text-xs text-amber-700 dark:text-amber-400">
209
- ℹ️ Note: Firefox has limited PWA support. Some features may not work as expected.
221
+ ℹ️ {labels.firefoxNote}
210
222
  </div>
211
223
  )}
212
224
 
213
225
  <DialogFooter>
214
226
  <Button onClick={onDismiss} variant="default" className="w-full">
215
227
  <Check className="w-4 h-4 mr-2" />
216
- Got It
228
+ {labels.gotIt}
217
229
  </Button>
218
230
  </DialogFooter>
219
231
  </DialogContent>
@@ -8,35 +8,15 @@
8
8
  */
9
9
 
10
10
  import { ArrowDown, ArrowUpRight, Check, CheckCircle, Share } from 'lucide-react';
11
- import React from 'react';
11
+ import React, { useMemo } from 'react';
12
12
 
13
+ import { useTypedT, type I18nTranslations } from '@djangocfg/i18n';
13
14
  import {
14
15
  Button, Card, CardContent, Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle
15
16
  } from '@djangocfg/ui-core/components';
16
17
 
17
18
  import type { IOSGuideModalProps, InstallStep } from '../types';
18
19
 
19
- const steps: InstallStep[] = [
20
- {
21
- number: 1,
22
- title: 'Tap Share',
23
- icon: ArrowUpRight,
24
- description: 'At the bottom of Safari',
25
- },
26
- {
27
- number: 2,
28
- title: 'Scroll & Tap',
29
- icon: ArrowDown,
30
- description: '"Add to Home Screen"',
31
- },
32
- {
33
- number: 3,
34
- title: 'Confirm',
35
- icon: CheckCircle,
36
- description: 'Tap "Add" in top-right',
37
- },
38
- ];
39
-
40
20
  function StepCard({ step }: { step: InstallStep }) {
41
21
  return (
42
22
  <Card className="border border-border">
@@ -63,16 +43,45 @@ function StepCard({ step }: { step: InstallStep }) {
63
43
  }
64
44
 
65
45
  export function IOSGuideDrawer({ onDismiss, open = true }: IOSGuideModalProps) {
46
+ const t = useTypedT<I18nTranslations>();
47
+
48
+ const labels = useMemo(() => ({
49
+ title: t('layouts.pwa.iosTitle'),
50
+ description: t('layouts.pwa.iosDescription'),
51
+ gotIt: t('layouts.pwa.gotIt'),
52
+ }), [t]);
53
+
54
+ const steps: InstallStep[] = useMemo(() => [
55
+ {
56
+ number: 1,
57
+ title: t('layouts.pwa.iosStep1Title'),
58
+ icon: ArrowUpRight,
59
+ description: t('layouts.pwa.iosStep1Desc'),
60
+ },
61
+ {
62
+ number: 2,
63
+ title: t('layouts.pwa.iosStep2Title'),
64
+ icon: ArrowDown,
65
+ description: t('layouts.pwa.iosStep2Desc'),
66
+ },
67
+ {
68
+ number: 3,
69
+ title: t('layouts.pwa.iosStep3Title'),
70
+ icon: CheckCircle,
71
+ description: t('layouts.pwa.iosStep3Desc'),
72
+ },
73
+ ], [t]);
74
+
66
75
  return (
67
76
  <Drawer open={open} onOpenChange={(isOpen) => !isOpen && onDismiss()}>
68
77
  <DrawerContent>
69
78
  <DrawerHeader className="text-left">
70
79
  <DrawerTitle className="flex items-center gap-2">
71
80
  <Share className="w-5 h-5 text-primary" />
72
- Add to Home Screen
81
+ {labels.title}
73
82
  </DrawerTitle>
74
83
  <DrawerDescription className="text-left">
75
- Install this app on your iPhone for quick access and a better experience
84
+ {labels.description}
76
85
  </DrawerDescription>
77
86
  </DrawerHeader>
78
87
 
@@ -85,7 +94,7 @@ export function IOSGuideDrawer({ onDismiss, open = true }: IOSGuideModalProps) {
85
94
  <div className="p-4 pt-0">
86
95
  <Button onClick={onDismiss} variant="default" className="w-full">
87
96
  <Check className="w-4 h-4 mr-2" />
88
- Got It
97
+ {labels.gotIt}
89
98
  </Button>
90
99
  </div>
91
100
  </DrawerContent>
@@ -7,8 +7,9 @@
7
7
  */
8
8
 
9
9
  import { ArrowDown, ArrowUpRight, Check, CheckCircle, Share } from 'lucide-react';
10
- import React from 'react';
10
+ import React, { useMemo } from 'react';
11
11
 
12
+ import { useTypedT, type I18nTranslations } from '@djangocfg/i18n';
12
13
  import {
13
14
  Button, Card, CardContent, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader,
14
15
  DialogTitle
@@ -16,27 +17,6 @@ import {
16
17
 
17
18
  import type { IOSGuideModalProps, InstallStep } from '../types';
18
19
 
19
- const steps: InstallStep[] = [
20
- {
21
- number: 1,
22
- title: 'Tap Share',
23
- icon: ArrowUpRight,
24
- description: 'At the bottom of Safari',
25
- },
26
- {
27
- number: 2,
28
- title: 'Scroll & Tap',
29
- icon: ArrowDown,
30
- description: '"Add to Home Screen"',
31
- },
32
- {
33
- number: 3,
34
- title: 'Confirm',
35
- icon: CheckCircle,
36
- description: 'Tap "Add" in top-right',
37
- },
38
- ];
39
-
40
20
  function StepCard({ step }: { step: InstallStep }) {
41
21
  return (
42
22
  <Card className="border border-border">
@@ -63,16 +43,45 @@ function StepCard({ step }: { step: InstallStep }) {
63
43
  }
64
44
 
65
45
  export function IOSGuideModal({ onDismiss, open = true }: IOSGuideModalProps) {
46
+ const t = useTypedT<I18nTranslations>();
47
+
48
+ const labels = useMemo(() => ({
49
+ title: t('layouts.pwa.iosTitle'),
50
+ description: t('layouts.pwa.iosDescription'),
51
+ gotIt: t('layouts.pwa.gotIt'),
52
+ }), [t]);
53
+
54
+ const steps: InstallStep[] = useMemo(() => [
55
+ {
56
+ number: 1,
57
+ title: t('layouts.pwa.iosStep1Title'),
58
+ icon: ArrowUpRight,
59
+ description: t('layouts.pwa.iosStep1Desc'),
60
+ },
61
+ {
62
+ number: 2,
63
+ title: t('layouts.pwa.iosStep2Title'),
64
+ icon: ArrowDown,
65
+ description: t('layouts.pwa.iosStep2Desc'),
66
+ },
67
+ {
68
+ number: 3,
69
+ title: t('layouts.pwa.iosStep3Title'),
70
+ icon: CheckCircle,
71
+ description: t('layouts.pwa.iosStep3Desc'),
72
+ },
73
+ ], [t]);
74
+
66
75
  return (
67
76
  <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onDismiss()}>
68
77
  <DialogContent className="sm:max-w-md">
69
78
  <DialogHeader className="text-left">
70
79
  <DialogTitle className="flex items-center gap-2">
71
80
  <Share className="w-5 h-5 text-primary" />
72
- Add to Home Screen
81
+ {labels.title}
73
82
  </DialogTitle>
74
83
  <DialogDescription className="text-left">
75
- Install this app on your iPhone for quick access and a better experience
84
+ {labels.description}
76
85
  </DialogDescription>
77
86
  </DialogHeader>
78
87
 
@@ -85,7 +94,7 @@ export function IOSGuideModal({ onDismiss, open = true }: IOSGuideModalProps) {
85
94
  <DialogFooter>
86
95
  <Button onClick={onDismiss} variant="default" className="w-full">
87
96
  <Check className="w-4 h-4 mr-2" />
88
- Got It
97
+ {labels.gotIt}
89
98
  </Button>
90
99
  </DialogFooter>
91
100
  </DialogContent>
@@ -8,9 +8,10 @@
8
8
  */
9
9
 
10
10
  import { Bell, X } from 'lucide-react';
11
- import React, { useEffect, useState } from 'react';
11
+ import React, { useEffect, useMemo, useState } from 'react';
12
12
 
13
13
  import { useAuth } from '@djangocfg/api/auth';
14
+ import { useTypedT, type I18nTranslations } from '@djangocfg/i18n';
14
15
  import { Button } from '@djangocfg/ui-core';
15
16
 
16
17
  import { usePushNotifications } from '../hooks/usePushNotifications';
@@ -66,10 +67,19 @@ export function PushPrompt({
66
67
  vapidPublicKey,
67
68
  subscribeEndpoint,
68
69
  });
70
+ const t = useTypedT<I18nTranslations>();
69
71
 
70
72
  const [show, setShow] = useState(false);
71
73
  const [enabling, setEnabling] = useState(false);
72
74
 
75
+ const labels = useMemo(() => ({
76
+ enableNotifications: t('layouts.push.enableNotifications'),
77
+ stayUpdated: t('layouts.push.stayUpdated'),
78
+ enable: t('layouts.push.enable'),
79
+ notNow: t('layouts.push.notNow'),
80
+ dismiss: t('layouts.push.dismiss'),
81
+ }), [t]);
82
+
73
83
  // Check if should show
74
84
  useEffect(() => {
75
85
  // Wait for auth to complete, don't show for unauthenticated users
@@ -132,9 +142,9 @@ export function PushPrompt({
132
142
 
133
143
  {/* Content */}
134
144
  <div className="flex-1 min-w-0">
135
- <p className="text-sm font-medium text-white mb-1">Enable notifications</p>
145
+ <p className="text-sm font-medium text-white mb-1">{labels.enableNotifications}</p>
136
146
  <p className="text-xs text-zinc-400 mb-3">
137
- Stay updated with important updates and alerts
147
+ {labels.stayUpdated}
138
148
  </p>
139
149
 
140
150
  {/* Actions */}
@@ -145,14 +155,14 @@ export function PushPrompt({
145
155
  size="sm"
146
156
  variant="default"
147
157
  >
148
- Enable
158
+ {labels.enable}
149
159
  </Button>
150
160
  <Button
151
161
  onClick={handleDismiss}
152
162
  size="sm"
153
163
  variant="ghost"
154
164
  >
155
- Not now
165
+ {labels.notNow}
156
166
  </Button>
157
167
  </div>
158
168
  </div>
@@ -163,7 +173,7 @@ export function PushPrompt({
163
173
  size="sm"
164
174
  variant="ghost"
165
175
  className="flex-shrink-0 p-1"
166
- aria-label="Dismiss"
176
+ aria-label={labels.dismiss}
167
177
  >
168
178
  <X className="w-4 h-4" />
169
179
  </Button>