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.
Files changed (175) hide show
  1. package/astro.config.ts +10 -2
  2. package/example.svelte +0 -0
  3. package/package.json +12 -7
  4. package/parent.svelte +0 -0
  5. package/pnpm-lock.yaml +301 -35
  6. package/src/App.svelte +0 -0
  7. package/src/blocks/Products.astro +53 -72
  8. package/src/components/Card.astro +2 -2
  9. package/src/components/Cart.astro +12 -3
  10. package/src/components/CartAdd.svelte +76 -0
  11. package/src/components/CartCheckout.svelte +58 -0
  12. package/src/components/CartForm.astro +87 -88
  13. package/src/components/CartForm.svelte +130 -0
  14. package/src/components/CartList.astro +84 -79
  15. package/src/components/CartList.svelte +88 -0
  16. package/src/components/CartQuantity.svelte +81 -0
  17. package/src/components/CartSummary.astro +8 -94
  18. package/src/components/CartTotal.svelte +15 -0
  19. package/src/components/Dialog.astro +1 -0
  20. package/src/components/Drawer.astro +1 -0
  21. package/src/components/Gallery.astro +3 -1
  22. package/src/components/Header.astro +2 -0
  23. package/src/components/Image.astro +2 -2
  24. package/src/components/Input.astro +17 -9
  25. package/src/components/ProductCard.astro +52 -0
  26. package/src/components/Prose.astro +1 -1
  27. package/src/components/Search.astro +106 -43
  28. package/src/components/Section.astro +11 -269
  29. package/src/components/Select.astro +1 -0
  30. package/src/components/_CartList backup.astro +125 -0
  31. package/src/components/_CartList copy.astro +213 -0
  32. package/src/components/_CartListSimple.astro +148 -0
  33. package/src/content/categories/mugs.md +7 -0
  34. package/src/content/config.ts +24 -4
  35. package/src/content/{pages/docs → docs}/_internationalization.mdx +0 -1
  36. package/src/content/{pages/docs → docs}/_using-blocks.mdx +0 -1
  37. package/src/content/{pages/docs → docs}/_using-presets.mdx +0 -1
  38. package/src/content/{pages/docs → docs}/blocks.mdx +0 -1
  39. package/src/content/{pages/docs → docs}/collections/images.mdx +3 -2
  40. package/src/content/{pages/docs → docs}/collections/pages.mdx +0 -1
  41. package/src/content/{pages/docs → docs}/collections/presets.mdx +0 -1
  42. package/src/content/{pages/docs → docs}/collections.mdx +0 -1
  43. package/src/content/{pages/docs → docs}/components/_card.mdx +0 -2
  44. package/src/content/{pages/docs → docs}/components/_dialog.mdx +0 -2
  45. package/src/content/{pages/docs → docs}/components/_drawer.mdx +0 -2
  46. package/src/content/{pages/docs → docs}/components/_localeswitcher.mdx +0 -2
  47. package/src/content/{pages/docs → docs}/components/_switch.mdx +0 -2
  48. package/src/content/{pages/docs → docs}/components/_tagline.mdx +0 -2
  49. package/src/content/{pages/docs → docs}/components/_toggle.mdx +0 -2
  50. package/src/content/{pages/docs → docs}/components/avatar.mdx +0 -2
  51. package/src/content/{pages/docs → docs}/components/badge.mdx +0 -2
  52. package/src/content/{pages/docs → docs}/components/badges.mdx +0 -2
  53. package/src/content/{pages/docs → docs}/components/button.mdx +0 -2
  54. package/src/content/{pages/docs → docs}/components/buttons.mdx +0 -2
  55. package/src/content/{pages/docs → docs}/components/channel.mdx +0 -2
  56. package/src/content/{pages/docs → docs}/components/channels.mdx +0 -2
  57. package/src/content/{pages/docs → docs}/components/checkbox.mdx +0 -2
  58. package/src/content/{pages/docs → docs}/components/code.mdx +0 -2
  59. package/src/content/{pages/docs → docs}/components/heading.mdx +0 -2
  60. package/src/content/{pages/docs → docs}/components/icon.mdx +0 -2
  61. package/src/content/{pages/docs → docs}/components/image.mdx +0 -2
  62. package/src/content/{pages/docs → docs}/components/input.mdx +0 -2
  63. package/src/content/{pages/docs → docs}/components/label.mdx +0 -2
  64. package/src/content/{pages/docs → docs}/components/lead.mdx +0 -2
  65. package/src/content/{pages/docs → docs}/components/link.mdx +0 -2
  66. package/src/content/{pages/docs → docs}/components/links.mdx +0 -2
  67. package/src/content/{pages/docs → docs}/components/list.mdx +0 -2
  68. package/src/content/{pages/docs → docs}/components/logo.mdx +0 -2
  69. package/src/content/{pages/docs → docs}/components/menu.mdx +0 -2
  70. package/src/content/{pages/docs → docs}/components/paragraph.mdx +0 -2
  71. package/src/content/{pages/docs → docs}/components/prose.mdx +0 -2
  72. package/src/content/{pages/docs → docs}/components/rating.mdx +0 -2
  73. package/src/content/{pages/docs → docs}/components/section.mdx +0 -2
  74. package/src/content/{pages/docs → docs}/components/select.mdx +0 -2
  75. package/src/content/{pages/docs → docs}/components/social.mdx +0 -2
  76. package/src/content/{pages/docs → docs}/components/socials.mdx +0 -2
  77. package/src/content/{pages/docs → docs}/components/switch.mdx +0 -2
  78. package/src/content/{pages/docs → docs}/components/table.mdx +0 -2
  79. package/src/content/{pages/docs → docs}/components/tagline.mdx +0 -2
  80. package/src/content/{pages/docs → docs}/components/textarea.mdx +0 -2
  81. package/src/content/{pages/docs → docs}/components/themer.mdx +0 -2
  82. package/src/content/{pages/docs → docs}/components.mdx +0 -1
  83. package/src/content/{pages/docs → docs}/customization.mdx +0 -1
  84. package/src/content/{pages/docs → docs}/frameworks.mdx +0 -1
  85. package/src/content/{pages/docs → docs}/generating-pages.mdx +0 -1
  86. package/src/content/{pages/docs → docs}/index.mdx +0 -1
  87. package/src/content/{pages/docs → docs}/installation.mdx +0 -1
  88. package/src/content/{pages/docs → docs}/layouts.mdx +0 -1
  89. package/src/content/layouts/base.yml +101 -0
  90. package/src/content/layouts/docs.yml +70 -0
  91. package/src/content/pages/blocks/_categories.mdx +0 -2
  92. package/src/content/pages/blocks/_footer.mdx +0 -2
  93. package/src/content/pages/blocks/_header.mdx +0 -2
  94. package/src/content/pages/blocks/_jobs.mdx +0 -2
  95. package/src/content/pages/blocks/_prices.mdx +0 -2
  96. package/src/content/pages/blocks/_product.mdx +0 -2
  97. package/src/content/pages/blocks/_products.mdx +0 -2
  98. package/src/content/pages/blocks/_stats.mdx +0 -2
  99. package/src/content/pages/blocks/banner.mdx +0 -2
  100. package/src/content/pages/blocks/colleagues.mdx +0 -2
  101. package/src/content/pages/blocks/contact.mdx +0 -2
  102. package/src/content/pages/blocks/content.mdx +0 -2
  103. package/src/content/pages/blocks/cta.mdx +0 -2
  104. package/src/content/pages/blocks/features.mdx +0 -2
  105. package/src/content/pages/blocks/hero.mdx +0 -2
  106. package/src/content/pages/blocks/intro.mdx +0 -2
  107. package/src/content/pages/blocks/posts.mdx +0 -2
  108. package/src/content/pages/blocks/reviews.mdx +0 -2
  109. package/src/content/pages/index.mdx +0 -2
  110. package/src/content/pages/showcase/anti-slip-profiles.md +2 -2
  111. package/src/content/pages/showcase/fulldev-ui.md +1 -1
  112. package/src/content/pages/showcase/lavis-detailing.md +1 -1
  113. package/src/content/pages/showcase/leren-trainingsacteren.md +1 -1
  114. package/src/content/pages/showcase/miele-witgoedcenter-amsterdam.md +1 -1
  115. package/src/content/pages/showcase/sloepverhuur-bolsward.md +1 -1
  116. package/src/content/pages/showcase/stark-vulcanising-products.md +1 -1
  117. package/src/content/pages/showcase/the-gym-haren.md +1 -1
  118. package/src/content/pages/showcase/van-dillen-antieke-bouwmaterialen.md +1 -1
  119. package/src/content/pages/showcase.mdx +0 -1
  120. package/src/content/products/product.md +20 -0
  121. package/src/env.d.ts +1 -0
  122. package/src/integration/index.ts +20 -8
  123. package/src/layouts/CategoryLayout.astro +12 -17
  124. package/src/layouts/DocLayout.astro +17 -0
  125. package/src/layouts/Layout.astro +11 -40
  126. package/src/layouts/PageLayout.astro +6 -12
  127. package/src/layouts/PostLayout.astro +6 -12
  128. package/src/layouts/ProductLayout.astro +28 -33
  129. package/src/pages/[...category].astro +17 -0
  130. package/src/pages/[...doc].astro +17 -0
  131. package/src/pages/[...page].astro +6 -25
  132. package/src/pages/[...post].astro +17 -0
  133. package/src/pages/[...product].astro +17 -0
  134. package/src/pages/test.astro +1 -16
  135. package/src/schemas/archive/_pageSchema.ts +94 -0
  136. package/src/schemas/categorySchema.ts +16 -0
  137. package/src/schemas/components/banner.ts +3 -0
  138. package/src/schemas/components/card.ts +1 -1
  139. package/src/schemas/components/footer.ts +1 -0
  140. package/src/schemas/components/header.ts +1 -0
  141. package/src/schemas/components/link.ts +21 -14
  142. package/src/schemas/components/section.ts +2 -0
  143. package/src/schemas/components/sections.ts +1 -1
  144. package/src/schemas/components/sidebar.ts +1 -0
  145. package/src/schemas/components/subheader.ts +1 -0
  146. package/src/schemas/components/writeup.ts +1 -1
  147. package/src/schemas/docSchema.ts +10 -0
  148. package/src/schemas/fields/categories.ts +3 -0
  149. package/src/schemas/fields/description.ts +3 -0
  150. package/src/schemas/fields/href.ts +3 -0
  151. package/src/schemas/fields/image.ts +24 -0
  152. package/src/schemas/fields/images.ts +4 -0
  153. package/src/schemas/fields/order.ts +3 -0
  154. package/src/schemas/fields/price.ts +3 -0
  155. package/src/schemas/fields/products.ts +5 -0
  156. package/src/schemas/fields/seo.ts +12 -0
  157. package/src/schemas/fields/soldout.ts +3 -0
  158. package/src/schemas/{components/price.ts → fields/title.ts} +1 -1
  159. package/src/schemas/fields/variants.ts +3 -0
  160. package/src/schemas/layoutSchema.ts +28 -0
  161. package/src/schemas/pageSchema.ts +12 -86
  162. package/src/schemas/postSchema.ts +16 -0
  163. package/src/schemas/productSchema.ts +22 -0
  164. package/src/stores/cart.svelte.ts +79 -0
  165. package/src/stores/cart.ts +59 -6
  166. package/src/utils/formatEntries.ts +8 -0
  167. package/src/utils/formatEntry.ts +29 -0
  168. package/src/utils/getHref.ts +22 -0
  169. package/svelte.config.js +5 -0
  170. package/src/content/presets/base.yml +0 -100
  171. package/src/content/presets/docs.yml +0 -6
  172. package/src/schemas/components/images.ts +0 -4
  173. package/src/schemas/presetSchema.ts +0 -3
  174. package/src/schemas/utils/categories.ts +0 -3
  175. 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 Text from './Text.astro'
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
- <Element
11
- if
12
- class:list="cart-list"
13
- {...rest}
14
- />
15
-
16
- <template>
17
- <Element class="cart-list-card">
18
- <img class="cart-list-image image" />
19
- <Element class="column">
20
- <Heading
21
- if
22
- level={4}
23
- class="heading"
24
- />
25
- <Element class="row">
26
- <Text
27
- if
28
- class="cart-list-price"
29
- />
30
- <Button
31
- class:list="cart-list-remove"
32
- variant="ghost"
33
- icon="trash"
34
- type="button"
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
- </Element>
39
- </template>
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
- function setCards(items: any) {
46
- const template = document.querySelector('template')
47
- const container = document.querySelector('.cart-list')
48
-
49
- if (!container || !template) return
50
-
51
- container.innerHTML = ''
52
-
53
- items.forEach((item: any, index: number) => {
54
- const clone = template?.content.cloneNode(true)
55
- if (!(clone instanceof DocumentFragment)) return
56
- const card = clone.querySelector('.cart-list-card')
57
- if (!card) return
58
-
59
- const img = card.querySelector('img')
60
- if (img) img.src = item.image
61
-
62
- const h4 = card.querySelector('h4')
63
- if (h4) h4.textContent = item.name
64
-
65
- const p = card.querySelector('p')
66
- if (p) p.textContent = formatPrice(item.price)
67
-
68
- const button = card.querySelector('button')
69
- if (button) {
70
- button.addEventListener('click', () => {
71
- const currentCart = $cart.get()
72
- const newCart = [...currentCart]
73
- newCart.splice(index, 1)
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
- $cart.subscribe((items: any) => {
86
- setCards(items)
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
- .image {
104
- @apply block h-auto w-24;
105
- }
104
+ .image {
105
+ @apply block h-auto w-24;
106
+ }
106
107
 
107
- .column {
108
- @apply flex h-full w-full flex-col justify-between gap-3;
109
- }
108
+ .cart-list-card-segment {
109
+ @apply flex h-full w-full flex-col justify-between gap-4;
110
+ }
110
111
 
111
- .row {
112
- @apply flex w-full flex-row justify-between;
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 Button from './Button.astro'
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
- <Price value={10} />
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
- <Button
32
- class:list="checkout-button"
33
- variant="primary"
34
- text="Afrekenen"
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>
@@ -20,6 +20,7 @@ const {
20
20
  ---
21
21
 
22
22
  <Button
23
+ size="sm"
23
24
  id={`${id}-button`}
24
25
  variant="secondary"
25
26
  onclick={`document.getElementById('${id}').showModal()`}
@@ -63,6 +63,7 @@ const {
63
63
  {...rest}
64
64
  >
65
65
  <Element class:list="drawer-body">
66
+ <button autofocus></button>
66
67
  <Element
67
68
  class:list="drawer-header"
68
69
  as="header"
@@ -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: (ComponentProps<typeof Image> | ComponentProps<typeof Image>['src'])[]
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
- {...rest}
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: CollectionEntry<'pages'>['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