@daryasidorovich/modsen-datepicker 1.0.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 (183) hide show
  1. package/.babelrc.json +7 -0
  2. package/.github/workflows/chromatic.yml +25 -0
  3. package/.github/workflows/ci.yml +56 -0
  4. package/.husky/commit-msg +1 -0
  5. package/.husky/pre-commit +1 -0
  6. package/.prettierignore +16 -0
  7. package/.prettierrc +6 -0
  8. package/.storybook/main.js +93 -0
  9. package/.storybook/preview-head.html +6 -0
  10. package/.storybook/preview.js +26 -0
  11. package/.storybook/preview.tsx +18 -0
  12. package/README.md +302 -0
  13. package/commitlint.config.js +23 -0
  14. package/dist/components/BaseCalendar/index.d.ts +2 -0
  15. package/dist/components/CalendarGrid/CalendarGridWithTasks/Tooltip/index.d.ts +8 -0
  16. package/dist/components/CalendarGrid/CalendarGridWithTasks/index.d.ts +2 -0
  17. package/dist/components/CalendarGrid/CalendarGridWithoutTasks/CalendarGridWithoutTasks.test.d.ts +1 -0
  18. package/dist/components/CalendarGrid/CalendarGridWithoutTasks/index.d.ts +4 -0
  19. package/dist/components/CalendarGrid/index.d.ts +2 -0
  20. package/dist/components/CalendarGrid/types.d.ts +21 -0
  21. package/dist/components/Clear/index.d.ts +5 -0
  22. package/dist/components/DatePicker/index.d.ts +5 -0
  23. package/dist/components/Day/index.d.ts +16 -0
  24. package/dist/components/Input/index.d.ts +10 -0
  25. package/dist/components/Modal/CrudModal/index.d.ts +2 -0
  26. package/dist/components/Modal/index.d.ts +12 -0
  27. package/dist/components/Modal/types.d.ts +12 -0
  28. package/dist/components/Month/index.d.ts +7 -0
  29. package/dist/components/RangePicker/index.d.ts +6 -0
  30. package/dist/components/TasksManager/AddModal/index.d.ts +6 -0
  31. package/dist/components/TasksManager/DeleteModal/index.d.ts +6 -0
  32. package/dist/components/TasksManager/EditModal/index.d.ts +7 -0
  33. package/dist/components/TasksManager/index.d.ts +9 -0
  34. package/dist/components/Week/index.d.ts +17 -0
  35. package/dist/components/WeekDay/index.d.ts +7 -0
  36. package/dist/constants/dateMask.d.ts +21 -0
  37. package/dist/constants/firstDayOfWeek.d.ts +5 -0
  38. package/dist/constants/holidays.d.ts +1 -0
  39. package/dist/constants/modes.d.ts +5 -0
  40. package/dist/constants/monthsNames.d.ts +1 -0
  41. package/dist/constants/weekdaysNames.d.ts +1 -0
  42. package/dist/hooks/useCalendar.d.ts +7 -0
  43. package/dist/hooks/useLockBodyScroll.d.ts +2 -0
  44. package/dist/hooks/useModal.d.ts +13 -0
  45. package/dist/hooks/useTooltip.d.ts +9 -0
  46. package/dist/hooks/useValidate.d.ts +11 -0
  47. package/dist/index.cjs +17250 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.ts +11 -0
  50. package/dist/index.js +17233 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/services/calendarService.d.ts +19 -0
  53. package/dist/services/decorators/withHolidays.d.ts +2 -0
  54. package/dist/services/decorators/withHolidays.test.d.ts +1 -0
  55. package/dist/services/decorators/withMinMax.d.ts +2 -0
  56. package/dist/services/decorators/withMinMax.test.d.ts +1 -0
  57. package/dist/services/holidayService.d.ts +5 -0
  58. package/dist/setupTests.d.ts +1 -0
  59. package/dist/store/localStorage.d.ts +3 -0
  60. package/dist/store/tasksStore.d.ts +8 -0
  61. package/dist/store/tasksStore.test.d.ts +1 -0
  62. package/dist/store/types.d.ts +18 -0
  63. package/dist/utils/calendar.d.ts +7 -0
  64. package/dist/utils/calendar.test.d.ts +1 -0
  65. package/dist/utils/controlDate.d.ts +1 -0
  66. package/dist/utils/dateChecks.d.ts +10 -0
  67. package/dist/utils/dateChecks.test.d.ts +1 -0
  68. package/dist/utils/formatDate.d.ts +3 -0
  69. package/dist/utils/formatDate.test.d.ts +1 -0
  70. package/dist/utils/schema.d.ts +6 -0
  71. package/dist/utils/schema.test.d.ts +1 -0
  72. package/dist/utils/weekdayOrder.d.ts +1 -0
  73. package/dist/utils/weekdayOrder.test.d.ts +1 -0
  74. package/docs/base-calendar.png +0 -0
  75. package/docs/dark-theme.png +0 -0
  76. package/docs/datepicker.png +0 -0
  77. package/docs/rangepicker-with-error.png +0 -0
  78. package/docs/rangepicker.png +0 -0
  79. package/eslint.config.ts +80 -0
  80. package/jest.config.json +21 -0
  81. package/package.json +106 -0
  82. package/rollup.config.js +65 -0
  83. package/src/assets/actions/Delete.svg +4 -0
  84. package/src/assets/actions/Edit.svg +3 -0
  85. package/src/assets/arrows/Next.svg +4 -0
  86. package/src/assets/arrows/Prev.svg +4 -0
  87. package/src/assets/input/Calendar.svg +3 -0
  88. package/src/assets/input/Clear.svg +3 -0
  89. package/src/components/BaseCalendar/BaseCalendar.stories.tsx +77 -0
  90. package/src/components/BaseCalendar/index.tsx +63 -0
  91. package/src/components/BaseCalendar/styles.module.scss +15 -0
  92. package/src/components/CalendarGrid/CalendarGrid.stories.tsx +136 -0
  93. package/src/components/CalendarGrid/CalendarGridWithTasks/Tooltip/index.tsx +27 -0
  94. package/src/components/CalendarGrid/CalendarGridWithTasks/Tooltip/styles.module.scss +9 -0
  95. package/src/components/CalendarGrid/CalendarGridWithTasks/index.tsx +51 -0
  96. package/src/components/CalendarGrid/CalendarGridWithoutTasks/CalendarGridWithoutTasks.test.tsx +223 -0
  97. package/src/components/CalendarGrid/CalendarGridWithoutTasks/index.tsx +36 -0
  98. package/src/components/CalendarGrid/CalendarGridWithoutTasks/styles.module.scss +11 -0
  99. package/src/components/CalendarGrid/index.tsx +19 -0
  100. package/src/components/CalendarGrid/types.ts +26 -0
  101. package/src/components/Clear/Clear.stories.tsx +16 -0
  102. package/src/components/Clear/index.tsx +12 -0
  103. package/src/components/Clear/styles.module.scss +34 -0
  104. package/src/components/DatePicker/DatePicker.stories.tsx +127 -0
  105. package/src/components/DatePicker/index.tsx +72 -0
  106. package/src/components/DatePicker/styles.module.scss +10 -0
  107. package/src/components/Day/Day.stories.tsx +75 -0
  108. package/src/components/Day/index.tsx +95 -0
  109. package/src/components/Day/styles.module.scss +97 -0
  110. package/src/components/Input/Input.stories.tsx +37 -0
  111. package/src/components/Input/index.tsx +64 -0
  112. package/src/components/Input/styles.module.scss +79 -0
  113. package/src/components/Modal/CrudModal/index.tsx +43 -0
  114. package/src/components/Modal/CrudModal/styles.module.scss +44 -0
  115. package/src/components/Modal/index.tsx +66 -0
  116. package/src/components/Modal/styles.module.scss +40 -0
  117. package/src/components/Modal/types.ts +13 -0
  118. package/src/components/Month/Month.stories.tsx +19 -0
  119. package/src/components/Month/index.tsx +31 -0
  120. package/src/components/Month/styles.module.scss +30 -0
  121. package/src/components/RangePicker/RangePicker.stories.tsx +134 -0
  122. package/src/components/RangePicker/index.tsx +144 -0
  123. package/src/components/RangePicker/styles.module.scss +19 -0
  124. package/src/components/TasksManager/AddModal/index.tsx +62 -0
  125. package/src/components/TasksManager/DeleteModal/index.tsx +22 -0
  126. package/src/components/TasksManager/EditModal/index.tsx +96 -0
  127. package/src/components/TasksManager/index.tsx +112 -0
  128. package/src/components/TasksManager/styles.module.scss +62 -0
  129. package/src/components/Week/Week.stories.tsx +49 -0
  130. package/src/components/Week/index.tsx +68 -0
  131. package/src/components/Week/styles.module.scss +7 -0
  132. package/src/components/WeekDay/WeekDay.stories.tsx +38 -0
  133. package/src/components/WeekDay/index.tsx +35 -0
  134. package/src/components/WeekDay/styles.module.scss +19 -0
  135. package/src/constants/dateMask.ts +23 -0
  136. package/src/constants/firstDayOfWeek.ts +7 -0
  137. package/src/constants/holidays.ts +32 -0
  138. package/src/constants/modes.ts +6 -0
  139. package/src/constants/monthsNames.ts +14 -0
  140. package/src/constants/weekdaysNames.ts +1 -0
  141. package/src/hooks/useCalendar.ts +62 -0
  142. package/src/hooks/useLockBodyScroll.ts +19 -0
  143. package/src/hooks/useModal.ts +45 -0
  144. package/src/hooks/useTooltip.ts +41 -0
  145. package/src/hooks/useValidate.ts +80 -0
  146. package/src/index.ts +15 -0
  147. package/src/services/calendarService.ts +62 -0
  148. package/src/services/decorators/withHolidays.test.ts +64 -0
  149. package/src/services/decorators/withHolidays.ts +12 -0
  150. package/src/services/decorators/withMinMax.test.ts +77 -0
  151. package/src/services/decorators/withMinMax.ts +19 -0
  152. package/src/services/holidayService.ts +56 -0
  153. package/src/setupTests.ts +1 -0
  154. package/src/store/localStorage.ts +33 -0
  155. package/src/store/tasksStore.test.tsx +208 -0
  156. package/src/store/tasksStore.tsx +146 -0
  157. package/src/store/types.ts +22 -0
  158. package/src/styles/_border.scss +9 -0
  159. package/src/styles/_colors.scss +53 -0
  160. package/src/styles/_gap.scss +4 -0
  161. package/src/styles/_globals.scss +61 -0
  162. package/src/styles/_grid.scss +9 -0
  163. package/src/styles/_mixins.scss +6 -0
  164. package/src/styles/_reset.scss +98 -0
  165. package/src/styles/_theme-mixins.scss +51 -0
  166. package/src/styles/_typography.scss +10 -0
  167. package/src/styles/_variables.scss +8 -0
  168. package/src/styles/main.scss +3 -0
  169. package/src/types/types.d.ts +15 -0
  170. package/src/utils/calendar.test.ts +154 -0
  171. package/src/utils/calendar.ts +82 -0
  172. package/src/utils/controlDate.ts +3 -0
  173. package/src/utils/dateChecks.test.ts +216 -0
  174. package/src/utils/dateChecks.ts +75 -0
  175. package/src/utils/formatDate.test.ts +57 -0
  176. package/src/utils/formatDate.ts +27 -0
  177. package/src/utils/schema.test.ts +40 -0
  178. package/src/utils/schema.ts +8 -0
  179. package/src/utils/weekdayOrder.test.ts +11 -0
  180. package/src/utils/weekdayOrder.ts +7 -0
  181. package/tsconfig.json +31 -0
  182. package/vitest.config.ts +38 -0
  183. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,208 @@
