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

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 (40) hide show
  1. package/package.json +1 -1
  2. package/src/blocks/Excerpt.astro +14 -0
  3. package/src/blocks/Product.astro +42 -3
  4. package/src/components/Drawer.astro +97 -54
  5. package/src/components/Footer.astro +4 -0
  6. package/src/components/Header.astro +19 -10
  7. package/src/components/Menu.astro +56 -0
  8. package/src/components/Section.astro +2 -0
  9. package/src/components/Sidebar.astro +61 -111
  10. package/src/components/ThemeSelect.astro +3 -0
  11. package/src/components/Toc.astro +36 -94
  12. package/src/components/experimental/Gallery.astro +50 -126
  13. package/src/components/experimental/Prose.astro +32 -0
  14. package/src/content/config.ts +1 -2
  15. package/src/content/pages/blocks/_product.mdx +73 -2
  16. package/src/content/pages/index.mdx +0 -2
  17. package/src/content/pages/layouts/_layout.mdx +8 -15
  18. package/src/content/pages/layouts/docslayout.mdx +10 -1
  19. package/src/content/pages/overview/components.mdx +5 -0
  20. package/src/content/pages/overview/content-collections.mdx +139 -0
  21. package/src/content/pages/overview/installation.mdx +25 -26
  22. package/src/content/pages/overview/introduction.mdx +16 -10
  23. package/src/content/pages/overview/theming.mdx +69 -0
  24. package/src/content/pages/schemas/page.mdx +6 -0
  25. package/src/content/presets/base.yml +57 -43
  26. package/src/content/presets/blocks.yml +0 -3
  27. package/src/content/presets/docs.yml +2 -61
  28. package/src/layouts/Layout.astro +24 -14
  29. package/src/layouts/PostLayout.astro +24 -0
  30. package/src/layouts/ProductLayout.astro +5 -2
  31. package/src/schemas/components/header.ts +7 -9
  32. package/src/schemas/components/menu.ts +13 -0
  33. package/src/schemas/components/sidebar.ts +15 -0
  34. package/src/schemas/components/toc.ts +3 -0
  35. package/src/schemas/pageSchema.ts +5 -6
  36. package/src/schemas/utils/navigation.ts +3 -53
  37. package/src/components/experimental/GalleryVertical.astro +0 -161
  38. package/src/content/pages/overview/content-layer.mdx +0 -128
  39. package/src/content/pages/overview/customization.mdx +0 -83
  40. package/src/schemas/presetSchema.ts +0 -33
@@ -1,16 +1,17 @@
1
1
  ---
2
- import type { HTMLAttributes } from 'astro/types'
2
+ import type { ComponentProps, HTMLAttributes } from 'astro/types'
3
3
  import type { CollectionEntry } from 'astro:content'
4
4
  import Button from 'fulldev-ui/components/Button.astro'
5
5
  import Element from 'fulldev-ui/components/Element.astro'
6
6
  import Heading from 'fulldev-ui/components/Heading.astro'
7
7
  import type { GlobalProps } from 'fulldev-ui/types/global-props'
8
8
 
