fulldev-ui 0.5.0-beta.1 → 0.5.0-beta.11
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/.env.example +3 -0
- package/CONTRIBUTING.md +10 -4
- package/astro.config.ts +2 -13
- package/package.json +8 -4
- package/pnpm-lock.yaml +82 -130
- package/src/blocks/Article.astro +31 -12
- package/src/blocks/Banner.astro +2 -1
- package/src/blocks/Contact.astro +7 -30
- package/src/blocks/Excerpt.astro +14 -0
- package/src/blocks/Intro.astro +3 -1
- package/src/blocks/Product.astro +55 -22
- package/src/components/Card.astro +11 -5
- package/src/components/Cart.astro +38 -0
- package/src/components/CartForm.astro +121 -0
- package/src/components/CartList.astro +134 -0
- package/src/components/CartSummary.astro +147 -0
- package/src/components/Drawer.astro +128 -52
- package/src/components/Footer.astro +6 -3
- package/src/components/Form.astro +49 -0
- package/src/components/Header.astro +19 -14
- package/src/components/Image.astro +0 -1
- package/src/components/Input.astro +6 -0
- package/src/components/Menu.astro +56 -0
- package/src/components/Price.astro +7 -11
- package/src/components/Search.astro +1 -4
- package/src/components/Section.astro +2 -1
- package/src/components/Sidebar.astro +61 -111
- package/src/components/Social.astro +7 -0
- package/src/components/ThemeSelect.astro +3 -0
- package/src/components/Toc.astro +33 -94
- package/src/components/docs/PropsTable.astro +1 -1
- package/src/components/experimental/Form.astro +31 -5
- package/src/components/experimental/Gallery.astro +50 -126
- package/src/components/experimental/Prose.astro +32 -0
- package/src/content/pages/base/select.mdx +0 -8
- package/src/content/pages/base/textarea.mdx +0 -5
- package/src/content/pages/blocks/_product.mdx +73 -2
- package/src/content/pages/index.mdx +0 -3
- package/src/content/pages/layouts/_layout.mdx +14 -0
- package/src/content/pages/layouts/docslayout.mdx +10 -1
- package/src/content/pages/overview/components.mdx +5 -0
- package/src/content/pages/overview/content-collections.mdx +139 -0
- package/src/content/pages/overview/installation.mdx +25 -26
- package/src/content/pages/overview/introduction.mdx +16 -10
- package/src/content/pages/overview/theming.mdx +69 -0
- package/src/content/pages/schemas/page.mdx +6 -0
- package/src/content/presets/base.yml +56 -43
- package/src/content/presets/blocks.yml +0 -3
- package/src/content/presets/docs.yml +3 -62
- package/src/env.d.ts +1 -1
- package/src/integration/index.ts +63 -34
- package/src/layouts/DocsLayout.astro +23 -35
- package/src/layouts/Layout.astro +37 -21
- package/src/layouts/OverviewLayout.astro +17 -10
- package/src/layouts/PostLayout.astro +7 -7
- package/src/layouts/ProductLayout.astro +5 -2
- package/src/schemas/components/footer.ts +1 -0
- package/src/schemas/components/header.ts +1 -0
- package/src/schemas/components/menu.ts +13 -0
- package/src/schemas/components/sidebar.ts +15 -0
- package/src/schemas/components/toc.ts +3 -0
- package/src/schemas/pageSchema.ts +72 -34
- package/src/schemas/presetSchema.ts +2 -28
- package/src/schemas/utils/navigation.ts +6 -51
- package/src/stores/cart.ts +23 -0
- package/src/utils/cart.ts +32 -0
- package/src/utils/{getChildPages.ts → getFolderChildren.ts} +3 -1
- package/src/utils/{getCategoryPages.ts → getReferenceChildren.ts} +6 -3
- package/tsconfig.json +1 -3
- package/src/components/experimental/GalleryVertical.astro +0 -161
- package/src/content/pages/layouts/layout.mdx +0 -21
- package/src/content/pages/layouts/pagelayout.mdx +0 -21
- package/src/content/pages/overview/content-layer.mdx +0 -128
- package/src/content/pages/overview/customization.mdx +0 -83
- package/src/layouts/ContentLayout.astro +0 -16
- package/src/layouts/PageLayout.astro +0 -15
- /package/src/schemas/utils/{categories.ts → parents.ts} +0 -0
- /package/src/types/{global-props.d.ts → global-props.ts} +0 -0
package/src/blocks/Contact.astro
CHANGED
|
@@ -13,35 +13,6 @@ import Tagline from 'fulldev-ui/components/Tagline.astro'
|
|
|
13
13
|
import Text from 'fulldev-ui/components/Text.astro'
|
|
14
14
|
import Textarea from 'fulldev-ui/components/Textarea.astro'
|
|
15
15
|
|
|
16
|
-
// interface Channel {
|
|
17
|
-
// type: 'tel' | 'email' | 'address'
|
|
18
|
-
// text: string
|
|
19
|
-
// heading?: string
|
|
20
|
-
// icon?: string
|
|
21
|
-
// href?: string
|
|
22
|
-
// }
|
|
23
|
-
|
|
24
|
-
// interface FormField {
|
|
25
|
-
// type: 'text' | 'email' | 'tel' | 'textarea'
|
|
26
|
-
// name: string
|
|
27
|
-
// label: string
|
|
28
|
-
// required?: boolean
|
|
29
|
-
// }
|
|
30
|
-
|
|
31
|
-
// interface Form {
|
|
32
|
-
// fields: FormField[]
|
|
33
|
-
// button: string
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
// type Props<As extends HTMLTag = 'section'> = ComponentProps<
|
|
37
|
-
// typeof Section<As>
|
|
38
|
-
// > & {
|
|
39
|
-
// form: Form
|
|
40
|
-
// googleMaps?: string
|
|
41
|
-
// socials?: any
|
|
42
|
-
// channels: Channel[]
|
|
43
|
-
// }
|
|
44
|
-
|
|
45
16
|
const {
|
|
46
17
|
heading,
|
|
47
18
|
form,
|
|
@@ -53,7 +24,7 @@ const {
|
|
|
53
24
|
position,
|
|
54
25
|
image,
|
|
55
26
|
channels,
|
|
56
|
-
level =
|
|
27
|
+
level = 1,
|
|
57
28
|
...rest
|
|
58
29
|
} = Astro.props
|
|
59
30
|
---
|
|
@@ -69,6 +40,7 @@ const {
|
|
|
69
40
|
text={tagline}
|
|
70
41
|
/>
|
|
71
42
|
<Heading
|
|
43
|
+
size={'sm'}
|
|
72
44
|
level={level}
|
|
73
45
|
text={heading}
|
|
74
46
|
/>
|
|
@@ -106,6 +78,7 @@ const {
|
|
|
106
78
|
<Button
|
|
107
79
|
type="submit"
|
|
108
80
|
color="brand"
|
|
81
|
+
variant="primary"
|
|
109
82
|
text={form.button}
|
|
110
83
|
/>
|
|
111
84
|
</Form>
|
|
@@ -126,6 +99,10 @@ const {
|
|
|
126
99
|
align-items: flex-start;
|
|
127
100
|
}
|
|
128
101
|
|
|
102
|
+
> .column {
|
|
103
|
+
gap: var(--space-5);
|
|
104
|
+
}
|
|
105
|
+
|
|
129
106
|
.channel + .channel {
|
|
130
107
|
margin-top: var(--space-3) !important;
|
|
131
108
|
}
|
package/src/blocks/Intro.astro
CHANGED
|
@@ -8,7 +8,7 @@ const { image, ...rest } = Astro.props
|
|
|
8
8
|
class:list="intro"
|
|
9
9
|
structure="column"
|
|
10
10
|
size="sm"
|
|
11
|
-
level={
|
|
11
|
+
level={1}
|
|
12
12
|
{...rest}
|
|
13
13
|
/>
|
|
14
14
|
|
|
@@ -16,6 +16,8 @@ const { image, ...rest } = Astro.props
|
|
|
16
16
|
@layer fulldev {
|
|
17
17
|
.intro {
|
|
18
18
|
border-bottom: 1px solid var(--base-6);
|
|
19
|
+
padding-top: var(--space-7);
|
|
20
|
+
padding-bottom: var(--space-7);
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
</style>
|
package/src/blocks/Product.astro
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
2
|
+
import { getImage } from 'astro:assets'
|
|
3
|
+
import CartForm from 'fulldev-ui/components/CartForm.astro'
|
|
3
4
|
import Element from 'fulldev-ui/components/Element.astro'
|
|
5
|
+
import Gallery from 'fulldev-ui/components/experimental/Gallery.astro'
|
|
4
6
|
import Heading from 'fulldev-ui/components/Heading.astro'
|
|
5
7
|
import Image from 'fulldev-ui/components/Image.astro'
|
|
6
|
-
import
|
|
7
|
-
import Price from 'fulldev-ui/components/Price.astro'
|
|
8
|
+
import List from 'fulldev-ui/components/List.astro'
|
|
8
9
|
import Section from 'fulldev-ui/components/Section.astro'
|
|
9
10
|
import Text from 'fulldev-ui/components/Text.astro'
|
|
10
11
|
|
|
@@ -19,11 +20,19 @@ const {
|
|
|
19
20
|
buttons,
|
|
20
21
|
text,
|
|
21
22
|
subheading,
|
|
23
|
+
variants,
|
|
22
24
|
button,
|
|
23
25
|
description,
|
|
24
26
|
form,
|
|
27
|
+
gallery = 'horizontal',
|
|
25
28
|
...rest
|
|
26
29
|
} = Astro.props
|
|
30
|
+
|
|
31
|
+
const slug = Astro.url.pathname.replace(/^\/|\/$/g, '') || 'index'
|
|
32
|
+
const src = `/src/images/${images?.[0].id}`
|
|
33
|
+
const gotImage = await getImage({ src, width: 200, height: 200 })
|
|
34
|
+
|
|
35
|
+
console.log({ hoi: gotImage.src })
|
|
27
36
|
---
|
|
28
37
|
|
|
29
38
|
<Section
|
|
@@ -31,47 +40,71 @@ const {
|
|
|
31
40
|
structure="split"
|
|
32
41
|
{...rest}
|
|
33
42
|
>
|
|
34
|
-
|
|
43
|
+
{
|
|
44
|
+
images && images.length > 1 ? (
|
|
45
|
+
<Gallery
|
|
46
|
+
{images}
|
|
47
|
+
direction={gallery}
|
|
48
|
+
/>
|
|
49
|
+
) : (
|
|
50
|
+
<Image {...(image || images?.[0])} />
|
|
51
|
+
)
|
|
52
|
+
}
|
|
35
53
|
<Element class:list="column">
|
|
36
54
|
<Heading
|
|
37
|
-
level={
|
|
55
|
+
level={2}
|
|
38
56
|
text={heading || title}
|
|
39
57
|
/>
|
|
40
58
|
<Text
|
|
41
59
|
style={{ maxWidth: '420px' }}
|
|
42
60
|
text={text || description}
|
|
43
61
|
/>
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
text={form?.submit}
|
|
55
|
-
/>
|
|
56
|
-
</Element>
|
|
57
|
-
<Button
|
|
58
|
-
style={{ marginTop: 'var(--space-3)', width: '100%', maxWidth: '400px' }}
|
|
59
|
-
variant="secondary"
|
|
60
|
-
{...button}
|
|
62
|
+
<List
|
|
63
|
+
items={list}
|
|
64
|
+
style={{ marginTop: 'var(--space-5)' }}
|
|
65
|
+
/>
|
|
66
|
+
<CartForm
|
|
67
|
+
image={gotImage.src}
|
|
68
|
+
{title}
|
|
69
|
+
{price}
|
|
70
|
+
{slug}
|
|
71
|
+
{variants}
|
|
61
72
|
/>
|
|
62
73
|
</Element>
|
|
63
74
|
</Section>
|
|
64
75
|
|
|
65
76
|
<style is:global lang="scss">
|
|
66
77
|
.product {
|
|
78
|
+
padding-top: 0px;
|
|
79
|
+
|
|
80
|
+
@media (min-width: 1024px) {
|
|
81
|
+
padding-top: var(--space-6);
|
|
82
|
+
}
|
|
83
|
+
|
|
67
84
|
.column {
|
|
68
85
|
display: flex;
|
|
69
86
|
flex-direction: column;
|
|
70
87
|
align-items: flex-start;
|
|
88
|
+
gap: var(--space-5);
|
|
71
89
|
}
|
|
72
90
|
|
|
73
91
|
.row {
|
|
74
92
|
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
gap: var(--space-5);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@media (max-width: 1023.99px) {
|
|
98
|
+
.gallery {
|
|
99
|
+
margin-right: calc(-1 * var(--gutter));
|
|
100
|
+
margin-left: calc(-1 * var(--gutter));
|
|
101
|
+
width: calc(100% + (var(--gutter) * 2));
|
|
102
|
+
|
|
103
|
+
.small-carousel {
|
|
104
|
+
padding-right: var(--gutter);
|
|
105
|
+
padding-left: var(--gutter);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
75
108
|
}
|
|
76
109
|
}
|
|
77
110
|
</style>
|
|
@@ -9,6 +9,7 @@ import Image from 'fulldev-ui/components/Image.astro'
|
|
|
9
9
|
import Writeup from 'fulldev-ui/components/Writeup.astro'
|
|
10
10
|
import type { GlobalProps } from 'fulldev-ui/types/global-props'
|
|
11
11
|
import Icon from './Icon.astro'
|
|
12
|
+
import Price from './Price.astro'
|
|
12
13
|
|
|
13
14
|
interface Props
|
|
14
15
|
extends GlobalProps,
|
|
@@ -22,9 +23,11 @@ interface Props
|
|
|
22
23
|
variant?: ComponentProps<typeof Button>['variant']
|
|
23
24
|
align?: ComponentProps<typeof Writeup>['align']
|
|
24
25
|
icon?: ComponentProps<typeof Icon>['name']
|
|
26
|
+
price?: ComponentProps<typeof Price>['value']
|
|
25
27
|
slug?: CollectionEntry<'pages'>['slug'] | undefined
|
|
26
28
|
id?: any
|
|
27
29
|
panel?: boolean | undefined
|
|
30
|
+
title?: ComponentProps<typeof Writeup>['heading']
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
const { slug } = Astro.props
|
|
@@ -33,7 +36,7 @@ const page = slug ? (await getEntry('pages', slug)).data : {}
|
|
|
33
36
|
const entryProps = {
|
|
34
37
|
heading: page.title,
|
|
35
38
|
text: page.description,
|
|
36
|
-
href: `/${slug}
|
|
39
|
+
href: slug ? `/${slug}/` : undefined,
|
|
37
40
|
...page,
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -47,12 +50,14 @@ const {
|
|
|
47
50
|
heading,
|
|
48
51
|
text,
|
|
49
52
|
variant,
|
|
53
|
+
price,
|
|
50
54
|
list,
|
|
51
55
|
button,
|
|
52
56
|
buttons,
|
|
53
57
|
panel,
|
|
54
58
|
image,
|
|
55
59
|
icon,
|
|
60
|
+
title,
|
|
56
61
|
images,
|
|
57
62
|
position,
|
|
58
63
|
...rest
|
|
@@ -81,14 +86,15 @@ const {
|
|
|
81
86
|
</slot>
|
|
82
87
|
<slot name="writeup">
|
|
83
88
|
<Writeup
|
|
89
|
+
heading={heading || title}
|
|
84
90
|
{level}
|
|
85
91
|
{rating}
|
|
86
92
|
{badge}
|
|
87
93
|
{tagline}
|
|
88
|
-
{heading}
|
|
89
94
|
{text}
|
|
90
95
|
{list}
|
|
91
96
|
/>
|
|
97
|
+
<Price value={price} />
|
|
92
98
|
</slot>
|
|
93
99
|
<slot name="buttons">
|
|
94
100
|
<Button
|
|
@@ -121,12 +127,12 @@ const {
|
|
|
121
127
|
&[href] {
|
|
122
128
|
cursor: pointer;
|
|
123
129
|
|
|
124
|
-
> .
|
|
125
|
-
transition: all;
|
|
130
|
+
> .image {
|
|
131
|
+
transition: all 0.2s ease;
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
&:hover {
|
|
129
|
-
> .
|
|
135
|
+
> .image {
|
|
130
136
|
opacity: 0.8;
|
|
131
137
|
}
|
|
132
138
|
}
|
|
@@ -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={Astro.url.origin ? Astro.url.origin + image : undefined}
|
|
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>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Element from 'fulldev-ui/components/Element.astro'
|
|
3
|
+
import Button from './Button.astro'
|
|
4
|
+
import Card from './Card.astro'
|
|
5
|
+
import Heading from './Heading.astro'
|
|
6
|
+
import Text from './Text.astro'
|
|
7
|
+
|
|
8
|
+
const { ...rest } = Astro.props
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<Element
|
|
12
|
+
if
|
|
13
|
+
class:list="cart-list"
|
|
14
|
+
{...rest}
|
|
15
|
+
/>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<Card class="cart-list-card">
|
|
19
|
+
<img class="cart-list-image image" />
|
|
20
|
+
<Element class="column">
|
|
21
|
+
<Heading
|
|
22
|
+
if
|
|
23
|
+
level={4}
|
|
24
|
+
class="heading"
|
|
25
|
+
/>
|
|
26
|
+
<Element class="row">
|
|
27
|
+
<Text
|
|
28
|
+
if
|
|
29
|
+
class="cart-list-price"
|
|
30
|
+
/>
|
|
31
|
+
<Button
|
|
32
|
+
class:list="cart-list-remove"
|
|
33
|
+
variant="tertiary"
|
|
34
|
+
icon="trash"
|
|
35
|
+
type="button"
|
|
36
|
+
/>
|
|
37
|
+
</Element>
|
|
38
|
+
</Element>
|
|
39
|
+
</Card>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script>
|
|
43
|
+
import { $cart } from 'fulldev-ui/stores/cart.ts'
|
|
44
|
+
import { formatPrice } from 'fulldev-ui/utils/cart'
|
|
45
|
+
|
|
46
|
+
function setCards(items: any) {
|
|
47
|
+
const template = document.querySelector('template')
|
|
48
|
+
const container = document.querySelector('.cart-list')
|
|
49
|
+
|
|
50
|
+
if (!container || !template) return
|
|
51
|
+
|
|
52
|
+
container.innerHTML = ''
|
|
53
|
+
|
|
54
|
+
items.forEach((item: any, index: number) => {
|
|
55
|
+
const clone = template?.content.cloneNode(true)
|
|
56
|
+
if (!(clone instanceof DocumentFragment)) return
|
|
57
|
+
const card = clone.querySelector('.cart-list-card')
|
|
58
|
+
if (!card) return
|
|
59
|
+
|
|
60
|
+
const img = card.querySelector('img')
|
|
61
|
+
if (img) img.src = item.image
|
|
62
|
+
|
|
63
|
+
const h4 = card.querySelector('h4')
|
|
64
|
+
if (h4) h4.textContent = item.name
|
|
65
|
+
|
|
66
|
+
const p = card.querySelector('p')
|
|
67
|
+
if (p) p.textContent = formatPrice(item.price)
|
|
68
|
+
|
|
69
|
+
const button = card.querySelector('button')
|
|
70
|
+
if (button) {
|
|
71
|
+
button.addEventListener('click', () => {
|
|
72
|
+
const currentCart = $cart.get()
|
|
73
|
+
const newCart = [...currentCart]
|
|
74
|
+
newCart.splice(index, 1)
|
|
75
|
+
$cart.set(newCart)
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
container.appendChild(clone)
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
document.addEventListener('astro:page-load', () => {
|
|
84
|
+
setCards($cart.get())
|
|
85
|
+
|
|
86
|
+
$cart.subscribe((items: any) => {
|
|
87
|
+
setCards(items)
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<style lang="scss" is:global>
|
|
93
|
+
@layer fulldev {
|
|
94
|
+
.cart-list {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
|
|
98
|
+
.card {
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-direction: row;
|
|
101
|
+
gap: var(--space-5);
|
|
102
|
+
width: 100%;
|
|
103
|
+
|
|
104
|
+
&:not(:first-child) {
|
|
105
|
+
margin-top: var(--space-5);
|
|
106
|
+
border-top: 1px solid var(--color-a6);
|
|
107
|
+
padding-top: var(--space-5);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.image {
|
|
111
|
+
display: block;
|
|
112
|
+
width: 100px;
|
|
113
|
+
height: auto;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.column {
|
|
117
|
+
display: flex;
|
|
118
|
+
flex-direction: column;
|
|
119
|
+
justify-content: space-between;
|
|
120
|
+
gap: var(--space-3);
|
|
121
|
+
width: 100%;
|
|
122
|
+
height: 100%;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.row {
|
|
126
|
+
display: flex;
|
|
127
|
+
flex-direction: row;
|
|
128
|
+
justify-content: space-between;
|
|
129
|
+
align-items: center;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
</style>
|