1
+ import { render, screen, waitFor } from '@testing-library/react';
2
+ import { userEvent } from '@testing-library/user-event';
3
+ import { TasksProvider, useTasks } from '@/store/tasksStore';
4
+ import { loadTasksFromStorage, saveTasksToStorage } from './localStorage';
5
+
6
+ jest.mock('@/store/localStorage', () => ({
7
+ loadTasksFromStorage: jest.fn(),
8
+ saveTasksToStorage: jest.fn(),
9
+ }));
10
+
11
+ const TestComponent = () => {
12
+ const {
13
+ tasks,
14
+ error,
15
+ getTasksByDate,
16
+ hasTasks,
17
+ addTask,
18
+ editTask,
19
+ deleteTask,
20
+ toggleTask,
21
+ } = useTasks();
22
+
23
+ return (
24
+ <div>
25
+ {error && <div data-testid="error">{error}</div>}
26
+
27
+ <div data-testid="tasks-count">Count: {tasks.length}</div>
28
+ <ul data-testid="tasks-list">
29
+ {Array.isArray(tasks) &&
30
+ tasks.map((task) => (
31
+ <li key={task.id}>
32
+ <p data-testid={`task-title-${task.id}`}>{task.title}</p>
33
+ <span data-testid={`task-completed-${task.id}`}>
34
+ {task.completed ? 'yes' : 'no'}
35
+ </span>
36
+ <button
37
+ data-testid={`toggle-${task.id}`}
38
+ onClick={() => toggleTask(task.id)}
39
+ >
40
+ Toggle
41
+ </button>
42
+ <button
43
+ data-testid={`delete-${task.id}`}
44
+ onClick={() => deleteTask(task.id)}
45
+ >
46
+ Delete
47
+ </button>
48
+ <button
49
+ data-testid={`edit-${task.id}`}
50
+ onClick={() => editTask(task.id, { title: 'Edited task' })}
51
+ ></button>
52
+ </li>
53
+ ))}
54
+ </ul>
55
+
56
+ <div data-testid="has-tasks-today">
57
+ Has tasks today:
58
+ {Array.isArray(tasks) && hasTasks(new Date()) ? 'yes' : 'no'}
59
+ </div>
60
+ <div data-testid="tasks-by-date">
61
+ Tasks today: {Array.isArray(tasks) && getTasksByDate(new Date()).length}
62
+ </div>
63
+
64
+ <button
65
+ data-testid="add-task-btn"
66
+ onClick={() => addTask(new Date(), 'New task')}
67
+ >
68
+ Add Task
69
+ </button>
70
+ </div>
71
+ );
72
+ };
73
+
74
+ describe('TasksContext:', () => {
75
+ beforeEach(() => {
76
+ jest.resetAllMocks();
77
+ });
78
+
79
+ const mockTasks = [
80
+ { id: '1', date: new Date(), title: 'Task 1', completed: false },
81
+ { id: '2', date: new Date(), title: 'Task 2', completed: true },
82
+ ];
83
+
84
+ test('loads tasks from localStorage on mount:', () => {
85
+ (loadTasksFromStorage as jest.Mock).mockReturnValue(mockTasks);
86
+
87
+ render(
88
+ <TasksProvider>
89
+ <TestComponent />
90
+ </TasksProvider>
91
+ );
92
+
93
+ expect(screen.getByTestId('tasks-count')).toHaveTextContent('Count: 2');
94
+
95
+ expect(screen.getByTestId('task-title-1')).toHaveTextContent('Task 1');
96
+ expect(screen.getByTestId('task-title-2')).toHaveTextContent('Task 2');
97
+ });
98
+
99
+ test('adds task correctly:', async () => {
100
+ (loadTasksFromStorage as jest.Mock).mockReturnValue([]);
101
+
102
+ render(
103
+ <TasksProvider>
104
+ <TestComponent />
105
+ </TasksProvider>
106
+ );
107
+
108
+ expect(screen.getByTestId('tasks-count')).toHaveTextContent('Count: 0');
109
+
110
+ await userEvent.click(screen.getByTestId('add-task-btn'));
111
+
112
+ expect(screen.getByTestId('tasks-count')).toHaveTextContent('Count: 1');
113
+ expect(screen.getByText('New task')).toBeInTheDocument();
114
+
115
+ expect(saveTasksToStorage).toHaveBeenCalled();
116
+ expect(saveTasksToStorage).toHaveBeenCalledWith([
117
+ expect.objectContaining({ title: 'New task' }),
118
+ ]);
119
+ });
120
+
121
+ test('edits task correctly:', async () => {
122
+ (loadTasksFromStorage as jest.Mock).mockReturnValue(mockTasks);
123
+
124
+ render(
125
+ <TasksProvider>
126
+ <TestComponent />
127
+ </TasksProvider>
128
+ );
129
+
130
+ await userEvent.click(screen.getByTestId('edit-1'));
131
+
132
+ expect(screen.getByTestId('task-title-1')).toHaveTextContent('Edited task');
133
+ });
134
+
135
+ test('deletes task correctly', async () => {
136
+ (loadTasksFromStorage as jest.Mock).mockReturnValue(mockTasks);
137
+
138
+ render(
139
+ <TasksProvider>
140
+ <TestComponent />
141
+ </TasksProvider>
142
+ );
143
+
144
+ expect(screen.getByTestId('task-title-1')).toBeInTheDocument();
145
+
146
+ await userEvent.click(screen.getByTestId('delete-1'));
147
+
148
+ expect(screen.queryByTestId('task-title-1')).not.toBeInTheDocument();
149
+ expect(screen.getByTestId('tasks-count')).toHaveTextContent('Count: 1');
150
+ });
151
+
152
+ test('toggles task completion status', async () => {
153
+ (loadTasksFromStorage as jest.Mock).mockReturnValue(mockTasks);
154
+
155
+ render(
156
+ <TasksProvider>
157
+ <TestComponent />
158
+ </TasksProvider>
159
+ );
160
+
161
+ expect(screen.getByTestId('task-completed-1')).toHaveTextContent('no');
162
+
163
+ await userEvent.click(screen.getByTestId('toggle-1'));
164
+
165
+ expect(screen.getByTestId('task-completed-1')).toHaveTextContent('yes');
166
+ });
167
+
168
+ test('checks if tasks exist for a date', () => {
169
+ (loadTasksFromStorage as jest.Mock).mockReturnValue(mockTasks);
170
+
171
+ render(
172
+ <TasksProvider>
173
+ <TestComponent />
174
+ </TasksProvider>
175
+ );
176
+
177
+ expect(screen.getByTestId('has-tasks-today')).toHaveTextContent('yes');
178
+ });
179
+
180
+ test('gets tasks by date', () => {
181
+ (loadTasksFromStorage as jest.Mock).mockReturnValue(mockTasks);
182
+
183
+ render(
184
+ <TasksProvider>
185
+ <TestComponent />
186
+ </TasksProvider>
187
+ );
188
+
189
+ expect(screen.getByTestId('tasks-by-date')).toHaveTextContent(
190
+ 'Tasks today: 2'
191
+ );
192
+ });
193
+
194
+ test('handles loading error', () => {
195
+ const errorMessage = 'Failed to load tasks';
196
+ (loadTasksFromStorage as jest.Mock).mockImplementation(() => {
197
+ throw new Error(errorMessage);
198
+ });
199
+
200
+ render(
201
+ <TasksProvider>
202
+ <TestComponent />
203
+ </TasksProvider>
204
+ );
205
+
206
+ expect(screen.getByTestId('error')).toHaveTextContent(errorMessage);
207
+ });
208
+ });
@@ -0,0 +1,146 @@
1
+ import {
2
+ createContext,
3
+ ReactNode,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useState,
8
+ } from 'react';
9
+
10
+ import { isSameDay } from '@/utils/dateChecks';
11
+
12
+ import { loadTasksFromStorage, saveTasksToStorage } from './localStorage';
13
+ import { Task, TasksContextValue } from './types';
14
+
15
+ const TasksContext = createContext<TasksContextValue | null>(null);
16
+
17
+ interface TasksProviderProps {
18
+ children: ReactNode;
19
+ }
20
+
21
+ export const TasksProvider = ({ children }: TasksProviderProps) => {
22
+ const [tasks, setTasks] = useState<Task[]>([]);
23
+ const [loading, setLoading] = useState(false);
24
+ const [error, setError] = useState<string>('');
25
+
26
+ const loadTasks = useCallback(() => {
27
+ setLoading(true);
28
+ setError('');
29
+ try {
30
+ const loadedTasks = loadTasksFromStorage();
31
+ setTasks(loadedTasks);
32
+ } catch (err) {
33
+ setError(err instanceof Error ? err.message : 'Failed to load tasks');
34
+ } finally {
35
+ setLoading(false);
36
+ }
37
+ }, []);
38
+
39
+ useEffect(() => {
40
+ loadTasks();
41
+ }, [loadTasks]);
42
+
43
+ const getTasksByDate = (date: Date) => {
44
+ return tasks.filter((task) => isSameDay(task.date, date));
45
+ };
46
+
47
+ const hasTasks = (date: Date) => {
48
+ return tasks.some((task) => isSameDay(task.date, date));
49
+ };
50
+
51
+ const addTask = (date: Date, title: string) => {
52
+ const newTask = {
53
+ id: Date.now().toString(),
54
+ date,
55
+ title,
56
+ completed: false,
57
+ };
58
+
59
+ setTasks((prev) => {
60
+ const updated = [...prev, newTask];
61
+ saveTasksToStorage(updated);
62
+ return updated;
63
+ });
64
+
65
+ return newTask;
66
+ };
67
+
68
+ const editTask = (id: string, updates: Partial<Omit<Task, 'id'>>) => {
69
+ let result: Task | undefined;
70
+
71
+ setTasks((prevTasks) => {
72
+ const updatedTasks = prevTasks.map((task) => {
73
+ if (task.id === id) {
74
+ result = { ...task, ...updates };
75
+ return result;
76
+ }
77
+ return task;
78
+ });
79
+
80
+ saveTasksToStorage(updatedTasks);
81
+ return updatedTasks;
82
+ });
83
+
84
+ return result;
85
+ };
86
+
87
+ const deleteTask = (id: string) => {
88
+ let deleted = false;
89
+
90
+ setTasks((prev) => {
91
+ const updated = prev.filter((task) => {
92
+ if (task.id === id) {
93
+ deleted = true;
94
+ return false;
95
+ }
96
+ return true;
97
+ });
98
+ saveTasksToStorage(updated);
99
+ return updated;
100
+ });
101
+
102
+ return deleted;
103
+ };
104
+
105
+ const toggleTask = (id: string) => {
106
+ let toggledTask;
107
+
108
+ setTasks((prev) => {
109
+ const updated = prev.map((task) => {
110
+ if (task.id === id) {
111
+ toggledTask = { ...task, completed: !task.completed };
112
+ return toggledTask;
113
+ }
114
+ return task;
115
+ });
116
+ saveTasksToStorage(updated);
117
+ return updated;
118
+ });
119
+
120
+ return toggledTask;
121
+ };
122
+
123
+ const value = {
124
+ tasks,
125
+ loading,
126
+ error,
127
+ getTasksByDate,
128
+ hasTasks,
129
+ addTask,
130
+ editTask,
131
+ deleteTask,
132
+ toggleTask,
133
+ loadTasks,
134
+ };
135
+ return (
136
+ <TasksContext.Provider value={value}>{children}</TasksContext.Provider>
137
+ );
138
+ };
139
+
140
+ export const useTasks = () => {
141
+ const context = useContext(TasksContext);
142
+ if (!context) {
143
+ throw new Error('Error while loading context');
144
+ }
145
+ return context;
146
+ };
@@ -0,0 +1,22 @@
1
+ export interface Task {
2
+ id: string;
3
+ date: Date;
4
+ title: string;
5
+ completed: boolean;
6
+ }
7
+
8
+ export interface TasksContextValue {
9
+ tasks: Task[];
10
+ loading: boolean;
11
+ error: string;
12
+ getTasksByDate: (date: Date) => Task[];
13
+ hasTasks: (date: Date) => boolean;
14
+ addTask: (date: Date, title: string) => Task;
15
+ editTask: (
16
+ id: string,
17
+ updates: Partial<Omit<Task, 'id'>>
18
+ ) => Task | undefined;
19
+ deleteTask: (id: string) => boolean;
20
+ toggleTask: (id: string) => Task | undefined;
21
+ loadTasks: () => void;
22
+ }
@@ -0,0 +1,9 @@
1
+ $radius-8: 8px;
2
+
3
+ $border-width: 1px;
4
+ $border-solid: solid;
5
+
6
+ @mixin border {
7
+ border-style: $border-solid;
8
+ border-width: $border-width;
9
+ }
@@ -0,0 +1,53 @@
1
+ @use 'sass:map';
2
+
3
+ $colors: (
4
+ color-blue: #2f80ed,
5
+ color-blue-60: #2f81ed93,
6
+ color-blue-10: #2f81ed2a,
7
+
8
+ color-white: #ffffff,
9
+ color-black: #333333,
10
+
11
+ color-red: #ff383c,
12
+ color-green: #62d0a2,
13
+ color-light-gray: #e1e1e1,
14
+ color-gray: #aaaaaa,
15
+ color-dark-gray: #2c314466,
16
+ );
17
+
18
+ @function color($key) {
19
+ @return map.get($colors, $key);
20
+ }
21
+
22
+ $themes: (
23
+ light: (
24
+ border: color(color-light-gray),
25
+ background: color(color-white),
26
+ text: color(color-black),
27
+ middle-blue: color(color-blue-60),
28
+ light-blue: color(color-blue-10),
29
+ blue: color(color-blue),
30
+ disabled: color(color-gray),
31
+ selected: color(color-blue),
32
+ accent: color(color-red),
33
+ marker: color(color-green),
34
+ white-color: color(color-white),
35
+ button-hover: color(color-blue-60),
36
+ overlay: color(color-dark-gray),
37
+ ),
38
+ dark: (
39
+ border: color(color-gray),
40
+ background: color(color-black),
41
+ text: color(color-white),
42
+ middle-blue: color(color-blue-60),
43
+ light-blue: color(color-blue-10),
44
+ blue: color(color-blue),
45
+ disabled: color(color-gray),
46
+ selected: color(color-blue),
47
+ accent: color(color-red),
48
+ marker: color(color-green),
49
+ white-color: color(color-light-gray),
50
+ button-hover: color(color-gray),
51
+ overlay: color(color-dark-gray),
52
+ ),
53
+ );
@@ -0,0 +1,4 @@
1
+ $gap-5: 5px;
2
+ $gap-8: 8px;
3
+ $gap-10: 10px;
4
+ $gap-24: 24px;
@@ -0,0 +1,61 @@
1
+ @use './colors' as *;
2
+ @use './typography' as *;
3
+ @use './border' as *;
4
+ @use './variables' as *;
5
+ @use './mixins' as *;
6
+ @use './theme-mixins' as *;
7
+
8
+ html {
9
+ &.is-lock {
10
+ overflow: hidden;
11
+ }
12
+ }
13
+
14
+ body {
15
+ font-weight: $font-weight-regular;
16
+ font-family: $font-family-base;
17
+ font-size: $font-size-14;
18
+
19
+ @include themify($themes) {
20
+ color: themed('text');
21
+ background: themed('gradient');
22
+ }
23
+ }
24
+
25
+ h1,
26
+ h2 {
27
+ margin: 0;
28
+ }
29
+
30
+ h1 {
31
+ font-size: $font-size-15;
32
+ font-weight: $font-weight-semibold;
33
+ }
34
+
35
+ h2 {
36
+ font-weight: $font-weight-bold;
37
+ }
38
+
39
+ a,
40
+ button,
41
+ label,
42
+ input,
43
+ textarea,
44
+ select,
45
+ svg * {
46
+ transition:
47
+ color $transition-duration $easing,
48
+ background-color $transition-duration $easing,
49
+ border-color $transition-duration $easing,
50
+ fill $transition-duration $easing,
51
+ opacity $transition-duration $easing;
52
+ }
53
+
54
+ a,
55
+ button {
56
+ &:has(svg) {
57
+ display: flex;
58
+ justify-content: center;
59
+ align-items: center;
60
+ }
61
+ }
@@ -0,0 +1,9 @@
1
+ @use './mixins' as *;
2
+ @use './gap' as *;
3
+
4
+ .grid {
5
+ display: grid;
6
+ width: 100%;
7
+
8
+ grid-template-columns: repeat(7, 1fr);
9
+ }
@@ -0,0 +1,6 @@
1
+ @use 'sass:map';
2
+
3
+ @mixin square($size) {
4
+ width: $size;
5
+ height: $size;
6
+ }
@@ -0,0 +1,98 @@
1
+ *,
2
+ ::before,
3
+ ::after {
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ :where(ul, ol):where([class]) {
8
+ padding-left: 0;
9
+ }
10
+
11
+ body,
12
+ :where(blockquote, figure):where([class]) {
13
+ margin: 0;
14
+ }
15
+
16
+ :where(h1, h2, h3, h4, h5, h6, p, ul, ol, dl):where([class]) {
17
+ margin-block: 0;
18
+ }
19
+
20
+ :where(dd[class]) {
21
+ margin-left: 0;
22
+ }
23
+
24
+ :where(fieldset[class]) {
25
+ margin-left: 0;
26
+ padding: 0;
27
+ border: none;
28
+ }
29
+
30
+ :where(ul[class]) {
31
+ list-style: none;
32
+ }
33
+
34
+ :where(address[class]) {
35
+ font-style: normal;
36
+ }
37
+
38
+ p {
39
+ margin-block: 0;
40
+ }
41
+
42
+ img,
43
+ video {
44
+ display: block;
45
+ max-width: 100%;
46
+ height: auto;
47
+ }
48
+
49
+ input,
50
+ textarea,
51
+ select,
52
+ button {
53
+ font: inherit;
54
+ }
55
+
56
+ html {
57
+ height: 100%;
58
+
59
+ scrollbar-gutter: stable;
60
+ }
61
+
62
+ html,
63
+ :has(:target) {
64
+ scroll-behavior: smooth;
65
+ }
66
+
67
+ body {
68
+ min-height: 100%;
69
+
70
+ line-height: 1.5;
71
+ }
72
+
73
+ a:where([class]) {
74
+ display: inline-flex;
75
+ }
76
+
77
+ button,
78
+ label {
79
+ cursor: pointer;
80
+ }
81
+
82
+ [stroke] {
83
+ stroke: currentColor;
84
+ }
85
+
86
+ svg * {
87
+ transition-property: fill, stroke;
88
+ }
89
+
90
+ @media (prefers-reduced-motion: reduce) {
91
+ *,
92
+ ::before,
93
+ ::after {
94
+ animation-duration: 0.01ms !important;
95
+ animation-iteration-count: 1 !important;
96
+ scroll-behavior: auto !important;
97
+ }
98
+ }
@@ -0,0 +1,51 @@
1
+ @use 'sass:map';
2
+ @use './colors' as *;
3
+
4
+ $theme-map: null;
5
+
6
+ @mixin themify-modules($themes) {
7
+ @each $theme, $map in $themes {
8
+ :global(.theme-#{$theme}) & {
9
+ $theme-map: () !global;
10
+
11
+ @each $key, $value in $map {
12
+ $theme-map: map.merge(
13
+ $theme-map,
14
+ (
15
+ $key: $value,
16
+ )
17
+ ) !global;
18
+ }
19
+
20
+ @content;
21
+
22
+ $theme-map: null !global;
23
+ }
24
+ }
25
+ }
26
+
27
+ @mixin themify($themes) {
28
+ @each $theme, $map in $themes {
29
+ .theme-#{$theme} & {
30
+ $theme-map: () !global;
31
+
32
+ @each $key, $submap in $map {
33
+ $value: map.get(map.get($themes, $theme), $key);
34
+ $theme-map: map.merge(
35
+ $theme-map,
36
+ (
37
+ $key: $value,
38
+ )
39
+ ) !global;
40
+ }
41
+
42
+ @content;
43
+
44
+ $theme-map: null !global;
45
+ }
46
+ }
47
+ }
48
+
49
+ @function themed($key) {
50
+ @return map.get($theme-map, $key);
51
+ }
@@ -0,0 +1,10 @@
1
+ $font-family-base: 'Open Sans', sans-serif;
2
+
3
+ $font-size-13: 13px;
4
+ $font-size-14: 14px;
5
+ $font-size-15: 15px;
6
+ $font-size-18: 18px;
7
+
8
+ $font-weight-regular: 400;
9
+ $font-weight-semibold: 600;
10
+ $font-weight-bold: 700;
@@ -0,0 +1,8 @@
1
+ $input-height: 42px;
2
+ $button-heght: 36px;
3
+ $icon-size: 16px;
4
+
5
+ $easing: ease;
6
+ $transition-duration: 0.2s;
7
+
8
+ $z-index-10: 10;
@@ -0,0 +1,3 @@
1
+ @use './reset';
2
+ @use './globals';
3
+ @use './grid';