attachEvent('[data-aw-toggle-color-scheme]', 'click', function () {
if (defaultTheme.endsWith(':only')) {
return;
}
document.documentElement.classList.toggle('dark');
localStorage.theme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
});
Note that this is a client event. BasicScripts.astro defines several other client-side functionality as well as this one.
slots are part of the component implementation, which is a common concept among many frameworks, including Astrojs. The typical slot definition in a component looks like this:
---
// (file: MyComponent.astro)
const { title } = Astro.props;
export interface Props {
title: string;
}
---
<div>
<h2>{title}</h2>
<slot />
<!-- slot contents injected here -->
<div></div>
</div>
And in usage elsewhere:
import MyComponent from "~/components/MyComponent"; ...
<MyComponent someArg="A Slot example">
<p>This content will be displayed in the slot</p>
</MyComponent>
There’s another way we can use slots, useful particularly when a component can have markdown content is as follows (study carefully…):
---
// (file: MyComponent.astro)
const { title } = Astro.props;
export interface Props {
title: string;
}
const content: string = await Astro.props.render('default');
---
// renders the html to the 'content' variable
<div>
<h2>{title}</h2>
<div set:html={content} />
<!-- slot contents injected here -->
<div></div>
</div>
Whoa!! What’s going on here?
Notice there is no slot definition in the html portion of the component. Instead, what we do is have Astro render the slot content (here, the ‘default’ content, but you can also render named slots) into a variable, and then use that content in a div (for instance).
So, if the usage is in a markdown file, like so:
import MyComponent from '../../components/MyComponent';
# Using the above component in a .mdx file (that can take components)
{' '}
<MyComponent title="This is a slot implementor">### Here is some markdown content - With a bullet item.</MyComponent>
MyComponent renders the markdown to html and then injects it into the div.
This actually has a big advantage — consider that with the normal usage you don’t have access to the slot contents: Astro just plops the content into the <slot/> tag. Using this method, however, allows you to access the content and further manipulate it before it gets inserted into the html.
This allows a great deal of flexibility in component design.
Now, we get to the techniques used in AstroWind, we’ll use the pages/index.astro file to illustrate.
You’ll note that the index file imports a lot of components, each one roughly analagous to a panel in the index page. Each of these components, in turn, is instantiated sequentially throughout the page. But, you’ll notice that some of them use this kind of construct (we’ll use the last section, CallToAction, as it is most illustrative of the technique):
<CallToAction
callToAction={{
text: 'Get template',
href: 'https://github.com/onwidget/astrowind',
icon: 'tabler:download',
}}
>
<Fragment slot="title">
Astro + <br class="block sm:hidden" /><span class="sm:whitespace-nowrap">Tailwind CSS</span>
</Fragment>
<Fragment slot="subtitle">
Be very surprised by these huge fake numbers you are seeing on this page. <br class="hidden md:inline" />Don't waste
more time! :P
</Fragment>
</CallToAction>
Some things to note, here:
This argument is actually being passed a javascript object — not a string. (However, in the TS definition, it could be a string…)
Furthermore, these <Fragment/> elements each have a slot=“(value)” specifier.
The latter seems odd, because <Fragment/> is a built-in component over which you have no control, and doesn’t have a provision for rendering slots, per se.
The answer lies in a paragraph in the Astro docs, slots section, which states:
Use a
slot="my-slot"
attribute on the child element that you want to pass through to a matching slotname="my-slot" />
placeholder in your component.
That’s pretty concise and a bit of a head-scratcher to read, but basically what it says is that:
slot="<slot-name>"
property assignment, where the slot-name is the parent’s slot.So, in the example above, the CallToAction component defines the subtitle slot, and the following <Fragment slot=“subtitle”> populates the slot with the following content:
<Fragment slot="subtitle">
Be very surprised by these huge fake numbers you are seeing on this page. <br class="hidden md:inline" />Don't waste
more time! :P
</Fragment>
And, the CallToAction component defines and renders it thusly:
---
//...
const { subtitle = await Astro.slots.render('subtitle') } = Astro.props;
---
//...
{subtitle && <p class="text-xl text-muted dark:text-slate-400" set:html={subtitle} />}
//...
There’s a lot to wrap your head around, here.
Notice first that subtitle is defined as a prop/argument, but it’s being processed as a slot. Interestingly, prop args and slots seem to be somewhat interchangeable: if the subtitle was just a string, it would simply take that assignment. The main difference is that if you render them independently, you have to call the render with an await modifier.
Aenean nec sapien sed arcu gravida scelerisque. Fusce vehicula risus vel urna. Cras venenatis leo id dui bibendum pretium. Cras sem sem, pretium vel, cursus id, facilisis eget, enim. Ut tempor. Donec augue lorem, sollicitudin sed, mattis quis, egestas at, risus. Praesent tempus orci in massa. Integer tempor ornare velit. Proin euismod. Nunc in augue.
Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum.
This is some dummy copy. You’re not really supposed to read this dummy copy, it is just a place holder for people who need some type to visualize what the actual copy might look like if it were real content.
If you want to read, I might suggest a good book, perhaps Hemingway or Melville. That’s why they call it, the dummy copy. This, of course, is not the real copy for this entry. Rest assured, the words will expand the concept. With clarity. Conviction. And a little wit.
Maecenas sed diam eget risus varius blandit sit amet non magna. Etiam porta sem malesuada magna mollis euismod. Vestibulum id ligula porta felis euismod semper.