@hyvor/design 2.1.8-beta.1 → 2.1.8-beta.3
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/marketing/AllFeaturesAccordion/AllFeaturesAccordion.svelte +251 -0
- package/dist/marketing/AllFeaturesAccordion/AllFeaturesAccordion.svelte.d.ts +23 -0
- package/dist/marketing/AllFeaturesAccordion/AllFeaturesAccordionFeature.svelte +75 -0
- package/dist/marketing/AllFeaturesAccordion/AllFeaturesAccordionFeature.svelte.d.ts +10 -0
- package/dist/marketing/FAQ/FAQ.svelte +233 -0
- package/dist/marketing/FAQ/FAQ.svelte.d.ts +13 -0
- package/dist/marketing/FeatureSplit/FeatureSplit.svelte +325 -0
- package/dist/marketing/FeatureSplit/FeatureSplit.svelte.d.ts +24 -0
- package/dist/marketing/Footer/Footer.svelte +15 -10
- package/dist/marketing/Footer/Footer.svelte.d.ts +5 -0
- package/dist/marketing/FullTrialSignup/FullTrialSignup.svelte +164 -0
- package/dist/marketing/FullTrialSignup/FullTrialSignup.svelte.d.ts +18 -0
- package/dist/marketing/Header/Header.svelte +7 -3
- package/dist/marketing/Header/Header.svelte.d.ts +2 -0
- package/dist/marketing/Header/HeaderLanguageToggle.svelte +121 -0
- package/dist/marketing/Header/HeaderLanguageToggle.svelte.d.ts +14 -0
- package/dist/marketing/Header/language.d.ts +18 -0
- package/dist/marketing/Header/language.js +35 -0
- package/dist/marketing/Hero/Hero.svelte +353 -0
- package/dist/marketing/Hero/Hero.svelte.d.ts +16 -0
- package/dist/marketing/Testimonials/Testimonials.svelte +382 -0
- package/dist/marketing/Testimonials/Testimonials.svelte.d.ts +23 -0
- package/dist/marketing/index.d.ts +10 -0
- package/dist/marketing/index.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Dropdown from '../../components/Dropdown/Dropdown.svelte';
|
|
3
|
+
import HeaderNavLink from './HeaderNavLink.svelte';
|
|
4
|
+
import type {
|
|
5
|
+
DropdownAlign,
|
|
6
|
+
DropdownPosition
|
|
7
|
+
} from '../../components/Dropdown/dropdown.types.js';
|
|
8
|
+
import type { LanguageOption } from './language.js';
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
languages: LanguageOption[];
|
|
12
|
+
current: string;
|
|
13
|
+
href: (code: string) => string;
|
|
14
|
+
showName?: boolean;
|
|
15
|
+
align?: DropdownAlign;
|
|
16
|
+
position?: DropdownPosition;
|
|
17
|
+
label?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
languages,
|
|
22
|
+
current,
|
|
23
|
+
href,
|
|
24
|
+
showName = false,
|
|
25
|
+
align = 'center',
|
|
26
|
+
position = 'bottom',
|
|
27
|
+
label = 'Change language'
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
|
|
30
|
+
const currentLanguage = $derived(languages.find((l) => l.code === current) ?? languages[0]);
|
|
31
|
+
|
|
32
|
+
let show = $state(false);
|
|
33
|
+
|
|
34
|
+
// close the dropdown once a language link inside it is clicked
|
|
35
|
+
function closeOnLinkClick(e: MouseEvent) {
|
|
36
|
+
const target = e.target as HTMLElement;
|
|
37
|
+
if (target.tagName === 'A' || target.closest('a')) {
|
|
38
|
+
show = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
{#if currentLanguage}
|
|
44
|
+
<div class="header-language-toggle">
|
|
45
|
+
<Dropdown bind:show {align} {position} contentPadding={8}>
|
|
46
|
+
{#snippet trigger()}
|
|
47
|
+
<HeaderNavLink aria-label={label} aria-expanded={show}>
|
|
48
|
+
<span class="flag">{currentLanguage.flag}</span>
|
|
49
|
+
{#if showName}{currentLanguage.name}{/if}
|
|
50
|
+
</HeaderNavLink>
|
|
51
|
+
{/snippet}
|
|
52
|
+
{#snippet content()}
|
|
53
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
|
54
|
+
<div class="menu" onclick={closeOnLinkClick}>
|
|
55
|
+
{#each languages as language (language.code)}
|
|
56
|
+
<HeaderNavLink
|
|
57
|
+
href={href(language.code)}
|
|
58
|
+
active={language.code === current}
|
|
59
|
+
data-lang={language.code}
|
|
60
|
+
menu
|
|
61
|
+
>
|
|
62
|
+
<span class="lang-row">
|
|
63
|
+
<span class="flag">{language.flag}</span>
|
|
64
|
+
<span class="name">{language.name}</span>
|
|
65
|
+
<span class="code">{language.code.toUpperCase()}</span>
|
|
66
|
+
</span>
|
|
67
|
+
</HeaderNavLink>
|
|
68
|
+
{/each}
|
|
69
|
+
</div>
|
|
70
|
+
{/snippet}
|
|
71
|
+
</Dropdown>
|
|
72
|
+
</div>
|
|
73
|
+
{/if}
|
|
74
|
+
|
|
75
|
+
<style>
|
|
76
|
+
.header-language-toggle {
|
|
77
|
+
position: relative;
|
|
78
|
+
display: inline-flex;
|
|
79
|
+
margin-left: 12px;
|
|
80
|
+
padding-left: 12px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* a short divider, centered on the toggle, separating it from nav links,
|
|
84
|
+
rather than a full-height border-left */
|
|
85
|
+
.header-language-toggle::before {
|
|
86
|
+
content: '';
|
|
87
|
+
position: absolute;
|
|
88
|
+
left: 0;
|
|
89
|
+
top: 50%;
|
|
90
|
+
transform: translateY(-50%);
|
|
91
|
+
width: 1px;
|
|
92
|
+
height: 16px;
|
|
93
|
+
background: var(--border);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.flag {
|
|
97
|
+
font-size: 15px;
|
|
98
|
+
line-height: 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.menu {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
gap: 2px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.lang-row {
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: center;
|
|
110
|
+
gap: 8px;
|
|
111
|
+
width: 100%;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.code {
|
|
115
|
+
margin-left: auto;
|
|
116
|
+
padding-left: 8px;
|
|
117
|
+
font-size: 11px;
|
|
118
|
+
font-weight: 600;
|
|
119
|
+
color: var(--text-light);
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DropdownAlign, DropdownPosition } from '../../components/Dropdown/dropdown.types.js';
|
|
2
|
+
import type { LanguageOption } from './language.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
languages: LanguageOption[];
|
|
5
|
+
current: string;
|
|
6
|
+
href: (code: string) => string;
|
|
7
|
+
showName?: boolean;
|
|
8
|
+
align?: DropdownAlign;
|
|
9
|
+
position?: DropdownPosition;
|
|
10
|
+
label?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const HeaderLanguageToggle: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type HeaderLanguageToggle = ReturnType<typeof HeaderLanguageToggle>;
|
|
14
|
+
export default HeaderLanguageToggle;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface LanguageOption {
|
|
2
|
+
/** language/locale code, e.g. "en", "fr" */
|
|
3
|
+
code: string;
|
|
4
|
+
/** an emoji flag shown next to the name */
|
|
5
|
+
flag: string;
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Rewrites `path` (the current pathname) from `currentLang` to `targetLang`,
|
|
10
|
+
* for the common convention where the default language is served without a
|
|
11
|
+
* prefix and every other language is served under `/{code}`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* buildLocalizedUrl('/pricing', 'en', 'fr', 'en') // '/fr/pricing'
|
|
15
|
+
* buildLocalizedUrl('/fr/pricing', 'fr', 'en', 'en') // '/pricing'
|
|
16
|
+
* buildLocalizedUrl('/fr', 'fr', 'en', 'en') // '/'
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildLocalizedUrl(path: string, currentLang: string, targetLang: string, defaultLang: string): string;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Shared helpers for marketing sites that serve translated pages on their own
|
|
2
|
+
// URLs (e.g. a SvelteKit `[[lang]]` route param) rather than switching
|
|
3
|
+
// language client-side on one page. This is a different case from
|
|
4
|
+
// `InternationalizationService`/`LanguageToggle` in
|
|
5
|
+
// `$lib/components/Internationalization`, which swap translated strings in
|
|
6
|
+
// place on a single page; use that instead if you don't have per-language
|
|
7
|
+
// routes.
|
|
8
|
+
/**
|
|
9
|
+
* Rewrites `path` (the current pathname) from `currentLang` to `targetLang`,
|
|
10
|
+
* for the common convention where the default language is served without a
|
|
11
|
+
* prefix and every other language is served under `/{code}`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* buildLocalizedUrl('/pricing', 'en', 'fr', 'en') // '/fr/pricing'
|
|
15
|
+
* buildLocalizedUrl('/fr/pricing', 'fr', 'en', 'en') // '/pricing'
|
|
16
|
+
* buildLocalizedUrl('/fr', 'fr', 'en', 'en') // '/'
|
|
17
|
+
*/
|
|
18
|
+
export function buildLocalizedUrl(path, currentLang, targetLang, defaultLang) {
|
|
19
|
+
let basePath = path;
|
|
20
|
+
// strip the current language prefix, if any, to get the language-agnostic path
|
|
21
|
+
if (currentLang !== defaultLang) {
|
|
22
|
+
const prefix = `/${currentLang}`;
|
|
23
|
+
if (basePath === prefix) {
|
|
24
|
+
basePath = '/';
|
|
25
|
+
}
|
|
26
|
+
else if (basePath.startsWith(`${prefix}/`)) {
|
|
27
|
+
basePath = basePath.slice(prefix.length);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// the default language is served without a prefix
|
|
31
|
+
if (targetLang === defaultLang) {
|
|
32
|
+
return basePath;
|
|
33
|
+
}
|
|
34
|
+
return basePath === '/' ? `/${targetLang}` : `/${targetLang}${basePath}`;
|
|
35
|
+
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Button from '../../components/Button/Button.svelte';
|
|
3
|
+
import IconChevronDown from '@hyvor/icons/IconChevronDown';
|
|
4
|
+
import type { ComponentProps, Snippet } from 'svelte';
|
|
5
|
+
|
|
6
|
+
type ButtonProps = ComponentProps<typeof Button>;
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
title: string | Snippet;
|
|
10
|
+
subtitle?: string | Snippet;
|
|
11
|
+
badge?: string | Snippet;
|
|
12
|
+
buttons?: ButtonProps | ButtonProps[] | null;
|
|
13
|
+
accentColor?: string;
|
|
14
|
+
accentColorDark?: string;
|
|
15
|
+
fullHeight?: boolean;
|
|
16
|
+
after?: Snippet;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
title,
|
|
21
|
+
subtitle,
|
|
22
|
+
badge,
|
|
23
|
+
buttons = null,
|
|
24
|
+
accentColor,
|
|
25
|
+
accentColorDark,
|
|
26
|
+
fullHeight = false,
|
|
27
|
+
after
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
|
|
30
|
+
const buttonList = $derived(buttons ? (Array.isArray(buttons) ? buttons : [buttons]) : []);
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<section
|
|
34
|
+
class="hero"
|
|
35
|
+
class:full-height={fullHeight}
|
|
36
|
+
style:--hero-accent={accentColor}
|
|
37
|
+
style:--hero-accent-dark={accentColorDark}
|
|
38
|
+
>
|
|
39
|
+
<svg class="hero-pattern" aria-hidden="true" focusable="false">
|
|
40
|
+
<defs>
|
|
41
|
+
<pattern id="hero-dot-pattern" width="28" height="28" patternUnits="userSpaceOnUse">
|
|
42
|
+
<circle cx="2" cy="2" r="1.6" fill="currentColor" />
|
|
43
|
+
</pattern>
|
|
44
|
+
</defs>
|
|
45
|
+
<rect width="100%" height="100%" fill="url(#hero-dot-pattern)" />
|
|
46
|
+
</svg>
|
|
47
|
+
|
|
48
|
+
<div class="hds-container inner">
|
|
49
|
+
<div class="left">
|
|
50
|
+
{#if badge}
|
|
51
|
+
<div class="badge anim anim-0">
|
|
52
|
+
{#if typeof badge === 'string'}
|
|
53
|
+
{badge}
|
|
54
|
+
{:else}
|
|
55
|
+
{@render badge()}
|
|
56
|
+
{/if}
|
|
57
|
+
</div>
|
|
58
|
+
{/if}
|
|
59
|
+
|
|
60
|
+
<h1 class="anim anim-1">
|
|
61
|
+
{#if typeof title === 'string'}
|
|
62
|
+
{@html title}
|
|
63
|
+
{:else}
|
|
64
|
+
{@render title()}
|
|
65
|
+
{/if}
|
|
66
|
+
</h1>
|
|
67
|
+
|
|
68
|
+
{#if subtitle}
|
|
69
|
+
<h2 class="subtitle anim anim-2">
|
|
70
|
+
{#if typeof subtitle === 'string'}
|
|
71
|
+
{@html subtitle}
|
|
72
|
+
{:else}
|
|
73
|
+
{@render subtitle()}
|
|
74
|
+
{/if}
|
|
75
|
+
</h2>
|
|
76
|
+
{/if}
|
|
77
|
+
|
|
78
|
+
{#if buttonList.length}
|
|
79
|
+
<div class="buttons anim anim-3">
|
|
80
|
+
{#each buttonList as b}
|
|
81
|
+
<Button
|
|
82
|
+
as="a"
|
|
83
|
+
href={b.href}
|
|
84
|
+
target={b.external ? '_blank' : undefined}
|
|
85
|
+
rel={b.external ? 'noopener' : undefined}
|
|
86
|
+
size={b.size || 'x-large'}
|
|
87
|
+
variant={b.variant}
|
|
88
|
+
>
|
|
89
|
+
{b.label}
|
|
90
|
+
</Button>
|
|
91
|
+
{/each}
|
|
92
|
+
</div>
|
|
93
|
+
{/if}
|
|
94
|
+
|
|
95
|
+
{#if after}
|
|
96
|
+
<div class="anim anim-3">
|
|
97
|
+
{@render after()}
|
|
98
|
+
</div>
|
|
99
|
+
{/if}
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="scroll-indicator anim anim-4" aria-hidden="true">
|
|
104
|
+
<div class="scroll-mouse">
|
|
105
|
+
<div class="scroll-dot"></div>
|
|
106
|
+
</div>
|
|
107
|
+
<IconChevronDown size={12} />
|
|
108
|
+
</div>
|
|
109
|
+
</section>
|
|
110
|
+
|
|
111
|
+
<style>
|
|
112
|
+
.hero {
|
|
113
|
+
--hero-accent-resolved: var(--hero-accent, var(--accent));
|
|
114
|
+
|
|
115
|
+
position: relative;
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
padding: 60px 0 80px;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.hero.full-height {
|
|
123
|
+
min-height: calc(100vh - var(--header-height, 60px));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
:global(:root.dark) .hero {
|
|
127
|
+
--hero-accent-resolved: var(--hero-accent-dark, var(--hero-accent, var(--accent)));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.hero-pattern {
|
|
131
|
+
position: absolute;
|
|
132
|
+
inset: 0;
|
|
133
|
+
width: 100%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
color: var(--border);
|
|
136
|
+
mask-image: radial-gradient(ellipse 65% 60% at 50% 38%, black 0%, transparent 75%);
|
|
137
|
+
-webkit-mask-image: radial-gradient(ellipse 65% 60% at 50% 38%, black 0%, transparent 75%);
|
|
138
|
+
pointer-events: none;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.inner {
|
|
142
|
+
position: relative;
|
|
143
|
+
z-index: 1;
|
|
144
|
+
display: flex;
|
|
145
|
+
align-items: center;
|
|
146
|
+
gap: 100px;
|
|
147
|
+
width: 1120px;
|
|
148
|
+
max-width: 100%;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.left {
|
|
152
|
+
flex: 1;
|
|
153
|
+
min-width: 0;
|
|
154
|
+
text-align: center;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.badge {
|
|
158
|
+
display: inline-flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: 6px;
|
|
161
|
+
padding: 4px 12px;
|
|
162
|
+
border-radius: 100px;
|
|
163
|
+
font-size: 13px;
|
|
164
|
+
font-weight: 600;
|
|
165
|
+
background: color-mix(in srgb, var(--hero-accent-resolved) 12%, transparent);
|
|
166
|
+
color: var(--hero-accent-resolved);
|
|
167
|
+
margin-bottom: 24px;
|
|
168
|
+
border: 1px solid color-mix(in srgb, var(--hero-accent-resolved) 25%, transparent);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
h1 {
|
|
172
|
+
margin: 0;
|
|
173
|
+
font-size: clamp(36px, 5vw, 56px);
|
|
174
|
+
line-height: 1.1;
|
|
175
|
+
letter-spacing: -0.02em;
|
|
176
|
+
font-weight: 800;
|
|
177
|
+
font-family: var(--font-serif);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* smaller second line inside the title, e.g. a parenthetical sub-line */
|
|
181
|
+
.left :global(h1 .heading-small) {
|
|
182
|
+
font-size: clamp(35px, 5vw, 46px);
|
|
183
|
+
font-weight: 800;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.subtitle {
|
|
187
|
+
font-weight: 500;
|
|
188
|
+
letter-spacing: -0.02em;
|
|
189
|
+
font-family: var(--font-serif);
|
|
190
|
+
|
|
191
|
+
margin: auto;
|
|
192
|
+
margin-top: 30px;
|
|
193
|
+
font-size: clamp(22px, 3vw, 26px);
|
|
194
|
+
line-height: 1.6;
|
|
195
|
+
color: color-mix(in srgb, var(--text) 70%, var(--text-light));
|
|
196
|
+
max-width: 480px;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.left :global(.hds-hl) {
|
|
200
|
+
color: var(--hero-accent-resolved);
|
|
201
|
+
font-weight: 700;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.left :global(.hds-marker) {
|
|
205
|
+
position: relative;
|
|
206
|
+
font-weight: 700;
|
|
207
|
+
background-image: linear-gradient(
|
|
208
|
+
100deg,
|
|
209
|
+
color-mix(in srgb, var(--hero-accent-resolved) 35%, transparent) 0%,
|
|
210
|
+
color-mix(in srgb, var(--hero-accent-resolved) 45%, transparent) 100%
|
|
211
|
+
);
|
|
212
|
+
background-repeat: no-repeat;
|
|
213
|
+
background-size: 100% 0.5em;
|
|
214
|
+
background-position: 0 88%;
|
|
215
|
+
box-decoration-break: clone;
|
|
216
|
+
-webkit-box-decoration-break: clone;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.buttons {
|
|
220
|
+
display: flex;
|
|
221
|
+
gap: 12px;
|
|
222
|
+
margin-top: 36px;
|
|
223
|
+
flex-wrap: wrap;
|
|
224
|
+
justify-content: center;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* Entrance animation */
|
|
228
|
+
.anim {
|
|
229
|
+
opacity: 0;
|
|
230
|
+
animation: hero-fade-up 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.anim-0 {
|
|
234
|
+
animation-delay: 0s;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.anim-1 {
|
|
238
|
+
animation-delay: 0.05s;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.anim-2 {
|
|
242
|
+
animation-delay: 0.15s;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.anim-3 {
|
|
246
|
+
animation-delay: 0.25s;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.anim-4 {
|
|
250
|
+
animation-delay: 0.6s;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
@keyframes hero-fade-up {
|
|
254
|
+
from {
|
|
255
|
+
opacity: 0;
|
|
256
|
+
transform: translateY(18px);
|
|
257
|
+
}
|
|
258
|
+
to {
|
|
259
|
+
opacity: 1;
|
|
260
|
+
transform: translateY(0);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@media (prefers-reduced-motion: reduce) {
|
|
265
|
+
.anim {
|
|
266
|
+
animation: none;
|
|
267
|
+
opacity: 1;
|
|
268
|
+
transform: none;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* Scroll indicator */
|
|
273
|
+
.scroll-indicator {
|
|
274
|
+
position: absolute;
|
|
275
|
+
left: 50%;
|
|
276
|
+
bottom: 28px;
|
|
277
|
+
transform: translateX(-50%);
|
|
278
|
+
z-index: 1;
|
|
279
|
+
display: flex;
|
|
280
|
+
flex-direction: column;
|
|
281
|
+
align-items: center;
|
|
282
|
+
gap: 8px;
|
|
283
|
+
color: var(--text-light);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.scroll-mouse {
|
|
287
|
+
width: 24px;
|
|
288
|
+
height: 38px;
|
|
289
|
+
border: 2px solid var(--border);
|
|
290
|
+
border-radius: 100px;
|
|
291
|
+
display: flex;
|
|
292
|
+
justify-content: center;
|
|
293
|
+
padding-top: 6px;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.scroll-dot {
|
|
297
|
+
width: 4px;
|
|
298
|
+
height: 8px;
|
|
299
|
+
border-radius: 2px;
|
|
300
|
+
background: var(--hero-accent-resolved);
|
|
301
|
+
animation: scroll-wheel 1.8s ease-in-out infinite;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
@keyframes scroll-wheel {
|
|
305
|
+
0% {
|
|
306
|
+
opacity: 1;
|
|
307
|
+
transform: translateY(0);
|
|
308
|
+
}
|
|
309
|
+
60% {
|
|
310
|
+
opacity: 0;
|
|
311
|
+
transform: translateY(12px);
|
|
312
|
+
}
|
|
313
|
+
100% {
|
|
314
|
+
opacity: 0;
|
|
315
|
+
transform: translateY(12px);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
@media (prefers-reduced-motion: reduce) {
|
|
320
|
+
.scroll-dot {
|
|
321
|
+
animation: none;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* Responsive */
|
|
326
|
+
@media (max-width: 992px) {
|
|
327
|
+
.hero.full-height {
|
|
328
|
+
min-height: unset;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.hero {
|
|
332
|
+
padding: 60px 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.inner {
|
|
336
|
+
flex-direction: column;
|
|
337
|
+
gap: 48px;
|
|
338
|
+
text-align: center;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.subtitle {
|
|
342
|
+
max-width: 100%;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.buttons {
|
|
346
|
+
justify-content: center;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.scroll-indicator {
|
|
350
|
+
display: none;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Button from '../../components/Button/Button.svelte';
|
|
2
|
+
import type { ComponentProps, Snippet } from 'svelte';
|
|
3
|
+
type ButtonProps = ComponentProps<typeof Button>;
|
|
4
|
+
interface Props {
|
|
5
|
+
title: string | Snippet;
|
|
6
|
+
subtitle?: string | Snippet;
|
|
7
|
+
badge?: string | Snippet;
|
|
8
|
+
buttons?: ButtonProps | ButtonProps[] | null;
|
|
9
|
+
accentColor?: string;
|
|
10
|
+
accentColorDark?: string;
|
|
11
|
+
fullHeight?: boolean;
|
|
12
|
+
after?: Snippet;
|
|
13
|
+
}
|
|
14
|
+
declare const Hero: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type Hero = ReturnType<typeof Hero>;
|
|
16
|
+
export default Hero;
|