@hyvor/design 1.1.10 → 1.1.12-beta.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/dist/components/DetailCard/DetailCard.svelte +56 -0
- package/dist/components/DetailCard/DetailCard.svelte.d.ts +9 -0
- package/dist/components/DetailCard/DetailCards.svelte +25 -0
- package/dist/components/DetailCard/DetailCards.svelte.d.ts +8 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/marketing/Affiliate/Affiliate.svelte +75 -0
- package/dist/marketing/Affiliate/Affiliate.svelte.d.ts +3 -0
- package/dist/marketing/Footer/Footer.svelte +9 -1
- package/dist/marketing/Footer/Footer.svelte.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
label: string | Snippet;
|
|
6
|
+
content?: string;
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { label, content, children }: Props = $props();
|
|
11
|
+
|
|
12
|
+
const labelId = `detail-card-${Math.random().toString(36).substring(2, 15)}`;
|
|
13
|
+
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div class="detail-card" role="region" aria-labelledby={labelId}>
|
|
17
|
+
|
|
18
|
+
<div class="label" id={labelId}>
|
|
19
|
+
{#if typeof label === "string"}
|
|
20
|
+
{label}
|
|
21
|
+
{:else}
|
|
22
|
+
{@render label()}
|
|
23
|
+
{/if}
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="content">
|
|
27
|
+
{#if children}
|
|
28
|
+
{@render children()}
|
|
29
|
+
{:else if content}
|
|
30
|
+
{content}
|
|
31
|
+
{/if}
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
.detail-card {
|
|
38
|
+
background: var(--hover);
|
|
39
|
+
padding: 15px 20px;
|
|
40
|
+
border-radius: var(--box-radius);
|
|
41
|
+
border: 1px solid var(--border);
|
|
42
|
+
}
|
|
43
|
+
.label {
|
|
44
|
+
display: block;
|
|
45
|
+
font-size: 12px;
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
color: var(--text-light);
|
|
48
|
+
text-transform: uppercase;
|
|
49
|
+
letter-spacing: 0.5px;
|
|
50
|
+
margin-bottom: 6px;
|
|
51
|
+
}
|
|
52
|
+
.content {
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
word-break: break-word;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface Props {
|
|
3
|
+
label: string | Snippet;
|
|
4
|
+
content?: string;
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
}
|
|
7
|
+
declare const DetailCard: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type DetailCard = ReturnType<typeof DetailCard>;
|
|
9
|
+
export default DetailCard;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
children?: Snippet
|
|
6
|
+
min?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
children,
|
|
11
|
+
min = 300
|
|
12
|
+
}: Props = $props();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<div class="cards" style="--min: {min}px">
|
|
16
|
+
{@render children?.()}
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<style>
|
|
20
|
+
.cards {
|
|
21
|
+
display: grid;
|
|
22
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--min), 1fr));
|
|
23
|
+
gap: 10px;
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
@@ -15,6 +15,8 @@ export { default as TabbedCodeBlock } from './CodeBlock/TabbedCodeBlock.svelte';
|
|
|
15
15
|
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
16
16
|
export { default as DarkProvider } from './Dark/DarkProvider.svelte';
|
|
17
17
|
export { default as DarkToggle } from './Dark/DarkToggle.svelte';
|
|
18
|
+
export { default as DetailCard } from './DetailCard/DetailCard.svelte';
|
|
19
|
+
export { default as DetailCards } from './DetailCard/DetailCards.svelte';
|
|
18
20
|
export { default as Dropdown } from './Dropdown/Dropdown.svelte';
|
|
19
21
|
export { default as Divider } from './Divider/Divider.svelte';
|
|
20
22
|
export { default as Caption } from './FormControl/Caption.svelte';
|
package/dist/components/index.js
CHANGED
|
@@ -15,6 +15,8 @@ export { default as TabbedCodeBlock } from './CodeBlock/TabbedCodeBlock.svelte';
|
|
|
15
15
|
export { default as ColorPicker } from './ColorPicker/ColorPicker.svelte';
|
|
16
16
|
export { default as DarkProvider } from './Dark/DarkProvider.svelte';
|
|
17
17
|
export { default as DarkToggle } from './Dark/DarkToggle.svelte';
|
|
18
|
+
export { default as DetailCard } from './DetailCard/DetailCard.svelte';
|
|
19
|
+
export { default as DetailCards } from './DetailCard/DetailCards.svelte';
|
|
18
20
|
export { default as Dropdown } from './Dropdown/Dropdown.svelte';
|
|
19
21
|
export { default as Divider } from './Divider/Divider.svelte';
|
|
20
22
|
export { default as Caption } from './FormControl/Caption.svelte';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Link from '../../components/Link/Link.svelte';
|
|
3
|
+
import Modal from '../../components/Modal/Modal.svelte';
|
|
4
|
+
import { replaceState } from '$app/navigation';
|
|
5
|
+
import { onMount } from 'svelte';
|
|
6
|
+
|
|
7
|
+
let partner: string | null = $state(null);
|
|
8
|
+
let showModal = $state(false);
|
|
9
|
+
|
|
10
|
+
onMount(() => {
|
|
11
|
+
const params = new URLSearchParams(window.location.search);
|
|
12
|
+
partner = params.get('partner');
|
|
13
|
+
|
|
14
|
+
if (partner) {
|
|
15
|
+
showModal = true;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
function handleConsent() {
|
|
20
|
+
const coreUrl = `${location.protocol}//${location.hostname.split('.').slice(-2).join('.')}`;
|
|
21
|
+
|
|
22
|
+
fetch(coreUrl + '/api/public/affiliate/placement', {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/json'
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
partner: partner,
|
|
29
|
+
url: window.location.href
|
|
30
|
+
}),
|
|
31
|
+
credentials: 'include'
|
|
32
|
+
}).then((response) => {
|
|
33
|
+
if (response.ok) {
|
|
34
|
+
console.info('Affiliate placement recorded for partner:', partner);
|
|
35
|
+
}
|
|
36
|
+
}).finally(() => {
|
|
37
|
+
const url = new URL(window.location.href);
|
|
38
|
+
url.searchParams.delete('partner');
|
|
39
|
+
replaceState(url, {});
|
|
40
|
+
showModal = false;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<Modal
|
|
46
|
+
title="Referred by {partner}"
|
|
47
|
+
bind:show={showModal}
|
|
48
|
+
closeOnOutsideClick={false}
|
|
49
|
+
footer={
|
|
50
|
+
{
|
|
51
|
+
cancel: {
|
|
52
|
+
text: "Do not track"
|
|
53
|
+
},
|
|
54
|
+
confirm: {
|
|
55
|
+
text: "Ok, Visit Site",
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
on:confirm={handleConsent}
|
|
60
|
+
>
|
|
61
|
+
<div class="notice">
|
|
62
|
+
You visited our site through our affiliate partner <strong>{partner}</strong>. To track this referral, we will place a small
|
|
63
|
+
cookie in your browser. This cookie helps us identify which affiliate partner referred you
|
|
64
|
+
if you sign up. It does not collect any personal data.
|
|
65
|
+
</div>
|
|
66
|
+
<p>
|
|
67
|
+
You can read more in our <Link href="https://hyvor.com/privacy" target="_blank">Privacy Policy</Link>.
|
|
68
|
+
</p>
|
|
69
|
+
</Modal>
|
|
70
|
+
|
|
71
|
+
<style>
|
|
72
|
+
.notice {
|
|
73
|
+
line-height: 24px;
|
|
74
|
+
}
|
|
75
|
+
</style>
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import LanguageToggle from '../../components/Internationalization/LanguageToggle.svelte';
|
|
14
14
|
import IconBluesky from '@hyvor/icons/IconBluesky';
|
|
15
15
|
import { SOCIAL_LINKS, type Socials } from '../social.js';
|
|
16
|
+
import Affiliate from '../Affiliate/Affiliate.svelte';
|
|
16
17
|
|
|
17
18
|
const year = new Date().getFullYear();
|
|
18
19
|
|
|
@@ -20,12 +21,14 @@
|
|
|
20
21
|
email?: string | null;
|
|
21
22
|
social?: Partial<Socials>;
|
|
22
23
|
center?: import('svelte').Snippet;
|
|
24
|
+
affiliate?: boolean;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
let {
|
|
26
28
|
email = null,
|
|
27
29
|
social = $bindable({} as Record<string, string | null>),
|
|
28
|
-
center
|
|
30
|
+
center,
|
|
31
|
+
affiliate = true
|
|
29
32
|
}: Props = $props();
|
|
30
33
|
|
|
31
34
|
social = {
|
|
@@ -109,6 +112,11 @@
|
|
|
109
112
|
<div class="footer-bottom-right">From France 🇫🇷</div>
|
|
110
113
|
</div>
|
|
111
114
|
</Container>
|
|
115
|
+
|
|
116
|
+
{#if affiliate}
|
|
117
|
+
<Affiliate />
|
|
118
|
+
{/if}
|
|
119
|
+
|
|
112
120
|
</footer>
|
|
113
121
|
|
|
114
122
|
<style>
|
package/package.json
CHANGED