9
- interface Props extends GlobalProps, HTMLAttributes<'aside'> {
9
+ interface Props extends GlobalProps, HTMLAttributes<'div'> {
10
+ heading?: ComponentProps<typeof Heading>['text']
10
11
  render?: CollectionEntry<'pages'>['render'] | undefined
11
12
  }
12
13
 
13
- const { size = 'sm', render } = Astro.props
14
+ const { size = 'sm', heading, render, ...rest } = Astro.props
14
15
 
15
16
  const headings = render ? (await render())?.headings : []
16
17
  const filteredHeadings = headings?.filter(
@@ -18,114 +19,55 @@ const filteredHeadings = headings?.filter(
18
19
  )
19
20
  ---
20
21
 
21
- <input
22
- id="toc"
23
- class="toc-checkbox"
24
- type="checkbox"
25
- />
26
-
27
22
  <Element
23
+ if={filteredHeadings?.length > 0}
28
24
  class:list="toc"
29
- as="aside"
30
25
  {size}
26
+ {...rest}
31
27
  >
28
+ <Heading
29
+ level={6}
30
+ text={heading}
31
+ />
32
32
  {
33
- filteredHeadings?.length > 0 && (
34
- <>
35
- <Heading
36
- text="On this page"
37
- level={6}
38
- />
39
- <nav class="toc-nav">
40
- <Button
41
- variant="link"
42
- href={`#${filteredHeadings[0]?.slug}`}
43
- text="Overview"
44
- class="toc-link toc-link-h2"
45
- />
46
- {filteredHeadings.map((heading: any) => (
47
- <Button
48
- variant="link"
49
- href={`#${heading.slug}`}
50
- text={heading.text}
51
- class={`toc-link toc-link-h${heading.depth}`}
52
- />
53
- ))}
54
- </nav>
55
- </>
56
- )
33
+ filteredHeadings?.map((button: any) => (
34
+ <Button
35
+ class:list={`depth-${button.depth}`}
36
+ href={`#${button.slug}`}
37
+ variant="link"
38
+ text={button.text}
39
+ />
40
+ ))
57
41
  }
58
42
  </Element>
59
43
 
60
44
  <style lang="scss" is:global>
61
45
  @layer fulldev {
62
- .toc-checkbox {
63
- display: none;
64
- }
65
-
66
- @media (max-width: 1023.999px) {
67
- body:has(.toc-checkbox:checked) {
68
- overflow: hidden;
69
- }
70
- }
71
-
72
46
  .toc {
73
- --toc-width: 240px;
74
-
75
47
  display: none;
76
- position: fixed;
77
- top: var(--header-height, 0px);
78
- right: 0;
79
- flex-shrink: 0;
80
- flex-direction: column;
81
- justify-content: flex-start;
82
- gap: calc(var(--space-4) + var(--space-1));
83
- z-index: 10;
84
- border-left-width: 1px;
85
- border-style: solid;
86
- border-color: var(--color-a6);
87
- background-color: var(--color-background);
88
- padding: var(--space-md-6) var(--gutter);
89
- width: 100%;
90
- max-height: calc(100vh - var(--header-height, 0px));
91
- overflow-y: auto;
92
-
93
- &:is(.toc-checkbox:checked + &) {
94
- display: flex;
95
- }
96
48
 
97
49
  @media (min-width: 1024px) {
98
50
  display: flex;
99
51
  position: sticky;
100
- border-left-width: 1px;
101
- width: var(--toc-width);
102
- }
103
-
104
- .button + .heading {
105
- margin-top: var(--space-5);
106
- }
107
-
108
- .toc-nav {
109
- display: flex;
52
+ top: var(--header-height, 0px);
53
+ bottom: 0;
54
+ flex-shrink: 0;
110
55
  flex-direction: column;
111
- }
112
-
113
- .toc-link {
114
- text-align: left;
115
- }
116
-
117
- .toc-link-h2 {
118
- margin-top: var(--space-3);
119
- }
120
-
121
- .toc-link-h3 {
122
- margin-top: var(--space-3);
123
- margin-left: var(--space-4);
124
- }
125
-
126
- .toc-link-h4 {
127
- margin-top: var(--space-2);
128
- margin-left: var(--space-5);
56
+ justify-content: flex-start;
57
+ gap: var(--space-4);
58
+ z-index: 10;
59
+ padding: var(--space-md-6) var(--gutter);
60
+ width: calc(var(--space-7) * 4);
61
+ height: calc(100vh - var(--header-height, 0px));
62
+ overflow-y: auto;
63
+
64
+ .depth-3 {
65
+ padding-left: var(--space-4);
66
+ }
67
+
68
+ .depth-4 {
69
+ padding-left: var(--space-5);
70
+ }
129
71
  }
130
72
  }
131
73
  }
@@ -1,180 +1,104 @@
1
1
  ---
2
- import Icon from 'fulldev-ui/components/Icon.astro'
2
+ import Element from 'fulldev-ui/components/Element.astro'
3
3
  import Image from 'fulldev-ui/components/Image.astro'
4
4
 
5
- const { images, direction } = Astro.props
5
+ const { images } = Astro.props
6
6
  ---
7
7
 
8
8
  <script>
9
- const carousel = document.querySelector('.gallery .large-carousel')
10
- const icon = document.querySelector('.gallery .icon')
11
- const smallImages = document.querySelectorAll('.gallery .small-image')
12
-
13
- carousel &&
14
- icon?.addEventListener('click', () => {
15
- const carouselWidth = (carousel as HTMLElement).offsetWidth
16
- const currentScroll = carousel.scrollLeft
17
- const maxScroll = carousel.scrollWidth - carouselWidth
18
-
19
- let scrollAmount = currentScroll + carouselWidth
20
- if (scrollAmount > maxScroll) {
21
- scrollAmount = 0 // Reset to beginning if we're at the end
22
- }
23
-
24
- carousel.scrollTo({
25
- left: scrollAmount,
26
- behavior: 'smooth',
27
- })
28
- })
29
-
30
- carousel &&
31
- smallImages?.forEach((image, i) => {
32
- image.addEventListener('click', () => {
33
- const imageWidth = (carousel as HTMLElement).offsetWidth
34
- carousel.scrollTo({
35
- left: i * imageWidth,
36
- behavior: 'smooth',
9
+ const setupGallery = (document: Document) => {
10
+ const galleries = document.querySelectorAll('.gallery')
11
+
12
+ galleries.forEach((gallery) => {
13
+ const carousel = gallery.querySelector('.large-carousel')
14
+ const smallImages = gallery.querySelectorAll('.small-image')
15
+
16
+ carousel &&
17
+ smallImages?.forEach((image, i) => {
18
+ image.addEventListener('click', () => {
19
+ const largeImages = carousel.querySelectorAll('.large-image')
20
+ if (largeImages[i]) {
21
+ largeImages[i].scrollIntoView({
22
+ behavior: 'smooth',
23
+ block: 'nearest',
24
+ inline: 'start',
25
+ })
26
+ }
27
+ })
37
28
  })
38
- })
39
29
  })
30
+ }
31
+
32
+ setupGallery(document)
33
+
34
+ document.addEventListener('astro:before-swap', (event) => {
35
+ setupGallery(event.newDocument)
36
+ })
40
37
  </script>
41
38
 
42
- <div
43
- class:list={[
44
- 'full',
45
- 'gallery',
46
- {
47
- [`direction-${direction}`]: direction,
48
- },
49
- ]}
50
- >
51
- <div class="large-container">
52
- <div class="large-carousel">
53
- {
54
- images?.map((image: any) => (
55
- <Image
56
- class="large-image"
57
- src={image}
58
- />
59
- ))
60
- }
61
- </div>
39
+ <Element class:list={['gallery']}>
40
+ <Element class="large-carousel">
62
41
  {
63
- images?.length > 1 && (
64
- <Icon
65
- class="icon"
66
- name="swipe-left"
42
+ images?.map((image: any) => (
43
+ <Image
44
+ class="large-image"
45
+ {...(typeof image === 'string' ? { src: image } : image)}
67
46
  />
68
- )
47
+ ))
69
48
  }
70
- </div>
71
- <div class="small-carousel">
49
+ </Element>
50
+ <Element class="small-carousel">
72
51
  {
73
52
  images?.length > 1 &&
74
53
  images.map((image: any) => (
75
54
  <Image
76
55
  class="small-image"
77
- src={image}
56
+ {...(typeof image === 'string' ? { src: image } : image)}
78
57
  />
79
58
  ))
80
59
  }
81
- </div>
82
- </div>
60
+ </Element>
61
+ </Element>
83
62
 
84
63
  <style is:global lang="scss">
85
64
  .gallery {
86
65
  display: flex;
87
66
  position: relative;
88
- column-gap: var(--space-4);
89
- row-gap: var(--space-1);
90
67
  flex-direction: column;
91
-
92
- @media (min-width: 1024px) {
93
- flex-direction: row-reverse;
94
- }
95
-
96
- .large-container {
97
- display: flex;
98
- justify-content: space-between;
99
- align-items: center;
100
-
101
- &:hover .icon {
102
- opacity: 1;
103
- }
104
-
105
- .icon {
106
- position: absolute;
107
- right: var(--space-3);
108
- opacity: 0.5;
109
- animation: swipe-icon 1.6s ease-in-out infinite;
110
- transition: opacity 0.2s ease-in-out;
111
- font-size: calc(var(--text-2) * 1.7);
112
-
113
- @media (min-width: 1024px) {
114
- display: none;
115
- }
116
- }
117
-
118
- @keyframes swipe-icon {
119
- 0%,
120
- 100% {
121
- right: var(--space-3);
122
- }
123
- 50% {
124
- right: calc(var(--space-3) * 2);
125
- }
126
- }
127
- }
68
+ gap: var(--space-1) var(--space-4);
128
69
 
129
70
  .small-carousel,
130
71
  .large-carousel {
131
- --column-width: 100%;
132
72
  display: flex;
133
73
  position: relative;
134
- align-items: flex-start;
74
+ align-items: center;
135
75
  gap: var(--space-4);
136
-
137
76
  box-sizing: border-box;
138
77
  padding-bottom: var(--space-4);
139
78
  width: 100%;
140
- overflow-x: auto;
79
+ overflow: auto;
141
80
  scroll-behavior: smooth;
142
81
  scroll-snap-type: x mandatory;
143
82
 
144
- > .root {
83
+ > .image {
145
84
  flex-grow: 0;
146
85
  flex-shrink: 0;
147
86
  width: var(--column-width);
148
87
  scroll-snap-align: center;
149
88
  }
89
+ }
150
90
 
151
- &.position-inset {
152
- margin-right: calc(var(--inner-x) * -1);
153
- margin-left: calc(var(--inner-x) * -1);
154
- padding-right: var(--inner-x);
155
- padding-left: var(--inner-x);
156
- width: calc(100% + var(--inner-x) * 2);
157
- }
91
+ .large-carousel {
92
+ --column-width: 100%;
158
93
  }
159
94
 
160
95
  .small-carousel {
161
96
  --column-width: var(--space-7);
162
97
 
163
- @media (min-width: 1024px) {
164
- --column-width: 100%;
165
-
166
- flex-direction: column;
167
- width: 40%;
98
+ .image:hover {
99
+ opacity: 0.8;
100
+ cursor: pointer;
168
101
  }
169
102
  }
170
-
171
- .small-image,
172
- .large-image {
173
- }
174
-
175
- .small-image:hover {
176
- opacity: 0.8;
177
- cursor: pointer;
178
- }
179
103
  }
180
104
  </style>
@@ -151,6 +151,38 @@ const { as = 'div', ...rest } = Astro.props
151
151
  }
152
152
  }
153
153
 
154
+ ul,
155
+ ol {
156
+ display: flex;
157
+ flex-direction: column;
158
+ margin: var(--space-4) 0;
159
+ padding-left: var(--space-5);
160
+ color: var(--color-11);
161
+ font-size: var(--text-2);
162
+ line-height: 1.625;
163
+ }
164
+
165
+ ul {
166
+ list-style-type: disc;
167
+ }
168
+
169
+ ol {
170
+ list-style-type: decimal;
171
+ }
172
+
173
+ li {
174
+ align-items: center;
175
+ margin-bottom: var(--space-2);
176
+ max-width: calc(var(--space-4) * 44);
177
+ color: var(--color-11);
178
+ font-size: var(--text-2);
179
+ line-height: 1.625;
180
+ }
181
+
182
+ li:last-child {
183
+ margin-bottom: 0;
184
+ }
185
+
154
186
  p code {
155
187
  background-color: var(--base-12);
156
188
  padding: 0 var(--space-1);
@@ -2,7 +2,6 @@ import { defineCollection } from 'astro:content'
2
2
  import imageLoader from 'fulldev-ui/loaders/imageLoader.ts'
3
3
  import imageSchema from 'fulldev-ui/schemas/imageSchema.ts'
4
4
  import pageSchema from 'fulldev-ui/schemas/pageSchema.ts'
5
- import presetSchema from 'fulldev-ui/schemas/presetSchema.ts'
6
5
 
7
6
  export const collections = {
8
7
  pages: defineCollection({
@@ -11,7 +10,7 @@ export const collections = {
11
10
  }),
12
11
  presets: defineCollection({
13
12
  type: 'data',
14
- schema: presetSchema,
13
+ schema: pageSchema,
15
14
  }),
16
15
  images: defineCollection({
17
16
  loader: imageLoader,
@@ -13,8 +13,79 @@ import Product from 'fulldev-ui/blocks/Product.astro'
13
13
  heading="Basic Tee"
14
14
  price={48}
15
15
  rating={5}
16
- image="/images/placeholder-landscape.webp"
17
- buttons={[{ text: 'Add to cart' }]}
16
+ image="placeholder-landscape.webp"
17
+ form={{ submit: 'Add to cart' }}
18
+ description="Oversized white tee made of 100% cotton."
19
+ list={[
20
+ 'Shortsleeve',
21
+ 'Ribbed collar',
22
+ 'Runs large',
23
+ 'Unisex',
24
+ 'Material: 100% cotton',
25
+ 'Imported',
26
+ ]}
27
+ />
28
+ ```
29
+
30
+ ```astro live
31
+ ---
32
+ import Product from 'fulldev-ui/blocks/Product.astro'
33
+ ---
34
+
35
+ <Product
36
+ heading="Basic Tee"
37
+ price={48}
38
+ rating={5}
39
+ images={[
40
+ '/images/blocks/colleagues.png',
41
+ '/images/blocks/content.png',
42
+ '/images/blocks/cta.png',
43
+ '/images/blocks/features.png',
44
+ '/images/blocks/footer.png',
45
+ '/images/blocks/header.png',
46
+ '/images/blocks/hero.png',
47
+ '/images/blocks/intro.png',
48
+ '/images/blocks/posts.png',
49
+ '/images/blocks/prices.png',
50
+ '/images/blocks/reviews.png',
51
+ ]}
52
+ form={{ submit: 'Add to cart' }}
53
+ description="Oversized white tee made of 100% cotton."
54
+ list={[
55
+ 'Shortsleeve',
56
+ 'Ribbed collar',
57
+ 'Runs large',
58
+ 'Unisex',
59
+ 'Material: 100% cotton',
60
+ 'Imported',
61
+ ]}
62
+ />
63
+ ```
64
+
65
+ ```astro live
66
+ ---
67
+ import Product from 'fulldev-ui/blocks/Product.astro'
68
+ ---
69
+
70
+ <Product
71
+ heading="Basic Tee"
72
+ price={48}
73
+ rating={5}
74
+ images={[
75
+ '/images/blocks/colleagues.png',
76
+ '/images/blocks/content.png',
77
+ '/images/blocks/cta.png',
78
+ '/images/blocks/features.png',
79
+ '/images/blocks/footer.png',
80
+ '/images/blocks/header.png',
81
+ '/images/blocks/hero.png',
82
+ '/images/blocks/intro.png',
83
+ '/images/blocks/posts.png',
84
+ '/images/blocks/prices.png',
85
+ '/images/blocks/reviews.png',
86
+ ]}
87
+ gallery="vertical"
88
+ form={{ submit: 'Add to cart' }}
18
89
  description="Oversized white tee made of 100% cotton."
19
90
  list={[
20
91
  'Shortsleeve',
@@ -1,7 +1,5 @@
1
1
  ---
2
2
  presets: [base]
3
- sidebar: false
4
- toc: false
5
3
 
6
4
  seo:
7
5
  title: Fulldev UI - Astro component and block library, open-source
@@ -1,21 +1,14 @@
1
1
  ---
2
- presets: [docs, blocks]
2
+ presets: [docs]
3
3
 
4
4
  title: Layout
5
5
  ---
6
6
 
7
- ```astro live
8
- ---
9
- import Hero from 'fulldev-ui/blocks/Hero.astro'
10
- import Layout from 'fulldev-ui/layouts/Layout.astro'
11
- ---
7
+ import Layout from 'fulldev-ui/layouts/Layout.astro?raw'
8
+ import { Code } from 'astro:components'
9
+
10
+ # Layout
11
+
12
+ The Layout component is used to wrap the content of a page. It provides a structured template for your website.
12
13
 
13
- <Layout>
14
- <Hero
15
- heading="Layout"
16
- text="The Layout component is used to wrap the content of a page."
17
- align="center"
18
- frame="viewport"
19
- />
20
- </Layout>
21
- ```
14
+ <Code code={Layout} lang="astro" />
@@ -1,5 +1,14 @@
1
1
  ---
2
- presets: [docs, blocks]
2
+ presets: [docs]
3
3
 
4
4
  title: DocsLayout
5
5
  ---
6
+
7
+ import Layout from 'fulldev-ui/layouts/DocsLayout.astro?raw'
8
+ import { Code } from 'astro:components'
9
+
10
+ # DocsLayout
11
+
12
+ The DocsLayout component is used to wrap the content of a page in a sidebar and a main content area and table of contents.
13
+
14
+ <Code code={Layout} lang="astro" />
@@ -68,3 +68,8 @@ import Button from 'fulldev-ui/components/Button.astro'
68
68
 
69
69
  {/* This will render a button */}
70
70
  <Button if={true} />
71
+ ```
72
+
73
+ ## Overriding Components
74
+
75
+ You can override components by creating a new component with the same name as one from the library in the **src/components** directory and adding your custom code. This also works for blocks and layouts.