fulldev-ui 0.6.0-beta.0 → 0.6.0-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/astro.config.ts +10 -2
- package/example.svelte +0 -0
- package/package.json +12 -7
- package/parent.svelte +0 -0
- package/pnpm-lock.yaml +301 -35
- package/src/App.svelte +0 -0
- package/src/blocks/Products.astro +53 -72
- package/src/components/Card.astro +2 -2
- package/src/components/Cart.astro +12 -3
- package/src/components/CartAdd.svelte +76 -0
- package/src/components/CartCheckout.svelte +58 -0
- package/src/components/CartForm.astro +87 -88
- package/src/components/CartForm.svelte +130 -0
- package/src/components/CartList.astro +84 -79
- package/src/components/CartList.svelte +88 -0
- package/src/components/CartQuantity.svelte +81 -0
- package/src/components/CartSummary.astro +8 -94
- package/src/components/CartTotal.svelte +15 -0
- package/src/components/Dialog.astro +1 -0
- package/src/components/Drawer.astro +1 -0
- package/src/components/Gallery.astro +3 -1
- package/src/components/Header.astro +2 -0
- package/src/components/Image.astro +2 -2
- package/src/components/Input.astro +17 -9
- package/src/components/ProductCard.astro +52 -0
- package/src/components/Prose.astro +1 -1
- package/src/components/Search.astro +106 -43
- package/src/components/Section.astro +11 -269
- package/src/components/Select.astro +1 -0
- package/src/components/_CartList backup.astro +125 -0
- package/src/components/_CartList copy.astro +213 -0
- package/src/components/_CartListSimple.astro +148 -0
- package/src/content/categories/mugs.md +7 -0
- package/src/content/config.ts +24 -4
- package/src/content/{pages/docs → docs}/_internationalization.mdx +0 -1
- package/src/content/{pages/docs → docs}/_using-blocks.mdx +0 -1
- package/src/content/{pages/docs → docs}/_using-presets.mdx +0 -1
- package/src/content/{pages/docs → docs}/blocks.mdx +0 -1
- package/src/content/{pages/docs → docs}/collections/images.mdx +3 -2
- package/src/content/{pages/docs → docs}/collections/pages.mdx +0 -1
- package/src/content/{pages/docs → docs}/collections/presets.mdx +0 -1
- package/src/content/{pages/docs → docs}/collections.mdx +0 -1
- package/src/content/{pages/docs → docs}/components/_card.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/_dialog.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/_drawer.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/_localeswitcher.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/_switch.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/_tagline.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/_toggle.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/avatar.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/badge.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/badges.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/button.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/buttons.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/channel.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/channels.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/checkbox.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/code.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/heading.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/icon.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/image.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/input.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/label.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/lead.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/link.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/links.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/list.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/logo.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/menu.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/paragraph.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/prose.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/rating.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/section.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/select.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/social.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/socials.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/switch.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/table.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/tagline.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/textarea.mdx +0 -2
- package/src/content/{pages/docs → docs}/components/themer.mdx +0 -2
- package/src/content/{pages/docs → docs}/components.mdx +0 -1
- package/src/content/{pages/docs → docs}/customization.mdx +0 -1
- package/src/content/{pages/docs → docs}/frameworks.mdx +0 -1
- package/src/content/{pages/docs → docs}/generating-pages.mdx +0 -1
- package/src/content/{pages/docs → docs}/index.mdx +0 -1
- package/src/content/{pages/docs → docs}/installation.mdx +0 -1
- package/src/content/{pages/docs → docs}/layouts.mdx +0 -1
- package/src/content/layouts/base.yml +101 -0
- package/src/content/layouts/docs.yml +70 -0
- package/src/content/pages/blocks/_categories.mdx +0 -2
- package/src/content/pages/blocks/_footer.mdx +0 -2
- package/src/content/pages/blocks/_header.mdx +0 -2
- package/src/content/pages/blocks/_jobs.mdx +0 -2
- package/src/content/pages/blocks/_prices.mdx +0 -2
- package/src/content/pages/blocks/_product.mdx +0 -2
- package/src/content/pages/blocks/_products.mdx +0 -2
- package/src/content/pages/blocks/_stats.mdx +0 -2
- package/src/content/pages/blocks/banner.mdx +0 -2
- package/src/content/pages/blocks/colleagues.mdx +0 -2
- package/src/content/pages/blocks/contact.mdx +0 -2
- package/src/content/pages/blocks/content.mdx +0 -2
- package/src/content/pages/blocks/cta.mdx +0 -2
- package/src/content/pages/blocks/features.mdx +0 -2
- package/src/content/pages/blocks/hero.mdx +0 -2
- package/src/content/pages/blocks/intro.mdx +0 -2
- package/src/content/pages/blocks/posts.mdx +0 -2
- package/src/content/pages/blocks/reviews.mdx +0 -2
- package/src/content/pages/index.mdx +0 -2
- package/src/content/pages/showcase/anti-slip-profiles.md +2 -2
- package/src/content/pages/showcase/fulldev-ui.md +1 -1
- package/src/content/pages/showcase/lavis-detailing.md +1 -1
- package/src/content/pages/showcase/leren-trainingsacteren.md +1 -1
- package/src/content/pages/showcase/miele-witgoedcenter-amsterdam.md +1 -1
- package/src/content/pages/showcase/sloepverhuur-bolsward.md +1 -1
- package/src/content/pages/showcase/stark-vulcanising-products.md +1 -1
- package/src/content/pages/showcase/the-gym-haren.md +1 -1
- package/src/content/pages/showcase/van-dillen-antieke-bouwmaterialen.md +1 -1
- package/src/content/pages/showcase.mdx +0 -1
- package/src/content/products/product.md +20 -0
- package/src/env.d.ts +1 -0
- package/src/integration/index.ts +20 -8
- package/src/layouts/CategoryLayout.astro +12 -17
- package/src/layouts/DocLayout.astro +17 -0
- package/src/layouts/Layout.astro +11 -40
- package/src/layouts/PageLayout.astro +6 -12
- package/src/layouts/PostLayout.astro +6 -12
- package/src/layouts/ProductLayout.astro +28 -33
- package/src/pages/[...category].astro +17 -0
- package/src/pages/[...doc].astro +17 -0
- package/src/pages/[...page].astro +6 -25
- package/src/pages/[...post].astro +17 -0
- package/src/pages/[...product].astro +17 -0
- package/src/pages/test.astro +1 -16
- package/src/schemas/archive/_pageSchema.ts +94 -0
- package/src/schemas/categorySchema.ts +16 -0
- package/src/schemas/components/banner.ts +3 -0
- package/src/schemas/components/card.ts +1 -1
- package/src/schemas/components/footer.ts +1 -0
- package/src/schemas/components/header.ts +1 -0
- package/src/schemas/components/link.ts +21 -14
- package/src/schemas/components/section.ts +2 -0
- package/src/schemas/components/sections.ts +1 -1
- package/src/schemas/components/sidebar.ts +1 -0
- package/src/schemas/components/subheader.ts +1 -0
- package/src/schemas/components/writeup.ts +1 -1
- package/src/schemas/docSchema.ts +10 -0
- package/src/schemas/fields/categories.ts +3 -0
- package/src/schemas/fields/description.ts +3 -0
- package/src/schemas/fields/href.ts +3 -0
- package/src/schemas/fields/image.ts +24 -0
- package/src/schemas/fields/images.ts +4 -0
- package/src/schemas/fields/order.ts +3 -0
- package/src/schemas/fields/price.ts +3 -0
- package/src/schemas/fields/products.ts +5 -0
- package/src/schemas/fields/seo.ts +12 -0
- package/src/schemas/fields/soldout.ts +3 -0
- package/src/schemas/{components/price.ts → fields/title.ts} +1 -1
- package/src/schemas/fields/variants.ts +3 -0
- package/src/schemas/layoutSchema.ts +28 -0
- package/src/schemas/pageSchema.ts +12 -86
- package/src/schemas/postSchema.ts +16 -0
- package/src/schemas/productSchema.ts +22 -0
- package/src/stores/cart.svelte.ts +79 -0
- package/src/stores/cart.ts +59 -6
- package/src/utils/formatEntries.ts +8 -0
- package/src/utils/formatEntry.ts +29 -0
- package/src/utils/getHref.ts +22 -0
- package/svelte.config.js +5 -0
- package/src/content/presets/base.yml +0 -100
- package/src/content/presets/docs.yml +0 -6
- package/src/schemas/components/images.ts +0 -4
- package/src/schemas/presetSchema.ts +0 -3
- package/src/schemas/utils/categories.ts +0 -3
- package/src/schemas/utils/navigation.ts +0 -8
|
@@ -1,89 +1,89 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Element from 'fulldev-ui/components/Element.astro'
|
|
3
|
+
import { scope } from 'simple:scope'
|
|
3
4
|
import Button from './Button.astro'
|
|
4
5
|
import Heading from './Heading.astro'
|
|
5
|
-
import
|
|
6
|
+
import Input from './Input.astro'
|
|
7
|
+
import Price from './Price.astro'
|
|
6
8
|
|
|
7
9
|
const { ...rest } = Astro.props
|
|
8
10
|
---
|
|
9
11
|
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<Element class="
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
12
|
+
<RootElement>
|
|
13
|
+
<Element
|
|
14
|
+
data-target={scope('list')}
|
|
15
|
+
class:list={'cart-list'}
|
|
16
|
+
if={true}
|
|
17
|
+
{...rest}
|
|
18
|
+
/>
|
|
19
|
+
|
|
20
|
+
<template data-target={scope('template')}>
|
|
21
|
+
<Element class="cart-list-card">
|
|
22
|
+
<img class="image" />
|
|
23
|
+
<Element class="cart-list-card-segment">
|
|
24
|
+
<Element class="cart-list-card-content">
|
|
25
|
+
<Heading
|
|
26
|
+
if
|
|
27
|
+
level={6}
|
|
28
|
+
/>
|
|
29
|
+
<Price if />
|
|
30
|
+
</Element>
|
|
31
|
+
<Element class="cart-list-card-actions">
|
|
32
|
+
<Input
|
|
33
|
+
type="number"
|
|
34
|
+
name="quantity"
|
|
35
|
+
value={1}
|
|
36
|
+
min={0}
|
|
37
|
+
/>
|
|
38
|
+
<Button
|
|
39
|
+
type="button"
|
|
40
|
+
variant="outline"
|
|
41
|
+
icon="trash"
|
|
42
|
+
type="button"
|
|
43
|
+
/>
|
|
44
|
+
</Element>
|
|
36
45
|
</Element>
|
|
37
46
|
</Element>
|
|
38
|
-
</
|
|
39
|
-
</
|
|
47
|
+
</template>
|
|
48
|
+
</RootElement>
|
|
40
49
|
|
|
41
50
|
<script>
|
|
42
|
-
import { $cart } from 'fulldev-ui/stores/cart.ts'
|
|
51
|
+
import { $cart, removeItem, updateQuantity } from 'fulldev-ui/stores/cart.ts'
|
|
43
52
|
import { formatPrice } from 'fulldev-ui/utils/cart'
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
$cart.set(newCart)
|
|
54
|
+
RootElement.ready(($) => {
|
|
55
|
+
$cart.subscribe((items) => {
|
|
56
|
+
const list = $('list')
|
|
57
|
+
const template = $('template') as HTMLTemplateElement
|
|
58
|
+
|
|
59
|
+
// list.innerHTML = ''
|
|
60
|
+
items.forEach((item) => {
|
|
61
|
+
const clone = template?.content.cloneNode(true) as HTMLElement
|
|
62
|
+
const clonedCard = clone.querySelector('.cart-list-card') as HTMLElement
|
|
63
|
+
const existingCard = list.querySelector(`[data-slug="${item.slug}"]`)
|
|
64
|
+
const card = existingCard || (clonedCard as HTMLElement)
|
|
65
|
+
const heading = card.querySelector('.heading') as HTMLElement
|
|
66
|
+
const price = card.querySelector('.price') as HTMLElement
|
|
67
|
+
const image = card.querySelector('.image') as HTMLImageElement
|
|
68
|
+
const remove = card.querySelector('.button') as HTMLButtonElement
|
|
69
|
+
const quantity = card.querySelector('.input') as HTMLInputElement
|
|
70
|
+
|
|
71
|
+
card.dataset.slug = item.slug
|
|
72
|
+
heading.textContent = item.title
|
|
73
|
+
price.textContent = formatPrice(item.price)
|
|
74
|
+
image.src = item.image
|
|
75
|
+
|
|
76
|
+
remove.addEventListener('click', () => removeItem(item.slug))
|
|
77
|
+
|
|
78
|
+
quantity.addEventListener('change', (e) => {
|
|
79
|
+
console.log('blur')
|
|
80
|
+
const target = e.target as HTMLInputElement
|
|
81
|
+
const value = Number(target.value)
|
|
82
|
+
updateQuantity(item.slug, value)
|
|
75
83
|
})
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
container.appendChild(clone)
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
document.addEventListener('astro:page-load', () => {
|
|
83
|
-
setCards($cart.get())
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
$('list').appendChild(clone)
|
|
86
|
+
})
|
|
87
87
|
})
|
|
88
88
|
})
|
|
89
89
|
</script>
|
|
@@ -99,18 +99,23 @@ const { ...rest } = Astro.props
|
|
|
99
99
|
&:not(:first-child) {
|
|
100
100
|
@apply mt-5 border-t pt-5;
|
|
101
101
|
}
|
|
102
|
+
}
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
.image {
|
|
105
|
+
@apply block h-auto w-24;
|
|
106
|
+
}
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
.cart-list-card-segment {
|
|
109
|
+
@apply flex h-full w-full flex-col justify-between gap-4;
|
|
110
|
+
}
|
|
110
111
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
.cart-list-card-content,
|
|
113
|
+
.cart-list-card-actions {
|
|
114
|
+
@apply flex justify-between gap-2;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.input {
|
|
118
|
+
@apply w-16;
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
121
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cart } from 'fulldev-ui/stores/cart.svelte.ts'
|
|
3
|
+
import { formatPrice } from 'fulldev-ui/utils/cart'
|
|
4
|
+
import CartQuantity from './CartQuantity.svelte'
|
|
5
|
+
|
|
6
|
+
function removeItem(index: number) {
|
|
7
|
+
cart.update((currentCart) => {
|
|
8
|
+
currentCart.splice(index, 1)
|
|
9
|
+
return [...currentCart]
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<div class="cart-list">
|
|
15
|
+
{#each $cart as item, index}
|
|
16
|
+
<div
|
|
17
|
+
class="cart-list-card"
|
|
18
|
+
data-slug={item.slug}
|
|
19
|
+
>
|
|
20
|
+
<img
|
|
21
|
+
class="image"
|
|
22
|
+
src={item.image}
|
|
23
|
+
alt={item.title}
|
|
24
|
+
/>
|
|
25
|
+
<div class="cart-list-card-segment">
|
|
26
|
+
<div class="cart-list-card-content">
|
|
27
|
+
<h3 class="heading">{item.title}</h3>
|
|
28
|
+
{#if item.price}
|
|
29
|
+
<div class="price">{formatPrice(item.price)}</div>
|
|
30
|
+
{/if}
|
|
31
|
+
</div>
|
|
32
|
+
<div class="cart-list-card-actions">
|
|
33
|
+
<CartQuantity bind:value={item.quantity} />
|
|
34
|
+
<button
|
|
35
|
+
class="button variant-outline size-sm"
|
|
36
|
+
type="button"
|
|
37
|
+
aria-label="trash"
|
|
38
|
+
on:click={() => removeItem(index)}
|
|
39
|
+
>
|
|
40
|
+
<svg
|
|
41
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
42
|
+
viewBox="0 0 24 24"
|
|
43
|
+
class="icon size-md"
|
|
44
|
+
>
|
|
45
|
+
<path
|
|
46
|
+
fill="none"
|
|
47
|
+
stroke="currentColor"
|
|
48
|
+
stroke-linecap="round"
|
|
49
|
+
stroke-linejoin="round"
|
|
50
|
+
stroke-width="2"
|
|
51
|
+
d="M4 7h16m-10 4v6m4-6v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3"
|
|
52
|
+
></path>
|
|
53
|
+
</svg>
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
{/each}
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<style lang="postcss">
|
|
62
|
+
@layer fulldev {
|
|
63
|
+
.cart-list {
|
|
64
|
+
@apply flex flex-col text-foreground;
|
|
65
|
+
|
|
66
|
+
.cart-list-card {
|
|
67
|
+
@apply flex w-full gap-5;
|
|
68
|
+
|
|
69
|
+
&:not(:first-child) {
|
|
70
|
+
@apply mt-5 border-t pt-5;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.image {
|
|
75
|
+
@apply block h-auto w-24;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.cart-list-card-segment {
|
|
79
|
+
@apply flex h-full w-full flex-col justify-between gap-4;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.cart-list-card-content,
|
|
83
|
+
.cart-list-card-actions {
|
|
84
|
+
@apply flex justify-between gap-2;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
</style>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tick } from 'svelte'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
value: number
|
|
6
|
+
size?: 'sm' | 'md' | 'lg'
|
|
7
|
+
change?: (quantity: number) => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { value = $bindable(), size = 'md', change }: Props = $props()
|
|
11
|
+
let inputElement: HTMLInputElement | null = $state(null)
|
|
12
|
+
|
|
13
|
+
let quantity = $state(value)
|
|
14
|
+
|
|
15
|
+
async function handleChange() {
|
|
16
|
+
value = quantity
|
|
17
|
+
if (change) change(value)
|
|
18
|
+
if (value === 11) {
|
|
19
|
+
await tick()
|
|
20
|
+
inputElement?.focus()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<label
|
|
26
|
+
class="quantity input select size-{size}"
|
|
27
|
+
for="quantity"
|
|
28
|
+
>
|
|
29
|
+
{#if value > 10}
|
|
30
|
+
<input
|
|
31
|
+
bind:this={inputElement}
|
|
32
|
+
bind:value={quantity}
|
|
33
|
+
class="input-input"
|
|
34
|
+
name="quantity"
|
|
35
|
+
type="number"
|
|
36
|
+
min={1}
|
|
37
|
+
onchange={handleChange}
|
|
38
|
+
/>
|
|
39
|
+
{:else}
|
|
40
|
+
<svg
|
|
41
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
42
|
+
viewBox="0 0 24 24"
|
|
43
|
+
class="icon size-{size}"
|
|
44
|
+
>
|
|
45
|
+
<path
|
|
46
|
+
fill="none"
|
|
47
|
+
stroke="currentColor"
|
|
48
|
+
stroke-linecap="round"
|
|
49
|
+
stroke-linejoin="round"
|
|
50
|
+
stroke-width="2"
|
|
51
|
+
d="m6 9l6 6l6-6"
|
|
52
|
+
></path>
|
|
53
|
+
</svg>
|
|
54
|
+
<select
|
|
55
|
+
class="select-select"
|
|
56
|
+
bind:value={quantity}
|
|
57
|
+
onchange={handleChange}
|
|
58
|
+
>
|
|
59
|
+
{#each Array(10) as _, i}
|
|
60
|
+
<option
|
|
61
|
+
value={i + 1}
|
|
62
|
+
selected={value === i + 1}
|
|
63
|
+
>
|
|
64
|
+
{i + 1}
|
|
65
|
+
</option>
|
|
66
|
+
{/each}
|
|
67
|
+
<option
|
|
68
|
+
value={11}
|
|
69
|
+
selected={value > 10}
|
|
70
|
+
>
|
|
71
|
+
Meer
|
|
72
|
+
</option>
|
|
73
|
+
</select>
|
|
74
|
+
{/if}
|
|
75
|
+
</label>
|
|
76
|
+
|
|
77
|
+
<style lang="postcss">
|
|
78
|
+
.quantity {
|
|
79
|
+
@apply w-20;
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
2
|
+
import { STRIPE_RESTRICTED_KEY, URL } from 'astro:env/client'
|
|
3
|
+
import CartCheckout from './CartCheckout.svelte'
|
|
4
|
+
import CartTotal from './CartTotal.svelte'
|
|
3
5
|
import Element from './Element.astro'
|
|
4
|
-
import Price from './Price.astro'
|
|
5
6
|
import Text from './Text.astro'
|
|
6
7
|
|
|
7
8
|
interface Props {}
|
|
@@ -22,16 +23,16 @@ const { ...rest } = Astro.props
|
|
|
22
23
|
text="Totaal"
|
|
23
24
|
contrast
|
|
24
25
|
/>
|
|
25
|
-
<
|
|
26
|
+
<CartTotal client:load />
|
|
26
27
|
</div>
|
|
27
28
|
<Text
|
|
28
29
|
class:list="shipping"
|
|
29
30
|
text="Verzendkosten worden berekend bij het afrekenen."
|
|
30
31
|
/>
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
<CartCheckout
|
|
33
|
+
{STRIPE_RESTRICTED_KEY}
|
|
34
|
+
{URL}
|
|
35
|
+
client:load
|
|
35
36
|
/>
|
|
36
37
|
</Element>
|
|
37
38
|
|
|
@@ -55,90 +56,3 @@ const { ...rest } = Astro.props
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
</style>
|
|
58
|
-
|
|
59
|
-
<script>
|
|
60
|
-
import { STRIPE_RESTRICTED_KEY, URL } from 'astro:env/client'
|
|
61
|
-
import { $cart } from 'fulldev-ui/stores/cart.ts'
|
|
62
|
-
import { formatPrice } from 'fulldev-ui/utils/cart'
|
|
63
|
-
import Stripe from 'stripe'
|
|
64
|
-
|
|
65
|
-
function setPrice(items: any) {
|
|
66
|
-
const price = document.querySelector('.cart-summary .price')
|
|
67
|
-
console.log('settings price', price)
|
|
68
|
-
if (price)
|
|
69
|
-
price.textContent = formatPrice(
|
|
70
|
-
items.reduce(
|
|
71
|
-
(acc: number, item: { price: number }) => acc + item.price,
|
|
72
|
-
0
|
|
73
|
-
)
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
document.addEventListener('astro:page-load', () => {
|
|
78
|
-
if (!STRIPE_RESTRICTED_KEY) return
|
|
79
|
-
const stripe = new Stripe(STRIPE_RESTRICTED_KEY)
|
|
80
|
-
setPrice($cart.get())
|
|
81
|
-
|
|
82
|
-
$cart.subscribe((items: any) => {
|
|
83
|
-
setPrice(items)
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
const button = document.querySelector('.cart-summary .checkout-button')
|
|
87
|
-
|
|
88
|
-
button?.addEventListener('click', async () => {
|
|
89
|
-
const items = $cart.get()
|
|
90
|
-
|
|
91
|
-
const checkoutConfig = {
|
|
92
|
-
success_url: `${URL}/checkout`,
|
|
93
|
-
mode: 'payment',
|
|
94
|
-
customer_creation: 'always',
|
|
95
|
-
shipping_address_collection: {
|
|
96
|
-
allowed_countries: ['NL'],
|
|
97
|
-
},
|
|
98
|
-
phone_number_collection: {
|
|
99
|
-
enabled: true,
|
|
100
|
-
},
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const lineItems = items.map((item: any) => ({
|
|
105
|
-
price_data: {
|
|
106
|
-
currency: 'eur',
|
|
107
|
-
product: item.id,
|
|
108
|
-
},
|
|
109
|
-
quantity: 1,
|
|
110
|
-
}))
|
|
111
|
-
|
|
112
|
-
// @ts-ignore
|
|
113
|
-
const checkoutSession = await stripe.checkout.sessions.create({
|
|
114
|
-
line_items: lineItems,
|
|
115
|
-
...checkoutConfig,
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
checkoutSession.url && window.location.replace(checkoutSession.url)
|
|
119
|
-
} catch (error) {
|
|
120
|
-
console.error(error)
|
|
121
|
-
|
|
122
|
-
const lineItems = items.map((item: any) => ({
|
|
123
|
-
quantity: 1,
|
|
124
|
-
price_data: {
|
|
125
|
-
currency: 'eur',
|
|
126
|
-
product_data: {
|
|
127
|
-
name: item.name,
|
|
128
|
-
images: [URL + item.image],
|
|
129
|
-
},
|
|
130
|
-
unit_amount: Math.round(item.price * 100),
|
|
131
|
-
},
|
|
132
|
-
}))
|
|
133
|
-
|
|
134
|
-
// @ts-ignore
|
|
135
|
-
const checkoutSession = await stripe.checkout.sessions.create({
|
|
136
|
-
line_items: lineItems,
|
|
137
|
-
...checkoutConfig,
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
checkoutSession.url && window.location.replace(checkoutSession.url)
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
})
|
|
144
|
-
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cart } from 'fulldev-ui/stores/cart.svelte.ts'
|
|
3
|
+
import { formatPrice } from 'fulldev-ui/utils/cart'
|
|
4
|
+
|
|
5
|
+
let total = $derived(
|
|
6
|
+
$cart.reduce(
|
|
7
|
+
(acc, item) => acc + (item.price || 0) * (item.quantity || 0),
|
|
8
|
+
0
|
|
9
|
+
)
|
|
10
|
+
)
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div>
|
|
14
|
+
{formatPrice(total)}
|
|
15
|
+
</div>
|
|
@@ -5,7 +5,9 @@ import Element from 'fulldev-ui/components/Element.astro'
|
|
|
5
5
|
import Image from 'fulldev-ui/components/Image.astro'
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
8
|
-
images
|
|
8
|
+
images?:
|
|
9
|
+
| (ComponentProps<typeof Image> | ComponentProps<typeof Image>['src'])[]
|
|
10
|
+
| undefined
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
const { images } = Astro.props
|
|
@@ -10,6 +10,7 @@ import Menu from 'fulldev-ui/components/Menu.astro'
|
|
|
10
10
|
import Socials from 'fulldev-ui/components/Socials.astro'
|
|
11
11
|
import Themer from 'fulldev-ui/components/Themer.astro'
|
|
12
12
|
import type { GlobalProps } from 'fulldev-ui/types/global-props'
|
|
13
|
+
import Search from './Search.astro'
|
|
13
14
|
|
|
14
15
|
interface Props extends GlobalProps, HTMLAttributes<'header'> {
|
|
15
16
|
logo?: ComponentProps<typeof Logo>
|
|
@@ -71,6 +72,7 @@ const {
|
|
|
71
72
|
{size}
|
|
72
73
|
{buttons}
|
|
73
74
|
>
|
|
75
|
+
<Search size="sm" />
|
|
74
76
|
<Themer
|
|
75
77
|
if={themer}
|
|
76
78
|
{size}
|
|
@@ -5,9 +5,9 @@ import type { HTMLAttributes } from 'astro/types'
|
|
|
5
5
|
import { Image as AstroImage } from 'astro:assets'
|
|
6
6
|
import { getEntry } from 'astro:content'
|
|
7
7
|
|
|
8
|
-
interface Props extends HTMLAttributes<'img'> {
|
|
9
|
-
size?: 'sm' | 'md' | 'lg' | undefined
|
|
8
|
+
interface Props extends GlobalProps, HTMLAttributes<'img'> {
|
|
10
9
|
id?: any
|
|
10
|
+
size?: 'sm' | 'md' | 'lg' | undefined
|
|
11
11
|
position?: 'background' | 'cover' | 'inset' | undefined
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -16,6 +16,10 @@ const {
|
|
|
16
16
|
name = label || placeholder,
|
|
17
17
|
id = name,
|
|
18
18
|
type = 'text',
|
|
19
|
+
min,
|
|
20
|
+
max,
|
|
21
|
+
value,
|
|
22
|
+
step,
|
|
19
23
|
size = 'md',
|
|
20
24
|
icon,
|
|
21
25
|
...rest
|
|
@@ -27,6 +31,7 @@ const {
|
|
|
27
31
|
as="label"
|
|
28
32
|
for={id}
|
|
29
33
|
{size}
|
|
34
|
+
{...rest}
|
|
30
35
|
>
|
|
31
36
|
<Label
|
|
32
37
|
for={name}
|
|
@@ -42,12 +47,23 @@ const {
|
|
|
42
47
|
{name}
|
|
43
48
|
{placeholder}
|
|
44
49
|
{type}
|
|
45
|
-
{
|
|
50
|
+
{min}
|
|
51
|
+
{max}
|
|
52
|
+
{value}
|
|
53
|
+
{step}
|
|
46
54
|
/>
|
|
47
55
|
</Element>
|
|
48
56
|
|
|
49
57
|
<style is:global>
|
|
50
58
|
@layer fulldev {
|
|
59
|
+
.input-input {
|
|
60
|
+
@apply flex w-full rounded-md border border-input bg-background text-sm text-foreground ring-offset-background;
|
|
61
|
+
@apply file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground;
|
|
62
|
+
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2;
|
|
63
|
+
@apply disabled:pointer-events-none disabled:opacity-50;
|
|
64
|
+
@apply [&[readonly]]:pointer-events-none;
|
|
65
|
+
}
|
|
66
|
+
|
|
51
67
|
.input {
|
|
52
68
|
@apply relative flex flex-col gap-1.5;
|
|
53
69
|
|
|
@@ -55,14 +71,6 @@ const {
|
|
|
55
71
|
@apply pointer-events-none absolute;
|
|
56
72
|
}
|
|
57
73
|
|
|
58
|
-
.input-input {
|
|
59
|
-
@apply flex w-full rounded-md border border-input bg-background text-sm ring-offset-background;
|
|
60
|
-
@apply file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground;
|
|
61
|
-
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2;
|
|
62
|
-
@apply disabled:pointer-events-none disabled:opacity-50;
|
|
63
|
-
@apply [&[readonly]]:pointer-events-none;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
74
|
&.size-sm {
|
|
67
75
|
@apply gap-1;
|
|
68
76
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { CollectionEntry } from 'astro:content'
|
|
3
|
+
import Element from 'fulldev-ui/components/Element.astro'
|
|
4
|
+
import Heading from 'fulldev-ui/components/Heading.astro'
|
|
5
|
+
import Image from 'fulldev-ui/components/Image.astro'
|
|
6
|
+
import Price from 'fulldev-ui/components/Price.astro'
|
|
7
|
+
import type { ProductSchema } from 'fulldev-ui/schemas/productSchema'
|
|
8
|
+
|
|
9
|
+
interface Props extends ProductSchema {
|
|
10
|
+
slug?: CollectionEntry<'products'>['slug']
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { slug, images, title, price, ...rest } = Astro.props
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<Element
|
|
17
|
+
class:list="product-card"
|
|
18
|
+
as="a"
|
|
19
|
+
href={`/producten/${slug}/`}
|
|
20
|
+
{...rest}
|
|
21
|
+
>
|
|
22
|
+
<Image {...images?.[0]} />
|
|
23
|
+
<Element class:list="product-card-content">
|
|
24
|
+
<Heading
|
|
25
|
+
as="h3"
|
|
26
|
+
level={5}
|
|
27
|
+
size={'sm'}
|
|
28
|
+
text={title}
|
|
29
|
+
/>
|
|
30
|
+
<Price value={price} />
|
|
31
|
+
</Element>
|
|
32
|
+
</Element>
|
|
33
|
+
|
|
34
|
+
<style is:global>
|
|
35
|
+
@layer fulldev {
|
|
36
|
+
.product-card {
|
|
37
|
+
@apply relative flex flex-col gap-3;
|
|
38
|
+
|
|
39
|
+
&:hover > .image {
|
|
40
|
+
@apply opacity-75 transition-opacity;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.image {
|
|
44
|
+
@apply rounded-md border;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.product-card-content {
|
|
48
|
+
@apply flex h-full flex-col gap-2;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
@@ -13,7 +13,7 @@ import type Sidebar from './Sidebar.astro'
|
|
|
13
13
|
|
|
14
14
|
interface Props extends HTMLAttributes<'div'> {
|
|
15
15
|
as?: HTMLTag | undefined
|
|
16
|
-
render
|
|
16
|
+
render?: any
|
|
17
17
|
sidebar?: ComponentProps<typeof Sidebar> | undefined
|
|
18
18
|
slug?: CollectionEntry<'pages'>['slug'] | undefined
|
|
19
19
|
toc?: boolean | ComponentProps<typeof Toc>['heading'] | undefined
|