@hyvor/design 2.1.9 → 2.1.11

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 (52) hide show
  1. package/dist/cloud/HyvorBar/BarSupport.svelte +1 -1
  2. package/dist/components/ColorPicker/ColorPicker.svelte +68 -9
  3. package/dist/components/ColorPicker/ColorPicker.svelte.d.ts +3 -0
  4. package/dist/components/Confetti/confetti.d.ts +7 -0
  5. package/dist/components/Confetti/confetti.js +102 -0
  6. package/dist/components/NavLink/NavLinkGroup.svelte +1 -0
  7. package/dist/index.css +4 -0
  8. package/dist/marketing/AllFeaturesAccordion/AllFeaturesAccordion.svelte +251 -0
  9. package/dist/marketing/AllFeaturesAccordion/AllFeaturesAccordion.svelte.d.ts +23 -0
  10. package/dist/marketing/AllFeaturesAccordion/AllFeaturesAccordionFeature.svelte +70 -0
  11. package/dist/marketing/AllFeaturesAccordion/AllFeaturesAccordionFeature.svelte.d.ts +10 -0
  12. package/dist/marketing/FAQ/FAQ.svelte +227 -0
  13. package/dist/marketing/FAQ/FAQ.svelte.d.ts +13 -0
  14. package/dist/marketing/FeatureSplit/FeatureSplit.svelte +325 -0
  15. package/dist/marketing/FeatureSplit/FeatureSplit.svelte.d.ts +24 -0
  16. package/dist/marketing/Footer/Footer.svelte +395 -98
  17. package/dist/marketing/Footer/Footer.svelte.d.ts +18 -2
  18. package/dist/marketing/Footer/FooterLinkList.svelte +10 -3
  19. package/dist/marketing/FullTrialSignup/FullTrialSignup.svelte +164 -0
  20. package/dist/marketing/FullTrialSignup/FullTrialSignup.svelte.d.ts +18 -0
  21. package/dist/marketing/Header/Header.svelte +72 -28
  22. package/dist/marketing/Header/Header.svelte.d.ts +5 -2
  23. package/dist/marketing/Header/HeaderLanguageToggle.svelte +119 -0
  24. package/dist/marketing/Header/HeaderLanguageToggle.svelte.d.ts +14 -0
  25. package/dist/marketing/Header/HeaderNavLink.svelte +149 -0
  26. package/dist/marketing/Header/HeaderNavLink.svelte.d.ts +18 -0
  27. package/dist/marketing/Header/language.d.ts +16 -0
  28. package/dist/marketing/Header/language.js +28 -0
  29. package/dist/marketing/Hero/Hero.svelte +349 -0
  30. package/dist/marketing/Hero/Hero.svelte.d.ts +16 -0
  31. package/dist/marketing/LogoStrip/LogoStrip.svelte +199 -0
  32. package/dist/marketing/LogoStrip/LogoStrip.svelte.d.ts +19 -0
  33. package/dist/marketing/Seal/CcpaSeal.svelte +29 -0
  34. package/dist/marketing/Seal/CcpaSeal.svelte.d.ts +6 -0
  35. package/dist/marketing/Seal/GdprSeal.svelte +60 -0
  36. package/dist/marketing/Seal/GdprSeal.svelte.d.ts +6 -0
  37. package/dist/marketing/Seal/IsoSeal.svelte +44 -0
  38. package/dist/marketing/Seal/IsoSeal.svelte.d.ts +6 -0
  39. package/dist/marketing/Seal/Seal.svelte +62 -0
  40. package/dist/marketing/Seal/Seal.svelte.d.ts +8 -0
  41. package/dist/marketing/Seal/SsoSeal.svelte +31 -0
  42. package/dist/marketing/Seal/SsoSeal.svelte.d.ts +6 -0
  43. package/dist/marketing/Seal/ccpa.svg +131 -0
  44. package/dist/marketing/SpotlightSplit/SpotlightSplit.svelte +256 -0
  45. package/dist/marketing/SpotlightSplit/SpotlightSplit.svelte.d.ts +19 -0
  46. package/dist/marketing/Testimonials/Testimonials.svelte +441 -0
  47. package/dist/marketing/Testimonials/Testimonials.svelte.d.ts +24 -0
  48. package/dist/marketing/index.d.ts +20 -2
  49. package/dist/marketing/index.js +26 -2
  50. package/dist/marketing/social.d.ts +1 -1
  51. package/dist/marketing/social.js +1 -1
  52. package/package.json +1 -1
