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.
- package/CONTRIBUTING.md +10 -4
- package/astro.config.ts +2 -3
- package/package.json +4 -2
- package/pnpm-lock.yaml +31 -69
- package/src/blocks/Article.astro +31 -12
- package/src/blocks/Banner.astro +2 -1
- package/src/blocks/Product.astro +11 -21
- package/src/components/Card.astro +1 -1
- 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 +146 -0
- package/src/components/Drawer.astro +41 -8
- package/src/components/Footer.astro +0 -1
- package/src/components/Form.astro +49 -0
- package/src/components/Header.astro +5 -8
- package/src/components/Image.astro +0 -1
- package/src/components/Input.astro +6 -0
- package/src/components/Price.astro +7 -11
- package/src/components/Search.astro +1 -4
- package/src/components/Section.astro +0 -1
- package/src/components/Sidebar.astro +1 -1
- package/src/components/Toc.astro +3 -6
- package/src/components/docs/PropsTable.astro +1 -1
- package/src/components/experimental/Form.astro +29 -5
- package/src/content/config.ts +2 -1
- package/src/content/pages/base/select.mdx +0 -8
- package/src/content/pages/base/textarea.mdx +0 -5
- package/src/content/presets/base.yml +1 -2
- package/src/content/presets/docs.yml +4 -4
- package/src/env.d.ts +1 -1
- package/src/layouts/DocsLayout.astro +23 -35
- package/src/layouts/Layout.astro +12 -16
- package/src/layouts/OverviewLayout.astro +5 -2
- package/src/layouts/PostLayout.astro +7 -10
- package/src/schemas/pageSchema.ts +53 -28
- package/src/schemas/presetSchema.ts +3 -0
- package/src/schemas/utils/navigation.ts +5 -1
- package/src/stores/cart.ts +23 -0
- package/src/utils/cart.ts +36 -0
- package/tsconfig.json +1 -3
- /package/src/types/{global-props.d.ts → global-props.ts} +0 -0
|
@@ -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>
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Button from './Button.astro'
|
|
3
|
+
import Element from './Element.astro'
|
|
4
|
+
import Price from './Price.astro'
|
|
5
|
+
import Text from './Text.astro'
|
|
6
|
+
|
|
7
|
+
interface Props {}
|
|
8
|
+
|
|
9
|
+
const { ...rest } = Astro.props
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<Element
|
|
13
|
+
size="md"
|
|
14
|
+
class="cart-summary"
|
|
15
|
+
>
|
|
16
|
+
<div
|
|
17
|
+
class="row"
|
|
18
|
+
{...rest}
|
|
19
|
+
>
|
|
20
|
+
<Text
|
|
21
|
+
class:list="total"
|
|
22
|
+
text="Totaal"
|
|
23
|
+
contrast
|
|
24
|
+
/>
|
|
25
|
+
<Price value={10} />
|
|
26
|
+
</div>
|
|
27
|
+
<Text
|
|
28
|
+
class:list="shipping"
|
|
29
|
+
text="Verzendkosten worden berekend bij het afrekenen."
|
|
30
|
+
/>
|
|
31
|
+
<Button
|
|
32
|
+
class:list="checkout-button"
|
|
33
|
+
variant="primary"
|
|
34
|
+
color="brand"
|
|
35
|
+
text="Afrekenen"
|
|
36
|
+
/>
|
|
37
|
+
</Element>
|
|
38
|
+
|
|
39
|
+
<style is:global lang="scss">
|
|
40
|
+
@layer fulldev {
|
|
41
|
+
.cart-summary {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
gap: var(--space-3);
|
|
45
|
+
|
|
46
|
+
.price,
|
|
47
|
+
.total {
|
|
48
|
+
font-size: var(--text-4);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.row {
|
|
52
|
+
display: flex;
|
|
53
|
+
justify-content: space-between;
|
|
54
|
+
align-items: center;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.shipping {
|
|
58
|
+
font-size: var(--text-1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
63
|
+
|
|
64
|
+
<script>
|
|
65
|
+
import { $cart } from 'fulldev-ui/stores/cart.ts'
|
|
66
|
+
import { formatPrice } from 'fulldev-ui/utils/cart'
|
|
67
|
+
import Stripe from 'stripe'
|
|
68
|
+
|
|
69
|
+
const stripe = new Stripe(import.meta.env.PUBLIC_STRIPE_CHECKOUT_KEY)
|
|
70
|
+
|
|
71
|
+
function setPrice(items: any) {
|
|
72
|
+
const price = document.querySelector('.cart-summary .price')
|
|
73
|
+
if (price)
|
|
74
|
+
price.textContent = formatPrice(
|
|
75
|
+
items.reduce(
|
|
76
|
+
(acc: number, item: { price: number }) => acc + item.price,
|
|
77
|
+
0
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
document.addEventListener('astro:page-load', () => {
|
|
83
|
+
setPrice($cart.get())
|
|
84
|
+
|
|
85
|
+
$cart.subscribe((items: any) => {
|
|
86
|
+
setPrice(items)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const button = document.querySelector('.cart-summary .checkout-button')
|
|
90
|
+
|
|
91
|
+
button?.addEventListener('click', async () => {
|
|
92
|
+
const items = $cart.get()
|
|
93
|
+
|
|
94
|
+
const checkoutConfig = {
|
|
95
|
+
success_url: `${import.meta.env.PUBLIC_SITE_URL}/checkout`,
|
|
96
|
+
mode: 'payment',
|
|
97
|
+
customer_creation: 'always',
|
|
98
|
+
shipping_address_collection: {
|
|
99
|
+
allowed_countries: ['NL'],
|
|
100
|
+
},
|
|
101
|
+
phone_number_collection: {
|
|
102
|
+
enabled: true,
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const lineItems = items.map((item: any) => ({
|
|
108
|
+
price_data: {
|
|
109
|
+
currency: 'eur',
|
|
110
|
+
product: item.id,
|
|
111
|
+
},
|
|
112
|
+
quantity: 1,
|
|
113
|
+
}))
|
|
114
|
+
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
const checkoutSession = await stripe.checkout.sessions.create({
|
|
117
|
+
line_items: lineItems,
|
|
118
|
+
...checkoutConfig,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
checkoutSession.url && window.location.replace(checkoutSession.url)
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error(error)
|
|
124
|
+
|
|
125
|
+
const lineItems = items.map((item: any) => ({
|
|
126
|
+
quantity: 1,
|
|
127
|
+
price_data: {
|
|
128
|
+
currency: 'eur',
|
|
129
|
+
product_data: {
|
|
130
|
+
name: item.name,
|
|
131
|
+
},
|
|
132
|
+
unit_amount: Math.round(item.price * 100),
|
|
133
|
+
},
|
|
134
|
+
}))
|
|
135
|
+
|
|
136
|
+
// @ts-ignore
|
|
137
|
+
const checkoutSession = await stripe.checkout.sessions.create({
|
|
138
|
+
line_items: lineItems,
|
|
139
|
+
...checkoutConfig,
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
checkoutSession.url && window.location.replace(checkoutSession.url)
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
</script>
|
|
@@ -5,6 +5,7 @@ import Element from 'fulldev-ui/components/Element.astro'
|
|
|
5
5
|
import Logo from 'fulldev-ui/components/experimental/Logo.astro'
|
|
6
6
|
import Menu from 'fulldev-ui/components/Menu.astro'
|
|
7
7
|
import type { GlobalProps } from 'fulldev-ui/types/global-props'
|
|
8
|
+
import Buttons from './Buttons.astro'
|
|
8
9
|
import Heading from './Heading.astro'
|
|
9
10
|
|
|
10
11
|
interface Props extends GlobalProps, HTMLAttributes<'aside'> {
|
|
@@ -15,6 +16,7 @@ interface Props extends GlobalProps, HTMLAttributes<'aside'> {
|
|
|
15
16
|
logo?: ComponentProps<typeof Logo> | undefined
|
|
16
17
|
company?: ComponentProps<typeof Logo>['company']
|
|
17
18
|
menu?: ComponentProps<typeof Menu>['groups']
|
|
19
|
+
buttons?: ComponentProps<typeof Buttons>['buttons']
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
const {
|
|
@@ -24,15 +26,21 @@ const {
|
|
|
24
26
|
color,
|
|
25
27
|
variant,
|
|
26
28
|
text,
|
|
29
|
+
buttons,
|
|
27
30
|
heading,
|
|
28
31
|
logo,
|
|
29
32
|
company,
|
|
30
33
|
menu,
|
|
34
|
+
if: ifProp,
|
|
31
35
|
...rest
|
|
32
36
|
} = Astro.props
|
|
37
|
+
|
|
38
|
+
const buttonsGroup = { heading: '', buttons: buttons }
|
|
39
|
+
const mergedMenu = [buttonsGroup, ...(menu || [])] as typeof menu
|
|
33
40
|
---
|
|
34
41
|
|
|
35
42
|
<Button
|
|
43
|
+
if={ifProp}
|
|
36
44
|
variant="secondary"
|
|
37
45
|
class:list={['drawer-button', `${id}-button`]}
|
|
38
46
|
onclick={`document.getElementById('${id}').showModal()`}
|
|
@@ -43,6 +51,7 @@ const {
|
|
|
43
51
|
/>
|
|
44
52
|
|
|
45
53
|
<Element
|
|
54
|
+
if={ifProp}
|
|
46
55
|
onclick={`event.target === this && this.close()`}
|
|
47
56
|
class:list="drawer"
|
|
48
57
|
as="dialog"
|
|
@@ -72,9 +81,15 @@ const {
|
|
|
72
81
|
<slot name="header" />
|
|
73
82
|
</Element>
|
|
74
83
|
<Element class:list="drawer-content">
|
|
75
|
-
<Menu groups={
|
|
84
|
+
<Menu groups={mergedMenu} />
|
|
76
85
|
<slot />
|
|
77
86
|
</Element>
|
|
87
|
+
<Element
|
|
88
|
+
class:list="drawer-footer"
|
|
89
|
+
as="footer"
|
|
90
|
+
>
|
|
91
|
+
<slot name="footer" />
|
|
92
|
+
</Element>
|
|
78
93
|
</Element>
|
|
79
94
|
</Element>
|
|
80
95
|
|
|
@@ -99,7 +114,7 @@ const {
|
|
|
99
114
|
max-height: 100%;
|
|
100
115
|
|
|
101
116
|
@media (min-width: 768px) {
|
|
102
|
-
width:
|
|
117
|
+
width: 440px;
|
|
103
118
|
}
|
|
104
119
|
|
|
105
120
|
&::backdrop {
|
|
@@ -108,19 +123,35 @@ const {
|
|
|
108
123
|
}
|
|
109
124
|
|
|
110
125
|
.drawer-body {
|
|
126
|
+
display: flex;
|
|
111
127
|
flex-shrink: 1;
|
|
128
|
+
flex-direction: column;
|
|
112
129
|
border-right: 1px solid var(--color-a6);
|
|
113
130
|
height: 100%;
|
|
114
131
|
overflow: auto;
|
|
115
132
|
}
|
|
116
133
|
|
|
117
|
-
.drawer-
|
|
134
|
+
.drawer-content {
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-direction: column;
|
|
137
|
+
padding: var(--space-6) var(--gutter);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.drawer-header,
|
|
141
|
+
.drawer-footer {
|
|
118
142
|
display: flex;
|
|
119
143
|
position: sticky;
|
|
144
|
+
flex-shrink: 0;
|
|
145
|
+
z-index: 1;
|
|
146
|
+
border-style: solid;
|
|
147
|
+
border-color: var(--color-a6);
|
|
148
|
+
background-color: var(--base-background);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.drawer-header {
|
|
120
152
|
top: 0;
|
|
121
153
|
align-items: center;
|
|
122
|
-
border-bottom: 1px
|
|
123
|
-
background-color: var(--base-background);
|
|
154
|
+
border-bottom-width: 1px;
|
|
124
155
|
padding: 0 var(--gutter);
|
|
125
156
|
height: 56px;
|
|
126
157
|
|
|
@@ -129,10 +160,12 @@ const {
|
|
|
129
160
|
}
|
|
130
161
|
}
|
|
131
162
|
|
|
132
|
-
.drawer-
|
|
133
|
-
|
|
163
|
+
.drawer-footer {
|
|
164
|
+
bottom: 0;
|
|
134
165
|
flex-direction: column;
|
|
135
|
-
|
|
166
|
+
margin-top: auto;
|
|
167
|
+
border-top-width: 1px;
|
|
168
|
+
padding: var(--space-5) var(--gutter);
|
|
136
169
|
}
|
|
137
170
|
}
|
|
138
171
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps, HTMLAttributes } from 'astro/types'
|
|
3
|
+
import Button from 'fulldev-ui/components/Button.astro'
|
|
4
|
+
import Element from 'fulldev-ui/components/Element.astro'
|
|
5
|
+
import Input from 'fulldev-ui/components/Input.astro'
|
|
6
|
+
import Select from 'fulldev-ui/components/Select.astro'
|
|
7
|
+
import Textarea from 'fulldev-ui/components/Textarea.astro'
|
|
8
|
+
import type { GlobalProps } from 'fulldev-ui/types/global-props'
|
|
9
|
+
|
|
10
|
+
interface Props extends GlobalProps, HTMLAttributes<'form'> {
|
|
11
|
+
fields: (
|
|
12
|
+
| ComponentProps<typeof Input>
|
|
13
|
+
| ComponentProps<typeof Select>
|
|
14
|
+
| (ComponentProps<typeof Textarea> & { type?: 'textarea' | undefined })
|
|
15
|
+
)[]
|
|
16
|
+
submit?: ComponentProps<typeof Button>['text']
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { fields, submit, ...rest } = Astro.props
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<Element
|
|
23
|
+
class:list="form"
|
|
24
|
+
as="form"
|
|
25
|
+
{...rest}
|
|
26
|
+
>
|
|
27
|
+
{
|
|
28
|
+
fields.map((field) => {
|
|
29
|
+
if ('options' in field) return <Select {...field} />
|
|
30
|
+
if ('type' in field && field.type === 'textarea')
|
|
31
|
+
return <Textarea {...field} />
|
|
32
|
+
return <Input {...(field as any)} />
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
<Button
|
|
36
|
+
type="submit"
|
|
37
|
+
text={submit}
|
|
38
|
+
/>
|
|
39
|
+
</Element>
|
|
40
|
+
|
|
41
|
+
<style is:global lang="scss">
|
|
42
|
+
.form {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
gap: var(--space-4);
|
|
46
|
+
width: 100%;
|
|
47
|
+
max-width: calc(var(--space-4) * 44);
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
@@ -3,9 +3,9 @@ import type { ComponentProps, HTMLAttributes } from 'astro/types'
|
|
|
3
3
|
import Buttons from 'fulldev-ui/components/Buttons.astro'
|
|
4
4
|
import Element from 'fulldev-ui/components/Element.astro'
|
|
5
5
|
import Logo from 'fulldev-ui/components/experimental/Logo.astro'
|
|
6
|
-
import Search from 'fulldev-ui/components/Search.astro'
|
|
7
6
|
import ThemeSelect from 'fulldev-ui/components/ThemeSelect.astro'
|
|
8
7
|
import type { GlobalProps } from 'fulldev-ui/types/global-props'
|
|
8
|
+
import Cart from './Cart.astro'
|
|
9
9
|
import Drawer from './Drawer.astro'
|
|
10
10
|
import type Menu from './Menu.astro'
|
|
11
11
|
|
|
@@ -52,20 +52,17 @@ const {
|
|
|
52
52
|
{buttons}
|
|
53
53
|
variant="link"
|
|
54
54
|
/>
|
|
55
|
-
{search && <Search />}
|
|
56
55
|
{themeselect && <ThemeSelect />}
|
|
57
56
|
<Drawer
|
|
58
57
|
icon="menu-2"
|
|
59
58
|
id="menu"
|
|
60
|
-
{menu}
|
|
61
59
|
{logo}
|
|
62
60
|
{company}
|
|
61
|
+
{buttons}
|
|
62
|
+
{menu}
|
|
63
63
|
/>
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
class="cart-button"
|
|
67
|
-
color="brand"
|
|
68
|
-
id="cart"
|
|
64
|
+
<Cart
|
|
65
|
+
if={cart}
|
|
69
66
|
heading={cart}
|
|
70
67
|
/>
|
|
71
68
|
</Element>
|
|
@@ -17,6 +17,7 @@ const {
|
|
|
17
17
|
disabled,
|
|
18
18
|
required,
|
|
19
19
|
placeholder,
|
|
20
|
+
readonly,
|
|
20
21
|
name = placeholder,
|
|
21
22
|
type = 'text',
|
|
22
23
|
...rest
|
|
@@ -41,6 +42,7 @@ const {
|
|
|
41
42
|
{value}
|
|
42
43
|
{disabled}
|
|
43
44
|
{required}
|
|
45
|
+
{readonly}
|
|
44
46
|
/>
|
|
45
47
|
<Icon name={icon} />
|
|
46
48
|
</Element>
|
|
@@ -97,6 +99,10 @@ const {
|
|
|
97
99
|
cursor: not-allowed;
|
|
98
100
|
pointer-events: none;
|
|
99
101
|
}
|
|
102
|
+
|
|
103
|
+
&[readonly] {
|
|
104
|
+
pointer-events: none;
|
|
105
|
+
}
|
|
100
106
|
}
|
|
101
107
|
}
|
|
102
108
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types'
|
|
3
3
|
import Element from 'fulldev-ui/components/Element.astro'
|
|
4
4
|
import type { GlobalProps } from 'fulldev-ui/types/global-props'
|
|
5
|
+
import { formatPrice } from 'fulldev-ui/utils/cart'
|
|
5
6
|
|
|
6
7
|
interface Props extends GlobalProps, HTMLAttributes<'div'> {
|
|
7
8
|
size?: 'sm' | 'md' | 'lg' | undefined
|
|
@@ -13,17 +14,12 @@ interface Props extends GlobalProps, HTMLAttributes<'div'> {
|
|
|
13
14
|
const { value, ...rest } = Astro.props
|
|
14
15
|
---
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
>
|
|
23
|
-
€{value?.toFixed(2).replace('.', ',')}
|
|
24
|
-
</Element>
|
|
25
|
-
)
|
|
26
|
-
}
|
|
17
|
+
<Element
|
|
18
|
+
class:list="price"
|
|
19
|
+
{...rest}
|
|
20
|
+
>
|
|
21
|
+
{value && <Fragment set:html={formatPrice(value)} />}
|
|
22
|
+
</Element>
|
|
27
23
|
|
|
28
24
|
<style is:global lang="scss">
|
|
29
25
|
@layer fulldev {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
---
|
|
2
|
-
import Pagefind from 'astro-pagefind/components/Search'
|
|
3
2
|
import Dialog from 'fulldev-ui/components/Dialog.astro'
|
|
4
3
|
|
|
5
4
|
const { variant = 'secondary', ...rest } = Astro.props
|
|
@@ -11,9 +10,7 @@ const { variant = 'secondary', ...rest } = Astro.props
|
|
|
11
10
|
icon="search"
|
|
12
11
|
{variant}
|
|
13
12
|
{...rest}
|
|
14
|
-
|
|
15
|
-
<Pagefind uiOptions={{ showImages: false }} />
|
|
16
|
-
</Dialog>
|
|
13
|
+
/>
|
|
17
14
|
|
|
18
15
|
<style is:global lang="scss">
|
|
19
16
|
:root {
|
package/src/components/Toc.astro
CHANGED
|
@@ -20,7 +20,7 @@ const filteredHeadings = headings?.filter(
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
22
|
<Element
|
|
23
|
-
if={filteredHeadings?.length >
|
|
23
|
+
if={filteredHeadings?.length > 1}
|
|
24
24
|
class:list="toc"
|
|
25
25
|
{size}
|
|
26
26
|
{...rest}
|
|
@@ -49,17 +49,14 @@ const filteredHeadings = headings?.filter(
|
|
|
49
49
|
@media (min-width: 1024px) {
|
|
50
50
|
display: flex;
|
|
51
51
|
position: sticky;
|
|
52
|
-
top: var(--header-height, 0px);
|
|
52
|
+
top: calc(var(--header-height, 0px) + var(--space-6));
|
|
53
53
|
bottom: 0;
|
|
54
54
|
flex-shrink: 0;
|
|
55
55
|
flex-direction: column;
|
|
56
56
|
justify-content: flex-start;
|
|
57
57
|
gap: var(--space-4);
|
|
58
58
|
z-index: 10;
|
|
59
|
-
|
|
60
|
-
width: calc(var(--space-7) * 4);
|
|
61
|
-
height: calc(100vh - var(--header-height, 0px));
|
|
62
|
-
overflow-y: auto;
|
|
59
|
+
min-width: calc(var(--space-7) * 3);
|
|
63
60
|
|
|
64
61
|
.depth-3 {
|
|
65
62
|
padding-left: var(--space-4);
|
|
@@ -3,7 +3,7 @@ import Table from 'fulldev-ui/components/Table.astro'
|
|
|
3
3
|
import { readFileSync } from 'node:fs'
|
|
4
4
|
import { pascal } from 'radash'
|
|
5
5
|
|
|
6
|
-
const slug = Astro.
|
|
6
|
+
const slug = Astro.params.page || 'index'
|
|
7
7
|
const componentName = pascal(slug)
|
|
8
8
|
|
|
9
9
|
const allComponents = import.meta.glob('/src/**/*.astro', { eager: true })
|
|
@@ -1,21 +1,45 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { HTMLAttributes } from 'astro/types'
|
|
2
|
+
import type { ComponentProps, HTMLAttributes } from 'astro/types'
|
|
3
3
|
import Element from 'fulldev-ui/components/Element.astro'
|
|
4
4
|
import type { GlobalProps } from 'fulldev-ui/types/global-props'
|
|
5
|
+
import Button from '../Button.astro'
|
|
6
|
+
import Input from '../Input.astro'
|
|
7
|
+
import Select from '../Select.astro'
|
|
8
|
+
import Textarea from '../Textarea.astro'
|
|
5
9
|
|
|
6
10
|
interface Props extends GlobalProps, HTMLAttributes<'form'> {
|
|
7
|
-
|
|
11
|
+
submit?: ComponentProps<typeof Button>['text']
|
|
12
|
+
fields?:
|
|
13
|
+
| (
|
|
14
|
+
| ComponentProps<typeof Input>
|
|
15
|
+
| ComponentProps<typeof Select>
|
|
16
|
+
| (ComponentProps<typeof Textarea> & { type?: 'textarea' | undefined })
|
|
17
|
+
)[]
|
|
18
|
+
| undefined
|
|
8
19
|
}
|
|
9
20
|
|
|
10
|
-
const {
|
|
21
|
+
const { fields, submit, ...rest } = Astro.props
|
|
11
22
|
---
|
|
12
23
|
|
|
13
24
|
<Element
|
|
14
|
-
class:list=
|
|
25
|
+
class:list="form"
|
|
15
26
|
as="form"
|
|
16
27
|
{...rest}
|
|
17
28
|
>
|
|
18
|
-
<slot
|
|
29
|
+
<slot>
|
|
30
|
+
{
|
|
31
|
+
fields?.map((field) => {
|
|
32
|
+
if ('options' in field) return <Select {...field} />
|
|
33
|
+
if ('type' in field && field.type === 'textarea')
|
|
34
|
+
return <Textarea {...field} />
|
|
35
|
+
return <Input {...(field as any)} />
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
<Button
|
|
39
|
+
type="submit"
|
|
40
|
+
text={submit}
|
|
41
|
+
/>
|
|
42
|
+
</slot>
|
|
19
43
|
</Element>
|
|
20
44
|
|
|
21
45
|
<style is:global lang="scss">
|