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.
Files changed (78) hide show
  1. package/.env.example +3 -0
  2. package/CONTRIBUTING.md +10 -4
  3. package/astro.config.ts +2 -13
  4. package/package.json +8 -4
  5. package/pnpm-lock.yaml +82 -130
  6. package/src/blocks/Article.astro +31 -12
  7. package/src/blocks/Banner.astro +2 -1
  8. package/src/blocks/Contact.astro +7 -30
  9. package/src/blocks/Excerpt.astro +14 -0
  10. package/src/blocks/Intro.astro +3 -1
  11. package/src/blocks/Product.astro +55 -22
  12. package/src/components/Card.astro +11 -5
  13. package/src/components/Cart.astro +38 -0
  14. package/src/components/CartForm.astro +121 -0
  15. package/src/components/CartList.astro +134 -0
  16. package/src/components/CartSummary.astro +147 -0
  17. package/src/components/Drawer.astro +128 -52
  18. package/src/components/Footer.astro +6 -3
  19. package/src/components/Form.astro +49 -0
  20. package/src/components/Header.astro +19 -14
  21. package/src/components/Image.astro +0 -1
  22. package/src/components/Input.astro +6 -0
  23. package/src/components/Menu.astro +56 -0
  24. package/src/components/Price.astro +7 -11
  25. package/src/components/Search.astro +1 -4
  26. package/src/components/Section.astro +2 -1
  27. package/src/components/Sidebar.astro +61 -111
  28. package/src/components/Social.astro +7 -0
  29. package/src/components/ThemeSelect.astro +3 -0
  30. package/src/components/Toc.astro +33 -94
  31. package/src/components/docs/PropsTable.astro +1 -1
  32. package/src/components/experimental/Form.astro +31 -5
  33. package/src/components/experimental/Gallery.astro +50 -126
  34. package/src/components/experimental/Prose.astro +32 -0
  35. package/src/content/pages/base/select.mdx +0 -8
  36. package/src/content/pages/base/textarea.mdx +0 -5
  37. package/src/content/pages/blocks/_product.mdx +73 -2
  38. package/src/content/pages/index.mdx +0 -3
  39. package/src/content/pages/layouts/_layout.mdx +14 -0
  40. package/src/content/pages/layouts/docslayout.mdx +10 -1
  41. package/src/content/pages/overview/components.mdx +5 -0
  42. package/src/content/pages/overview/content-collections.mdx +139 -0
  43. package/src/content/pages/overview/installation.mdx +25 -26
  44. package/src/content/pages/overview/introduction.mdx +16 -10
  45. package/src/content/pages/overview/theming.mdx +69 -0
  46. package/src/content/pages/schemas/page.mdx +6 -0
  47. package/src/content/presets/base.yml +56 -43
  48. package/src/content/presets/blocks.yml +0 -3
  49. package/src/content/presets/docs.yml +3 -62
  50. package/src/env.d.ts +1 -1
  51. package/src/integration/index.ts +63 -34
  52. package/src/layouts/DocsLayout.astro +23 -35
  53. package/src/layouts/Layout.astro +37 -21
  54. package/src/layouts/OverviewLayout.astro +17 -10
  55. package/src/layouts/PostLayout.astro +7 -7
  56. package/src/layouts/ProductLayout.astro +5 -2
  57. package/src/schemas/components/footer.ts +1 -0
  58. package/src/schemas/components/header.ts +1 -0
  59. package/src/schemas/components/menu.ts +13 -0
  60. package/src/schemas/components/sidebar.ts +15 -0
  61. package/src/schemas/components/toc.ts +3 -0
  62. package/src/schemas/pageSchema.ts +72 -34
  63. package/src/schemas/presetSchema.ts +2 -28
  64. package/src/schemas/utils/navigation.ts +6 -51
  65. package/src/stores/cart.ts +23 -0
  66. package/src/utils/cart.ts +32 -0
  67. package/src/utils/{getChildPages.ts → getFolderChildren.ts} +3 -1
  68. package/src/utils/{getCategoryPages.ts → getReferenceChildren.ts} +6 -3
  69. package/tsconfig.json +1 -3
  70. package/src/components/experimental/GalleryVertical.astro +0 -161
  71. package/src/content/pages/layouts/layout.mdx +0 -21
  72. package/src/content/pages/layouts/pagelayout.mdx +0 -21
  73. package/src/content/pages/overview/content-layer.mdx +0 -128
  74. package/src/content/pages/overview/customization.mdx +0 -83
  75. package/src/layouts/ContentLayout.astro +0 -16
  76. package/src/layouts/PageLayout.astro +0 -15
  77. /package/src/schemas/utils/{categories.ts → parents.ts} +0 -0
  78. /package/src/types/{global-props.d.ts → global-props.ts} +0 -0
@@ -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 = 2,
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
  }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import Section from 'fulldev-ui/components/Section.astro'
3
+
4
+ const { ...rest } = Astro.props
5
+ ---
6
+
7
+ <Section
8
+ level={1}
9
+ size="lg"
10
+ align="center"
11
+ variant="primary"
12
+ color="brand"
13
+ {...rest}
14
+ />
@@ -8,7 +8,7 @@ const { image, ...rest } = Astro.props
8
8
  class:list="intro"
9
9
  structure="column"
10
10
  size="sm"
11
- level={2}
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>
@@ -1,10 +1,11 @@
1
1
  ---
2
- import Button from 'fulldev-ui/components/Button.astro'
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 Input from 'fulldev-ui/components/Input.astro'
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
- <Image {...image || images?.[0]} />
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={1}
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
- <Price value={price} />
45
- <Element class:list="row">
46
- <Input
47
- value={1}
48
- name={'quantity'}
49
- style={{ width: 'var(--space-6)' }}
50
- type="number"
51
- />
52
- <Button
53
- color="brand"
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
- > .root.image {
125
- transition: all;
130
+ > .image {
131
+ transition: all 0.2s ease;
126
132
  }
127
133
 
128
134
  &:hover {
129
- > .root.image {
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>