fulldev-ui 0.5.0-beta.5 → 0.5.0-beta.7

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 (42) hide show
  1. package/CONTRIBUTING.md +10 -4
  2. package/astro.config.ts +2 -3
  3. package/package.json +4 -2
  4. package/pnpm-lock.yaml +31 -69
  5. package/src/blocks/Article.astro +31 -12
  6. package/src/blocks/Banner.astro +2 -1
  7. package/src/blocks/Product.astro +11 -21
  8. package/src/components/Card.astro +1 -1
  9. package/src/components/Cart.astro +38 -0
  10. package/src/components/CartForm.astro +121 -0
  11. package/src/components/CartList.astro +134 -0
  12. package/src/components/CartSummary.astro +146 -0
  13. package/src/components/Drawer.astro +41 -8
  14. package/src/components/Footer.astro +0 -1
  15. package/src/components/Form.astro +49 -0
  16. package/src/components/Header.astro +5 -8
  17. package/src/components/Image.astro +0 -1
  18. package/src/components/Input.astro +6 -0
  19. package/src/components/Price.astro +7 -11
  20. package/src/components/Search.astro +1 -4
  21. package/src/components/Section.astro +0 -1
  22. package/src/components/Sidebar.astro +1 -1
  23. package/src/components/Toc.astro +3 -6
  24. package/src/components/docs/PropsTable.astro +1 -1
  25. package/src/components/experimental/Form.astro +29 -5
  26. package/src/content/config.ts +2 -1
  27. package/src/content/pages/base/select.mdx +0 -8
  28. package/src/content/pages/base/textarea.mdx +0 -5
  29. package/src/content/presets/base.yml +1 -2
  30. package/src/content/presets/docs.yml +4 -4
  31. package/src/env.d.ts +1 -1
  32. package/src/layouts/DocsLayout.astro +23 -35
  33. package/src/layouts/Layout.astro +12 -16
  34. package/src/layouts/OverviewLayout.astro +5 -2
  35. package/src/layouts/PostLayout.astro +7 -10
  36. package/src/schemas/pageSchema.ts +53 -28
  37. package/src/schemas/presetSchema.ts +3 -0
  38. package/src/schemas/utils/navigation.ts +5 -1
  39. package/src/stores/cart.ts +23 -0
  40. package/src/utils/cart.ts +36 -0
  41. package/tsconfig.json +1 -3
  42. /package/src/types/{global-props.d.ts → global-props.ts} +0 -0
package/CONTRIBUTING.md CHANGED
@@ -15,19 +15,25 @@ Here lay a few resources we wrote to help you do it!
15
15
  │ ├── content/
16
16
  │ │ ├── pages/
17
17
  │ │ │ └── ...
18
- │ │ ├── settings/
18
+ │ │ ├── presets/
19
19
  │ │ │ └── ...
20
20
  │ │ └── ...
21
21
  │ ├── css/
22
22
  │ │ └── ...
23
+ │ ├── images/
24
+ │ │ └── ...
23
25
  │ ├── integration/
24
26
  │ │ └── ...
25
27
  │ ├── layouts/
26
28
  │ │ └── ...
29
+ │ ├── loaders/
30
+ │ │ └── ...
27
31
  │ ├── pages/
28
32
  │ │ └── ...
29
33
  │ ├── schemas/
30
34
  │ │ └── ...
35
+ │ ├── types/
36
+ │ │ └── ...
31
37
  │ └── utils/
32
38
  │ └── ...
33
39
  ├── public/
