feat: flex component, document higher-order layout components
This commit is contained in:
		
							parent
							
								
									87b803790c
								
							
						
					
					
						commit
						2718ab9019
					
				
							
								
								
									
										62
									
								
								docs/layout-components.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								docs/layout-components.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | ||||
| --- | ||||
| title: Higher-Order Layout Components | ||||
| --- | ||||
| 
 | ||||
| Quartz provides several higher-order components that help with layout composition and responsive design. These components wrap other components to add additional functionality or modify their behavior. | ||||
| 
 | ||||
| ## `Flex` Component | ||||
| 
 | ||||
| The `Flex` component creates a [flexible box layout](https://developer.mozilla.org/en-US/docs/Web/CSS/flex) that can arrange child components in various ways. It's particularly useful for creating responsive layouts and organizing components in rows or columns. | ||||
| 
 | ||||
| ```typescript | ||||
| type FlexConfig = { | ||||
|   components: { | ||||
|     Component: QuartzComponent | ||||
|     grow?: boolean // whether component should grow to fill space | ||||
|     shrink?: boolean // whether component should shrink if needed | ||||
|     basis?: string // initial main size of the component | ||||
|     order?: number // order in flex container | ||||
|     align?: "start" | "end" | "center" | "stretch" // cross-axis alignment | ||||
|     justify?: "start" | "end" | "center" | "between" | "around" // main-axis alignment | ||||
|   }[] | ||||
|   direction?: "row" | "row-reverse" | "column" | "column-reverse" | ||||
|   wrap?: "nowrap" | "wrap" | "wrap-reverse" | ||||
|   gap?: string | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Example Usage | ||||
| 
 | ||||
| ```typescript | ||||
| Component.Flex({ | ||||
|   components: [ | ||||
|     { | ||||
|       Component: Component.Search(), | ||||
|       grow: true, // Search will grow to fill available space | ||||
|     }, | ||||
|     { Component: Component.Darkmode() }, // Darkmode keeps its natural size | ||||
|   ], | ||||
|   direction: "row", | ||||
|   gap: "1rem", | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| ## `MobileOnly` Component | ||||
| 
 | ||||
| The `MobileOnly` component is a wrapper that makes its child component only visible on mobile devices. This is useful for creating responsive layouts where certain components should only appear on smaller screens. | ||||
| 
 | ||||
| ### Example Usage | ||||
| 
 | ||||
| ```typescript | ||||
| Component.MobileOnly(Component.Spacer()) | ||||
| ``` | ||||
| 
 | ||||
| ## `DesktopOnly` Component | ||||
| 
 | ||||
| The `DesktopOnly` component is the counterpart to `MobileOnly`. It makes its child component only visible on desktop devices. This helps create responsive layouts where certain components should only appear on larger screens. | ||||
| 
 | ||||
| ### Example Usage | ||||
| 
 | ||||
| ```typescript | ||||
| Component.DesktopOnly(Component.TableOfContents()) | ||||
| ``` | ||||
| @ -35,7 +35,9 @@ These correspond to following parts of the page: | ||||
| 
 | ||||
| Quartz **components**, like plugins, can take in additional properties as configuration options. If you're familiar with React terminology, you can think of them as Higher-order Components. | ||||
| 
 | ||||
| See [a list of all the components](component.md) for all available components along with their configuration options. You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. | ||||
| See [a list of all the components](component.md) for all available components along with their configuration options. Additionally, Quartz provides several built-in higher-order components for layout composition - see [[layout-components]] for more details. | ||||
| 
 | ||||
| You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. | ||||
| 
 | ||||
| ### Layout breakpoints | ||||
| 
 | ||||
|  | ||||
| @ -25,8 +25,15 @@ export const defaultContentPageLayout: PageLayout = { | ||||
|   left: [ | ||||
|     Component.PageTitle(), | ||||
|     Component.MobileOnly(Component.Spacer()), | ||||
|     Component.Search(), | ||||
|     Component.Darkmode(), | ||||
|     Component.Flex({ | ||||
|       components: [ | ||||
|         { | ||||
|           Component: Component.Search(), | ||||
|           grow: true, | ||||
|         }, | ||||
|         { Component: Component.Darkmode() }, | ||||
|       ], | ||||
|     }), | ||||
|     Component.Explorer(), | ||||
|   ], | ||||
|   right: [ | ||||
|  | ||||
| @ -1,18 +1,14 @@ | ||||
| import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" | ||||
| 
 | ||||
| export default ((component?: QuartzComponent) => { | ||||
|   if (component) { | ||||
|     const Component = component | ||||
|     const DesktopOnly: QuartzComponent = (props: QuartzComponentProps) => { | ||||
|       return <Component displayClass="desktop-only" {...props} /> | ||||
|     } | ||||
| 
 | ||||
|     DesktopOnly.displayName = component.displayName | ||||
|     DesktopOnly.afterDOMLoaded = component?.afterDOMLoaded | ||||
|     DesktopOnly.beforeDOMLoaded = component?.beforeDOMLoaded | ||||
|     DesktopOnly.css = component?.css | ||||
|     return DesktopOnly | ||||
|   } else { | ||||
|     return () => <></> | ||||
| export default ((component: QuartzComponent) => { | ||||
|   const Component = component | ||||
|   const DesktopOnly: QuartzComponent = (props: QuartzComponentProps) => { | ||||
|     return <Component displayClass="desktop-only" {...props} /> | ||||
|   } | ||||
| }) satisfies QuartzComponentConstructor | ||||
| 
 | ||||
|   DesktopOnly.displayName = component.displayName | ||||
|   DesktopOnly.afterDOMLoaded = component?.afterDOMLoaded | ||||
|   DesktopOnly.beforeDOMLoaded = component?.beforeDOMLoaded | ||||
|   DesktopOnly.css = component?.css | ||||
|   return DesktopOnly | ||||
| }) satisfies QuartzComponentConstructor<QuartzComponent> | ||||
|  | ||||
							
								
								
									
										55
									
								
								quartz/components/Flex.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								quartz/components/Flex.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| import { concatenateResources } from "../util/resources" | ||||
| import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" | ||||
| 
 | ||||
| type FlexConfig = { | ||||
|   components: { | ||||
|     Component: QuartzComponent | ||||
|     grow?: boolean | ||||
|     shrink?: boolean | ||||
|     basis?: string | ||||
|     order?: number | ||||
|     align?: "start" | "end" | "center" | "stretch" | ||||
|     justify?: "start" | "end" | "center" | "between" | "around" | ||||
|   }[] | ||||
|   direction?: "row" | "row-reverse" | "column" | "column-reverse" | ||||
|   wrap?: "nowrap" | "wrap" | "wrap-reverse" | ||||
|   gap?: string | ||||
| } | ||||
| 
 | ||||
| export default ((config: FlexConfig) => { | ||||
|   const Flex: QuartzComponent = (props: QuartzComponentProps) => { | ||||
|     const direction = config.direction ?? "row" | ||||
|     const wrap = config.wrap ?? "nowrap" | ||||
|     const gap = config.gap ?? "1rem" | ||||
| 
 | ||||
|     return ( | ||||
|       <div style={`display: flex; flex-direction: ${direction}; flex-wrap: ${wrap}; gap: ${gap};`}> | ||||
|         {config.components.map((c) => { | ||||
|           const grow = c.grow ? 1 : 0 | ||||
|           const shrink = (c.shrink ?? true) ? 1 : 0 | ||||
|           const basis = c.basis ?? "auto" | ||||
|           const order = c.order ?? 0 | ||||
|           const align = c.align ?? "center" | ||||
|           const justify = c.justify ?? "center" | ||||
| 
 | ||||
|           return ( | ||||
|             <div | ||||
|               style={`flex-grow: ${grow}; flex-shrink: ${shrink}; flex-basis: ${basis}; order: ${order}; align-self: ${align}; justify-self: ${justify};`} | ||||
|             > | ||||
|               <c.Component {...props} /> | ||||
|             </div> | ||||
|           ) | ||||
|         })} | ||||
|       </div> | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   Flex.afterDOMLoaded = concatenateResources( | ||||
|     ...config.components.map((c) => c.Component.afterDOMLoaded), | ||||
|   ) | ||||
|   Flex.beforeDOMLoaded = concatenateResources( | ||||
|     ...config.components.map((c) => c.Component.beforeDOMLoaded), | ||||
|   ) | ||||
|   Flex.css = concatenateResources(...config.components.map((c) => c.Component.css)) | ||||
|   return Flex | ||||
| }) satisfies QuartzComponentConstructor<FlexConfig> | ||||
| @ -1,18 +1,14 @@ | ||||
| import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" | ||||
| 
 | ||||
| export default ((component?: QuartzComponent) => { | ||||
|   if (component) { | ||||
|     const Component = component | ||||
|     const MobileOnly: QuartzComponent = (props: QuartzComponentProps) => { | ||||
|       return <Component displayClass="mobile-only" {...props} /> | ||||
|     } | ||||
| 
 | ||||
|     MobileOnly.displayName = component.displayName | ||||
|     MobileOnly.afterDOMLoaded = component?.afterDOMLoaded | ||||
|     MobileOnly.beforeDOMLoaded = component?.beforeDOMLoaded | ||||
|     MobileOnly.css = component?.css | ||||
|     return MobileOnly | ||||
|   } else { | ||||
|     return () => <></> | ||||
| export default ((component: QuartzComponent) => { | ||||
|   const Component = component | ||||
|   const MobileOnly: QuartzComponent = (props: QuartzComponentProps) => { | ||||
|     return <Component displayClass="mobile-only" {...props} /> | ||||
|   } | ||||
| }) satisfies QuartzComponentConstructor | ||||
| 
 | ||||
|   MobileOnly.displayName = component.displayName | ||||
|   MobileOnly.afterDOMLoaded = component?.afterDOMLoaded | ||||
|   MobileOnly.beforeDOMLoaded = component?.beforeDOMLoaded | ||||
|   MobileOnly.css = component?.css | ||||
|   return MobileOnly | ||||
| }) satisfies QuartzComponentConstructor<QuartzComponent> | ||||
|  | ||||
| @ -20,6 +20,7 @@ import MobileOnly from "./MobileOnly" | ||||
| import RecentNotes from "./RecentNotes" | ||||
| import Breadcrumbs from "./Breadcrumbs" | ||||
| import Comments from "./Comments" | ||||
| import Flex from "./Flex" | ||||
| 
 | ||||
| export { | ||||
|   ArticleTitle, | ||||
| @ -44,4 +45,5 @@ export { | ||||
|   NotFound, | ||||
|   Breadcrumbs, | ||||
|   Comments, | ||||
|   Flex, | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user