@asafarim/shared-i18n 0.7.0 → 0.8.1

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 (82) hide show
  1. package/README.md +71 -1
  2. package/demo/README.md +148 -0
  3. package/demo/dist/Icon Dropdown_Limited Languages.png +0 -0
  4. package/demo/dist/Select Dropdown_Text Only.png +0 -0
  5. package/demo/dist/assets/favicon-BZYZvBLo.svg +4 -0
  6. package/demo/dist/assets/index-BdjqKw_N.css +1 -0
  7. package/demo/dist/assets/index-C1Tq1uEr.js +191 -0
  8. package/demo/dist/favicon.svg +4 -0
  9. package/demo/dist/index.html +27 -0
  10. package/demo/dist/logo.svg +24 -0
  11. package/demo/node_modules/.bin/browserslist +21 -0
  12. package/demo/node_modules/.bin/browserslist.CMD +12 -0
  13. package/demo/node_modules/.bin/browserslist.ps1 +41 -0
  14. package/demo/node_modules/.bin/tsc +4 -4
  15. package/demo/node_modules/.bin/tsc.CMD +12 -0
  16. package/demo/node_modules/.bin/tsc.ps1 +41 -0
  17. package/demo/node_modules/.bin/tsserver +4 -4
  18. package/demo/node_modules/.bin/tsserver.CMD +12 -0
  19. package/demo/node_modules/.bin/tsserver.ps1 +41 -0
  20. package/demo/node_modules/.bin/vite +4 -4
  21. package/demo/node_modules/.bin/vite.CMD +12 -0
  22. package/demo/node_modules/.bin/vite.ps1 +41 -0
  23. package/demo/node_modules/.vite/deps/@asafarim_country-language-selector.js +848 -0
  24. package/demo/node_modules/.vite/deps/@asafarim_country-language-selector.js.map +7 -0
  25. package/demo/node_modules/.vite/deps/_metadata.json +76 -0
  26. package/demo/node_modules/.vite/deps/chunk-5WRI5ZAA.js +30 -0
  27. package/demo/node_modules/.vite/deps/chunk-5WRI5ZAA.js.map +7 -0
  28. package/demo/node_modules/.vite/deps/chunk-B3AHR5EX.js +1004 -0
  29. package/demo/node_modules/.vite/deps/chunk-B3AHR5EX.js.map +7 -0
  30. package/demo/node_modules/.vite/deps/chunk-E6BG6WAU.js +292 -0
  31. package/demo/node_modules/.vite/deps/chunk-E6BG6WAU.js.map +7 -0
  32. package/demo/node_modules/.vite/deps/chunk-MVARZQEG.js +280 -0
  33. package/demo/node_modules/.vite/deps/chunk-MVARZQEG.js.map +7 -0
  34. package/demo/node_modules/.vite/deps/i18next-browser-languagedetector.js +400 -0
  35. package/demo/node_modules/.vite/deps/i18next-browser-languagedetector.js.map +7 -0
  36. package/demo/node_modules/.vite/deps/i18next.js +2392 -0
  37. package/demo/node_modules/.vite/deps/i18next.js.map +7 -0
  38. package/demo/node_modules/.vite/deps/package.json +3 -0
  39. package/demo/node_modules/.vite/deps/react-dom.js +6 -0
  40. package/demo/node_modules/.vite/deps/react-dom.js.map +7 -0
  41. package/demo/node_modules/.vite/deps/react-dom_client.js +20217 -0
  42. package/demo/node_modules/.vite/deps/react-dom_client.js.map +7 -0
  43. package/demo/node_modules/.vite/deps/react-i18next.js +869 -0
  44. package/demo/node_modules/.vite/deps/react-i18next.js.map +7 -0
  45. package/demo/node_modules/.vite/deps/react.js +5 -0
  46. package/demo/node_modules/.vite/deps/react.js.map +7 -0
  47. package/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js +278 -0
  48. package/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
  49. package/demo/node_modules/.vite/deps/react_jsx-runtime.js +6 -0
  50. package/demo/node_modules/.vite/deps/react_jsx-runtime.js.map +7 -0
  51. package/demo/package.json +27 -24
  52. package/demo/public/favicon.svg +4 -4
  53. package/demo/public/logo.svg +24 -24
  54. package/demo/src/App.tsx +129 -116
  55. package/demo/src/components/CountryLanguageDemo.tsx +140 -0
  56. package/demo/src/components/GetStartedSection.tsx +56 -56
  57. package/demo/src/components/KeyTable.tsx +29 -29
  58. package/demo/src/components/LanguageBar.tsx +102 -62
  59. package/demo/src/components/LanguageSwitcherDemo.module.css +114 -113
  60. package/demo/src/components/LanguageSwitcherDemo.tsx +256 -202
  61. package/demo/src/components/Logo.tsx +6 -6
  62. package/demo/src/components/OverviewSection.tsx +43 -43
  63. package/demo/src/components/Panel.tsx +15 -15
  64. package/demo/src/components/StatusCard.tsx +109 -109
  65. package/demo/src/index.css +644 -644
  66. package/demo/src/locales/de/demo.json +85 -0
  67. package/demo/src/locales/en/demo.json +85 -85
  68. package/demo/src/locales/fr/demo.json +85 -85
  69. package/demo/src/locales/it/demo.json +85 -0
  70. package/demo/src/locales/nl/demo.json +85 -85
  71. package/demo/src/main.tsx +29 -24
  72. package/demo/tsconfig.json +18 -18
  73. package/demo/tsconfig.node.json +10 -10
  74. package/demo/tsconfig.tsbuildinfo +1 -1
  75. package/demo/vite-env.d.ts +7 -7
  76. package/demo/vite.config.d.ts +2 -2
  77. package/demo/vite.config.js +10 -10
  78. package/dist/components/LanguageSwitcher.module.css +303 -303
  79. package/dist/locales/de/common.json +68 -0
  80. package/dist/locales/it/common.json +68 -0
  81. package/dist/tsconfig.tsbuildinfo +1 -1
  82. package/package.json +1 -1
