@hyvor/design 2.1.7 → 2.1.8-beta.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.
- package/dist/cloud/HyvorBar/BarSupport.svelte +1 -1
- package/dist/cloud/HyvorBar/Organization/BarOrganization.svelte +1 -1
- package/dist/components/Tooltip/Tooltip.svelte +28 -54
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +35 -15
- package/dist/marketing/Footer/Footer.svelte +402 -98
- package/dist/marketing/Footer/Footer.svelte.d.ts +18 -2
- package/dist/marketing/Footer/FooterLinkList.svelte +10 -3
- package/dist/marketing/Header/Header.svelte +72 -28
- package/dist/marketing/Header/Header.svelte.d.ts +5 -2
- package/dist/marketing/Header/HeaderLanguageToggle.svelte +121 -0
- package/dist/marketing/Header/HeaderLanguageToggle.svelte.d.ts +14 -0
- package/dist/marketing/Header/HeaderNavLink.svelte +148 -0
- package/dist/marketing/Header/HeaderNavLink.svelte.d.ts +17 -0
- package/dist/marketing/Header/language.d.ts +18 -0
- package/dist/marketing/Header/language.js +35 -0
- package/dist/marketing/index.d.ts +4 -0
- package/dist/marketing/index.js +3 -0
- package/dist/marketing/social.d.ts +1 -1
- package/dist/marketing/social.js +1 -1
- 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
|
|
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,212 @@
|
|
|
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
|
-
|
|
33
|
+
languageToggle?: boolean;
|
|
34
|
+
gdpr?: boolean;
|
|
25
35
|
affiliate?: boolean;
|
|
26
36
|
recordVisit?: boolean;
|
|
37
|
+
center?: 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 =
|
|
33
|
-
|
|
56
|
+
social = {},
|
|
57
|
+
languageToggle = true,
|
|
58
|
+
gdpr = true,
|
|
34
59
|
affiliate = true,
|
|
35
60
|
recordVisit = true,
|
|
36
|
-
|
|
61
|
+
center,
|
|
62
|
+
max = false,
|
|
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
|
-
|
|
40
|
-
...SOCIAL_LINKS,
|
|
41
|
-
...social
|
|
42
|
-
};
|
|
73
|
+
const socialLinks = $derived({ ...SOCIAL_LINKS, ...social });
|
|
43
74
|
|
|
44
|
-
|
|
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
|
-
|
|
47
|
-
|
|
84
|
+
let emailCopied = $state(false);
|
|
85
|
+
function handleCopyEmail() {
|
|
86
|
+
if (!email) return;
|
|
87
|
+
navigator.clipboard.writeText(email);
|
|
48
88
|
emailCopied = true;
|
|
49
|
-
setTimeout(() =>
|
|
50
|
-
|
|
51
|
-
|
|
89
|
+
setTimeout(() => (emailCopied = false), 1000);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// the floating mascot (only shown when a `logo` is given) tilts/fades in
|
|
93
|
+
// once it's scrolled into view, instead of just appearing on page load
|
|
94
|
+
let mascotInView = $state(false);
|
|
95
|
+
function onView(node: HTMLElement, callback: () => void) {
|
|
96
|
+
const observer = new IntersectionObserver(
|
|
97
|
+
(entries) => {
|
|
98
|
+
if (entries[0]?.isIntersecting) {
|
|
99
|
+
setTimeout(callback, 400);
|
|
100
|
+
observer.disconnect();
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{ threshold: 0.3 }
|
|
104
|
+
);
|
|
105
|
+
observer.observe(node);
|
|
106
|
+
return {
|
|
107
|
+
destroy() {
|
|
108
|
+
observer.disconnect();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
52
111
|
}
|
|
112
|
+
|
|
113
|
+
// a single 5-pointed star (outer/inner vertices alternating), centered on
|
|
114
|
+
// its own origin — reused via `transform="translate(...)"` per position
|
|
115
|
+
// below, rather than a plain dot, for the EU ring on the GDPR badge
|
|
116
|
+
function starPath(outerR: number, innerR: number) {
|
|
117
|
+
const points: string[] = [];
|
|
118
|
+
for (let i = 0; i < 10; i++) {
|
|
119
|
+
const angle = -Math.PI / 2 + (i * Math.PI) / 5;
|
|
120
|
+
const r = i % 2 === 0 ? outerR : innerR;
|
|
121
|
+
points.push(`${(r * Math.cos(angle)).toFixed(2)},${(r * Math.sin(angle)).toFixed(2)}`);
|
|
122
|
+
}
|
|
123
|
+
return `M${points.join('L')}Z`;
|
|
124
|
+
}
|
|
125
|
+
const gdprStarPath = starPath(1.7, 0.68);
|
|
126
|
+
|
|
127
|
+
// positions for the 12-star EU ring on the small GDPR badge
|
|
128
|
+
const gdprStars = Array.from({ length: 12 }, (_, i) => {
|
|
129
|
+
const angle = (i * 30 * Math.PI) / 180;
|
|
130
|
+
return {
|
|
131
|
+
x: 16 + 12 * Math.cos(angle),
|
|
132
|
+
y: 16 + 12 * Math.sin(angle)
|
|
133
|
+
};
|
|
134
|
+
});
|
|
53
135
|
</script>
|
|
54
136
|
|
|
55
|
-
<footer>
|
|
56
|
-
|
|
57
|
-
<div class="
|
|
58
|
-
<
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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}
|
|
137
|
+
<div class="footer-outer">
|
|
138
|
+
{#if mascotLogo}
|
|
139
|
+
<div class="mascot-wrap" use:onView={() => (mascotInView = true)}>
|
|
140
|
+
<img
|
|
141
|
+
src={mascotLogo}
|
|
142
|
+
alt="{name} {logoAltText}"
|
|
143
|
+
width="100"
|
|
144
|
+
height="100"
|
|
145
|
+
class:in-view={mascotInView}
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
148
|
+
{/if}
|
|
79
149
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
|
|
150
|
+
<footer class:card style:--footer-bg={background} style:--footer-bg-dark={backgroundDark}>
|
|
151
|
+
<Container {max}>
|
|
152
|
+
<div class="top-row">
|
|
153
|
+
<div class="brand">
|
|
154
|
+
<span>{name}</span>
|
|
155
|
+
{#if subname}
|
|
156
|
+
<div class="subname">{subname}</div>
|
|
86
157
|
{/if}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
{#if
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="top-row-right">
|
|
161
|
+
{#if email}
|
|
162
|
+
<div class="email-wrap">
|
|
163
|
+
<a class="email" href="mailto:{email}">
|
|
164
|
+
<IconEnvelope size={14} />
|
|
165
|
+
{email}
|
|
166
|
+
</a>
|
|
167
|
+
<Tooltip text={emailCopied ? copiedLabel : copyEmailLabel} position="top">
|
|
168
|
+
<IconButton
|
|
169
|
+
size="small"
|
|
170
|
+
variant="invisible"
|
|
171
|
+
onclick={handleCopyEmail}
|
|
172
|
+
onmouseleave={() => (emailCopied = false)}
|
|
173
|
+
>
|
|
174
|
+
<IconCopy size={12} />
|
|
175
|
+
</IconButton>
|
|
176
|
+
</Tooltip>
|
|
177
|
+
</div>
|
|
95
178
|
{/if}
|
|
96
|
-
|
|
97
|
-
|
|
179
|
+
|
|
180
|
+
<div class="socials">
|
|
181
|
+
{#each SOCIAL_PLATFORMS as platform (platform.key)}
|
|
182
|
+
{@const href = socialLinks[platform.key]}
|
|
183
|
+
{#if href}
|
|
184
|
+
<a {href} target="_blank" rel="nofollow" aria-label={platform.label}>
|
|
185
|
+
<platform.icon size={16} />
|
|
186
|
+
</a>
|
|
187
|
+
{/if}
|
|
188
|
+
{/each}
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
{#if languageToggle}
|
|
192
|
+
<span class="language-toggle-wrap">
|
|
193
|
+
<LanguageToggle align="end" position="top" staticPage />
|
|
194
|
+
</span>
|
|
98
195
|
{/if}
|
|
99
196
|
</div>
|
|
100
197
|
</div>
|
|
101
198
|
|
|
102
|
-
<div class="footer-
|
|
103
|
-
|
|
104
|
-
<LanguageToggle align="end" position="top" staticPage />
|
|
105
|
-
</span>
|
|
199
|
+
<div class="footer-center">
|
|
200
|
+
{@render center?.()}
|
|
106
201
|
</div>
|
|
107
|
-
</div>
|
|
108
202
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
</div>
|
|
203
|
+
<div class="bottom-bar">
|
|
204
|
+
<div>HYVOR © {year}</div>
|
|
112
205
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
206
|
+
{#if gdpr}
|
|
207
|
+
<div class="bottom-center">
|
|
208
|
+
<a class="gdpr-chip" href="https://hyvor.com/compliance" target="_blank">
|
|
209
|
+
<span class="gdpr-chip-icon">
|
|
210
|
+
<svg class="ring" viewBox="0 0 32 32" aria-hidden="true">
|
|
211
|
+
<circle cx="16" cy="16" r="16" fill="#173a8a" />
|
|
212
|
+
{#each gdprStars as s}
|
|
213
|
+
<path d={gdprStarPath} fill="#ffcd3c" transform="translate({s.x}, {s.y})" />
|
|
214
|
+
{/each}
|
|
215
|
+
</svg>
|
|
216
|
+
<span class="lock"><IconLockFill size={10} /></span>
|
|
217
|
+
</span>
|
|
218
|
+
<span class="gdpr-chip-text">{gdprText}</span>
|
|
219
|
+
</a>
|
|
220
|
+
</div>
|
|
221
|
+
{/if}
|
|
222
|
+
|
|
223
|
+
<div class="bottom-right">
|
|
224
|
+
<div class="france">{fromFranceText} <span class="flag">🇫🇷</span></div>
|
|
225
|
+
</div>
|
|
116
226
|
</div>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
</Container>
|
|
227
|
+
</Container>
|
|
228
|
+
</footer>
|
|
120
229
|
|
|
121
230
|
{#if affiliate}
|
|
122
231
|
<Affiliate />
|
|
@@ -125,57 +234,252 @@
|
|
|
125
234
|
{#if recordVisit}
|
|
126
235
|
<RecordVisit />
|
|
127
236
|
{/if}
|
|
128
|
-
</
|
|
237
|
+
</div>
|
|
129
238
|
|
|
130
239
|
<style>
|
|
131
|
-
footer {
|
|
132
|
-
|
|
240
|
+
.footer-outer {
|
|
241
|
+
position: relative;
|
|
242
|
+
margin-top: 100px;
|
|
133
243
|
}
|
|
134
244
|
|
|
135
|
-
.
|
|
136
|
-
|
|
245
|
+
.mascot-wrap {
|
|
246
|
+
position: absolute;
|
|
247
|
+
z-index: 10;
|
|
137
248
|
display: flex;
|
|
138
|
-
|
|
249
|
+
justify-content: center;
|
|
250
|
+
pointer-events: none;
|
|
251
|
+
left: 0;
|
|
252
|
+
bottom: 100%;
|
|
253
|
+
transform: translate(-35%, 45%) rotate(20deg);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.mascot-wrap img {
|
|
257
|
+
opacity: 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.mascot-wrap img.in-view {
|
|
261
|
+
animation: mascot-tilt-in 0.8s ease forwards;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@keyframes mascot-tilt-in {
|
|
265
|
+
0% {
|
|
266
|
+
opacity: 0;
|
|
267
|
+
transform: rotate(-14deg) scale(0.9) translateY(16px);
|
|
268
|
+
}
|
|
269
|
+
55% {
|
|
270
|
+
opacity: 1;
|
|
271
|
+
transform: rotate(10deg) scale(1.06) translateY(-4px);
|
|
272
|
+
}
|
|
273
|
+
100% {
|
|
274
|
+
opacity: 1;
|
|
275
|
+
transform: rotate(0deg) scale(1) translateY(0);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@media (prefers-reduced-motion: reduce) {
|
|
280
|
+
.mascot-wrap img {
|
|
281
|
+
opacity: 1;
|
|
282
|
+
}
|
|
283
|
+
.mascot-wrap img.in-view {
|
|
284
|
+
animation: none;
|
|
285
|
+
}
|
|
139
286
|
}
|
|
140
|
-
|
|
287
|
+
|
|
288
|
+
footer {
|
|
289
|
+
--footer-text: var(--text);
|
|
290
|
+
--footer-text-strong: var(--text);
|
|
291
|
+
--footer-muted: var(--text-light);
|
|
292
|
+
--footer-border: var(--border);
|
|
293
|
+
--footer-hover: var(--accent);
|
|
294
|
+
|
|
295
|
+
position: relative;
|
|
296
|
+
z-index: 1;
|
|
297
|
+
background: var(--footer-bg, transparent);
|
|
298
|
+
color: var(--footer-text);
|
|
141
299
|
padding-top: 50px;
|
|
142
300
|
}
|
|
143
|
-
|
|
144
|
-
|
|
301
|
+
|
|
302
|
+
/*
|
|
303
|
+
`backgroundDark` only when needed for dark mode - not complusory
|
|
304
|
+
*/
|
|
305
|
+
:global(:root.dark) footer {
|
|
306
|
+
background: var(--footer-bg-dark, var(--footer-bg, transparent));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
footer.card {
|
|
310
|
+
--footer-text: rgba(255, 255, 255, 0.75);
|
|
311
|
+
--footer-text-strong: #fff;
|
|
312
|
+
--footer-muted: rgba(255, 255, 255, 0.45);
|
|
313
|
+
--footer-border: rgba(255, 255, 255, 0.08);
|
|
314
|
+
--footer-hover: #fff;
|
|
145
315
|
}
|
|
146
|
-
|
|
316
|
+
|
|
317
|
+
.top-row {
|
|
147
318
|
display: flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
justify-content: space-between;
|
|
321
|
+
flex-wrap: wrap;
|
|
322
|
+
gap: 20px;
|
|
323
|
+
padding-bottom: 40px;
|
|
324
|
+
border-bottom: 1px solid var(--footer-border);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.brand {
|
|
328
|
+
font-size: 16px;
|
|
329
|
+
font-weight: 700;
|
|
330
|
+
color: var(--footer-text-strong);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.subname {
|
|
334
|
+
font-size: 13px;
|
|
335
|
+
font-weight: 400;
|
|
336
|
+
color: var(--footer-muted);
|
|
148
337
|
}
|
|
338
|
+
|
|
339
|
+
.top-row-right {
|
|
340
|
+
display: flex;
|
|
341
|
+
align-items: center;
|
|
342
|
+
gap: 24px;
|
|
343
|
+
flex-wrap: wrap;
|
|
344
|
+
}
|
|
345
|
+
|
|
149
346
|
.email-wrap {
|
|
150
347
|
display: inline-flex;
|
|
151
348
|
align-items: center;
|
|
152
|
-
gap:
|
|
153
|
-
margin-bottom: 15px;
|
|
349
|
+
gap: 2px;
|
|
154
350
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
351
|
+
|
|
352
|
+
.email {
|
|
353
|
+
display: inline-flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
gap: 6px;
|
|
356
|
+
font-size: 13px;
|
|
357
|
+
color: var(--footer-text);
|
|
160
358
|
}
|
|
161
|
-
|
|
162
|
-
|
|
359
|
+
|
|
360
|
+
.email:hover {
|
|
361
|
+
color: var(--footer-hover);
|
|
163
362
|
}
|
|
164
|
-
|
|
165
|
-
|
|
363
|
+
|
|
364
|
+
.socials {
|
|
365
|
+
display: flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
gap: 14px;
|
|
166
368
|
}
|
|
167
369
|
|
|
168
|
-
.
|
|
169
|
-
|
|
170
|
-
padding-bottom: 30px;
|
|
370
|
+
.socials a {
|
|
371
|
+
color: var(--footer-text);
|
|
171
372
|
display: flex;
|
|
172
373
|
}
|
|
173
|
-
|
|
174
|
-
|
|
374
|
+
|
|
375
|
+
.socials a:hover {
|
|
376
|
+
color: var(--footer-hover);
|
|
175
377
|
}
|
|
176
378
|
|
|
177
379
|
.language-toggle-wrap {
|
|
178
|
-
margin-left: 8px;
|
|
179
380
|
font-size: 18px;
|
|
180
381
|
}
|
|
382
|
+
|
|
383
|
+
.footer-center:not(:empty) {
|
|
384
|
+
padding: 48px 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* only if there is no center element - to prevent double border apperance */
|
|
388
|
+
.footer-center:not(:empty) + .bottom-bar {
|
|
389
|
+
border-top: 1px solid var(--footer-border);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.bottom-bar {
|
|
393
|
+
display: flex;
|
|
394
|
+
align-items: center;
|
|
395
|
+
justify-content: space-between;
|
|
396
|
+
flex-wrap: wrap;
|
|
397
|
+
gap: 10px;
|
|
398
|
+
padding: 24px 0 32px;
|
|
399
|
+
font-size: 13px;
|
|
400
|
+
color: var(--footer-muted);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.bottom-right {
|
|
404
|
+
display: flex;
|
|
405
|
+
align-items: center;
|
|
406
|
+
gap: 16px;
|
|
407
|
+
flex-wrap: wrap;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.france {
|
|
411
|
+
display: inline-flex;
|
|
412
|
+
align-items: center;
|
|
413
|
+
gap: 6px;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.gdpr-chip {
|
|
417
|
+
display: inline-flex;
|
|
418
|
+
align-items: center;
|
|
419
|
+
gap: 8px;
|
|
420
|
+
padding: 5px 12px 5px 5px;
|
|
421
|
+
border-radius: 100px;
|
|
422
|
+
background: #1f2f57;
|
|
423
|
+
color: #fff;
|
|
424
|
+
opacity: 0.9;
|
|
425
|
+
transition: opacity 0.15s ease;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.gdpr-chip:hover {
|
|
429
|
+
opacity: 1;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.gdpr-chip-icon {
|
|
433
|
+
position: relative;
|
|
434
|
+
width: 22px;
|
|
435
|
+
height: 22px;
|
|
436
|
+
flex-shrink: 0;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.gdpr-chip-icon .ring {
|
|
440
|
+
position: absolute;
|
|
441
|
+
inset: 0;
|
|
442
|
+
width: 100%;
|
|
443
|
+
height: 100%;
|
|
444
|
+
display: block;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.gdpr-chip-icon .lock {
|
|
448
|
+
position: absolute;
|
|
449
|
+
inset: 0;
|
|
450
|
+
display: flex;
|
|
451
|
+
align-items: center;
|
|
452
|
+
justify-content: center;
|
|
453
|
+
color: #fff;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.gdpr-chip-text {
|
|
457
|
+
font-size: 11px;
|
|
458
|
+
font-weight: 800;
|
|
459
|
+
letter-spacing: 0.02em;
|
|
460
|
+
color: #fff;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* emoji glyphs are pre-colored — never let the surrounding muted text
|
|
464
|
+
color dim or filter them */
|
|
465
|
+
.flag {
|
|
466
|
+
color: initial;
|
|
467
|
+
filter: none;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
@media (max-width: 560px) {
|
|
471
|
+
.mascot-wrap {
|
|
472
|
+
/* keep it clear of the brand wordmark that sits right below it */
|
|
473
|
+
margin-bottom: -40px;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
footer {
|
|
477
|
+
padding-top: 130px;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.top-row {
|
|
481
|
+
flex-direction: column;
|
|
482
|
+
align-items: flex-start;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
181
485
|
</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
|
-
|
|
14
|
+
languageToggle?: boolean;
|
|
15
|
+
gdpr?: boolean;
|
|
6
16
|
affiliate?: boolean;
|
|
7
17
|
recordVisit?: boolean;
|
|
18
|
+
center?: 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, {}, "
|
|
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-
|
|
24
|
+
font-size: 12px;
|
|
25
|
+
font-weight: 700;
|
|
24
26
|
text-transform: uppercase;
|
|
25
|
-
|
|
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
|
-
|
|
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>
|