| | |
| | | |
| | | In effect, components allow you to write a JavaScript function that takes some data and produces HTML as an output. **While Quartz doesn't use React, it uses the same component concept to allow you to easily express layout templates in your Quartz site.** |
| | | |
| | | > [!hint] |
| | | > For those coming from React, Quartz components are different from React components in that it only uses JSX for templating and layout. Hooks like `useEffect`, `useState`, etc. are not rendered. |
| | | |
| | | ## An Example Component |
| | | |
| | | ### Constructor |
| | |
| | | ```tsx {6-10} title="quartz/components/YourComponent.tsx" |
| | | export default (() => { |
| | | function YourComponent() { |
| | | return <p>Example Component</p> |
| | | return <p class="red-text">Example Component</p> |
| | | } |
| | | |
| | | YourComponent.css = ` |
| | | p { |
| | | p.red-text { |
| | | color: red; |
| | | } |
| | | ` |
| | |
| | | |
| | | ### Scripts and Interactivity |
| | | |
| | | - listening for the nav event |
| | | - best practice: anything here should unmount any existing event handlers to prevent memory leaks |
| | | What about interactivity? Suppose you want to add an-click handler for example. Like the `.css` property on the component, you can also declare `.beforeDOMLoaded` and `.afterDOMLoaded` properties that are strings that contain the script. |
| | | |
| | | ```tsx title="quartz/components/YourComponent.tsx" |
| | | export default (() => { |
| | | function YourComponent() { |
| | | return <button id="btn">Click me</button> |
| | | } |
| | | |
| | | YourComponent.beforeDOM = ` |
| | | console.log("hello from before the page loads!") |
| | | ` |
| | | |
| | | YourComponent.afterDOM = ` |
| | | document.getElementById('btn').onclick = () => { |
| | | alert('button clicked!') |
| | | } |
| | | ` |
| | | return YourComponent |
| | | }) satisfies QuartzComponentConstructor |
| | | |
| | | ``` |
| | | |
| | | > [!hint] |
| | | > For those coming from React, Quartz components are different from React components in that it only uses JSX for templating and layout. Hooks like `useEffect`, `useState`, etc. are not rendered and other properties that accept functions like `onClick` handlers will not work. Instead, do it using a regular JS script that modifies the DOM element directly. |
| | | |
| | | As the names suggest, the `.beforeDOMLoaded` scripts are executed *before* the page is done loading so it doesn't have access to any elements on the page. This is mostly used to prefetch any critical data. |
| | | |
| | | The `.afterDOMLoaded` script executes once the page has been completely loaded. This is a good place to setup anything that should last for the duration of a site visit (e.g. getting something saved from local storage). |
| | | |
| | | If you need to create an `afterDOMLoaded` script that depends on *page specific* elements that may change when navigating to a new page, you can listen for the `"nav"` event that gets fired whenever a page loads (which may happen on navigation if [[SPA Routing]] is enabled). |
| | | |
| | | ```ts |
| | | document.addEventListener("nav", () => { |
| | | // do page specific logic here |
| | | // e.g. attach event listeners |
| | | const toggleSwitch = document.querySelector("#switch") as HTMLInputElement |
| | | toggleSwitch.removeEventListener("change", switchTheme) |
| | | toggleSwitch.addEventListener("change", switchTheme) |
| | | }) |
| | | ``` |
| | | |
| | | It is best practice to also unmount any existing event handlers to prevent memory leaks. |
| | | #### Importing Code |
| | | Of course, it isn't always practical (nor desired!) to write your code as a string literal in the component. |
| | | |
| | | Quartz supports importing component code through `.inline.ts` files. |
| | | |
| | | ```tsx title="quartz/components/YourComponent.tsx" |
| | | // @ts-ignore: typescript doesn't know about our inline bundling system |
| | | // so we need to silence the error |
| | | import script from "./scripts/graph.inline" |
| | | |
| | | export default (() => { |
| | | function YourComponent() { |
| | | return <button id="btn">Click me</button> |
| | | } |
| | | |
| | | YourComponent.afterDOM = script |
| | | return YourComponent |
| | | }) satisfies QuartzComponentConstructor |
| | | |
| | | ``` |
| | | |
| | | ```ts title="quartz/components/scripts/graph.inline.ts" |
| | | // any imports here are bundled for the browser |
| | | import * as d3 from "d3" |
| | | |
| | | document.getElementById('btn').onclick = () => { |
| | | alert('button clicked!') |
| | | } |
| | | ``` |
| | | |
| | | Additionally, like what is shown in the example above, you can import packages in `.inline.ts` files. This will be bundled by Quartz and included in the actual script. |
| | | ### Using a Component |
| | | After creating your custom component, re-export it in `quartz/components/index.ts`: |
| | | |
| | | #### In a layout |
| | | ```ts title="quartz/components/index.ts" {4,10} |
| | | import ArticleTitle from "./ArticleTitle" |
| | | import Content from "./pages/Content" |
| | | import Darkmode from "./Darkmode" |
| | | import YourComponent from "./YourComponent" |
| | | |
| | | #### In the configuration |
| | | export { |
| | | ArticleTitle, |
| | | Content, |
| | | Darkmode, |
| | | YourComponent |
| | | } |
| | | ``` |
| | | |
| | | Then, you can use it like any other component in `quartz.layout.ts` via `Component.YourComponent()`. See the [[configuration#Layout|layout]] section for more details. |
| | | |
| | | As Quartz components are just functions that return React components, you can compositionally use them in other Quartz components. |
| | | |
| | | ```tsx title="quartz/components/AnotherComponent.tsx" |
| | | import YourComponent from "./YourComponent" |
| | | |
| | | export default (() => { |
| | | function AnotherComponent(props: QuartzComponentProps) { |
| | | return <div> |
| | | <p>It's nested!</p> |
| | | <YourComponent {...props} /> |
| | | </div> |
| | | } |
| | | |
| | | return AnotherComponent |
| | | }) satisfies QuartzComponentConstructor |
| | | ``` |
| | | |
| | | > [!hint] |
| | | > Look in `quartz/components` for more examples of components in Quartz as reference for your own components! |