@xetwa/design-system 1.0.2

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 (168) hide show
  1. package/.github/workflows/publish.yml +30 -0
  2. package/.storybook/main.ts +17 -0
  3. package/.storybook/preview.tsx +65 -0
  4. package/eslint.config.js +22 -0
  5. package/index.html +13 -0
  6. package/package.json +55 -0
  7. package/public/favicon.svg +1 -0
  8. package/public/icons.svg +24 -0
  9. package/src/App.css +184 -0
  10. package/src/App.tsx +122 -0
  11. package/src/BordasSombras.mdx +343 -0
  12. package/src/Colors.mdx +393 -0
  13. package/src/GrelhaLayout.mdx +375 -0
  14. package/src/Icons.mdx +42 -0
  15. package/src/MovimentoBreakpoints.mdx +379 -0
  16. package/src/Spacing.mdx +231 -0
  17. package/src/Typography.mdx +321 -0
  18. package/src/assets/Mascots/vava/estaticos/vava-acenar.svg +3 -0
  19. package/src/assets/Mascots/vava/estaticos/vava-acertou.svg +3 -0
  20. package/src/assets/Mascots/vava/estaticos/vava-celebrar.svg +3 -0
  21. package/src/assets/Mascots/vava/estaticos/vava-com-autocolantes.svg +3 -0
  22. package/src/assets/Mascots/vava/estaticos/vava-dormir.svg +3 -0
  23. package/src/assets/Mascots/vava/estaticos/vava-errou.svg +3 -0
  24. package/src/assets/Mascots/vava/estaticos/vava-feliz.svg +3 -0
  25. package/src/assets/Mascots/vava/estaticos/vava-neutra.svg +3 -0
  26. package/src/assets/Mascots/vava/estaticos/vava-original.svg +3 -0
  27. package/src/assets/Mascots/vava/estaticos/vava-pensar.svg +3 -0
  28. package/src/assets/Mascots/vava/estaticos/vava-surpresa.svg +3 -0
  29. package/src/assets/Mascots/yaya/avatar/yaya-avatar-falar.svg +7 -0
  30. package/src/assets/Mascots/yaya/avatar/yaya-avatar-feliz.svg +7 -0
  31. package/src/assets/Mascots/yaya/avatar/yaya-avatar-transparente.svg +6 -0
  32. package/src/assets/Mascots/yaya/estaticos/yaya-acertou.svg +13 -0
  33. package/src/assets/Mascots/yaya/estaticos/yaya-celebrar.svg +13 -0
  34. package/src/assets/Mascots/yaya/estaticos/yaya-dormir.svg +13 -0
  35. package/src/assets/Mascots/yaya/estaticos/yaya-errou.svg +13 -0
  36. package/src/assets/Mascots/yaya/estaticos/yaya-falar.svg +13 -0
  37. package/src/assets/Mascots/yaya/estaticos/yaya-feliz.svg +13 -0
  38. package/src/assets/Mascots/yaya/estaticos/yaya-neutra.svg +13 -0
  39. package/src/assets/Mascots/yaya/estaticos/yaya-pensar.svg +13 -0
  40. package/src/assets/Mascots/yaya/estaticos/yaya-surpresa.svg +13 -0
  41. package/src/assets/hero.png +0 -0
  42. package/src/assets/react.svg +1 -0
  43. package/src/assets/vite.svg +1 -0
  44. package/src/components/Buttons/BackButton/BackButton.stories.tsx +86 -0
  45. package/src/components/Buttons/BackButton/BackButton.tsx +107 -0
  46. package/src/components/Buttons/FabButton/FabButton.stories.tsx +74 -0
  47. package/src/components/Buttons/FabButton/FabButton.tsx +161 -0
  48. package/src/components/Buttons/IconButton/IconButton.stories.tsx +99 -0
  49. package/src/components/Buttons/IconButton/IconButton.tsx +189 -0
  50. package/src/components/Buttons/JourneyButton/JourneyButton.stories.tsx +80 -0
  51. package/src/components/Buttons/JourneyButton/JourneyButton.tsx +194 -0
  52. package/src/components/Buttons/MainButton/MainButton.stories.tsx +144 -0
  53. package/src/components/Buttons/MainButton/MainButton.tsx +258 -0
  54. package/src/components/Buttons/WordChip/WordChip.stories.tsx +84 -0
  55. package/src/components/Buttons/WordChip/WordChip.tsx +157 -0
  56. package/src/components/Buttons/WordChip/index.ts +1 -0
  57. package/src/components/Cards/AnswerOptionCard/AnswerOptionCard.stories.tsx +181 -0
  58. package/src/components/Cards/AnswerOptionCard/AnswerOptionCard.tsx +201 -0
  59. package/src/components/Cards/BaseCard/BaseCard.stories.tsx +148 -0
  60. package/src/components/Cards/BaseCard/BaseCard.tsx +181 -0
  61. package/src/components/Cards/BoardingPassCard/BoardingPassCard.stories.tsx +205 -0
  62. package/src/components/Cards/BoardingPassCard/BoardingPassCard.tsx +384 -0
  63. package/src/components/Cards/BoardingPassCard/FlightIcon.tsx +21 -0
  64. package/src/components/Cards/BoardingPassCard/FlightIcon.web.tsx +18 -0
  65. package/src/components/Cards/CountryCard/CountryCard.stories.tsx +97 -0
  66. package/src/components/Cards/CountryCard/CountryCard.tsx +185 -0
  67. package/src/components/Cards/LevelProgressCard/LevelProgressCard.stories.tsx +61 -0
  68. package/src/components/Cards/LevelProgressCard/LevelProgressCard.tsx +143 -0
  69. package/src/components/Cards/ModuleCard/ModuleCard.stories.tsx +108 -0
  70. package/src/components/Cards/ModuleCard/ModuleCard.tsx +304 -0
  71. package/src/components/Cards/ModuleCompletionCard/ModuleCompletionCard.stories.tsx +53 -0
  72. package/src/components/Cards/ModuleCompletionCard/ModuleCompletionCard.tsx +167 -0
  73. package/src/components/Cards/Passport/PassportCover.tsx +114 -0
  74. package/src/components/Cards/Passport/PassportIDPage.tsx +217 -0
  75. package/src/components/Cards/Passport/PassportStampPage.tsx +253 -0
  76. package/src/components/Cards/Passport/PassportViewer.stories.tsx +95 -0
  77. package/src/components/Cards/Passport/PassportViewer.tsx +328 -0
  78. package/src/components/Cards/PlanCard/PlanCard.stories.tsx +159 -0
  79. package/src/components/Cards/PlanCard/PlanCard.tsx +317 -0
  80. package/src/components/Cards/PricingCard/PricingCard.stories.tsx +83 -0
  81. package/src/components/Cards/PricingCard/PricingCard.tsx +144 -0
  82. package/src/components/Cards/SelectionCard/SelectionCard.stories.tsx +77 -0
  83. package/src/components/Cards/SelectionCard/SelectionCard.tsx +111 -0
  84. package/src/components/Cards/TeacherCard/TeacherCard.stories.tsx +126 -0
  85. package/src/components/Cards/TeacherCard/TeacherCard.tsx +236 -0
  86. package/src/components/Charts/WeeklyProgressChart/WeeklyProgressChart.stories.tsx +89 -0
  87. package/src/components/Charts/WeeklyProgressChart/WeeklyProgressChart.tsx +179 -0
  88. package/src/components/Charts/WeeklyProgressChart/index.ts +1 -0
  89. package/src/components/DataDisplay/Avatar/Avatar.stories.tsx +85 -0
  90. package/src/components/DataDisplay/Avatar/Avatar.tsx +118 -0
  91. package/src/components/DataDisplay/Avatar/index.ts +1 -0
  92. package/src/components/DataDisplay/Badge/Badge.stories.tsx +62 -0
  93. package/src/components/DataDisplay/Badge/Badge.tsx +146 -0
  94. package/src/components/DataDisplay/Flag/Flag.stories.tsx +98 -0
  95. package/src/components/DataDisplay/Flag/Flag.tsx +347 -0
  96. package/src/components/DataDisplay/Flag/Flag.web.tsx +334 -0
  97. package/src/components/DataDisplay/InstructionBubble/InstructionBubble.stories.tsx +80 -0
  98. package/src/components/DataDisplay/InstructionBubble/InstructionBubble.tsx +86 -0
  99. package/src/components/DataDisplay/LevelBadge/LevelBadge.stories.tsx +99 -0
  100. package/src/components/DataDisplay/LevelBadge/LevelBadge.tsx +118 -0
  101. package/src/components/DataDisplay/ProgressBar/ProgressBar.stories.tsx +95 -0
  102. package/src/components/DataDisplay/ProgressBar/ProgressBar.tsx +117 -0
  103. package/src/components/DataDisplay/StatBadge/StatBadge.stories.tsx +82 -0
  104. package/src/components/DataDisplay/StatBadge/StatBadge.tsx +135 -0
  105. package/src/components/DataDisplay/StatBadge/index.ts +1 -0
  106. package/src/components/DataDisplay/Tag/Tag.stories.tsx +63 -0
  107. package/src/components/DataDisplay/Tag/Tag.tsx +148 -0
  108. package/src/components/Feedback/FeedbackBottomSheet/FeedbackBottomSheet.stories.tsx +74 -0
  109. package/src/components/Feedback/FeedbackBottomSheet/FeedbackBottomSheet.tsx +200 -0
  110. package/src/components/Forms/Checkbox/Checkbox.stories.tsx +60 -0
  111. package/src/components/Forms/Checkbox/Checkbox.tsx +127 -0
  112. package/src/components/Forms/Checkbox/index.ts +1 -0
  113. package/src/components/Forms/DaySelector/DaySelector.stories.tsx +62 -0
  114. package/src/components/Forms/DaySelector/DaySelector.tsx +133 -0
  115. package/src/components/Forms/Radio/Radio.stories.tsx +61 -0
  116. package/src/components/Forms/Radio/Radio.tsx +141 -0
  117. package/src/components/Forms/Radio/index.ts +1 -0
  118. package/src/components/Forms/SegmentedToggle/SegmentedToggle.stories.tsx +67 -0
  119. package/src/components/Forms/SegmentedToggle/SegmentedToggle.tsx +150 -0
  120. package/src/components/Forms/SegmentedToggle/index.ts +1 -0
  121. package/src/components/Forms/Select/Select.stories.tsx +59 -0
  122. package/src/components/Forms/Select/Select.tsx +255 -0
  123. package/src/components/Forms/Select/index.ts +1 -0
  124. package/src/components/Forms/Switch/Switch.stories.tsx +57 -0
  125. package/src/components/Forms/Switch/Switch.tsx +120 -0
  126. package/src/components/Forms/Switch/index.ts +1 -0
  127. package/src/components/Forms/TimeSlot/TimeSlot.stories.tsx +62 -0
  128. package/src/components/Forms/TimeSlot/TimeSlot.tsx +116 -0
  129. package/src/components/Headers/CountryHeader/CountryHeader.stories.tsx +114 -0
  130. package/src/components/Headers/CountryHeader/CountryHeader.tsx +147 -0
  131. package/src/components/Headers/ProfileHeader/ProfileHeader.stories.tsx +141 -0
  132. package/src/components/Headers/ProfileHeader/ProfileHeader.tsx +233 -0
  133. package/src/components/Inputs/FillInTheBlank/FillInTheBlank.stories.tsx +333 -0
  134. package/src/components/Inputs/FillInTheBlank/FillInTheBlank.tsx +287 -0
  135. package/src/components/Inputs/FillInTheBlank/index.ts +1 -0
  136. package/src/components/Inputs/TextInput/TextInput.stories.tsx +103 -0
  137. package/src/components/Inputs/TextInput/TextInput.tsx +187 -0
  138. package/src/components/Mascots/Vava/Vava.stories.tsx +114 -0
  139. package/src/components/Mascots/Vava/Vava.tsx +276 -0
  140. package/src/components/Mascots/Yaya/Yaya.stories.tsx +98 -0
  141. package/src/components/Mascots/Yaya/Yaya.tsx +233 -0
  142. package/src/components/Navigation/BottomTabBar/BottomTabBar.stories.tsx +68 -0
  143. package/src/components/Navigation/BottomTabBar/BottomTabBar.tsx +85 -0
  144. package/src/components/Navigation/BottomTabBar/BottomTabBarItem.tsx +68 -0
  145. package/src/components/Navigation/BottomTabBar/index.ts +2 -0
  146. package/src/components/Navigation/PaginationDots/PaginationDots.stories.tsx +62 -0
  147. package/src/components/Navigation/PaginationDots/PaginationDots.tsx +81 -0
  148. package/src/components/Navigation/PaginationDots/index.ts +1 -0
  149. package/src/components/Navigation/ProgressMap/ProgressMap.stories.tsx +116 -0
  150. package/src/components/Navigation/ProgressMap/ProgressMap.tsx +827 -0
  151. package/src/components/Navigation/WorldProgressMap/WorldProgressMap.stories.tsx +169 -0
  152. package/src/components/Navigation/WorldProgressMap/WorldProgressMap.tsx +790 -0
  153. package/src/components/Typography/Typography.stories.tsx +127 -0
  154. package/src/components/Typography/Typography.tsx +53 -0
  155. package/src/hooks/useResponsive.ts +41 -0
  156. package/src/hooks/useTheme.ts +32 -0
  157. package/src/index.css +355 -0
  158. package/src/index.ts +28 -0
  159. package/src/main.tsx +10 -0
  160. package/src/mocks/codegenNativeComponent.ts +5 -0
  161. package/src/styles/countryThemes.ts +79 -0
  162. package/src/styles/theme.ts +297 -0
  163. package/src/utils/iconMap.ts +23 -0
  164. package/tsconfig.app.json +25 -0
  165. package/tsconfig.json +7 -0
  166. package/tsconfig.node.json +24 -0
  167. package/vite.config.ts +51 -0
  168. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,127 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { View } from 'react-native';