@@ -1,24 +1,24 @@
1
- <svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
- <stop offset="0%" stop-color="#3A5AFE" />
5
- <stop offset="100%" stop-color="#14B8A6" />
6
- </linearGradient>
7
- <linearGradient id="accent" x1="0%" y1="0%" x2="0%" y2="100%">
8
- <stop offset="0%" stop-color="#FFFFFF" stop-opacity="0.9" />
9
- <stop offset="100%" stop-color="#FFFFFF" stop-opacity="0.2" />
10
- </linearGradient>
11
- <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%" color-interpolation-filters="sRGB">
12
- <feDropShadow dx="0" dy="8" stdDeviation="12" flood-color="#0B1220" flood-opacity="0.28" />
13
- </filter>
14
- </defs>
15
- <rect width="180" height="180" rx="32" fill="url(#bg)" filter="url(#shadow)" />
16
- <g transform="translate(45 45)">
17
- <path d="M45 0C20.147 0 0 20.147 0 45C0 69.853 20.147 90 45 90C69.853 90 90 69.853 90 45C90 20.147 69.853 0 45 0ZM45 72C29.088 72 15.75 58.662 15.75 42.75C15.75 26.838 29.088 13.5 45 13.5C60.912 13.5 74.25 26.838 74.25 42.75C74.25 58.662 60.912 72 45 72Z" fill="white" opacity="0.2" />
18
- <path d="M24 27H66C70.971 27 75 31.029 75 36V54C75 58.971 70.971 63 66 63H24C19.029 63 15 58.971 15 54V36C15 31.029 19.029 27 24 27Z" fill="url(#accent)" />
19
- <path d="M36 54V45C36 40.029 40.029 36 45 36C49.971 36 54 40.029 54 45V54" stroke="#0B1220" stroke-width="4" stroke-linecap="round" />
20
- <circle cx="45" cy="21" r="6" fill="white" />
21
- <path d="M33 69H57" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.7" />
22
- <path d="M27 15H63" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.4" />
23
- </g>
24
- </svg>
1
+ <svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#3A5AFE" />
5
+ <stop offset="100%" stop-color="#14B8A6" />
6
+ </linearGradient>
7
+ <linearGradient id="accent" x1="0%" y1="0%" x2="0%" y2="100%">
8
+ <stop offset="0%" stop-color="#FFFFFF" stop-opacity="0.9" />
9
+ <stop offset="100%" stop-color="#FFFFFF" stop-opacity="0.2" />
10
+ </linearGradient>
11
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%" color-interpolation-filters="sRGB">
12
+ <feDropShadow dx="0" dy="8" stdDeviation="12" flood-color="#0B1220" flood-opacity="0.28" />
13
+ </filter>
14
+ </defs>
15
+ <rect width="180" height="180" rx="32" fill="url(#bg)" filter="url(#shadow)" />
16
+ <g transform="translate(45 45)">
17
+ <path d="M45 0C20.147 0 0 20.147 0 45C0 69.853 20.147 90 45 90C69.853 90 90 69.853 90 45C90 20.147 69.853 0 45 0ZM45 72C29.088 72 15.75 58.662 15.75 42.75C15.75 26.838 29.088 13.5 45 13.5C60.912 13.5 74.25 26.838 74.25 42.75C74.25 58.662 60.912 72 45 72Z" fill="white" opacity="0.2" />
18
+ <path d="M24 27H66C70.971 27 75 31.029 75 36V54C75 58.971 70.971 63 66 63H24C19.029 63 15 58.971 15 54V36C15 31.029 19.029 27 24 27Z" fill="url(#accent)" />
19
+ <path d="M36 54V45C36 40.029 40.029 36 45 36C49.971 36 54 40.029 54 45V54" stroke="#0B1220" stroke-width="4" stroke-linecap="round" />
20
+ <circle cx="45" cy="21" r="6" fill="white" />
21
+ <path d="M33 69H57" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.7" />
22
+ <path d="M27 15H63" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.4" />
23
+ </g>
24
+ </svg>
package/demo/src/App.tsx CHANGED
@@ -1,116 +1,129 @@
1
- import { useState } from 'react'
2
- import { useTranslation } from '@asafarim/shared-i18n'
3
- import LanguageBar from './components/LanguageBar'
4
- import Panel from './components/Panel'
5
- import KeyTable from './components/KeyTable'
6
- import StatusCard from './components/StatusCard'
7
- import OverviewSection from './components/OverviewSection'
8
- import GetStartedSection from './components/GetStartedSection'
9
- import LanguageSwitcherDemo from './components/LanguageSwitcherDemo'
10
- import Logo from './components/Logo'
11
-
12
- type TabType = 'overview' | 'getStarted' | 'demo'
13
-
14
-
15
-
16
- export default function App() {
17
- const { t } = useTranslation('demo')
18
- const [activeTab, setActiveTab] = useState<TabType>('overview')
19
-
20
- return (
21
- <div className="app-container">
22
- <header className="app-header">
23
- <Logo />
24
- <div className="header-content">
25
- <h1>{t('title')}</h1>
26
- <p className="subtitle">{t('subtitle')}</p>
27
- </div>
28
- <LanguageBar />
29
- </header>
30
-
31
- <main className="app-main">
32
- <div className="nav-tabs">
33
- <button
34
- className={`nav-tab ${activeTab === 'overview' ? 'active' : ''}`}
35
- onClick={() => setActiveTab('overview')}
36
- >
37
- Overview
38
- </button>
39
- <button
40
- className={`nav-tab ${activeTab === 'getStarted' ? 'active' : ''}`}
41
- onClick={() => setActiveTab('getStarted')}
42
- >
43
- Get Started
44
- </button>
45
- <button
46
- className={`nav-tab ${activeTab === 'demo' ? 'active' : ''}`}
47
- onClick={() => setActiveTab('demo')}
48
- >
49
- Demo
50
- </button>
51
- </div>
52
-
53
- {activeTab === 'overview' && <OverviewSection />}
54
-
55
- {activeTab === 'getStarted' && <GetStartedSection />}
56
-
57
- {activeTab === 'demo' && (
58
- <>
59
- <Panel title="LanguageSwitcher Component">
60
- <LanguageSwitcherDemo />
61
- </Panel>
62
-
63
- <Panel title="Translations">
64
- <div className="panel-grid">
65
- <div>
66
- <h3>Common Namespace</h3>
67
- <KeyTable
68
- namespace="common"
69
- keys={['welcome', 'language', 'apps.appName.identity', 'apps.description.identity']}
70
- />
71
- </div>
72
- <div>
73
- <h3>Identity Portal Namespace</h3>
74
- <KeyTable
75
- namespace="identityPortal"
76
- keys={[
77
- 'navbar.admin-area',
78
- 'navbar.auth.signIn',
79
- 'navbar.auth.signOut',
80
- 'dashboard.title',
81
- 'dashboard.user-management.title'
82
- ]}
83
- />
84
- </div>
85
- </div>
86
- </Panel>
87
-
88
- <Panel title="Interpolation & Trans Component">
89
- <InterpolationDemo />
90
- </Panel>
91
-
92
- <StatusCard />
93
- </>
94
- )}
95
- </main>
96
- </div>
97
- )
98
- }
99
-
100
- function InterpolationDemo() {
101
- const { t, i18n } = useTranslation('identityPortal')
102
-
103
- return (
104
- <div className="interpolation-demo">
105
- <div className="demo-item">
106
- <h4>navbar.auth.welcome with interpolation</h4>
107
- <p className="demo-output">
108
- {t('navbar.auth.welcome', { userName: 'Ali' })}
109
- </p>
110
- </div>
111
- <div className="demo-item">
112
- <h4>Current language: {i18n.language}</h4>
113
- </div>
114
- </div>
115
- )
116
- }
1
+ import { useState } from 'react'
2
+ import { useTranslation } from '@asafarim/shared-i18n'
3
+ import LanguageBar from './components/LanguageBar'
4
+ import Panel from './components/Panel'
5
+ import KeyTable from './components/KeyTable'
6
+ import StatusCard from './components/StatusCard'
7
+ import OverviewSection from './components/OverviewSection'
8
+ import GetStartedSection from './components/GetStartedSection'
9
+ import LanguageSwitcherDemo from './components/LanguageSwitcherDemo'
10
+ import CountryLanguageDemo from './components/CountryLanguageDemo'
11
+ import Logo from './components/Logo'
12
+
13
+ type TabType = 'overview' | 'getStarted' | 'demo' | 'countryDemo'
14
+
15
+
16
+
17
+ export default function App() {
18
+ const { t } = useTranslation('demo')
19
+ const [activeTab, setActiveTab] = useState<TabType>('overview')
20
+
21
+ return (
22
+ <div className="app-container">
23
+ <header className="app-header">
24
+ <Logo />
25
+ <div className="header-content">
26
+ <h1>{t('title')}</h1>
27
+ <p className="subtitle">{t('subtitle')}</p>
28
+ </div>
29
+ <LanguageBar />
30
+ </header>
31
+
32
+ <main className="app-main">
33
+ <div className="nav-tabs">
34
+ <button
35
+ className={`nav-tab ${activeTab === 'overview' ? 'active' : ''}`}
36
+ onClick={() => setActiveTab('overview')}
37
+ >
38
+ Overview
39
+ </button>
40
+ <button
41
+ className={`nav-tab ${activeTab === 'getStarted' ? 'active' : ''}`}
42
+ onClick={() => setActiveTab('getStarted')}
43
+ >
44
+ Get Started
45
+ </button>
46
+ <button
47
+ className={`nav-tab ${activeTab === 'demo' ? 'active' : ''}`}
48
+ onClick={() => setActiveTab('demo')}
49
+ >
50
+ Demo
51
+ </button>
52
+ <button
53
+ className={`nav-tab ${activeTab === 'countryDemo' ? 'active' : ''}`}
54
+ onClick={() => setActiveTab('countryDemo')}
55
+ >
56
+ Country Selector
57
+ </button>
58
+ </div>
59
+
60
+ {activeTab === 'overview' && <OverviewSection />}
61
+
62
+ {activeTab === 'getStarted' && <GetStartedSection />}
63
+
64
+ {activeTab === 'demo' && (
65
+ <>
66
+ <Panel title="LanguageSwitcher Component">
67
+ <LanguageSwitcherDemo />
68
+ </Panel>
69
+
70
+ <Panel title="Translations">
71
+ <div className="panel-grid">
72
+ <div>
73
+ <h3>Common Namespace</h3>
74
+ <KeyTable
75
+ namespace="common"
76
+ keys={['welcome', 'language', 'apps.appName.identity', 'apps.description.identity']}
77
+ />
78
+ </div>
79
+ <div>
80
+ <h3>Identity Portal Namespace</h3>
81
+ <KeyTable
82
+ namespace="identityPortal"
83
+ keys={[
84
+ 'navbar.admin-area',
85
+ 'navbar.auth.signIn',
86
+ 'navbar.auth.signOut',
87
+ 'dashboard.title',
88
+ 'dashboard.user-management.title'
89
+ ]}
90
+ />
91
+ </div>
92
+ </div>
93
+ </Panel>
94
+
95
+ <Panel title="Interpolation & Trans Component">
96
+ <InterpolationDemo />
97
+ </Panel>
98
+
99
+ <StatusCard />
100
+ </>
101
+ )}
102
+
103
+ {activeTab === 'countryDemo' && (
104
+ <Panel title="Country / Language Selector Examples">
105
+ <CountryLanguageDemo />
106
+ </Panel>
107
+ )}
108
+ </main>
109
+ </div>
110
+ )
111
+ }
112
+
113
+ function InterpolationDemo() {
114
+ const { t, i18n } = useTranslation('identityPortal')
115
+
116
+ return (
117
+ <div className="interpolation-demo">
118
+ <div className="demo-item">
119
+ <h4>navbar.auth.welcome with interpolation</h4>
120
+ <p className="demo-output">
121
+ {t('navbar.auth.welcome', { userName: 'Ali' })}
122
+ </p>
123
+ </div>
124
+ <div className="demo-item">
125
+ <h4>Current language: {i18n.language}</h4>
126
+ </div>
127
+ </div>
128
+ )
129
+ }
@@ -0,0 +1,140 @@
1
+ import { useState } from 'react'
2
+ import type { ReactNode } from 'react'
3
+ import { CountryLanguageSelector } from '@asafarim/country-language-selector'
4
+ import styles from './LanguageSwitcherDemo.module.css'
5
+
6
+ interface DemoItemProps {
7
+ title: string
8
+ description: string
9
+ code: string
10
+ children: ReactNode
11
+ }
12
+
13
+ function DemoItem({ title, description, code, children }: DemoItemProps) {
14
+ return (
15
+ <div className={styles.demoItem}>
16
+ <div className={styles.demoHeader}>
17
+ <h4 className={styles.demoTitle}>{title}</h4>
18
+ <p className={styles.demoDescription}>{description}</p>
19
+ </div>
20
+ <div className={styles.demoContent}>
21
+ <div className={styles.demoPreview}>
22
+ <div className={styles.previewLabel}>Preview</div>
23
+ {children}
24
+ </div>
25
+ <div className={styles.demoCode}>
26
+ <div className={styles.codeLabel}>Code</div>
27
+ <pre className={styles.codeBlock}>{code}</pre>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ )
32
+ }
33
+
34
+ const countries = [
35
+ {
36
+ code: 'BE',
37
+ name: 'Belgium',
38
+ nativeName: 'België',
39
+ flag: '🇧🇪',
40
+ languages: [
41
+ { code: 'nl', label: 'Dutch', nativeLabel: 'Nederlands' },
42
+ { code: 'fr', label: 'French', nativeLabel: 'Français' },
43
+ { code: 'de', label: 'German', nativeLabel: 'Deutsch' }
44
+ ]
45
+ },
46
+ {
47
+ code: 'CH',
48
+ name: 'Switzerland',
49
+ nativeName: 'Schweiz',
50
+ flag: '🇨🇭',
51
+ languages: [
52
+ { code: 'de', label: 'German', nativeLabel: 'Deutsch' },
53
+ { code: 'fr', label: 'French', nativeLabel: 'Français' },
54
+ { code: 'it', label: 'Italian', nativeLabel: 'Italiano' },
55
+ { code: 'rm', label: 'Romansh', nativeLabel: 'Rumantsch' }
56
+ ]
57
+ },
58
+ {
59
+ code: 'CA',
60
+ name: 'Canada',
61
+ nativeName: 'Canada',
62
+ flag: '🇨🇦',
63
+ languages: [
64
+ { code: 'en', label: 'English' },
65
+ { code: 'fr', label: 'French', nativeLabel: 'Français' }
66
+ ]
67
+ }
68
+ ]
69
+
70
+ export default function CountryLanguageDemo() {
71
+ const [selectedLocale, setSelectedLocale] = useState({ country: 'BE', language: 'nl' })
72
+ const [customLocale, setCustomLocale] = useState({ country: 'CH', language: 'it' })
73
+
74
+ return (
75
+ <div className={styles.container}>
76
+ <DemoItem
77
+ title="Default Selector"
78
+ description="A standard country-language selector with compact trigger mode and persistence."
79
+ code={`<CountryLanguageSelector
80
+ countries={countries}
81
+ defaultValue={{ country: 'BE', language: 'nl' }}
82
+ persistKey="country-locale"
83
+ />`}
84
+ >
85
+ <CountryLanguageSelector
86
+ countries={countries}
87
+ defaultValue={{ country: 'BE', language: 'nl' }}
88
+ persistKey="country-locale"
89
+ onChange={(locale) => setSelectedLocale(locale)}
90
+ />
91
+ <p style={{ marginTop: '1rem' }}>
92
+ Selected locale: <strong>{selectedLocale.country}</strong> / <strong>{selectedLocale.language}</strong>
93
+ </p>
94
+ </DemoItem>
95
+
96
+ <DemoItem
97
+ title="Full Trigger Variant"
98
+ description="Render the current selection using full country and language names."
99
+ code={`<CountryLanguageSelector
100
+ countries={countries}
101
+ defaultValue={{ country: 'CA', language: 'fr' }}
102
+ triggerVariant="full"
103
+ />`}
104
+ >
105
+ <CountryLanguageSelector
106
+ countries={countries}
107
+ defaultValue={{ country: 'CA', language: 'fr' }}
108
+ triggerVariant="full"
109
+ onChange={(locale) => setSelectedLocale(locale)}
110
+ />
111
+ </DemoItem>
112
+
113
+ <DemoItem
114
+ title="Custom Trigger"
115
+ description="Use a custom trigger renderer to show selected country and language in your own button style."
116
+ code={`<CountryLanguageSelector
117
+ countries={countries}
118
+ defaultValue={{ country: 'CH', language: 'it' }}
119
+ renderTrigger={({ country, language, open }) => (
120
+ <button>{open ? 'Close' : 'Open'} {country.code} · {language.code}</button>
121
+ )}
122
+ />`}
123
+ >
124
+ <CountryLanguageSelector
125
+ countries={countries}
126
+ defaultValue={{ country: 'CH', language: 'it' }}
127
+ renderTrigger={({ country, language, open }) => (
128
+ <button type="button" style={{ padding: '0.75rem 1rem', borderRadius: 8, border: '1px solid #ccc', background: open ? '#f0f4ff' : '#fff' }}>
129
+ {open ? 'Close' : 'Open'} {country.flag} {country.name} · {language.nativeLabel ?? language.label}
130
+ </button>
131
+ )}
132
+ onChange={(locale) => setCustomLocale(locale)}
133
+ />
134
+ <p style={{ marginTop: '1rem' }}>
135
+ Custom trigger locale: <strong>{customLocale.country}</strong> / <strong>{customLocale.language}</strong>
136
+ </p>
137
+ </DemoItem>
138
+ </div>
139
+ )
140
+ }
@@ -1,56 +1,56 @@
1
- import { useState } from 'react'
2
- import { useTranslation } from '@asafarim/shared-i18n'
3
-
4
- export default function GetStartedSection() {
5
- const { t } = useTranslation('demo')
6
- const [expandedStep, setExpandedStep] = useState<number>(0)
7
- const getStarted = t('getStarted', { returnObjects: true }) as any
8
-
9
- return (
10
- <div className="get-started-section">
11
- <div className="gs-header">
12
- <h2 className="gs-title">{getStarted.heading}</h2>
13
- <p className="gs-intro">{getStarted.intro}</p>
14
- </div>
15
-
16
- <div className="steps-container">
17
- {getStarted.steps.map((step: any, idx: number) => (
18
- <div key={idx} className="step-item">
19
- <button
20
- className={`step-header ${expandedStep === idx ? 'expanded' : ''}`}
21
- onClick={() => setExpandedStep(expandedStep === idx ? -1 : idx)}
22
- >
23
- <div className="step-number">{idx + 1}</div>
24
- <div className="step-info">
25
- <h3>{step.title}</h3>
26
- <p>{step.description}</p>
27
- </div>
28
- <div className="step-toggle">
29
- {expandedStep === idx ? '−' : '+'}
30
- </div>
31
- </button>
32
- {expandedStep === idx && (
33
- <div className="step-content">
34
- <pre className="code-block">
35
- <code>{step.code}</code>
36
- </pre>
37
- </div>
38
- )}
39
- </div>
40
- ))}
41
- </div>
42
-
43
- <div className="tips-section">
44
- <div className="tips-icon">💡</div>
45
- <div className="tips-content">
46
- <h3>{getStarted.tips.title}</h3>
47
- <ul className="tips-list">
48
- {getStarted.tips.items.map((tip: string, idx: number) => (
49
- <li key={idx}>{tip}</li>
50
- ))}
51
- </ul>
52
- </div>
53
- </div>
54
- </div>
55
- )
56
- }
1
+ import { useState } from 'react'
2
+ import { useTranslation } from '@asafarim/shared-i18n'
3
+
4
+ export default function GetStartedSection() {
5
+ const { t } = useTranslation('demo')
6
+ const [expandedStep, setExpandedStep] = useState<number>(0)
7
+ const getStarted = t('getStarted', { returnObjects: true }) as any
8
+
9
+ return (
10
+ <div className="get-started-section">
11
+ <div className="gs-header">
12
+ <h2 className="gs-title">{getStarted.heading}</h2>
13
+ <p className="gs-intro">{getStarted.intro}</p>
14
+ </div>
15
+
16
+ <div className="steps-container">
17
+ {getStarted.steps.map((step: any, idx: number) => (
18
+ <div key={idx} className="step-item">
19
+ <button
20
+ className={`step-header ${expandedStep === idx ? 'expanded' : ''}`}
21
+ onClick={() => setExpandedStep(expandedStep === idx ? -1 : idx)}
22
+ >
23
+ <div className="step-number">{idx + 1}</div>
24
+ <div className="step-info">
25
+ <h3>{step.title}</h3>
26
+ <p>{step.description}</p>
27
+ </div>
28
+ <div className="step-toggle">
29
+ {expandedStep === idx ? '−' : '+'}
30
+ </div>
31
+ </button>
32
+ {expandedStep === idx && (
33
+ <div className="step-content">
34
+ <pre className="code-block">
35
+ <code>{step.code}</code>
36
+ </pre>
37
+ </div>
38
+ )}
39
+ </div>
40
+ ))}
41
+ </div>
42
+
43
+ <div className="tips-section">
44
+ <div className="tips-icon">💡</div>
45
+ <div className="tips-content">
46
+ <h3>{getStarted.tips.title}</h3>
47
+ <ul className="tips-list">
48
+ {getStarted.tips.items.map((tip: string, idx: number) => (
49
+ <li key={idx}>{tip}</li>
50
+ ))}
51
+ </ul>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ )
56
+ }
@@ -1,29 +1,29 @@
1
- import { useTranslation } from '@asafarim/shared-i18n'
2
-
3
- interface KeyTableProps {
4
- namespace: string
5
- keys: string[]
6
- }
7
-
8
- export default function KeyTable({ namespace, keys }: KeyTableProps) {
9
- const { t } = useTranslation(namespace)
10
-
11
- return (
12
- <table className="key-table">
13
- <thead>
14
- <tr>
15
- <th>Key</th>
16
- <th>Value</th>
17
- </tr>
18
- </thead>
19
- <tbody>
20
- {keys.map((key) => (
21
- <tr key={key}>
22
- <td>{key}</td>
23
- <td>{t(key)}</td>
24
- </tr>
25
- ))}
26
- </tbody>
27
- </table>
28
- )
29
- }
1
+ import { useTranslation } from '@asafarim/shared-i18n'
2
+
3
+ interface KeyTableProps {
4
+ namespace: string
5
+ keys: string[]
6
+ }
7
+
8
+ export default function KeyTable({ namespace, keys }: KeyTableProps) {
9
+ const { t } = useTranslation(namespace)
10
+
11
+ return (
12
+ <table className="key-table">
13
+ <thead>
14
+ <tr>
15
+ <th>Key</th>
16
+ <th>Value</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ {keys.map((key) => (
21
+ <tr key={key}>
22
+ <td>{key}</td>
23
+ <td>{t(key)}</td>
24
+ </tr>
25
+ ))}
26
+ </tbody>
27
+ </table>
28
+ )
29
+ }