@@ -101,9 +107,9 @@ For a faster and easier review we advise you to use [conventional commits](https
101
107
  Have you used fulldev-ui to build a website? Add it to the showcase!
102
108
 
103
109
  1. Fork this repository.
104
- 2. Add a screenshot of your site to the `public/images/showcase/` directory.
105
- 3. Create a file which is your unslugged domain in `src/pages/records/showcase/` for example `src/pages/records/showcase/google-com.mdx`.
106
- 4. Go to the forked repository on your Github and clicke the 'Contribute` button to make a Pull Request.
110
+ 2. Add a screenshot of your site to the `/src/images/showcase/` directory.
111
+ 3. Create a file which in `/src/content/pages/showcase/` for example `/src/content/pages/showcase/google.md`.
112
+ 4. Go to the forked repository on your Github and clicke the "Contribute" button to make a Pull Request.
107
113
 
108
114
  ## Community / Contact
109
115
 
package/astro.config.ts CHANGED
@@ -2,7 +2,6 @@ import mdx from '@astrojs/mdx'
2
2
  import sitemap from '@astrojs/sitemap'
3
3
  // @ts-ignore
4
4
  import liveCode from 'astro-live-code'
5
- import pagefind from 'astro-pagefind'
6
5
  import { defineConfig } from 'astro/config'
7
6
  import integration from 'fulldev-ui/integration'
8
7
 
@@ -19,7 +18,6 @@ export default defineConfig({
19
18
  integrations: [
20
19
  sitemap(),
21
20
  mdx(),
22
- pagefind(),
23
21
  liveCode({
24
22
  layout: '/src/components/experimental/Window.astro',
25
23
  }),
@@ -27,6 +25,8 @@ export default defineConfig({
27
25
  company: 'Fulldev UI',
28
26
  favicon: 'src/images/favicon.svg',
29
27
  css: '/src/css/custom.css',
28
+ basePreset: 'base',
29
+ injectRoutes: true,
30
30
  colors: {
31
31
  theme: 'dark',
32
32
  light: {
@@ -40,7 +40,6 @@ export default defineConfig({
40
40
  brand: '#F50',
41
41
  },
42
42
  },
43
- injectRoutes: true,
44
43
  }),
45
44
  ],
46
45
  redirects: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fulldev-ui",
3
- "version": "0.5.0-beta.5",
3
+ "version": "0.5.0-beta.7",
4
4
  "description": "A component library built for Astro",
5
5
  "homepage": "https://ui.full.dev",
6
6
  "bugs": "https://github.com/fulldotdev/ui/issues",
@@ -41,6 +41,7 @@
41
41
  "@astrojs/sitemap": "^3.2.1",
42
42
  "@astrolib/seo": "1.0.0-beta.8",
43
43
  "@iconify-json/tabler": "^1.2.5",
44
+ "@nanostores/persistent": "^0.10.2",
44
45
  "@radix-ui/colors": "^3.0.0",
45
46
  "@rollup/plugin-yaml": "^4.1.2",
46
47
  "@types/js-yaml": "^4.0.9",
@@ -48,7 +49,6 @@
48
49
  "astro": "^4.16.6",
49
50
  "astro-favicons": "^2.0.2",
50
51
  "astro-live-code": "^0.0.3",
51
- "astro-pagefind": "^1.6.0",
52
52
  "astro-seo": "^0.8.4",
53
53
  "bezier-easing": "^2.1.0",
54
54
  "colorjs.io": "^0.5.2",
@@ -56,11 +56,13 @@
56
56
  "fs": "0.0.1-security",
57
57
  "install": "^0.13.0",
58
58
  "js-yaml": "^4.1.0",
59
+ "nanostores": "^0.11.3",
59
60
  "npm": "^10.9.0",
60
61
  "radash": "^12.1.0",
61
62
  "remeda": "2.15.2",
62
63
  "sass": "^1.80.2",
63
64
  "sharp": "^0.33.5",
65
+ "stripe": "^17.2.1",
64
66
  "tailwindcss": "^3.4.14",
65
67
  "typescript": "^5.6.3",
66
68
  "unocss": "^0.63.4",
package/pnpm-lock.yaml CHANGED
@@ -17,6 +17,9 @@ dependencies:
17
17
  '@iconify-json/tabler':
18
18
  specifier: ^1.2.5
19
19
  version: 1.2.5
20
+ '@nanostores/persistent':
21
+ specifier: ^0.10.2
22
+ version: 0.10.2(nanostores@0.11.3)
20
23
  '@radix-ui/colors':
21
24
  specifier: ^3.0.0
22
25
  version: 3.0.0
@@ -38,9 +41,6 @@ dependencies:
38
41
  astro-live-code:
39
42
  specifier: ^0.0.3
40
43
  version: 0.0.3
41
- astro-pagefind:
42
- specifier: ^1.6.0
43
- version: 1.6.0(astro@4.16.6)
44
44
  astro-seo:
45
45
  specifier: ^0.8.4
46
46
  version: 0.8.4(prettier-plugin-astro@0.14.1)(prettier@3.3.3)(typescript@5.6.3)
@@ -62,6 +62,9 @@ dependencies:
62
62
  js-yaml:
63
63
  specifier: ^4.1.0
64
64
  version: 4.1.0
65
+ nanostores:
66
+ specifier: ^0.11.3
67
+ version: 0.11.3
65
68
  npm:
66
69
  specifier: ^10.9.0
67
70
  version: 10.9.0
@@ -77,6 +80,9 @@ dependencies:
77
80
  sharp:
78
81
  specifier: ^0.33.5
79
82
  version: 0.33.5
83
+ stripe:
84
+ specifier: ^17.2.1
85
+ version: 17.2.1
80
86
  tailwindcss:
81
87
  specifier: ^3.4.14
82
88
  version: 3.4.14
@@ -1299,6 +1305,15 @@ packages:
1299
1305
  - supports-color
1300
1306
  dev: false
1301
1307
 
1308
+ /@nanostores/persistent@0.10.2(nanostores@0.11.3):
1309
+ resolution: {integrity: sha512-BEndnLhRC+yP7gXTESepBbSj8XNl8OXK9hu4xAgKC7MWJHKXnEqJMqY47LUyHxK6vYgFnisyHmqq+vq8AUFyIg==}
1310
+ engines: {node: ^18.0.0 || >=20.0.0}
1311
+ peerDependencies:
1312
+ nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0
1313
+ dependencies:
1314
+ nanostores: 0.11.3
1315
+ dev: false
1316
+
1302
1317
  /@nodelib/fs.scandir@2.1.5:
1303
1318
  resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
1304
1319
  engines: {node: '>= 8'}
@@ -1321,50 +1336,6 @@ packages:
1321
1336
  resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
1322
1337
  dev: false
1323
1338
 
1324
- /@pagefind/darwin-arm64@1.1.1:
1325
- resolution: {integrity: sha512-tZ9tysUmQpFs2EqWG2+E1gc+opDAhSyZSsgKmFzhnWfkK02YHZhvL5XJXEZDqYy3s1FAKhwjTg8XDxneuBlDZQ==}
1326
- cpu: [arm64]
1327
- os: [darwin]
1328
- requiresBuild: true
1329
- dev: false
1330
- optional: true
1331
-
1332
- /@pagefind/darwin-x64@1.1.1:
1333
- resolution: {integrity: sha512-ChohLQ39dLwaxQv0jIQB/SavP3TM5K5ENfDTqIdzLkmfs3+JlzSDyQKcJFjTHYcCzQOZVeieeGq8PdqvLJxJxQ==}
1334
- cpu: [x64]
1335
- os: [darwin]
1336
- requiresBuild: true
1337
- dev: false
1338
- optional: true
1339
-
1340
- /@pagefind/default-ui@1.1.1:
1341
- resolution: {integrity: sha512-ZM0zDatWDnac/VGHhQCiM7UgA4ca8jpjA+VfuTJyHJBaxGqZMQnm4WoTz9E0KFcue1Bh9kxpu7uWFZfwpZZk0A==}
1342
- dev: false
1343
-
1344
- /@pagefind/linux-arm64@1.1.1:
1345
- resolution: {integrity: sha512-H5P6wDoCoAbdsWp0Zx0DxnLUrwTGWGLu/VI1rcN2CyFdY2EGSvPQsbGBMrseKRNuIrJDFtxHHHyjZ7UbzaM9EA==}
1346
- cpu: [arm64]
1347
- os: [linux]
1348
- requiresBuild: true
1349
- dev: false
1350
- optional: true
1351
-
1352
- /@pagefind/linux-x64@1.1.1:
1353
- resolution: {integrity: sha512-yJs7tTYbL2MI3HT+ngs9E1BfUbY9M4/YzA0yEM5xBo4Xl8Yu8Qg2xZTOQ1/F6gwvMrjCUFo8EoACs6LRDhtMrQ==}
1354
- cpu: [x64]
1355
- os: [linux]
1356
- requiresBuild: true
1357
- dev: false
1358
- optional: true
1359
-
1360
- /@pagefind/windows-x64@1.1.1:
1361
- resolution: {integrity: sha512-b7/qPqgIl+lMzkQ8fJt51SfguB396xbIIR+VZ3YrL2tLuyifDJ1wL5mEm+ddmHxJ2Fki340paPcDan9en5OmAw==}
1362
- cpu: [x64]
1363
- os: [win32]
1364
- requiresBuild: true
1365
- dev: false
1366
- optional: true
1367
-
1368
1339
  /@parcel/watcher-android-arm64@2.4.1:
1369
1340
  resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==}
1370
1341
  engines: {node: '>= 10.0.0'}
@@ -2257,17 +2228,6 @@ packages:
2257
2228
  unist-util-visit-parents: 6.0.1
2258
2229
  dev: false
2259
2230
 
2260
- /astro-pagefind@1.6.0(astro@4.16.6):
2261
- resolution: {integrity: sha512-U/WuE0ktkZkoFJf6yopWO4DjIJ3+wrnopE2L3kUYiyqNTJpqmp13bFLR8gir6B+KzQ5dsXQtJZYTQtKJg1FxIA==}
2262
- peerDependencies:
2263
- astro: ^2.0.4 || ^3.0.0 || ^4.0.0
2264
- dependencies:
2265
- '@pagefind/default-ui': 1.1.1
2266
- astro: 4.16.6(sass@1.80.2)(typescript@5.6.3)
2267
- pagefind: 1.1.1
2268
- sirv: 2.0.4
2269
- dev: false
2270
-
2271
2231
  /astro-seo@0.8.4(prettier-plugin-astro@0.14.1)(prettier@3.3.3)(typescript@5.6.3):
2272
2232
  resolution: {integrity: sha512-Ou1vzQSXAxa0K8rtNtXNvSpYqOGEgMhh0immMxJeXmbVZac3UKCNWAoXWyOQDFYsZvBugCRSg0N1phBqPMVgCw==}
2273
2233
  dependencies:
@@ -4419,6 +4379,11 @@ packages:
4419
4379
  engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
4420
4380
  hasBin: true
4421
4381
 
4382
+ /nanostores@0.11.3:
4383
+ resolution: {integrity: sha512-TUes3xKIX33re4QzdxwZ6tdbodjmn3tWXCEc1uokiEmo14sI1EaGYNs2k3bU2pyyGNmBqFGAVl6jAGWd06AVIg==}
4384
+ engines: {node: ^18.0.0 || >=20.0.0}
4385
+ dev: false
4386
+
4422
4387
  /napi-build-utils@1.0.2:
4423
4388
  resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
4424
4389
  dev: false
@@ -4641,17 +4606,6 @@ packages:
4641
4606
  resolution: {integrity: sha512-E385OSk9qDcXhcM9LNSe4sdhx8a9mAPrZ4sMLW+tmxl5ZuGtPUcdFu+MPP2jbgiWAZ6Pfe5soGFMd+0Db5Vrog==}
4642
4607
  dev: false
4643
4608
 
4644
- /pagefind@1.1.1:
4645
- resolution: {integrity: sha512-U2YR0dQN5B2fbIXrLtt/UXNS0yWSSYfePaad1KcBPTi0p+zRtsVjwmoPaMQgTks5DnHNbmDxyJUL5TGaLljK3A==}
4646
- hasBin: true
4647
- optionalDependencies:
4648
- '@pagefind/darwin-arm64': 1.1.1
4649
- '@pagefind/darwin-x64': 1.1.1
4650
- '@pagefind/linux-arm64': 1.1.1
4651
- '@pagefind/linux-x64': 1.1.1
4652
- '@pagefind/windows-x64': 1.1.1
4653
- dev: false
4654
-
4655
4609
  /parse-entities@4.0.1:
4656
4610
  resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==}
4657
4611
  dependencies:
@@ -5540,6 +5494,14 @@ packages:
5540
5494
  engines: {node: '>=0.10.0'}
5541
5495
  dev: false
5542
5496
 
5497
+ /stripe@17.2.1:
5498
+ resolution: {integrity: sha512-Mwb0SitV/UjxTLSUiTlUQ0VDE/gfyQ7OHDGdvDdvKIH4CNNqobPKlzlWhoZHFFU0OA/YsZyBtPULK4JG86BAAg==}
5499
+ engines: {node: '>=12.*'}
5500
+ dependencies:
5501
+ '@types/node': 17.0.45
5502
+ qs: 6.13.0
5503
+ dev: false
5504
+
5543
5505
  /style-to-object@0.4.4:
5544
5506
  resolution: {integrity: sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==}
5545
5507
  dependencies:
@@ -1,21 +1,40 @@
1
1
  ---
2
- import { getEntry } from 'astro:content'
3
2
  import Prose from 'fulldev-ui/components/experimental/Prose.astro'
4
3
  import Section from 'fulldev-ui/components/Section.astro'
4
+ import Toc from 'fulldev-ui/components/Toc.astro'
5
5
 
6
- const { ...rest } = Astro.props
7
-
8
- const slug = Astro.url.pathname.replace(/^\/|\/$/g, '') || 'index'
9
- const currentEntry = await getEntry('pages', slug)
10
- const render = currentEntry && (await currentEntry.render())
11
- const { Content } = render || {}
6
+ const { toc = 'Op deze pagina', render } = Astro.props
7
+ const { Content } = (render && (await render())) || {}
12
8
  ---
13
9
 
14
- <Section
15
- style={{ '--screen': '768px' }}
16
- {...rest}
17
- >
18
- <Prose id="prose">
10
+ <Section class:list="article">
11
+ <Prose>
19
12
  {Content && <Content />}
13
+ <slot />
20
14
  </Prose>
15
+ <Toc
16
+ {render}
17
+ heading={toc}
18
+ />
21
19
  </Section>
20
+
21
+ <style is:global lang="scss">
22
+ .article {
23
+ display: flex;
24
+ position: relative;
25
+ flex-grow: 1;
26
+ flex-direction: row;
27
+ align-items: start;
28
+ height: 100%;
29
+
30
+ &:first-child {
31
+ padding-top: var(--space-6);
32
+ }
33
+
34
+ .prose {
35
+ margin-right: auto;
36
+ margin-left: auto;
37
+ max-width: 768px;
38
+ }
39
+ }
40
+ </style>
@@ -31,8 +31,9 @@ const { color = 'brand', size = 'sm', text, ...rest } = Astro.props
31
31
  background-color: var(--color-9);
32
32
  padding: 0 var(--gutter);
33
33
  width: 100%;
34
- height: var(--banner-height);
34
+ min-height: var(--banner-height);
35
35
  overflow: hidden;
36
+ text-align: center;
36
37
 
37
38
  .text {
38
39
  color: var(--color-contrast);
@@ -1,12 +1,10 @@
1
1
  ---
2
- import Button from 'fulldev-ui/components/Button.astro'
2
+ import CartForm from 'fulldev-ui/components/CartForm.astro'
3
3
  import Element from 'fulldev-ui/components/Element.astro'
4
4
  import Gallery from 'fulldev-ui/components/experimental/Gallery.astro'
5
5
  import Heading from 'fulldev-ui/components/Heading.astro'
6
6
  import Image from 'fulldev-ui/components/Image.astro'
7
- import Input from 'fulldev-ui/components/Input.astro'
8
7
  import List from 'fulldev-ui/components/List.astro'
9
- import Price from 'fulldev-ui/components/Price.astro'
10
8
  import Section from 'fulldev-ui/components/Section.astro'
11
9
  import Text from 'fulldev-ui/components/Text.astro'
12
10
 
@@ -21,12 +19,16 @@ const {
21
19
  buttons,
22
20
  text,
23
21
  subheading,
22
+ variants,
24
23
  button,
25
24
  description,
26
25
  form,
27
26
  gallery = 'horizontal',
28
27
  ...rest
29
28
  } = Astro.props
29
+
30
+ const slug = Astro.params.page || 'index'
31
+ const src = `/src/images/${images?.[0].id}`
30
32
  ---
31
33
 
32
34
  <Section
@@ -53,28 +55,16 @@ const {
53
55
  style={{ maxWidth: '420px' }}
54
56
  text={text || description}
55
57
  />
56
- <Price value={price} />
57
58
  <List
58
59
  items={list}
59
60
  style={{ marginTop: 'var(--space-5)' }}
60
61
  />
61
- <Element class:list="row">
62
- <Input
63
- value={1}
64
- name={'quantity'}
65
- style={{ width: 'var(--space-7)' }}
66
- type="number"
67
- min={1}
68
- />
69
- <Button
70
- color="brand"
71
- text={form?.submit}
72
- />
73
- </Element>
74
- <Button
75
- style={{ marginTop: 'var(--space-3)', width: '100%', maxWidth: '400px' }}
76
- variant="secondary"
77
- {...button}
62
+ <CartForm
63
+ image={src}
64
+ {title}
65
+ {price}
66
+ {slug}
67
+ {variants}
78
68
  />
79
69
  </Element>
80
70
  </Section>
@@ -36,7 +36,7 @@ const page = slug ? (await getEntry('pages', slug)).data : {}
36
36
  const entryProps = {
37
37
  heading: page.title,
38
38
  text: page.description,
39
- href: `/${slug}/`,
39
+ href: slug ? `/${slug}/` : undefined,
40
40
  ...page,
41
41
  }
42
42
 
@@ -0,0 +1,38 @@
1
+ ---
2
+ import type { ComponentProps } from 'astro/types'
3
+ import CartList from 'fulldev-ui/components/CartList.astro'
4
+ import CartSummary from 'fulldev-ui/components/CartSummary.astro'
5
+ import Drawer from 'fulldev-ui/components/Drawer.astro'
6
+
7
+ interface Props extends ComponentProps<typeof Drawer> {}
8
+
9
+ const {
10
+ icon = 'shopping-cart',
11
+ color = 'brand',
12
+ id = 'cart',
13
+ if: ifProp,
14
+ ...rest
15
+ } = Astro.props
16
+ ---
17
+
18
+ <Drawer
19
+ if={ifProp}
20
+ class:list="cart"
21
+ {icon}
22
+ {color}
23
+ {id}
24
+ {...rest}
25
+ >
26
+ <CartList />
27
+ <CartSummary slot="footer" />
28
+ </Drawer>
29
+
30
+ <style lang="scss" is:global>
31
+ @layer fulldev {
32
+ form {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: var(--space-4);
36
+ }
37
+ }
38
+ </style>
@@ -0,0 +1,121 @@
1
+ ---
2
+ import type { ComponentProps } from 'astro/types'
3
+ import Button from 'fulldev-ui/components/Button.astro'
4
+ import Input from 'fulldev-ui/components/Input.astro'
5
+ import Select from 'fulldev-ui/components/Select.astro'
6
+ import { capitalize } from 'radash'
7
+ import Form from './experimental/Form.astro'
8
+ import Price from './Price.astro'
9
+
10
+ interface Props extends Omit<ComponentProps<typeof Form>, 'fields' | 'submit'> {
11
+ title: string
12
+ slug: string
13
+ price: number
14
+ image?: string | undefined
15
+ variants?:
16
+ | {
17
+ [key: string]: string[]
18
+ }
19
+ | undefined
20
+ }
21
+
22
+ const { title, slug, image, price, variants, ...rest } = Astro.props
23
+ ---
24
+
25
+ <Form
26
+ class:list="cart-form"
27
+ {...rest}
28
+ >
29
+ <Input
30
+ type="hidden"
31
+ name="title"
32
+ value={title}
33
+ />
34
+ <Input
35
+ type="hidden"
36
+ name="slug"
37
+ value={slug}
38
+ />
39
+ <Input
40
+ type="hidden"
41
+ name="url"
42
+ value={Astro.site ? Astro.site.href + slug : undefined}
43
+ />
44
+ <Input
45
+ type="hidden"
46
+ name="image"
47
+ value={image}
48
+ />
49
+ {
50
+ Object.entries(variants ?? {}).map(([key, options]) => (
51
+ <Select
52
+ label={capitalize(key)}
53
+ name={`variant-${key}`}
54
+ options={options}
55
+ />
56
+ ))
57
+ }
58
+ <Price value={price} />
59
+ <Input
60
+ type="hidden"
61
+ name="price"
62
+ value={price}
63
+ />
64
+ <Button
65
+ variant="primary"
66
+ color="brand"
67
+ type="submit"
68
+ class="cart-add"
69
+ text="Toevoegen aan winkelwagen"
70
+ />
71
+ </Form>
72
+
73
+ <script>
74
+ import { $cart } from 'fulldev-ui/stores/cart.ts'
75
+ import { generateProductId, generateProductName } from 'fulldev-ui/utils/cart'
76
+
77
+ document.addEventListener('astro:page-load', () => {
78
+ const cartForm = document.querySelector('.cart-form')
79
+
80
+ cartForm?.addEventListener('submit', (e) => {
81
+ e.preventDefault()
82
+
83
+ if (e.target instanceof HTMLFormElement) {
84
+ const formData = new FormData(e.target)
85
+
86
+ const title = formData.get('title') as string
87
+ const slug = formData.get('slug') as string
88
+ const url = formData.get('url') as string
89
+ const image = formData.get('image') as string
90
+ const price = Number(formData.get('price')) as number
91
+ const variants = Array.from(formData.entries())
92
+ .filter(([key]) => key.startsWith('variant-'))
93
+ .map(([_, value]) => value) as string[]
94
+
95
+ const id = generateProductId(slug, variants)
96
+ const name = generateProductName(title, variants)
97
+
98
+ const currentCart = $cart.get()
99
+ const newCart = [...currentCart, { id, name, price, image, url }]
100
+ $cart.set(newCart)
101
+
102
+ const cartDialog = document?.querySelector('dialog#cart')
103
+ if (cartDialog instanceof HTMLDialogElement) cartDialog.showModal()
104
+ }
105
+ })
106
+ })
107
+ </script>
108
+
109
+ <style is:global lang="scss">
110
+ @layer fulldev {
111
+ .cart-form {
112
+ display: flex;
113
+ flex-direction: column;
114
+ gap: var(--space-4);
115
+
116
+ .input {
117
+ display: none;
118
+ }
119
+ }
120
+ }
121
+ </style>