3
+ import { Typography } from './Typography';
4
+
5
+ const meta: Meta<typeof Typography> = {
6
+ title: 'Components/Typography',
7
+ component: Typography,
8
+ tags: ['autodocs'],
9
+ argTypes: {
10
+ variant: {
11
+ control: 'select',
12
+ options: [
13
+ 'display1',
14
+ 'display2',
15
+ 'h1',
16
+ 'h2',
17
+ 'h3',
18
+ 'label',
19
+ 'bodyLg',
20
+ 'bodyMd',
21
+ 'bodySm',
22
+ 'caption',
23
+ 'btnLg',
24
+ 'btnMd',
25
+ 'btnSm',
26
+ ],
27
+ },
28
+ color: { control: 'color' },
29
+ },
30
+ };
31
+
32
+ export default meta;
33
+ type Story = StoryObj<typeof Typography>;
34
+
35
+ export const Default: Story = {
36
+ args: {
37
+ variant: 'bodyMd',
38
+ children: 'A Vava viaja contigo de Paris a Beirute pelo mundo francófono.',
39
+ },
40
+ };
41
+
42
+ export const Display1: Story = {
43
+ args: {
44
+ variant: 'display1',
45
+ children: 'Aprende francês',
46
+ },
47
+ };
48
+
49
+ export const Display2: Story = {
50
+ args: {
51
+ variant: 'display2',
52
+ children: 'Aprende francês',
53
+ },
54
+ };
55
+
56
+ export const H1: Story = {
57
+ args: {
58
+ variant: 'h1',
59
+ children: 'Aprende francês',
60
+ },
61
+ };
62
+
63
+ export const H2: Story = {
64
+ args: {
65
+ variant: 'h2',
66
+ children: 'Cumprimentos',
67
+ },
68
+ };
69
+
70
+ export const H3: Story = {
71
+ args: {
72
+ variant: 'h3',
73
+ children: 'Bom dia',
74
+ },
75
+ };
76
+
77
+ export const Label: Story = {
78
+ args: {
79
+ variant: 'label',
80
+ children: 'MÓDULO 1',
81
+ },
82
+ };
83
+
84
+ export const BodyLg: Story = {
85
+ args: {
86
+ variant: 'bodyLg',
87
+ children: '5 minutos por dia + aulas a sério com os professores da Xetwa.',
88
+ },
89
+ };
90
+
91
+ export const BodyMd: Story = {
92
+ args: {
93
+ variant: 'bodyMd',
94
+ children: 'A Vava viaja contigo de Paris a Beirute pelo mundo francófono.',
95
+ },
96
+ };
97
+
98
+ export const BodySm: Story = {
99
+ args: {
100
+ variant: 'bodySm',
101
+ children: '3 de 5 lições concluídas',
102
+ },
103
+ };
104
+
105
+ export const Caption: Story = {
106
+ args: {
107
+ variant: 'caption',
108
+ children: 'com professor • abre o Módulo 2',
109
+ },
110
+ };
111
+
112
+ export const ScaleDemonstration: StoryObj = {
113
+ render: () => (
114
+ <View style={{ gap: 16, padding: 12 }}>
115
+ <Typography variant="display1">Display 1 • Aprende francês</Typography>
116
+ <Typography variant="display2">Display 2 • Aprende francês</Typography>
117
+ <Typography variant="h1">H1 • Aprende francês</Typography>
118
+ <Typography variant="h2">H2 • Cumprimentos</Typography>
119
+ <Typography variant="h3">H3 • Bom dia</Typography>
120
+ <Typography variant="label">LABEL • MÓDULO 1</Typography>
121
+ <Typography variant="bodyLg">Body LG • 5 minutos por dia + aulas a sério com os professores da Xetwa.</Typography>
122
+ <Typography variant="bodyMd">Body MD • A Vava viaja contigo de Paris a Beirute pelo mundo francófono.</Typography>
123
+ <Typography variant="bodySm">Body SM • 3 de 5 lições concluídas</Typography>
124
+ <Typography variant="caption">Caption • com professor • abre o Módulo 2</Typography>
125
+ </View>
126
+ ),
127
+ };
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { Text as RNText } from 'react-native';
3
+ import type { TextProps as RNTextProps, TextStyle } from 'react-native';
4
+ import { theme } from '../../styles/theme';
5
+ import type { TypographyVariant } from '../../styles/theme';
6
+ import { useTheme } from '../../hooks/useTheme';
7
+ import { useResponsive } from '../../hooks/useResponsive';
8
+
9
+ /**
10
+ * Componente base para renderização de texto com a tipografia do sistema.
11
+ */
12
+ export interface TypographyProps extends RNTextProps {
13
+ /** Variante tipográfica (h1, h2, body, caption, etc). Controla tamanho e peso. */
14
+ variant?: TypographyVariant;
15
+ /** Alinhamento do texto. */
16
+ align?: 'auto' | 'left' | 'right' | 'center' | 'justify';
17
+ /** Cor do texto (em formato hexadecimal ou rgba). */
18
+ color?: string;
19
+ }
20
+
21
+ export const Typography = React.forwardRef<React.ElementRef<typeof RNText>, TypographyProps>(
22
+ ({ variant = 'bodyMd', color, style, children, ...props }, ref) => {
23
+ const { colors } = useTheme();
24
+ const { scaleText } = useResponsive();
25
+
26
+ // Resolve variant styles from the static theme tokens
27
+ const typographyStyle = theme.typography[variant];
28
+
29
+ // Default text color based on the current active theme
30
+ const defaultColor = colors.textPrimary;
31
+
32
+ const responsiveStyle: TextStyle = {
33
+ ...typographyStyle,
34
+ fontSize: typographyStyle.fontSize ? scaleText(typographyStyle.fontSize) : undefined,
35
+ lineHeight: typographyStyle.lineHeight ? scaleText(typographyStyle.lineHeight) : undefined,
36
+ };
37
+
38
+ const combinedStyles = [
39
+ { color: defaultColor },
40
+ responsiveStyle,
41
+ color ? { color } : null,
42
+ style,
43
+ ];
44
+
45
+ return (
46
+ <RNText ref={ref} style={combinedStyles} {...props}>
47
+ {children}
48
+ </RNText>
49
+ );
50
+ }
51
+ );
52
+
53
+ Typography.displayName = 'Typography';
@@ -0,0 +1,41 @@
1
+ import { useWindowDimensions } from 'react-native';
2
+
3
+ export function useResponsive() {
4
+ const { width, height } = useWindowDimensions();
5
+
6
+ // Baseline standard mobile width (e.g. iPhone SE / 14 width is 375px or 390px)
7
+ const BASE_WIDTH = 375;
8
+
9
+ // Compute layout scale factor relative to 375px.
10
+ // We clamp this factor to prevent layouts from getting way too small on tiny screens
11
+ // or way too large on tablet/desktop displays.
12
+ const layoutFactor = Math.min(Math.max(width / BASE_WIDTH, 0.8), 1.25);
13
+
14
+ // Moderate scale factor for text sizing, so fonts scale slightly more gently
15
+ // than pure layout dimensions (text sizes are critical for legibility).
16
+ const textFactor = 1 + (layoutFactor - 1) * 0.7;
17
+
18
+ /**
19
+ * Scales a layout dimension (padding, margin, width, height, radius)
20
+ */
21
+ const scale = (size: number): number => {
22
+ return Math.round(size * layoutFactor);
23
+ };
24
+
25
+ /**
26
+ * Scales a font size
27
+ */
28
+ const scaleText = (size: number): number => {
29
+ return Math.round(size * textFactor);
30
+ };
31
+
32
+ return {
33
+ scale,
34
+ scaleText,
35
+ width,
36
+ height,
37
+ isMobile: width < 768,
38
+ isTablet: width >= 768 && width < 1024,
39
+ isDesktop: width >= 1024,
40
+ };
41
+ }
@@ -0,0 +1,32 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { Appearance } from 'react-native';
3
+ import { theme } from '../styles/theme';
4
+
5
+ export function useTheme() {
6
+ const [isDark, setIsDark] = useState(() => {
7
+ if (typeof window !== 'undefined') {
8
+ return document.documentElement.classList.contains('dark-theme');
9
+ }
10
+ return Appearance.getColorScheme() === 'dark';
11
+ });
12
+
13
+ useEffect(() => {
14
+ if (typeof window !== 'undefined') {
15
+ const observer = new MutationObserver(() => {
16
+ setIsDark(document.documentElement.classList.contains('dark-theme'));
17
+ });
18
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
19
+ return () => observer.disconnect();
20
+ } else {
21
+ const subscription = Appearance.addChangeListener(({ colorScheme }) => {
22
+ setIsDark(colorScheme === 'dark');
23
+ });
24
+ return () => subscription.remove();
25
+ }
26
+ }, []);
27
+
28
+ return {
29
+ colors: isDark ? theme.colors.dark : theme.colors.light,
30
+ isDark,
31
+ };
32
+ }
package/src/index.css ADDED
@@ -0,0 +1,355 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap');
2
+ @import "tailwindcss";
3
+
4
+ @theme {
5
+ --font-sans: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
6
+ --font-title: 'Fredoka', sans-serif;
7
+
8
+ --color-primary: var(--primary);
9
+ --color-primary-dark: var(--primary-dark);
10
+ --color-primary-light: var(--primary-light);
11
+
12
+ --color-brown-900: var(--brown-900);
13
+ --color-brown-800: var(--brown-800);
14
+ --color-brown-700: var(--brown-700);
15
+ --color-brown-600: var(--brown-600);
16
+ --color-brown-500: var(--brown-500);
17
+ --color-brown-400: var(--brown-400);
18
+ --color-brown-300: var(--brown-300);
19
+ --color-brown-100: var(--brown-100);
20
+ --color-brown-50: var(--brown-50);
21
+
22
+ --color-cream: var(--cream);
23
+ --color-canvas: var(--canvas);
24
+
25
+ --color-success: var(--success);
26
+ --color-error: var(--error);
27
+ --color-info: var(--info);
28
+ --color-black: var(--black);
29
+ --color-white: var(--white);
30
+
31
+ --color-bg-app: var(--bg-app);
32
+ --color-bg-surface: var(--bg-surface);
33
+ --color-bg-surface-hover: var(--bg-surface-hover);
34
+ --color-border-color: var(--border-color);
35
+
36
+ --color-text-primary: var(--text-primary);
37
+ --color-text-secondary: var(--text-secondary);
38
+
39
+ --radius-xs: 6px;
40
+ --radius-sm: 10px;
41
+ --radius-md: 12px;
42
+ --radius-lg: 16px;
43
+ --radius-xl: 20px;
44
+ --radius-2xl: 24px;
45
+ --radius-screen: 34px;
46
+ --radius-phone: 42px;
47
+
48
+ --shadow-xs: 0 1px 3px rgba(81, 51, 45, 0.08);
49
+ --shadow-sm: 0 2px 8px rgba(81, 51, 45, 0.10);
50
+ --shadow-md: 0 4px 14px rgba(81, 51, 45, 0.13);
51
+ --shadow-lg: 0 8px 26px rgba(81, 51, 45, 0.18);
52
+ --shadow-xl: 0 18px 40px rgba(81, 51, 45, 0.28);
53
+ --shadow-btn-primary: 0 4px 0 #cf7a30;
54
+ --shadow-btn-secondary: 0 4px 0 #efe2d6;
55
+ --shadow-btn-dark: 0 4px 0 #3a241f;
56
+ --shadow-focus: 0 0 0 3px rgba(242, 151, 75, 0.22);
57
+
58
+ --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
59
+ --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
60
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
61
+
62
+ --duration-fast: 120ms;
63
+ --duration-base: 200ms;
64
+ --duration-medium: 300ms;
65
+ --duration-slow: 500ms;
66
+
67
+ --breakpoint-xs: 0px;
68
+ --breakpoint-sm: 375px;
69
+ --breakpoint-md: 430px;
70
+ --breakpoint-lg: 768px;
71
+ --breakpoint-xl: 1024px;
72
+ --breakpoint-xxl: 1280px;
73
+ --breakpoint-xxxl: 1440px;
74
+
75
+ --space-1: 4px;
76
+ --space-2: 8px;
77
+ --space-3: 12px;
78
+ --space-4: 16px;
79
+ --space-5: 20px;
80
+ --space-6: 24px;
81
+ --space-8: 32px;
82
+ --space-10: 40px;
83
+ --space-12: 48px;
84
+ --space-16: 64px;
85
+
86
+ --layout-mobile-header-height: 52px;
87
+ --layout-mobile-tab-height: 56px;
88
+ --layout-desktop-sidebar-width: 220px;
89
+ --layout-tablet-header-height: 64px;
90
+ --layout-max-content-width: 1200px;
91
+ }
92
+
93
+ :root {
94
+ --primary: #f2974b;
95
+ --primary-dark: #cf7a30;
96
+ --primary-light: #fef6ee;
97
+
98
+ --brown-900: #15100d;
99
+ --brown-800: #51332d;
100
+ --brown-700: #3f2620;
101
+ --brown-600: #6e5a4f;
102
+ --brown-500: #9a8478;
103
+ --brown-400: #b9a392;
104
+ --brown-300: #c3b1a4;
105
+ --brown-100: #efe2d6;
106
+ --brown-50: #fdf3ea;
107
+
108
+ --cream: #fbf6f0;
109
+ --canvas: #e7e5df;
110
+
111
+ --success: #16915a;
112
+ --error: #cf5b48;
113
+ --info: #2a6fc2;
114
+ --black: #000000;
115
+ --white: #ffffff;
116
+
117
+ /* Light Theme Mapping */
118
+ --bg-app: #fbf6f0; /* cream */
119
+ --bg-surface: #ffffff; /* white */
120
+ --bg-surface-hover: #fdf3ea; /* brown-50 */
121
+ --border-color: #efe2d6; /* brown-100 */
122
+
123
+ --text-primary: #51332d; /* brown-800 */
124
+ --text-secondary: #9a8478; /* brown-500 */
125
+ }
126
+
127
+ .dark-theme {
128
+ /* Dark Theme Mapping */
129
+ --bg-app: #15100d; /* brown-900 */
130
+ --bg-surface: #51332d; /* brown-800 */
131
+ --bg-surface-hover: #3f2620; /* brown-700 */
132
+ --border-color: #3f2620; /* brown-700 */
133
+
134
+ --text-primary: #efe2d6; /* brown-100 */
135
+ --text-secondary: #b9a392; /* brown-400 */
136
+
137
+ --primary-light: rgba(242, 151, 75, 0.15);
138
+ }
139
+
140
+ body {
141
+ background-color: var(--bg-app);
142
+ color: var(--text-primary);
143
+ font-family: var(--font-sans);
144
+ transition: background-color 250ms, color 250ms;
145
+ }
146
+
147
+ /* Typography Scale */
148
+ .text-display-1 {
149
+ font-family: var(--font-title);
150
+ font-weight: 700;
151
+ font-size: 28px;
152
+ line-height: 1.08;
153
+ }
154
+ @media (min-width: 1024px) {
155
+ .text-display-1 {
156
+ font-size: 42px;
157
+ }
158
+ }
159
+
160
+ .text-display-2 {
161
+ font-family: var(--font-title);
162
+ font-weight: 700;
163
+ font-size: 24px;
164
+ line-height: 1.12;
165
+ }
166
+ @media (min-width: 1024px) {
167
+ .text-display-2 {
168
+ font-size: 34px;
169
+ }
170
+ }
171
+
172
+ .text-h1 {
173
+ font-family: var(--font-title);
174
+ font-weight: 700;
175
+ font-size: 22px;
176
+ line-height: 1.15;
177
+ }
178
+ @media (min-width: 1024px) {
179
+ .text-h1 {
180
+ font-size: 28px;
181
+ }
182
+ }
183
+
184
+ .text-h2 {
185
+ font-family: var(--font-title);
186
+ font-weight: 600;
187
+ font-size: 18px;
188
+ line-height: 1.2;
189
+ }
190
+ @media (min-width: 1024px) {
191
+ .text-h2 {
192
+ font-size: 22px;
193
+ }
194
+ }
195
+
196
+ .text-h3 {
197
+ font-family: var(--font-title);
198
+ font-weight: 600;
199
+ font-size: 16px;
200
+ line-height: 1.25;
201
+ }
202
+ @media (min-width: 1024px) {
203
+ .text-h3 {
204
+ font-size: 19px;
205
+ }
206
+ }
207
+
208
+ .text-label {
209
+ font-family: var(--font-sans);
210
+ font-weight: 800;
211
+ font-size: 10px;
212
+ line-height: 1.0;
213
+ letter-spacing: 0.12em;
214
+ text-transform: uppercase;
215
+ }
216
+ @media (min-width: 1024px) {
217
+ .text-label {
218
+ font-size: 11px;
219
+ }
220
+ }
221
+
222
+ .text-body-lg {
223
+ font-family: var(--font-sans);
224
+ font-weight: 600;
225
+ font-size: 15px;
226
+ line-height: 1.55;
227
+ }
228
+ @media (min-width: 1024px) {
229
+ .text-body-lg {
230
+ font-size: 17px;
231
+ }
232
+ }
233
+
234
+ .text-body-md {
235
+ font-family: var(--font-sans);
236
+ font-weight: 600;
237
+ font-size: 13.5px;
238
+ line-height: 1.5;
239
+ }
240
+ @media (min-width: 1024px) {
241
+ .text-body-md {
242
+ font-size: 15px;
243
+ }
244
+ }
245
+
246
+ .text-body-sm {
247
+ font-family: var(--font-sans);
248
+ font-weight: 700;
249
+ font-size: 12px;
250
+ line-height: 1.45;
251
+ }
252
+ @media (min-width: 1024px) {
253
+ .text-body-sm {
254
+ font-size: 13px;
255
+ }
256
+ }
257
+
258
+ .text-caption {
259
+ font-family: var(--font-sans);
260
+ font-weight: 700;
261
+ font-size: 10px;
262
+ line-height: 1.4;
263
+ }
264
+ @media (min-width: 1024px) {
265
+ .text-caption {
266
+ font-size: 11px;
267
+ }
268
+ }
269
+
270
+ .text-btn-lg {
271
+ font-family: var(--font-sans);
272
+ font-weight: 800;
273
+ font-size: 16px;
274
+ line-height: 1.0;
275
+ letter-spacing: 0.04em;
276
+ }
277
+ @media (min-width: 1024px) {
278
+ .text-btn-lg {
279
+ font-size: 17px;
280
+ }
281
+ }
282
+
283
+ .text-btn-md {
284
+ font-family: var(--font-sans);
285
+ font-weight: 800;
286
+ font-size: 14px;
287
+ line-height: 1.0;
288
+ letter-spacing: 0.04em;
289
+ }
290
+ @media (min-width: 1024px) {
291
+ .text-btn-md {
292
+ font-size: 15px;
293
+ }
294
+ }
295
+
296
+ .text-btn-sm {
297
+ font-family: var(--font-sans);
298
+ font-weight: 800;
299
+ font-size: 12px;
300
+ line-height: 1.0;
301
+ letter-spacing: 0.04em;
302
+ }
303
+ @media (min-width: 1024px) {
304
+ .text-btn-sm {
305
+ font-size: 12px;
306
+ }
307
+ }
308
+
309
+ /* Animation Keyframes and Helper Classes */
310
+ @keyframes xtBob {
311
+ 0% { transform: translateY(0); }
312
+ 50% { transform: translateY(-7px); }
313
+ 100% { transform: translateY(0); }
314
+ }
315
+
316
+ @keyframes xtPop {
317
+ 0% { transform: translateY(0); }
318
+ 50% { transform: translateY(-5px); }
319
+ 100% { transform: translateY(0); }
320
+ }
321
+
322
+ @keyframes xtFlame {
323
+ 0%, 100% { transform: scale(1) rotate(0deg); }
324
+ 50% { transform: scale(1.15) rotate(5deg); }
325
+ }
326
+
327
+ @keyframes xtRing {
328
+ 0% { box-shadow: 0 0 0 0 rgba(242, 151, 75, 0.55); }
329
+ 100% { box-shadow: 0 0 0 16px rgba(242, 151, 75, 0); }
330
+ }
331
+
332
+ .animate-bob {
333
+ animation: xtBob 2.9s ease-in-out infinite;
334
+ }
335
+
336
+ .animate-pop {
337
+ animation: xtPop 1.6s ease-in-out infinite;
338
+ }
339
+
340
+ .animate-flame {
341
+ animation: xtFlame 1.8s ease-in-out infinite;
342
+ }
343
+
344
+ .animate-ring {
345
+ animation: xtRing 1.8s cubic-bezier(0, 0, 0.2, 1) infinite;
346
+ }
347
+
348
+ @keyframes xtShadow {
349
+ 0%, 100% { transform: scale(1); opacity: 0.20; }
350
+ 50% { transform: scale(0.6); opacity: 0.08; }
351
+ }
352
+
353
+ .animate-contact-shadow {
354
+ animation: xtShadow 2.9s ease-in-out infinite;
355
+ }
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ export * from './components/Headers/CountryHeader/CountryHeader';
2
+ export * from './components/Buttons/MainButton/MainButton';
3
+ export * from './components/Buttons/BackButton/BackButton';
4
+ export * from './components/Cards/ModuleCard/ModuleCard';
5
+ export * from './components/Cards/ModuleCompletionCard/ModuleCompletionCard';
6
+ export * from './components/Cards/AnswerOptionCard/AnswerOptionCard';
7
+ export * from './components/DataDisplay/ProgressBar/ProgressBar';
8
+ export * from './components/DataDisplay/Tag/Tag';
9
+ export * from './components/DataDisplay/Badge/Badge';
10
+ export * from './components/Inputs/TextInput/TextInput';
11
+ export * from './components/Typography/Typography';
12
+ export * from './components/Cards/BoardingPassCard/BoardingPassCard';
13
+ export * from './components/Cards/SelectionCard/SelectionCard';
14
+ export * from './components/Cards/PricingCard/PricingCard';
15
+ export * from './components/DataDisplay/Flag/Flag';
16
+ export * from './components/Cards/BaseCard/BaseCard';
17
+ export * from './components/Cards/TeacherCard/TeacherCard';
18
+ export * from './components/Cards/CountryCard/CountryCard';
19
+ export * from './components/Cards/PlanCard/PlanCard';
20
+ export * from './components/DataDisplay/LevelBadge/LevelBadge';
21
+ export * from './hooks/useResponsive';
22
+ export * from './components/Mascots/Vava/Vava';
23
+ export * from './components/Mascots/Yaya/Yaya';
24
+ export * from './components/Feedback/FeedbackBottomSheet/FeedbackBottomSheet';
25
+ export * from './components/Headers/ProfileHeader/ProfileHeader';
26
+ export * from './components/Inputs/FillInTheBlank/FillInTheBlank';
27
+ export * from './components/Charts/WeeklyProgressChart';
28
+ export * from './components/Navigation/ProgressMap/ProgressMap';
package/src/main.tsx ADDED
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1,5 @@
1
+ /* eslint-disable */
2
+ // Mock for codegenNativeComponent to prevent Vite build failures on Web
3
+ export default function codegenNativeComponent(name: string, _options?: any): any {
4
+ return name;
5
+ }