@@ -1,17 +1,18 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import Container from '../Container/Container.svelte';
4
+ import IconEnvelope from '@hyvor/icons/IconEnvelope';
3
5
  import IconCopy from '@hyvor/icons/IconCopy';
4
6
  import IconDiscord from '@hyvor/icons/IconDiscord';
5
- import IconEnvelope from '@hyvor/icons/IconEnvelope';
6
7
  import IconGithub from '@hyvor/icons/IconGithub';
7
8
  import IconLinkedin from '@hyvor/icons/IconLinkedin';
8
9
  import IconTwitterX from '@hyvor/icons/IconTwitterX';
9
10
  import IconYoutube from '@hyvor/icons/IconYoutube';
10
- import Link from '../../components/Link/Link.svelte';
11
+ import IconBluesky from '@hyvor/icons/IconBluesky';
12
+ import IconLockFill from '@hyvor/icons/IconLockFill';
11
13
  import IconButton from '../../components/IconButton/IconButton.svelte';
12
14
  import Tooltip from '../../components/Tooltip/Tooltip.svelte';
13
15
  import LanguageToggle from '../../components/Internationalization/LanguageToggle.svelte';
14
- import IconBluesky from '@hyvor/icons/IconBluesky';
15
16
  import { SOCIAL_LINKS, type Socials } from '../social.js';
16
17
  import Affiliate from '../Affiliate/Affiliate.svelte';
17
18
  import RecordVisit from './RecordVisit.svelte';
@@ -19,104 +20,208 @@
19
20
  const year = new Date().getFullYear();
20
21
 
21
22
  interface Props {
23
+ name?: string;
24
+ subname?: string;
25
+ product?: string;
26
+ instance?: string;
27
+ logo?: string;
28
+ background?: string;
29
+ backgroundDark?: string;
30
+ card?: boolean;
22
31
  email?: string | null;
23
32
  social?: Partial<Socials>;
24
- center?: import('svelte').Snippet;
33
+ languageToggle?: boolean;
34
+ gdpr?: boolean;
25
35
  affiliate?: boolean;
26
36
  recordVisit?: boolean;
37
+ children?: Snippet;
27
38
  max?: boolean;
39
+ logoAltText?: string;
40
+ copyEmailLabel?: string;
41
+ copiedLabel?: string;
42
+ gdprText?: string;
43
+ fromFranceText?: string;
28
44
  }
29
45
 
30
46
  let {
47
+ name = 'HYVOR',
48
+ subname,
49
+ product,
50
+ instance = 'https://hyvor.com',
51
+ logo,
52
+ background,
53
+ backgroundDark,
54
+ card = false,
31
55
  email = null,
32
- social = $bindable({} as Record<string, string | null>),
33
- center,
56
+ social = {},
57
+ languageToggle = true,
58
+ gdpr = true,
34
59
  affiliate = true,
35
60
  recordVisit = true,
36
- max = false
61
+ children,
62
+ max = true,
63
+ logoAltText = 'Logo',
64
+ copyEmailLabel = 'Copy email',
65
+ copiedLabel = 'Copied!',
66
+ gdprText = 'GDPR Compliant',
67
+ fromFranceText = 'From France'
37
68
  }: Props = $props();
69
+ const mascotLogo = $derived(
70
+ logo || (product ? `${instance}/api/public/logo/${product}.svg` : undefined)
71
+ );
38
72
 
39
- social = {
40
- ...SOCIAL_LINKS,
41
- ...social
42
- };
73
+ const socialLinks = $derived({ ...SOCIAL_LINKS, ...social });
43
74
 
44
- let emailCopied = $state(false);
75
+ const SOCIAL_PLATFORMS = [
76
+ { key: 'x', icon: IconTwitterX, label: 'X (Twitter)' },
77
+ { key: 'github', icon: IconGithub, label: 'GitHub' },
78
+ { key: 'discord', icon: IconDiscord, label: 'Discord' },
79
+ { key: 'linkedin', icon: IconLinkedin, label: 'LinkedIn' },
80
+ { key: 'youtube', icon: IconYoutube, label: 'YouTube' },
81
+ { key: 'bluesky', icon: IconBluesky, label: 'Bluesky' }
82
+ ] as const satisfies { key: keyof Socials; icon: unknown; label: string }[];
45
83
 
