---
title: "Patterns"
description: "Patterns, recipes, and working examples."
---

import { getFolder } from '../../lib/content';
import { PATTERN_CATEGORIES, groupFilesByCategory } from '../../lib/content-groups';
import JumpTo from '../../components/JumpTo.astro';

export const folder = await getFolder('patterns');
export const groupedPatterns = groupFilesByCategory(folder.files, PATTERN_CATEGORIES).map(group => ({
    slug: group.slug,
    label: group.category,
    items: group.files.map(f => ({
        title: f.frontmatter.title,
        url: f.url,
        description: f.frontmatter.description,
        icon: f.frontmatter.icon || '',
        soon: f.frontmatter.soon || false,
    })),
}));

export const getPageHeadings = () => groupedPatterns.map(group => ({
    depth: 2,
    slug: group.slug,
    text: group.label,
}));

<label data-active-search class="not-prose text-field" for="patterns-search">
    <span class="sr-only">Search patterns</span>
    <i class="icon-[mdi--magnify]" aria-hidden="true"></i>
    <input
        id="patterns-search"
        type="text"
        placeholder="Search patterns..."
        autocomplete="off"
        autocapitalize="off"
        autocorrect="off"
        spellcheck="false"
        enterkeyhint="search"
        aria-keyshortcuts="/"
        _="install ActiveSearch"
    />
    <span aria-hidden="true">Focus <kbd>/</kbd></span>
</label>

<JumpTo headings={getPageHeadings()} />

{groupedPatterns.map(group => (
<section role="group">

<h2 id={group.slug}>
    <span>
        <a href={`#${group.slug}`} class="no-underline interact:underline">
            {group.label}
        </a>
    </span>
</h2>

<table>
    <tbody>
        {group.items.map(item => (
            <tr class={`stretch-link ${item.soon ? 'opacity-50' : ''}`}>
                <td>
                    <div class="flex items-center gap-4 sm:gap-7">
                        {item.icon && <i class={`${item.icon} size-5 shrink-0`}></i>}
                        <span class="min-w-0">
                            {item.soon
                                ? <span>{item.title}</span>
                                : <a href={item.url}>{item.title}</a>}
                            {item.soon && <span class="sm:hidden text-[9px] ml-2 px-1.5 py-0.5 rounded bg-yellow-300/5 text-yellow-700 dark:text-yellow-300 border border-yellow-600/50 dark:border-yellow-300 font-medium uppercase tracking-wide">Soon</span>}
                            {item.description && <span class="block sm:hidden text-neutral-650 dark:text-neutral-350">{item.description}</span>}
                        </span>
                    </div>
                </td>
                <td class="hidden sm:table-cell text-neutral-650 dark:text-neutral-350">
                    {item.description || ''}
                    {item.soon && <span class="text-[9px] ml-2 px-1.5 py-0.5 rounded bg-yellow-300/5 text-yellow-700 dark:text-yellow-300 border border-yellow-600/50 dark:border-yellow-300 font-medium uppercase tracking-wide">Soon</span>}
                </td>
            </tr>
        ))}
    </tbody>
</table>

</section>
))}
