@helpwave/hightide 0.0.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.
- package/.storybook/main.ts +24 -0
- package/.storybook/preview.tsx +67 -0
- package/LICENSE +373 -0
- package/README.md +8 -0
- package/coloring/shading.ts +46 -0
- package/coloring/types.ts +13 -0
- package/components/Avatar.tsx +58 -0
- package/components/AvatarGroup.tsx +48 -0
- package/components/BreadCrumb.tsx +35 -0
- package/components/Button.tsx +236 -0
- package/components/ChipList.tsx +89 -0
- package/components/Circle.tsx +27 -0
- package/components/ErrorComponent.tsx +40 -0
- package/components/Expandable.tsx +61 -0
- package/components/HelpwaveBadge.tsx +35 -0
- package/components/HideableContentSection.tsx +43 -0
- package/components/InputGroup.tsx +72 -0
- package/components/LoadingAndErrorComponent.tsx +47 -0
- package/components/LoadingAnimation.tsx +40 -0
- package/components/LoadingButton.tsx +27 -0
- package/components/MarkdownInterpreter.tsx +278 -0
- package/components/Pagination.tsx +65 -0
- package/components/Profile.tsx +124 -0
- package/components/ProgressIndicator.tsx +58 -0
- package/components/Ring.tsx +286 -0
- package/components/SearchableList.tsx +69 -0
- package/components/SortButton.tsx +33 -0
- package/components/Span.tsx +0 -0
- package/components/StepperBar.tsx +124 -0
- package/components/Table.tsx +330 -0
- package/components/TechRadar.tsx +247 -0
- package/components/TextImage.tsx +86 -0
- package/components/TimeDisplay.tsx +121 -0
- package/components/Tooltip.tsx +92 -0
- package/components/VerticalDivider.tsx +51 -0
- package/components/date/DatePicker.tsx +164 -0
- package/components/date/DayPicker.tsx +95 -0
- package/components/date/TimePicker.tsx +167 -0
- package/components/date/YearMonthPicker.tsx +130 -0
- package/components/examples/InputGroupExample.tsx +58 -0
- package/components/examples/MultiSelectExample.tsx +57 -0
- package/components/examples/SearchableSelectExample.tsx +34 -0
- package/components/examples/SelectExample.tsx +28 -0
- package/components/examples/StackingModals.tsx +54 -0
- package/components/examples/TableExample.tsx +159 -0
- package/components/examples/TextareaExample.tsx +23 -0
- package/components/examples/TileExample.tsx +25 -0
- package/components/examples/Title.tsx +0 -0
- package/components/examples/date/DateTimePickerExample.tsx +53 -0
- package/components/examples/properties/CheckboxPropertyExample.tsx +29 -0
- package/components/examples/properties/DatePropertyExample.tsx +44 -0
- package/components/examples/properties/MultiSelectPropertyExample.tsx +39 -0
- package/components/examples/properties/NumberPropertyExample.tsx +28 -0
- package/components/examples/properties/SelectPropertyExample.tsx +39 -0
- package/components/examples/properties/TextPropertyExample.tsx +30 -0
- package/components/icons/Helpwave.tsx +51 -0
- package/components/icons/Tag.tsx +29 -0
- package/components/layout/Carousel.tsx +396 -0
- package/components/layout/DividerInserter.tsx +37 -0
- package/components/layout/FAQSection.tsx +57 -0
- package/components/layout/Tile.tsx +67 -0
- package/components/modals/ConfirmDialog.tsx +105 -0
- package/components/modals/DiscardChangesDialog.tsx +71 -0
- package/components/modals/InputModal.tsx +26 -0
- package/components/modals/LanguageModal.tsx +76 -0
- package/components/modals/Modal.tsx +149 -0
- package/components/modals/ModalRegister.tsx +45 -0
- package/components/properties/CheckboxProperty.tsx +62 -0
- package/components/properties/DateProperty.tsx +58 -0
- package/components/properties/MultiSelectProperty.tsx +82 -0
- package/components/properties/NumberProperty.tsx +86 -0
- package/components/properties/PropertyBase.tsx +84 -0
- package/components/properties/SelectProperty.tsx +67 -0
- package/components/properties/TextProperty.tsx +81 -0
- package/components/user-input/Checkbox.tsx +139 -0
- package/components/user-input/DateAndTimePicker.tsx +156 -0
- package/components/user-input/Input.tsx +192 -0
- package/components/user-input/Label.tsx +32 -0
- package/components/user-input/Menu.tsx +75 -0
- package/components/user-input/MultiSelect.tsx +158 -0
- package/components/user-input/ScrollPicker.tsx +240 -0
- package/components/user-input/SearchableSelect.tsx +36 -0
- package/components/user-input/Select.tsx +132 -0
- package/components/user-input/Textarea.tsx +86 -0
- package/components/user-input/ToggleableInput.tsx +115 -0
- package/eslint.config.js +3 -0
- package/globals.css +488 -0
- package/hooks/useHoverState.ts +88 -0
- package/hooks/useLanguage.tsx +78 -0
- package/hooks/useLocalStorage.tsx +33 -0
- package/hooks/useOutsideClick.ts +25 -0
- package/hooks/useSaveDelay.ts +46 -0
- package/hooks/useTheme.tsx +57 -0
- package/hooks/useTranslation.ts +43 -0
- package/index.ts +0 -0
- package/package.json +71 -0
- package/postcss.config.mjs +7 -0
- package/stories/README.md +23 -0
- package/stories/coloring/shading.stories.tsx +54 -0
- package/stories/geometry/Circle.stories.tsx +16 -0
- package/stories/geometry/rings/AnimatedRing.stories.tsx +18 -0
- package/stories/geometry/rings/RadialRings.stories.tsx +19 -0
- package/stories/geometry/rings/Ring.stories.tsx +17 -0
- package/stories/geometry/rings/RingWave.stories.tsx +20 -0
- package/stories/layout/FAQSection.stories.tsx +49 -0
- package/stories/layout/InputGroup.stories.tsx +19 -0
- package/stories/layout/Table.stories.tsx +19 -0
- package/stories/layout/TextImage.stories.tsx +24 -0
- package/stories/layout/chip/Chip.stories.tsx +19 -0
- package/stories/layout/chip/ChipList.stories.tsx +27 -0
- package/stories/layout/tile/Tile.stories.ts +20 -0
- package/stories/layout/tile/TileWithImage.stories.tsx +27 -0
- package/stories/other/BreadCrumbs.stories.tsx +21 -0
- package/stories/other/HelpwaveBadge.stories.tsx +18 -0
- package/stories/other/HelpwaveSpinner.stories.tsx +19 -0
- package/stories/other/MarkdownInterpreter.stories.tsx +18 -0
- package/stories/other/Profile.stories.tsx +52 -0
- package/stories/other/SearchableList.stories.tsx +21 -0
- package/stories/other/StackingModals.stories.tsx +16 -0
- package/stories/other/TechRadar.stories.tsx +14 -0
- package/stories/other/Translation.stories.tsx +56 -0
- package/stories/other/VerticalDivider.stories.tsx +20 -0
- package/stories/other/avatar/Avatar.stories.tsx +19 -0
- package/stories/other/avatar/AvatarGroup.stories.tsx +26 -0
- package/stories/other/tooltip/Tooltip.stories.tsx +30 -0
- package/stories/other/tooltip/TooltipStack.stories.tsx +39 -0
- package/stories/user-action/button/LoadingButton.stories.tsx +21 -0
- package/stories/user-action/button/OutlineButton.stories.tsx +22 -0
- package/stories/user-action/button/SolidButton.stories.tsx +22 -0
- package/stories/user-action/button/TextButton.stories.tsx +22 -0
- package/stories/user-action/input/Checkbox.stories.tsx +20 -0
- package/stories/user-action/input/Label.stories.tsx +18 -0
- package/stories/user-action/input/ScrollPicker.stories.tsx +20 -0
- package/stories/user-action/input/Textarea.stories.tsx +22 -0
- package/stories/user-action/input/date/DatePicker.stories.tsx +23 -0
- package/stories/user-action/input/date/DateTimePicker.stories.tsx +26 -0
- package/stories/user-action/input/date/DayPicker.stories.tsx +20 -0
- package/stories/user-action/input/date/TimePicker.stories.tsx +20 -0
- package/stories/user-action/input/date/YearMonthPicker.stories.tsx +21 -0
- package/stories/user-action/input/select/MultiSelect.stories.tsx +39 -0
- package/stories/user-action/input/select/SearchableSelect.stories.tsx +32 -0
- package/stories/user-action/input/select/Select.stories.tsx +30 -0
- package/stories/user-action/properties/CheckboxProperty.stories.tsx +20 -0
- package/stories/user-action/properties/DateProperty.stories.tsx +21 -0
- package/stories/user-action/properties/MultiSelectProperty.stories.tsx +33 -0
- package/stories/user-action/properties/NumberProperty.stories.tsx +21 -0
- package/stories/user-action/properties/PropertyBase.stories.tsx +28 -0
- package/stories/user-action/properties/SingleSelectProperty.stories.tsx +35 -0
- package/stories/user-action/properties/TextProperty.stories.tsx +20 -0
- package/tsconfig.json +20 -0
- package/util/array.ts +115 -0
- package/util/builder.ts +9 -0
- package/util/date.ts +180 -0
- package/util/easeFunctions.ts +37 -0
- package/util/emailValidation.ts +3 -0
- package/util/loopingArray.ts +94 -0
- package/util/math.ts +3 -0
- package/util/news.ts +43 -0
- package/util/noop.ts +1 -0
- package/util/simpleSearch.ts +65 -0
- package/util/storage.ts +37 -0
- package/util/types.ts +4 -0
package/globals.css
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
|
|
3
|
+
/* variants */
|
|
4
|
+
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
|
|
5
|
+
@custom-variant light (&:where([data-theme=light], [data-theme=light] *));
|
|
6
|
+
|
|
7
|
+
/* utilities */
|
|
8
|
+
@utility col {
|
|
9
|
+
@apply flex flex-col gap-y-2;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@utility row {
|
|
13
|
+
@apply flex flex-row gap-x-2;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@layer utilities {
|
|
17
|
+
.animation-delay-0 {
|
|
18
|
+
animation-delay: 0ms;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.animation-delay-100 {
|
|
22
|
+
animation-delay: 100ms;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.animation-delay-200 {
|
|
26
|
+
animation-delay: 200ms;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.animation-delay-300 {
|
|
30
|
+
animation-delay: 300ms;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.animation-delay-400 {
|
|
34
|
+
animation-delay: 400ms;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.animation-delay-500 {
|
|
38
|
+
animation-delay: 500ms;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.animation-delay-1000 {
|
|
42
|
+
animation-delay: 1000ms;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@keyframes fade-in {
|
|
46
|
+
0% {
|
|
47
|
+
opacity: 0;
|
|
48
|
+
}
|
|
49
|
+
100% {
|
|
50
|
+
opacity: 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@keyframes fade-out {
|
|
55
|
+
0% {
|
|
56
|
+
opacity: 1;
|
|
57
|
+
}
|
|
58
|
+
100% {
|
|
59
|
+
opacity: 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@keyframes bigLeftUp {
|
|
64
|
+
0%, 25% {
|
|
65
|
+
stroke-dashoffset: 1000;
|
|
66
|
+
}
|
|
67
|
+
50%, 75%, 100% {
|
|
68
|
+
stroke-dashoffset: 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@keyframes bigRightDown {
|
|
73
|
+
0%, 25%, 50% {
|
|
74
|
+
stroke-dashoffset: 0;
|
|
75
|
+
}
|
|
76
|
+
75%, 100% {
|
|
77
|
+
stroke-dashoffset: -1000;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@keyframes smallLeftUp {
|
|
82
|
+
0%, 25%, 50% {
|
|
83
|
+
stroke-dashoffset: 1000;
|
|
84
|
+
}
|
|
85
|
+
75%, 100% {
|
|
86
|
+
stroke-dashoffset: 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes smallRightDown {
|
|
91
|
+
0%, 25% {
|
|
92
|
+
stroke-dashoffset: 0;
|
|
93
|
+
}
|
|
94
|
+
50%, 75%, 100% {
|
|
95
|
+
stroke-dashoffset: -1000;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.animate-fade {
|
|
100
|
+
animation: fade-out 3s ease-in-out;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.animate-wave-big-left-up {
|
|
104
|
+
animation: bigLeftUp 1.7s ease-in infinite normal;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.animate-wave-big-right-down {
|
|
108
|
+
animation: bigRightDown 1.7s ease-in infinite reverse;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.animate-wave-small-left-up {
|
|
112
|
+
animation: smallLeftUp 1.7s ease-in infinite normal;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.animate-wave-small-right-down {
|
|
116
|
+
animation: smallRightDown 1.7s ease-in infinite reverse;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.animate-tooltip-fade-in {
|
|
120
|
+
animation: fade-in 0.2s ease-in-out forwards;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.animate-tooltip-fade-out {
|
|
124
|
+
animation: fade-in 0.2s ease-in-out forwards;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.shadow-around {
|
|
128
|
+
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.02),
|
|
129
|
+
0 -2px 2px 0 rgba(0, 0, 0, 0.02),
|
|
130
|
+
2px 0 2px 0 rgba(0, 0, 0, 0.02),
|
|
131
|
+
-2px 0 2px 0 rgba(0, 0, 0, 0.02);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.shadow-around-md {
|
|
135
|
+
box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.02),
|
|
136
|
+
0 -5px 5px 0 rgba(0, 0, 0, 0.02),
|
|
137
|
+
5px 0 5px 0 rgba(0, 0, 0, 0.02),
|
|
138
|
+
-5px 0 5px 0 rgba(0, 0, 0, 0.02);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.shadow-around-lg {
|
|
142
|
+
box-shadow: 0 10px 10px 0 rgba(0, 0, 0, 0.02),
|
|
143
|
+
0 -10px 10px 0 rgba(0, 0, 0, 0.02),
|
|
144
|
+
10px 0 10px 0 rgba(0, 0, 0, 0.02),
|
|
145
|
+
-10px 0 10px 0 rgba(0, 0, 0, 0.02);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.shadow-around-xl {
|
|
149
|
+
box-shadow: 0 20px 20px 0 rgba(0, 0, 0, 0.02),
|
|
150
|
+
0 -20px 20px 0 rgba(0, 0, 0, 0.02),
|
|
151
|
+
20px 0 20px 0 rgba(0, 0, 0, 0.02),
|
|
152
|
+
-20px 0 20px 0 rgba(0, 0, 0, 0.02);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* The theme variables */
|
|
157
|
+
@theme {
|
|
158
|
+
/* Colors for with default values of the light theme */
|
|
159
|
+
--color-white: #FFFFFF;
|
|
160
|
+
--color-black: #000000;
|
|
161
|
+
--color-gray-25: #F8F8F8;
|
|
162
|
+
--color-gray-50: #F2F2F2;
|
|
163
|
+
--color-gray-100: #E6E6E6;
|
|
164
|
+
--color-gray-200: #CCCCCC;
|
|
165
|
+
--color-gray-300: #B3B3B3;
|
|
166
|
+
--color-gray-400: #999999;
|
|
167
|
+
--color-gray-500: #888888;
|
|
168
|
+
--color-gray-600: #666666;
|
|
169
|
+
--color-gray-700: #4D4D4D;
|
|
170
|
+
--color-gray-800: #333333;
|
|
171
|
+
--color-gray-900: #1A1A1A;
|
|
172
|
+
--color-gray-950: #0D0D0D;
|
|
173
|
+
|
|
174
|
+
--color-green-100: #D1EFD8;
|
|
175
|
+
--color-green-500: #69CB81;
|
|
176
|
+
--color-green-900: #2C5536;
|
|
177
|
+
|
|
178
|
+
--color-orange-100: #FBECD9;
|
|
179
|
+
--color-orange-200: #F7D8B3;
|
|
180
|
+
--color-orange-500: #EA9E40;
|
|
181
|
+
|
|
182
|
+
--color-purple-50: #EFE6FD;
|
|
183
|
+
--color-purple-100: #CEB0FA;
|
|
184
|
+
--color-purple-400: #8470c5;
|
|
185
|
+
--color-purple-500: #694BB4;
|
|
186
|
+
|
|
187
|
+
--color-blue-50: #F6FAFF;
|
|
188
|
+
--color-blue-100: #D6E3F9;
|
|
189
|
+
--color-blue-200: #99B9EF;
|
|
190
|
+
--color-blue-500: #3272DF;
|
|
191
|
+
--color-blue-600: #285BB2;
|
|
192
|
+
--color-blue-800: #1A4080;
|
|
193
|
+
|
|
194
|
+
--color-red-50: #FFF9F9;
|
|
195
|
+
--color-red-100: #FBE0E2;
|
|
196
|
+
--color-red-200: #F7C2C5;
|
|
197
|
+
--color-red-300: #F4A3A7;
|
|
198
|
+
--color-red-400: #E3798A;
|
|
199
|
+
--color-red-500: #DC576D;
|
|
200
|
+
--color-red-900: #5C252E;
|
|
201
|
+
|
|
202
|
+
--color-primary: var(--color-purple-500);
|
|
203
|
+
--color-on-primary: #FFFFFF;
|
|
204
|
+
--color-secondary: #11243E;
|
|
205
|
+
--color-on-secondary: #FFFFFF;
|
|
206
|
+
--color-warning: #EA9E40;
|
|
207
|
+
--color-on-warning: #FFFFFF;
|
|
208
|
+
--color-positive: #69CB81;
|
|
209
|
+
--color-on-positive: #FFFFFF;
|
|
210
|
+
--color-negative: #DC576D;
|
|
211
|
+
--color-on-negative: #FFFFFF;
|
|
212
|
+
--color-surface: #FFFFFF;
|
|
213
|
+
--color-on-surface: #1A1A1A;
|
|
214
|
+
--color-surface-variant: #F8F8F8;
|
|
215
|
+
--color-surface-warning: #FBECD9;
|
|
216
|
+
--color-highlight: #3272DF;
|
|
217
|
+
--color-background: #EEEEEE;
|
|
218
|
+
--color-on-background: #1A1A1A;
|
|
219
|
+
|
|
220
|
+
--color-female: #E3798A;
|
|
221
|
+
--color-female-outline: #F4A3A7;
|
|
222
|
+
--color-female-surface: #FBE0E2;
|
|
223
|
+
--color-female-background: #FFF9F9;
|
|
224
|
+
|
|
225
|
+
--color-male: #3272DF;
|
|
226
|
+
--color-male-outline: #99B9EF;
|
|
227
|
+
--color-male-surface: #D6E3F9;
|
|
228
|
+
--color-male-background: #F6FAFF;
|
|
229
|
+
|
|
230
|
+
--color-neutral: #4D4D4D;
|
|
231
|
+
--color-neutral-outline: #B3B3B3;
|
|
232
|
+
--color-neutral-surface: #E6E6E6;
|
|
233
|
+
--color-neutral-background: #F8F8F8;
|
|
234
|
+
|
|
235
|
+
--color-text-primary: #1A1A1A;
|
|
236
|
+
--color-text-secondary: #666666;
|
|
237
|
+
--color-text-tertiary: #B3B3B3;
|
|
238
|
+
--color-text-highlight: #3272DF;
|
|
239
|
+
--color-icon-primary: #1A1A1A;
|
|
240
|
+
--color-icon-secondary: #666666;
|
|
241
|
+
--color-icon-highlight: #3272DF;
|
|
242
|
+
--color-divider: #E6E6E6;
|
|
243
|
+
--color-description: #555555;
|
|
244
|
+
--color-outline: #E6E6E6;
|
|
245
|
+
--color-outline-variant: #CCCCCC;
|
|
246
|
+
--color-disabled-background: #BBBBBB;
|
|
247
|
+
--color-disabled-text: #555555;
|
|
248
|
+
--color-disabled-icon: #555555;
|
|
249
|
+
--color-disabled-outline: #555555;
|
|
250
|
+
|
|
251
|
+
--color-button-solid-primary-background: var(--color-purple-500);
|
|
252
|
+
--color-button-solid-primary-text: #FFFFFF;
|
|
253
|
+
--color-button-solid-primary-icon: #FFFFFF;
|
|
254
|
+
--color-button-solid-secondary-background: #EFE6FD;
|
|
255
|
+
--color-button-solid-secondary-text: var(--color-purple-500);
|
|
256
|
+
--color-button-solid-secondary-icon: var(--color-purple-500);
|
|
257
|
+
--color-button-solid-tertiary-background: #F2F2F2;
|
|
258
|
+
--color-button-solid-tertiary-icon: #888888;
|
|
259
|
+
--color-button-solid-tertiary-text: #888888;
|
|
260
|
+
--color-button-outline-primary-outline: var(--color-purple-500);
|
|
261
|
+
--color-button-outline-primary-icon: var(--color-purple-500);
|
|
262
|
+
--color-button-outline-primary-text: var(--color-purple-500);
|
|
263
|
+
--color-button-solid-positive-background: #69CB81;
|
|
264
|
+
--color-button-solid-positive-icon: #FFFFFF;
|
|
265
|
+
--color-button-solid-positive-text: #FFFFFF;
|
|
266
|
+
--color-button-solid-warning-background: #EA9E40;
|
|
267
|
+
--color-button-solid-warning-icon: #FFFFFF;
|
|
268
|
+
--color-button-solid-warning-text: #FFFFFF;
|
|
269
|
+
--color-button-solid-negative-background: #DC576D;
|
|
270
|
+
--color-button-solid-negative-icon: #FFFFFF;
|
|
271
|
+
--color-button-solid-negative-text: #FFFFFF;
|
|
272
|
+
|
|
273
|
+
--color-button-text-hover-background: #E1E1E1;
|
|
274
|
+
--color-button-text-neutral-text: #333333;
|
|
275
|
+
--color-button-text-neutral-icon: #333333;
|
|
276
|
+
--color-button-text-negative-text: #DC576D;
|
|
277
|
+
--color-button-text-negative-icon: #DC576D;
|
|
278
|
+
|
|
279
|
+
--color-menu-background: #FFFFFF;
|
|
280
|
+
--color-menu-text: #1A1A1A;
|
|
281
|
+
--color-menu-border: #999999;
|
|
282
|
+
|
|
283
|
+
--color-tag-default-background: #F6FAFF;
|
|
284
|
+
--color-tag-default-text: #1A4080;
|
|
285
|
+
--color-tag-default-icon: #1A4080;
|
|
286
|
+
--color-tag-dark-background: #333333;
|
|
287
|
+
--color-tag-dark-text: #FFFFFF;
|
|
288
|
+
--color-tag-dark-icon: #FFFFFF;
|
|
289
|
+
--color-tag-green-background: #E2E9DB;
|
|
290
|
+
--color-tag-green-text: #7A977E;
|
|
291
|
+
--color-tag-green-icon: #7A977E;
|
|
292
|
+
--color-tag-yellow-background: #FEEACB;
|
|
293
|
+
--color-tag-yellow-text: #C79345;
|
|
294
|
+
--color-tag-yellow-icon: #C79345;
|
|
295
|
+
--color-tag-red-background: #FEE0DD;
|
|
296
|
+
--color-tag-red-text: #D67268;
|
|
297
|
+
--color-tag-red-icon: #D67268;
|
|
298
|
+
--color-tag-blue-background: #F6FAFF;
|
|
299
|
+
--color-tag-blue-text: #1A4080;
|
|
300
|
+
--color-tag-blue-icon: #1A4080;
|
|
301
|
+
--color-tag-pink-background: #CEA3B8;
|
|
302
|
+
--color-tag-pink-text: #CE75A0;
|
|
303
|
+
--color-tag-pink-icon: #CE75A0;
|
|
304
|
+
|
|
305
|
+
--color-tabel-header-background: #F6FAFF;
|
|
306
|
+
|
|
307
|
+
--color-text-image-primary-background: var(--color-purple-500);
|
|
308
|
+
--color-text-image-primary-text: #FFFFFF;
|
|
309
|
+
--color-text-image-secondary-background: #3171DE;
|
|
310
|
+
--color-text-image-secondary-text: #FFFFFF;
|
|
311
|
+
--color-text-image-dark-background: #11243E;
|
|
312
|
+
--color-text-image-dark-text: #FFFFFF;
|
|
313
|
+
|
|
314
|
+
/* breakpoints */
|
|
315
|
+
--breakpoint-tablet: 48rem; /* 768px for 16px font-size */
|
|
316
|
+
--breakpoint-desktop: 64rem; /* 1024px for 16px font-size*/
|
|
317
|
+
/* fonts */
|
|
318
|
+
--font-inter: 'Inter', sans-serif;
|
|
319
|
+
--font-space: 'Space Grotesk', sans-serif;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* Overrides of the dark theme */
|
|
323
|
+
@layer base {
|
|
324
|
+
/* Here are overrides for the light theme */
|
|
325
|
+
@variant dark {
|
|
326
|
+
--color-primary: var(--color-purple-400);
|
|
327
|
+
|
|
328
|
+
--color-surface: #333333;
|
|
329
|
+
--color-on-surface: #EEEEEE;
|
|
330
|
+
--color-surface-variant: #494949;
|
|
331
|
+
--color-surface-warning: #FBECD9;
|
|
332
|
+
--color-highlight: #3272DF;
|
|
333
|
+
--color-background: #1A1A1A;
|
|
334
|
+
--color-on-background: #EEEEEE;
|
|
335
|
+
|
|
336
|
+
--color-neutral: #4D4D4D;
|
|
337
|
+
--color-neutral-outline: #B3B3B3;
|
|
338
|
+
--color-neutral-surface: #E6E6E6;
|
|
339
|
+
--color-neutral-background: #F8F8F8;
|
|
340
|
+
|
|
341
|
+
--color-text-primary: #EEEEEE;
|
|
342
|
+
--color-text-secondary: #666666;
|
|
343
|
+
--color-text-tertiary: #B3B3B3;
|
|
344
|
+
--color-text-highlight: #3272DF;
|
|
345
|
+
--color-icon-primary: #EEEEEE;
|
|
346
|
+
--color-icon-secondary: #666666;
|
|
347
|
+
--color-icon-highlight: #3272DF;
|
|
348
|
+
--color-description: #999999;
|
|
349
|
+
|
|
350
|
+
--color-disabled-background: #555555;
|
|
351
|
+
--color-disabled-text: #888888;
|
|
352
|
+
|
|
353
|
+
--color-button-text-hover-background: #383838;
|
|
354
|
+
--color-button-text-neutral-text: #EEEEEE;
|
|
355
|
+
--color-button-text-neutral-icon: #EEEEEE;
|
|
356
|
+
|
|
357
|
+
--color-menu-background: #333333;
|
|
358
|
+
--color-menu-text: #EEEEEE;
|
|
359
|
+
--color-menu-border: #999999;
|
|
360
|
+
|
|
361
|
+
--color-tabel-header-background: #F6FAFF;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* Styles that can be overwritten by utils */
|
|
366
|
+
@layer components {
|
|
367
|
+
.btn-sm {
|
|
368
|
+
@apply row items-center justify-center gap-x-1 px-[0.625rem] py-[0.25rem] rounded-[0.375rem];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.btn-md {
|
|
372
|
+
@apply row items-center justify-center gap-x-2 px-[0.75rem] py-[0.5rem] rounded-[0.375rem];
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.btn-lg {
|
|
376
|
+
@apply row items-center justify-center gap-x-2 px-[1rem] py-[0.675rem] rounded-[0.375rem];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.card-sm {
|
|
380
|
+
@apply col gap-y-2 bg-surface text-on-surface px-2 py-1 rounded;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.card-md {
|
|
384
|
+
@apply col gap-y-2 bg-surface text-on-surface px-4 py-2 rounded-md;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.card-lg {
|
|
388
|
+
@apply col gap-y-2 bg-surface text-on-surface px-8 py-4 rounded-lg;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.chip {
|
|
392
|
+
@apply row gap-x-1 items-center justify-center px-2 py-1 rounded-md;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.chip-full {
|
|
396
|
+
@apply row gap-x-1 items-center justify-center px-2 py-1 rounded-full;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.section-padding-x {
|
|
400
|
+
@apply px-6 tablet:px-12 desktop:px-24;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.section-padding-y {
|
|
404
|
+
@apply py-16;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.section-padding {
|
|
408
|
+
@apply px-6 tablet:px-12 desktop:px-24 py-16;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
@layer components {
|
|
413
|
+
html, main {
|
|
414
|
+
@apply bg-background text-on-background;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
button {
|
|
418
|
+
@apply cursor-pointer;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.textstyle-title-3xl {
|
|
422
|
+
@apply text-5xl font-space font-bold;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.textstyle-title-2xl {
|
|
426
|
+
@apply text-4xl font-space font-bold;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.textstyle-title-xl {
|
|
430
|
+
@apply text-3xl font-space font-bold;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.textstyle-title-lg {
|
|
434
|
+
@apply text-2xl font-space font-bold;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.textstyle-title-md {
|
|
438
|
+
@apply text-xl font-space font-bold;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.textstyle-title-normal {
|
|
442
|
+
@apply text-lg font-semibold;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.textstyle-title-sm {
|
|
446
|
+
@apply font-space font-bold;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.textstyle-accent {
|
|
450
|
+
@apply text-sm text-gray-600 font-bold;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.textstyle-description {
|
|
454
|
+
@apply text-gray-400;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.textstyle-label-lg {
|
|
458
|
+
@apply text-gray-700 text-lg font-semibold;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.textstyle-label-md {
|
|
462
|
+
@apply text-gray-700 font-semibold;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.textstyle-label-sm {
|
|
466
|
+
@apply text-sm text-gray-700 font-semibold;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.textstyle-table-name {
|
|
470
|
+
@apply text-lg font-space font-medium;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.textstyle-table-header {
|
|
474
|
+
@apply text-gray-600 font-bold;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.textstyle-navigation-item {
|
|
478
|
+
@apply font-bold font-space;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.textstyle-form-error {
|
|
482
|
+
@apply text-negative text-sm;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.textstyle-form-description {
|
|
486
|
+
@apply text-gray-500 text-sm;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Dispatch, SetStateAction } from 'react'
|
|
2
|
+
import { useEffect, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
type UseHoverStateProps = {
|
|
5
|
+
/**
|
|
6
|
+
* The delay after which the menu is closed in milliseconds
|
|
7
|
+
*
|
|
8
|
+
* default: 200ms
|
|
9
|
+
*/
|
|
10
|
+
closingDelay: number,
|
|
11
|
+
/**
|
|
12
|
+
* Whether the hover state management should be disabled
|
|
13
|
+
*
|
|
14
|
+
* default: false
|
|
15
|
+
*/
|
|
16
|
+
isDisabled: boolean,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type UseHoverStateReturnType = {
|
|
20
|
+
/**
|
|
21
|
+
* Whether the element is hovered
|
|
22
|
+
*/
|
|
23
|
+
isHovered: boolean,
|
|
24
|
+
/**
|
|
25
|
+
* Function to change the current hover status
|
|
26
|
+
*/
|
|
27
|
+
setIsHovered: Dispatch<SetStateAction<boolean>>,
|
|
28
|
+
/**
|
|
29
|
+
* Handlers to pass on to the component that should be hovered
|
|
30
|
+
*/
|
|
31
|
+
handlers: {
|
|
32
|
+
onMouseEnter: () => void,
|
|
33
|
+
onMouseLeave: () => void,
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const defaultUseHoverStateProps: UseHoverStateProps = {
|
|
38
|
+
closingDelay: 200,
|
|
39
|
+
isDisabled: false,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param props See UseHoverStateProps
|
|
44
|
+
*
|
|
45
|
+
* A react hook for managing the hover state of a component. The handlers provided should be
|
|
46
|
+
* forwarded to the component which should be hovered over
|
|
47
|
+
*/
|
|
48
|
+
export const useHoverState = (props: Partial<UseHoverStateProps> | undefined = undefined): UseHoverStateReturnType => {
|
|
49
|
+
const { closingDelay, isDisabled } = { ...defaultUseHoverStateProps, ...props }
|
|
50
|
+
|
|
51
|
+
const [isHovered, setIsHovered] = useState(false)
|
|
52
|
+
const [timer, setTimer] = useState<NodeJS.Timeout>()
|
|
53
|
+
|
|
54
|
+
const onMouseEnter = () => {
|
|
55
|
+
if (isDisabled) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
clearTimeout(timer)
|
|
59
|
+
setIsHovered(true)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const onMouseLeave = () => {
|
|
63
|
+
if (isDisabled) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
setTimer(setTimeout(() => {
|
|
67
|
+
setIsHovered(false)
|
|
68
|
+
}, closingDelay))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (timer) {
|
|
73
|
+
return () => {
|
|
74
|
+
clearTimeout(timer)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (timer) {
|
|
81
|
+
clearTimeout(timer)
|
|
82
|
+
}
|
|
83
|
+
}, [isDisabled]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
isHovered, setIsHovered, handlers: { onMouseEnter, onMouseLeave }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'
|
|
2
|
+
import { createContext, useContext, useEffect, useState } from 'react'
|
|
3
|
+
import useLocalStorage from './useLocalStorage'
|
|
4
|
+
|
|
5
|
+
export const languages = ['en', 'de'] as const
|
|
6
|
+
export type Languages = typeof languages[number]
|
|
7
|
+
export const languagesLocalNames: Record<Languages, string> = {
|
|
8
|
+
en: 'English',
|
|
9
|
+
de: 'Deutsch',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_LANGUAGE = 'en'
|
|
13
|
+
|
|
14
|
+
export type LanguageContextValue = {
|
|
15
|
+
language: Languages,
|
|
16
|
+
setLanguage: Dispatch<SetStateAction<Languages>>,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const LanguageContext = createContext<LanguageContextValue>({ language: DEFAULT_LANGUAGE, setLanguage: (v) => v })
|
|
20
|
+
|
|
21
|
+
export const useLanguage = () => useContext(LanguageContext)
|
|
22
|
+
|
|
23
|
+
export const useLocale = (overWriteLanguage?: Languages) => {
|
|
24
|
+
const { language } = useLanguage()
|
|
25
|
+
const mapping: Record<Languages, string> = {
|
|
26
|
+
en: 'en-US',
|
|
27
|
+
de: 'de-DE'
|
|
28
|
+
}
|
|
29
|
+
return mapping[overWriteLanguage ?? language]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type ProvideLanguageProps = {
|
|
33
|
+
initialLanguage?: Languages,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const ProvideLanguage = ({ initialLanguage, children }: PropsWithChildren<ProvideLanguageProps>) => {
|
|
37
|
+
const [language, setLanguage] = useState<Languages>(initialLanguage ?? DEFAULT_LANGUAGE)
|
|
38
|
+
const [storedLanguage, setStoredLanguage] = useLocalStorage<Languages>('language', initialLanguage ?? DEFAULT_LANGUAGE)
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if(language !== initialLanguage && initialLanguage){
|
|
42
|
+
console.warn('LanguageProvider initial state changed: Prefer using useLanguages\'s setLanguage instead')
|
|
43
|
+
setLanguage(initialLanguage)
|
|
44
|
+
}
|
|
45
|
+
}, [initialLanguage]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
// TODO set locale of html tag here as well
|
|
49
|
+
setStoredLanguage(language)
|
|
50
|
+
}, [language, setStoredLanguage])
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (storedLanguage !== null) {
|
|
54
|
+
setLanguage(storedLanguage)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const languagesToTestAgainst = Object.values(languages)
|
|
59
|
+
|
|
60
|
+
const matchingBrowserLanguages = window.navigator.languages
|
|
61
|
+
.map(language => languagesToTestAgainst.find((test) => language === test || language.split('-')[0] === test))
|
|
62
|
+
.filter(entry => entry !== undefined)
|
|
63
|
+
|
|
64
|
+
if (matchingBrowserLanguages.length === 0) return
|
|
65
|
+
|
|
66
|
+
const firstMatch = matchingBrowserLanguages[0] as Languages
|
|
67
|
+
setLanguage(firstMatch)
|
|
68
|
+
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<LanguageContext.Provider value={{
|
|
72
|
+
language,
|
|
73
|
+
setLanguage
|
|
74
|
+
}}>
|
|
75
|
+
{children}
|
|
76
|
+
</LanguageContext.Provider>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Dispatch, SetStateAction } from 'react'
|
|
2
|
+
import { useCallback, useEffect, useState } from 'react'
|
|
3
|
+
import { LocalStorageService } from '../util/storage'
|
|
4
|
+
|
|
5
|
+
type SetValue<T> = Dispatch<SetStateAction<T>>
|
|
6
|
+
const useLocalStorage = <T, >(key: string, initValue: T): [T, SetValue<T>] => {
|
|
7
|
+
const get = useCallback((): T => {
|
|
8
|
+
if (typeof window === 'undefined') {
|
|
9
|
+
return initValue
|
|
10
|
+
}
|
|
11
|
+
const storageService = new LocalStorageService()
|
|
12
|
+
const value = storageService.get<T>(key)
|
|
13
|
+
return value || initValue
|
|
14
|
+
}, [initValue, key])
|
|
15
|
+
|
|
16
|
+
const [storedValue, setStoredValue] = useState<T>(get)
|
|
17
|
+
|
|
18
|
+
const setValue: SetValue<T> = useCallback(value => {
|
|
19
|
+
const newValue = value instanceof Function ? value(storedValue) : value
|
|
20
|
+
const storageService = new LocalStorageService()
|
|
21
|
+
storageService.set(key, value)
|
|
22
|
+
|
|
23
|
+
setStoredValue(newValue)
|
|
24
|
+
}, [storedValue, setStoredValue, key])
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
setStoredValue(get())
|
|
28
|
+
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
|
29
|
+
|
|
30
|
+
return [storedValue, setValue]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default useLocalStorage
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import type { RefObject } from 'react'
|
|
3
|
+
|
|
4
|
+
export const useOutsideClick = <Ts extends RefObject<HTMLElement>[]>(refs: Ts, handler: () => void) => {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const listener = (event: MouseEvent | TouchEvent) => {
|
|
7
|
+
// returning means not "not clicking outside"
|
|
8
|
+
|
|
9
|
+
// if no target exists, return
|
|
10
|
+
if (event.target === null) return
|
|
11
|
+
// if the target is a ref's element or descendent thereof, return
|
|
12
|
+
if (refs.some((ref) => !ref.current || ref.current.contains(event.target as Node))) {
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
handler()
|
|
17
|
+
}
|
|
18
|
+
document.addEventListener('mousedown', listener)
|
|
19
|
+
document.addEventListener('touchstart', listener)
|
|
20
|
+
return () => {
|
|
21
|
+
document.removeEventListener('mousedown', listener)
|
|
22
|
+
document.removeEventListener('touchstart', listener)
|
|
23
|
+
}
|
|
24
|
+
}, [refs, handler])
|
|
25
|
+
}
|