46
- function handleCopy() {
47
- navigator.clipboard.writeText(email!);
84
+ let emailCopied = $state(false);
85
+ function handleCopyEmail() {
86
+ if (!email) return;
87
+ navigator.clipboard.writeText(email);
48
88
  emailCopied = true;
49
- setTimeout(() => {
50
- emailCopied = false;
51
- }, 1000);
89
+ setTimeout(() => (emailCopied = false), 1000);
90
+ }
91
+
92
+ let mascotInView = $state(false);
93
+ function onView(node: HTMLElement, callback: () => void) {
94
+ const observer = new IntersectionObserver(
95
+ (entries) => {
96
+ if (entries[0]?.isIntersecting) {
97
+ setTimeout(callback, 400);
98
+ observer.disconnect();
99
+ }
100
+ },
101
+ { threshold: 0.3 }
102
+ );
103
+ observer.observe(node);
104
+ return {
105
+ destroy() {
106
+ observer.disconnect();
107
+ }
108
+ };
109
+ }
110
+
111
+ function starPath(outerR: number, innerR: number) {
112
+ const points: string[] = [];
113
+ for (let i = 0; i < 10; i++) {
114
+ const angle = -Math.PI / 2 + (i * Math.PI) / 5;
115
+ const r = i % 2 === 0 ? outerR : innerR;
116
+ points.push(`${(r * Math.cos(angle)).toFixed(2)},${(r * Math.sin(angle)).toFixed(2)}`);
117
+ }
118
+ return `M${points.join('L')}Z`;
52
119
  }
120
+ const gdprStarPath = starPath(1.7, 0.68);
121
+
122
+ // positions for the 12-star EU ring on the small GDPR badge
123
+ const gdprStars = Array.from({ length: 12 }, (_, i) => {
124
+ const angle = (i * 30 * Math.PI) / 180;
125
+ return {
126
+ x: 16 + 12 * Math.cos(angle),
127
+ y: 16 + 12 * Math.sin(angle)
128
+ };
129
+ });
53
130
  </script>
54
131
 
55
- <footer>
56
- <Container {max}>
57
- <div class="footer-top">
58
- <div class="footer-top-left">
59
- {#if email}
60
- <div class="email-wrap">
61
- <Link href="mailto:{email}" underline={false} color="text" rel="nofollow">
62
- {#snippet start()}
63
- <IconEnvelope />
64
- {/snippet}
65
- {email}
66
- </Link>
67
- <Tooltip text={emailCopied ? 'Copied!' : 'Copy email'} position="top">
68
- <IconButton
69
- size="small"
70
- variant="invisible"
71
- on:click={handleCopy}
72
- on:mouseleave={() => (emailCopied = false)}
73
- >
74
- <IconCopy size={12} />
75
- </IconButton>
76
- </Tooltip>
77
- </div>
78
- {/if}
132
+ <div class="footer-outer">
133
+ {#if mascotLogo}
134
+ <div class="mascot-wrap" use:onView={() => (mascotInView = true)}>
135
+ <img
136
+ src={mascotLogo}
137
+ alt="{name} {logoAltText}"
138
+ width="100"
139
+ height="100"
140
+ class:in-view={mascotInView}
141
+ />
142
+ </div>
143
+ {/if}
79
144
 
80
- <div class="social-media">
81
- {#if social.github}
82
- <a href={social.github} target="_blank" rel="nofollow"><IconGithub /></a>
83
- {/if}
84
- {#if social.discord}
85
- <a href={social.discord} target="_blank" rel="nofollow"><IconDiscord /></a>
86
- {/if}
87
- {#if social.blueksy}
88
- <a href={social.blueksy} target="_blank" rel="nofollow"><IconBluesky /></a>
89
- {/if}
90
- {#if social.x}
91
- <a href={social.x} target="_blank" rel="nofollow"><IconTwitterX /></a>
145
+ <footer class:card style:--footer-bg={background} style:--footer-bg-dark={backgroundDark}>
146
+ <Container {max}>
147
+ <div class="top-row">
148
+ <div class="brand">
149
+ <span>{name}</span>
150
+ {#if subname}
151
+ <div class="subname">{subname}</div>
92
152
  {/if}
93
- {#if social.youtube}
94
- <a href={social.youtube} target="_blank" rel="nofollow"><IconYoutube /></a>
153
+ </div>
154
+
155
+ <div class="top-row-right">
156
+ {#if email}
157
+ <div class="email-wrap">
158
+ <a class="email" href="mailto:{email}">
159
+ <IconEnvelope size={14} />
160
+ {email}
161
+ </a>
162
+ <Tooltip text={emailCopied ? copiedLabel : copyEmailLabel} position="top">
163
+ <IconButton
164
+ size="small"
165
+ variant="invisible"
166
+ color="input"
167
+ onclick={handleCopyEmail}
168
+ onmouseleave={() => (emailCopied = false)}
169
+ >
170
+ <IconCopy size={12} />
171
+ </IconButton>
172
+ </Tooltip>
173
+ </div>
95
174
  {/if}
96
- {#if social.linkedin}
97
- <a href={social.linkedin} target="_blank" rel="nofollow"><IconLinkedin /></a>
175
+
176
+ <div class="socials">
177
+ {#each SOCIAL_PLATFORMS as platform (platform.key)}
178
+ {@const href = socialLinks[platform.key]}
179
+ {#if href}
180
+ <a {href} target="_blank" rel="nofollow" aria-label={platform.label}>
181
+ <platform.icon size={16} />
182
+ </a>
183
+ {/if}
184
+ {/each}
185
+ </div>
186
+
187
+ {#if languageToggle}
188
+ <span class="language-toggle-wrap">
189
+ <LanguageToggle align="end" position="top" staticPage />
190
+ </span>
98
191
  {/if}
99
192
  </div>
100
193
  </div>
101
194
 
102
- <div class="footer-top-right">
103
- <span class="language-toggle-wrap">
104
- <LanguageToggle align="end" position="top" staticPage />
105
- </span>
195
+ <div class="footer-center">
196
+ {@render children?.()}
106
197
  </div>
107
- </div>
108
198
 
109
- <div class="footer-center">
110
- {@render center?.()}
111
- </div>
199
+ <div class="bottom-bar">
200
+ <div>HYVOR &copy; {year}</div>
201
+
202
+ {#if gdpr}
203
+ <div class="bottom-center">
204
+ <a class="gdpr-chip" href="https://hyvor.com/compliance" target="_blank">
205
+ <span class="gdpr-chip-icon">
206
+ <svg class="ring" viewBox="0 0 32 32" aria-hidden="true">
207
+ <circle cx="16" cy="16" r="16" fill="#173a8a" />
208
+ {#each gdprStars as s}
209
+ <path d={gdprStarPath} fill="#ffcd3c" transform="translate({s.x}, {s.y})" />
210
+ {/each}
211
+ </svg>
212
+ <span class="lock"><IconLockFill size={10} /></span>
213
+ </span>
214
+ <span class="gdpr-chip-text">{gdprText}</span>
215
+ </a>
216
+ </div>
217
+ {/if}
112
218
 
113
- <div class="footer-bottom">
114
- <div class="footer-bottom-left">
115
- HYVOR © {year}
219
+ <div class="bottom-right">
220
+ <div class="france">{fromFranceText} <span class="flag">🇫🇷</span></div>
221
+ </div>
116
222
  </div>
117
- <div class="footer-bottom-right">From France 🇫🇷</div>
118
- </div>
119
- </Container>
223
+ </Container>
224
+ </footer>
120
225
 
121
226
  {#if affiliate}
122
227
  <Affiliate />
@@ -125,57 +230,249 @@
125
230
  {#if recordVisit}
126
231
  <RecordVisit />
127
232
  {/if}
128
- </footer>
233
+ </div>
129
234
 
130
235
  <style>
131
- footer {
132
- border-top: 1px solid var(--border);
236
+ .footer-outer {
237
+ position: relative;
238
+ margin-top: 100px;
133
239
  }
134
240
 
135
- .footer-top {
136
- padding-top: 60px;
241
+ .mascot-wrap {
242
+ position: absolute;
243
+ z-index: 10;
137
244
  display: flex;
138
- align-items: flex-start;
245
+ justify-content: center;
246
+ pointer-events: none;
247
+ left: 0;
248
+ bottom: 100%;
249
+ transform: translate(-35%, 45%) rotate(20deg);
139
250
  }
140
- .footer-center {
251
+
252
+ .mascot-wrap img {
253
+ opacity: 0;
254
+ }
255
+
256
+ .mascot-wrap img.in-view {
257
+ animation: mascot-tilt-in 0.8s ease forwards;
258
+ }
259
+
260
+ @keyframes mascot-tilt-in {
261
+ 0% {
262
+ opacity: 0;
263
+ transform: rotate(-14deg) scale(0.9) translateY(16px);
264
+ }
265
+ 55% {
266
+ opacity: 1;
267
+ transform: rotate(10deg) scale(1.06) translateY(-4px);
268
+ }
269
+ 100% {
270
+ opacity: 1;
271
+ transform: rotate(0deg) scale(1) translateY(0);
272
+ }
273
+ }
274
+
275
+ @media (prefers-reduced-motion: reduce) {
276
+ .mascot-wrap img {
277
+ opacity: 1;
278
+ }
279
+ .mascot-wrap img.in-view {
280
+ animation: none;
281
+ }
282
+ }
283
+
284
+ footer {
285
+ --footer-text: var(--text);
286
+ --footer-text-strong: var(--text);
287
+ --footer-muted: var(--text-light);
288
+ --footer-border: var(--border);
289
+ --footer-hover: var(--accent);
290
+
291
+ position: relative;
292
+ z-index: 1;
293
+ background: var(--footer-bg, transparent);
294
+ color: var(--footer-text);
141
295
  padding-top: 50px;
142
296
  }
143
- .footer-top-left {
144
- flex: 1;
297
+
298
+ :global(:root.dark) footer {
299
+ background: var(--footer-bg-dark, var(--footer-bg, transparent));
300
+ }
301
+
302
+ footer.card {
303
+ --footer-text: rgba(255, 255, 255, 0.75);
304
+ --footer-text-strong: #fff;
305
+ --footer-muted: rgba(255, 255, 255, 0.45);
306
+ --footer-border: rgba(255, 255, 255, 0.08);
307
+ --footer-hover: #fff;
308
+ }
309
+
310
+ .top-row {
311
+ display: flex;
312
+ align-items: center;
313
+ justify-content: space-between;
314
+ flex-wrap: wrap;
315
+ gap: 20px;
316
+ padding-bottom: 40px;
317
+ border-bottom: 1px solid var(--footer-border);
318
+ }
319
+
320
+ .brand {
321
+ font-size: 16px;
322
+ font-weight: 700;
323
+ color: var(--footer-text-strong);
324
+ }
325
+
326
+ .subname {
327
+ font-size: 13px;
328
+ font-weight: 400;
329
+ color: var(--footer-muted);
145
330
  }
146
- .footer-top-right {
331
+
332
+ .top-row-right {
147
333
  display: flex;
334
+ align-items: center;
335
+ gap: 24px;
336
+ flex-wrap: wrap;
148
337
  }
338
+
149
339
  .email-wrap {
150
340
  display: inline-flex;
151
341
  align-items: center;
152
- gap: 4px;
153
- margin-bottom: 15px;
342
+ gap: 2px;
154
343
  }
155
- .social-media a {
156
- display: inline-block;
157
- padding: 3px;
158
- margin-right: 8px;
159
- color: var(--text-light);
344
+
345
+ .email {
346
+ display: inline-flex;
347
+ align-items: center;
348
+ gap: 6px;
349
+ font-size: 13px;
350
+ color: var(--footer-text);
160
351
  }
161
- .social-media a:first-child {
162
- padding-left: 0;
352
+
353
+ .email:hover {
354
+ color: var(--footer-hover);
163
355
  }
164
- .social-media a:hover {
165
- color: var(--accent);
356
+
357
+ .socials {
358
+ display: flex;
359
+ align-items: center;
360
+ gap: 14px;
166
361
  }
167
362
 
168
- .footer-bottom {
169
- padding-top: 50px;
170
- padding-bottom: 30px;
363
+ .socials a {
364
+ color: var(--footer-text);
171
365
  display: flex;
172
366
  }
173
- .footer-bottom-left {
174
- flex: 1;
367
+
368
+ .socials a:hover {
369
+ color: var(--footer-hover);
175
370
  }
176
371
 
177
372
  .language-toggle-wrap {
178
- margin-left: 8px;
179
373
  font-size: 18px;
180
374
  }
375
+
376
+ .footer-center {
377
+ display: flex;
378
+ }
379
+
380
+ .footer-center:not(:empty) {
381
+ padding: 48px 0;
382
+ }
383
+
384
+ .footer-center:not(:empty) + .bottom-bar {
385
+ border-top: 1px solid var(--footer-border);
386
+ }
387
+
388
+ .bottom-bar {
389
+ display: flex;
390
+ align-items: center;
391
+ justify-content: space-between;
392
+ flex-wrap: wrap;
393
+ gap: 10px;
394
+ padding: 24px 0 32px;
395
+ font-size: 13px;
396
+ color: var(--footer-muted);
397
+ }
398
+
399
+ .bottom-right {
400
+ display: flex;
401
+ align-items: center;
402
+ gap: 16px;
403
+ flex-wrap: wrap;
404
+ }
405
+
406
+ .france {
407
+ display: inline-flex;
408
+ align-items: center;
409
+ gap: 6px;
410
+ }
411
+
412
+ .gdpr-chip {
413
+ display: inline-flex;
414
+ align-items: center;
415
+ gap: 8px;
416
+ padding: 5px 12px 5px 5px;
417
+ border-radius: 100px;
418
+ background: #1f2f57;
419
+ color: #fff;
420
+ opacity: 0.9;
421
+ transition: opacity 0.15s ease;
422
+ }
423
+
424
+ .gdpr-chip:hover {
425
+ opacity: 1;
426
+ }
427
+
428
+ .gdpr-chip-icon {
429
+ position: relative;
430
+ width: 22px;
431
+ height: 22px;
432
+ flex-shrink: 0;
433
+ }
434
+
435
+ .gdpr-chip-icon .ring {
436
+ position: absolute;
437
+ inset: 0;
438
+ width: 100%;
439
+ height: 100%;
440
+ display: block;
441
+ }
442
+
443
+ .gdpr-chip-icon .lock {
444
+ position: absolute;
445
+ inset: 0;
446
+ display: flex;
447
+ align-items: center;
448
+ justify-content: center;
449
+ color: #fff;
450
+ }
451
+
452
+ .gdpr-chip-text {
453
+ font-size: 11px;
454
+ font-weight: 800;
455
+ letter-spacing: 0.02em;
456
+ color: #fff;
457
+ }
458
+
459
+ .flag {
460
+ color: initial;
461
+ filter: none;
462
+ }
463
+
464
+ @media (max-width: 560px) {
465
+ .mascot-wrap {
466
+ margin-bottom: -40px;
467
+ }
468
+
469
+ footer {
470
+ padding-top: 130px;
471
+ }
472
+
473
+ .top-row {
474
+ flex-direction: column;
475
+ align-items: flex-start;
476
+ }
477
+ }
181
478
  </style>
@@ -1,12 +1,28 @@
1
+ import type { Snippet } from 'svelte';
1
2
  import { type Socials } from '../social.js';
2
3
  interface Props {
4
+ name?: string;
5
+ subname?: string;
6
+ product?: string;
7
+ instance?: string;
8
+ logo?: string;
9
+ background?: string;
10
+ backgroundDark?: string;
11
+ card?: boolean;
3
12
  email?: string | null;
4
13
  social?: Partial<Socials>;
5
- center?: import('svelte').Snippet;
14
+ languageToggle?: boolean;
15
+ gdpr?: boolean;
6
16
  affiliate?: boolean;
7
17
  recordVisit?: boolean;
18
+ children?: Snippet;
8
19
  max?: boolean;
20
+ logoAltText?: string;
21
+ copyEmailLabel?: string;
22
+ copiedLabel?: string;
23
+ gdprText?: string;
24
+ fromFranceText?: string;
9
25
  }
10
- declare const Footer: import("svelte").Component<Props, {}, "social">;
26
+ declare const Footer: import("svelte").Component<Props, {}, "">;
11
27
  type Footer = ReturnType<typeof Footer>;
12
28
  export default Footer;
@@ -17,12 +17,16 @@
17
17
  <style>
18
18
  .link-list {
19
19
  flex: 1;
20
+ min-width: 150px;
20
21
  }
21
22
 
22
23
  .title {
23
- font-weight: 600;
24
+ font-size: 12px;
25
+ font-weight: 700;
24
26
  text-transform: uppercase;
25
- margin-bottom: 10px;
27
+ letter-spacing: 0.05em;
28
+ color: var(--footer-muted, var(--text-light));
29
+ margin-bottom: 14px;
26
30
  }
27
31
 
28
32
  .links {
@@ -32,9 +36,12 @@
32
36
  }
33
37
 
34
38
  .links :global(a) {
35
- margin-top: 12px;
39
+ font-size: 14px;
40
+ color: var(--footer-text, var(--text-light));
41
+ margin-top: 10px;
36
42
  }
37
43
  .links :global(a:hover) {
44
+ color: var(--footer-text-strong, var(--text));
38
45
  text-decoration: underline;
39
46
  }
40
47
  </style>