Almost done with documentation

This commit is contained in:
Ronan Berder
2025-05-01 12:50:40 +08:00
parent ba71f2ea79
commit 930e0ee6f1
47 changed files with 681 additions and 577 deletions
+55
View File
@@ -0,0 +1,55 @@
.content {
> h2 {
@apply mt-16 mb-6 scroll-m-22 border-b pb-4 text-xl font-semibold tracking-tight first:mt-0;
}
> h3 {
@apply mt-8 mb-6 scroll-m-22 text-lg font-semibold tracking-tight;
}
.prose {
@apply my-6;
a {
@apply font-medium underline underline-offset-4;
}
code:not(pre > code) {
@apply relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm;
}
blockquote {
@apply border-l-4 border-border pl-4;
}
ol {
@apply list-decimal ml-6;
}
ul {
@apply list-disc ml-6;
}
b,
strong {
@apply font-semibold;
}
> p,
> blockquote,
> ul,
> ol,
> dl,
> table,
> pre,
> p {
@apply my-4;
}
> *:first-child {
@apply !mt-0;
}
> *:last-child {
@apply !mb-0;
}
}
.step {
counter-increment: step;
}
.step:before {
@apply md:absolute w-8 h-8 md:w-9 md:h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 mr-2 border-background;
@apply md:ml-[-50px] md:mt-[-4px];
content: counter(step);
}
}
+16
View File
@@ -0,0 +1,16 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Lora&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Fira+Code&display=swap");
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Inter&display=swap");
@import "tailwindcss";
@import "basecoat";
@import "./custom.css";
@theme {
--font-sans: 'Inter';
--font-mono: 'JetBrains Mono';
}
/* @import "./theme-orange.css"; */
+68
View File
@@ -0,0 +1,68 @@
:root {
--radius: 0.5rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.606 0.25 292.717);
--primary-foreground: oklch(0.969 0.016 293.756);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.606 0.25 292.717);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.606 0.25 292.717);
--sidebar-primary-foreground: oklch(0.969 0.016 293.756);
--sidebar-accent: oklch(0.967 0.001 286.375);
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
--sidebar-border: oklch(0.92 0.004 286.32);
--sidebar-ring: oklch(0.606 0.25 292.717);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.21 0.006 285.885);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.541 0.281 293.009);
--primary-foreground: oklch(0.969 0.016 293.756);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.541 0.281 293.009);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.541 0.281 293.009);
--sidebar-primary-foreground: oklch(0.969 0.016 293.756);
--sidebar-accent: oklch(0.274 0.006 286.033);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.541 0.281 293.009);
}
+146
View File
@@ -0,0 +1,146 @@
:root {
--background: oklch(1.00 0 0);
--foreground: oklch(0.27 0 0);
--card: oklch(1.00 0 0);
--card-foreground: oklch(0.27 0 0);
--popover: oklch(1.00 0 0);
--popover-foreground: oklch(0.27 0 0);
--primary: oklch(0.77 0.16 70.08);
--primary-foreground: oklch(0 0 0);
--secondary: oklch(0.97 0.00 264.54);
--secondary-foreground: oklch(0.45 0.03 256.80);
--muted: oklch(0.98 0.00 247.84);
--muted-foreground: oklch(0.55 0.02 264.36);
--accent: oklch(0.99 0.02 95.28);
--accent-foreground: oklch(0.47 0.12 46.20);
--destructive: oklch(0.64 0.21 25.33);
--destructive-foreground: oklch(1.00 0 0);
--border: oklch(0.93 0.01 264.53);
--input: oklch(0.93 0.01 264.53);
--ring: oklch(0.77 0.16 70.08);
--chart-1: oklch(0.77 0.16 70.08);
--chart-2: oklch(0.67 0.16 58.32);
--chart-3: oklch(0.56 0.15 49.00);
--chart-4: oklch(0.47 0.12 46.20);
--chart-5: oklch(0.41 0.11 45.90);
--sidebar: oklch(0.98 0.00 247.84);
--sidebar-foreground: oklch(0.27 0 0);
--sidebar-primary: oklch(0.77 0.16 70.08);
--sidebar-primary-foreground: oklch(1.00 0 0);
--sidebar-accent: oklch(0.99 0.02 95.28);
--sidebar-accent-foreground: oklch(0.47 0.12 46.20);
--sidebar-border: oklch(0.93 0.01 264.53);
--sidebar-ring: oklch(0.77 0.16 70.08);
--font-sans: Inter, sans-serif;
--font-serif: Source Serif 4, serif;
--font-mono: JetBrains Mono, monospace;
--radius: 0.375rem;
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
}
.dark {
--background: oklch(0.20 0 0);
--foreground: oklch(0.92 0 0);
--card: oklch(0.27 0 0);
--card-foreground: oklch(0.92 0 0);
--popover: oklch(0.27 0 0);
--popover-foreground: oklch(0.92 0 0);
--primary: oklch(0.77 0.16 70.08);
--primary-foreground: oklch(0 0 0);
--secondary: oklch(0.27 0 0);
--secondary-foreground: oklch(0.92 0 0);
--muted: oklch(0.27 0 0);
--muted-foreground: oklch(0.72 0 0);
--accent: oklch(0.47 0.12 46.20);
--accent-foreground: oklch(0.92 0.12 95.75);
--destructive: oklch(0.64 0.21 25.33);
--destructive-foreground: oklch(1.00 0 0);
--border: oklch(0.37 0 0);
--input: oklch(0.37 0 0);
--ring: oklch(0.77 0.16 70.08);
--chart-1: oklch(0.84 0.16 84.43);
--chart-2: oklch(0.67 0.16 58.32);
--chart-3: oklch(0.47 0.12 46.20);
--chart-4: oklch(0.56 0.15 49.00);
--chart-5: oklch(0.47 0.12 46.20);
--sidebar: oklch(0.17 0 0);
--sidebar-foreground: oklch(0.92 0 0);
--sidebar-primary: oklch(0.77 0.16 70.08);
--sidebar-primary-foreground: oklch(1.00 0 0);
--sidebar-accent: oklch(0.47 0.12 46.20);
--sidebar-accent-foreground: oklch(0.92 0.12 95.75);
--sidebar-border: oklch(0.37 0 0);
--sidebar-ring: oklch(0.77 0.16 70.08);
--font-sans: Inter, sans-serif;
--font-serif: Source Serif 4, serif;
--font-mono: JetBrains Mono, monospace;
--radius: 0.375rem;
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
--font-serif: var(--font-serif);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--shadow-2xs: var(--shadow-2xs);
--shadow-xs: var(--shadow-xs);
--shadow-sm: var(--shadow-sm);
--shadow: var(--shadow);
--shadow-md: var(--shadow-md);
--shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl);
--shadow-2xl: var(--shadow-2xl);
}
+1 -1
View File
@@ -110,7 +110,7 @@
@click="hide()"
aria-label="Close dialog"
>
{% lucide "x" %}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
{% endif %}
</article>
@@ -1,3 +1,14 @@
{#
Renders a dropdown menu component.
@param id {string} [optional] - Unique identifier for the dropdown component.
@param trigger {string} [optional] - HTML content for the button that triggers the dropdown.
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
@param content_attrs {object} [optional] - Additional HTML attributes for the dropdown content div.
@param include_script {boolean} [optional] [default=false] - Whether to include the Alpine.js component script.
@param register_on {array} [optional] [default=[\"alpine:init\"]] - Alpine.js events to register the component on.
#}
{% macro dropdown_menu(
id=None,
trigger=None,
+11
View File
@@ -1,3 +1,14 @@
{#
Renders a generic popover component, often used internally by other components like dropdowns or selects.
@param id {string} [optional] - Unique identifier for the popover component.
@param trigger {string} [optional] - HTML content for the element that triggers the popover.
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger element.
@param content_attrs {object} [optional] - Additional HTML attributes for the popover content div.
@param include_script {boolean} [optional] [default=false] - Whether to include the Alpine.js component script.
@param register_on {array} [optional] [default=[\"alpine:init\"]] - Alpine.js events to register the component on.
#}
{% macro popover(
id=None,
trigger=None,
+19 -3
View File
@@ -1,3 +1,19 @@
{#
Renders a select or combobox component.
@param id {string} [optional] - Unique identifier for the select component.
@param selected {string} [optional] - The initially selected value.
@param name {string} [optional] - The name attribute for the hidden input storing the selected value.
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
@param content_attrs {object} [optional] - Additional HTML attributes for the popover content div.
@param listbox_attrs {object} [optional] - Additional HTML attributes for the listbox div.
@param input_attrs {object} [optional] - Additional HTML attributes for the hidden input.
@param search_placeholder {string} [optional] [default="Search entries..."] - Placeholder text for the search input (combobox only).
@param is_combobox {boolean} [optional] [default=false] - Renders a combobox with search functionality if true.
@param include_script {boolean} [optional] [default=false] - Whether to include the Alpine.js component script.
@param register_on {array} [optional] [default=[\"alpine:init\"]] - Alpine.js events to register the component on.
#}
{% macro select(
id=None,
selected=None,
@@ -42,9 +58,9 @@
<div x-html="selectedLabel" class="flex items-center gap-x-2"
></div>
{% if is_combobox %}
{% lucide "chevrons-up-down", class="text-muted-foreground opacity-50 shrink-0" %}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevrons-up-down-icon lucide-chevrons-up-down text-muted-foreground opacity-50 shrink-0"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
{% else %}
{% lucide "chevron-down", class="text-muted-foreground opacity-50 shrink-0" %}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down-icon lucide-chevron-down text-muted-foreground opacity-50 shrink-0"><path d="m6 9 6 6 6-6"/></svg>
{% endif %}
</button>
<div
@@ -58,7 +74,7 @@
>
{% if is_combobox %}
<header>
{% lucide "search" %}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search-icon lucide-search"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
<input
type="text"
value=""
+17
View File
@@ -1,3 +1,20 @@
{#
Renders a tabs component.
@param id {string} - Unique identifier for the tabs component.
@param tabsets {array} - An array of objects, each representing a tab and its panel.
Each object should have:
- id {string}: Unique identifier prefix for the tab and panel.
- tab {string}: HTML content for the tab button.
- panel {string} [optional]: HTML content for the tab panel.
- tab_attrs {object} [optional]: Additional HTML attributes for the tab button.
- panel_attrs {object} [optional]: Additional HTML attributes for the tab panel div.
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
@param tablist_attrs {object} [optional] - Additional HTML attributes for the tablist nav element.
@param default_tab_index {number} [optional] [default=1] - The 1-based index of the tab to be active initially.
@param include_script {boolean} [optional] [default=false] - Whether to include the Alpine.js component script.
@param register_on {array} [optional] [default=[\"alpine:init\"]] - Alpine.js events to register the component on.
#}
{% macro tabs(
id,
tabsets=[],
+21
View File
@@ -1,3 +1,24 @@
{#
Renders a toaster container and individual toast messages.
Can render the initial container or be used with htmx OOB swaps to add toasts dynamically.
@param id {string} [optional] [default="toaster"] - Unique identifier for the toaster container.
@param toasts {array} [optional] - An array of toast objects to render initially.
Each toast object can have:
- category {string} [optional]: Type of toast ('success', 'error', 'info', 'warning'). Determines icon and ARIA role.
- title {string} [optional]: The main title text of the toast.
- description {string} [optional]: The secondary description text.
- duration {number} [optional] [default=5000]: Duration in milliseconds before the toast auto-dismisses.
- action {object} [optional]: Defines an action button.
- label {string}: Button text.
- click {string}: JavaScript code to execute on click (e.g., '$dispatch(\'custom-event\')').
- url {string}: URL for an anchor link button.
- cancel {object} [optional]: Defines a cancel/dismiss button (similar structure to action).
@param main_attrs {object} [optional] - Additional HTML attributes for the main toaster container div.
@param is_fragment {boolean} [optional] [default=false] - If true, renders only the toast elements with hx-swap-oob="beforeend", suitable for htmx responses. Skips script and template inclusion.
@param include_script {boolean} [optional] [default=false] - Whether to include the Alpine.js component script. Ignored if is_fragment is true.
@param register_on {array} [optional] [default=[\"alpine:init\"]] - Alpine.js events to register the component on. Ignored if is_fragment is true.
#}
{% macro toaster(
id="toaster",
toasts=[],
-39
View File
@@ -1,39 +0,0 @@
---
layout: layouts/base.njk
---
<main class="mx-auto relative py-6 lg:gap-10 lg:py-8 flex w-full max-w-screen-lg">
<div class="mx-auto w-full min-w-0 max-w-screen-md">
<header class="space-y-2">
<h1 class="text-3xl font-semibold tracking-tight">{{ title }}</h1>
<p class="text-muted-foreground">{{ description }}</p>
</header>
<article class="pb-12 pt-8 [&>h2]:mt-16 [&>h2]:scroll-m-22 [&>h2]:border-b [&>h2]:pb-4 [&>h2]:text-xl [&>h2]:font-semibold [&>h2]:tracking-tight [&>h2]:first:mt-0 [&>h3]:font-heading [&>h3]:mt-8 [&>h3]:scroll-m-22 [&>h3]:text-lg [&>h3]:font-semibold [&>h3]:tracking-tight">
{{ content | safe }}
</article>
</div>
<div class="hidden text-sm xl:block w-full max-w-[300px]">
<nav class="sticky top-22 space-y-2 [&_ul]:m-0 [&_ul]:list-none [&_ul_ul]:pl-4 [&_li]:mt-0 [&_li]:pt-2 [&_a]:inline-block [&_a]:no-underline [&_a]:transition-colors [&_a]:hover:text-foreground [&_a]:text-muted-foreground">
<h4 class="font-medium">On This Page</h4>
{% if toc %}
{% macro renderToc(items) %}
{% if items and items.length %}
<ul>
{% for item in items %}
<li>
<a href="#{{ item.id }}">{{ item.label }}</a>
{% if item.children and item.children.length %}
{{ renderToc(item.children) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{{ renderToc(toc) }}
{% else %}
<p class="text-muted-foreground text-center bg-muted rounded-md p-2">No table of contents.</p>
{% endif %}
</nav>
</div>
</main>
+27 -27
View File
@@ -3,37 +3,37 @@ layout: layouts/base.njk
---
<main class="mx-auto relative py-6 lg:gap-10 lg:py-8 flex w-full max-w-screen-lg">
<div class="mx-auto w-full min-w-0 max-w-screen-md">
<div class="mx-auto w-full max-w-screen-md">
<header class="space-y-2">
<h1 class="text-3xl font-semibold tracking-tight">{{ title }}</h1>
<h1 class="text-3xl font-medium tracking-tight">{{ title }}</h1>
<p class="text-muted-foreground">{{ description }}</p>
</header>
<article class="pb-12 pt-8 [&>h2]:mt-16 [&>h2]:scroll-m-22 [&>h2]:border-b [&>h2]:pb-4 [&>h2]:text-xl [&>h2]:font-semibold [&>h2]:tracking-tight [&>h2]:first:mt-0 [&>h3]:font-heading [&>h3]:mt-8 [&>h3]:scroll-m-22 [&>h3]:text-lg [&>h3]:font-semibold [&>h3]:tracking-tight">
<article class="pb-12 mt-8 content">
{{ content | safe }}
</article>
</div>
<div class="hidden text-sm xl:block w-full max-w-[300px]">
<nav class="sticky top-22 space-y-2 [&_ul]:m-0 [&_ul]:list-none [&_ul_ul]:pl-4 [&_li]:mt-0 [&_li]:pt-2 [&_a]:inline-block [&_a]:no-underline [&_a]:transition-colors [&_a]:hover:text-foreground [&_a]:text-muted-foreground">
<h4 class="font-medium">On This Page</h4>
{% if toc %}
{% macro renderToc(items) %}
{% if items and items.length %}
<ul>
{% for item in items %}
<li>
<a href="#{{ item.id }}">{{ item.label }}</a>
{% if item.children and item.children.length %}
{{ renderToc(item.children) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{{ renderToc(toc) }}
{% else %}
<p class="text-muted-foreground text-center bg-muted rounded-md p-2">No table of contents.</p>
{% endif %}
</nav>
</div>
{% if toc %}
<div class="hidden text-sm xl:block w-full max-w-[300px]">
<nav class="sticky top-22 space-y-2 [&_ul]:m-0 [&_ul]:list-none [&_ul_ul]:pl-4 [&_li]:mt-0 [&_li]:pt-2 [&_a]:inline-block [&_a]:no-underline [&_a]:transition-colors [&_a]:hover:text-foreground [&_a]:text-muted-foreground">
<h4 class="font-medium">On This Page</h4>
{% if toc %}
{% macro renderToc(items) %}
{% if items and items.length %}
<ul>
{% for item in items %}
<li>
<a href="#{{ item.id }}">{{ item.label }}</a>
{% if item.children and item.children.length %}
{{ renderToc(item.children) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{{ renderToc(toc) }}
{% endif %}
</nav>
</div>
{% endif %}
</main>
+3 -4
View File
@@ -1,6 +1,6 @@
{% macro code_block(code, language="html") %}
{% macro code_block(code, language="html", class="my-4") %}
<div
class="relative"
class="relative {{ class }}"
x-data="{
copied: false,
copy() {
@@ -25,5 +25,4 @@
{% lucide "check", { "class": "size-4", "x-show": "copied" } %}
</button>
</div>
{% endmacro %}
{% endmacro %}
+1 -1
View File
@@ -1,6 +1,6 @@
{% macro code_preview(id, code, class=None, default_code=false) %}
{% from "./code_block.njk" import code_block %}
{% set code_panel = code_block(code) %}
{% set code_panel = code_block(code, class="") %}
{% set preview_panel %}
<div class="ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative rounded-md border">
<div class="preview flex min-h-[350px] w-full justify-center p-10 items-center">
+146 -189
View File
@@ -1,4 +1,7 @@
/*! tailwindcss v4.1.4 | MIT License | https://tailwindcss.com */
@import url("https://fonts.googleapis.com/css2?family=Poppins&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Lora&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Fira+Code&display=swap");
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Inter&display=swap");
@layer properties;
@@ -45,8 +48,6 @@
--text-lg--line-height: calc(1.75 / 1.125);
--text-xl: 1.25rem;
--text-xl--line-height: calc(1.75 / 1.25);
--text-2xl: 1.5rem;
--text-2xl--line-height: calc(2 / 1.5);
--text-3xl: 1.875rem;
--text-3xl--line-height: calc(2.25 / 1.875);
--font-weight-normal: 400;
@@ -340,18 +341,30 @@
.mx-auto {
margin-inline: auto;
}
.my-4 {
margin-block: calc(var(--spacing) * 4);
}
.my-6 {
margin-block: calc(var(--spacing) * 6);
}
.mt-4 {
margin-top: calc(var(--spacing) * 4);
}
.mt-8 {
margin-top: calc(var(--spacing) * 8);
}
.mr-auto {
margin-right: auto;
}
.mb-4 {
margin-bottom: calc(var(--spacing) * 4);
}
.mb-6 {
margin-bottom: calc(var(--spacing) * 6);
}
.mb-12 {
margin-bottom: calc(var(--spacing) * 12);
}
.ml-\(--sidebar-width\) {
margin-left: var(--sidebar-width);
}
@@ -370,6 +383,9 @@
.hidden {
display: none;
}
.inline {
display: inline;
}
.inline-block {
display: inline-block;
}
@@ -503,9 +519,6 @@
.max-w-xl {
max-width: var(--container-xl);
}
.min-w-0 {
min-width: calc(var(--spacing) * 0);
}
.min-w-5 {
min-width: calc(var(--spacing) * 5);
}
@@ -538,6 +551,9 @@
.cursor-pointer {
cursor: pointer;
}
.scroll-m-20 {
scroll-margin: calc(var(--spacing) * 20);
}
.scroll-mt-16 {
scroll-margin-top: calc(var(--spacing) * 16);
}
@@ -758,9 +774,6 @@
.py-6 {
padding-block: calc(var(--spacing) * 6);
}
.pt-8 {
padding-top: calc(var(--spacing) * 8);
}
.pb-4 {
padding-bottom: calc(var(--spacing) * 4);
}
@@ -1205,6 +1218,11 @@
gap: calc(var(--spacing) * 2.5);
}
}
.md\:ml-4 {
@media (width >= 48rem) {
margin-left: calc(var(--spacing) * 4);
}
}
.md\:max-w-\[200px\] {
@media (width >= 48rem) {
max-width: 200px;
@@ -1215,6 +1233,17 @@
flex-direction: row;
}
}
.md\:border-l {
@media (width >= 48rem) {
border-left-style: var(--tw-border-style);
border-left-width: 1px;
}
}
.md\:pl-8 {
@media (width >= 48rem) {
padding-left: calc(var(--spacing) * 8);
}
}
.lg\:gap-10 {
@media (width >= 64rem) {
gap: calc(var(--spacing) * 10);
@@ -1527,80 +1556,6 @@
height: calc(var(--spacing) * 4);
}
}
.\[\&\>h2\]\:mt-16 {
&>h2 {
margin-top: calc(var(--spacing) * 16);
}
}
.\[\&\>h2\]\:scroll-m-22 {
&>h2 {
scroll-margin: calc(var(--spacing) * 22);
}
}
.\[\&\>h2\]\:border-b {
&>h2 {
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
}
}
.\[\&\>h2\]\:pb-4 {
&>h2 {
padding-bottom: calc(var(--spacing) * 4);
}
}
.\[\&\>h2\]\:text-xl {
&>h2 {
font-size: var(--text-xl);
line-height: var(--tw-leading, var(--text-xl--line-height));
}
}
.\[\&\>h2\]\:font-semibold {
&>h2 {
--tw-font-weight: var(--font-weight-semibold);
font-weight: var(--font-weight-semibold);
}
}
.\[\&\>h2\]\:tracking-tight {
&>h2 {
--tw-tracking: var(--tracking-tight);
letter-spacing: var(--tracking-tight);
}
}
.\[\&\>h2\]\:first\:mt-0 {
&>h2 {
&:first-child {
margin-top: calc(var(--spacing) * 0);
}
}
}
.\[\&\>h3\]\:mt-8 {
&>h3 {
margin-top: calc(var(--spacing) * 8);
}
}
.\[\&\>h3\]\:scroll-m-22 {
&>h3 {
scroll-margin: calc(var(--spacing) * 22);
}
}
.\[\&\>h3\]\:text-lg {
&>h3 {
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
}
}
.\[\&\>h3\]\:font-semibold {
&>h3 {
--tw-font-weight: var(--font-weight-semibold);
font-weight: var(--font-weight-semibold);
}
}
.\[\&\>h3\]\:tracking-tight {
&>h3 {
--tw-tracking: var(--tracking-tight);
letter-spacing: var(--tracking-tight);
}
}
.\[\&\>svg\]\:size-4 {
&>svg {
width: calc(var(--spacing) * 4);
@@ -3823,117 +3778,119 @@
}
}
}
@layer components {
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6, .h1, .h2, .h3, .h4, .h5, .h6 {
--tw-leading: var(--leading-tight);
line-height: var(--leading-tight);
--tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium);
}
.prose h1, .h1 {
font-size: var(--text-2xl);
line-height: var(--tw-leading, var(--text-2xl--line-height));
}
.prose h2, .h2 {
.content {
> h2 {
margin-top: calc(var(--spacing) * 16);
margin-bottom: calc(var(--spacing) * 6);
scroll-margin: calc(var(--spacing) * 22);
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
padding-bottom: calc(var(--spacing) * 4);
font-size: var(--text-xl);
line-height: var(--tw-leading, var(--text-xl--line-height));
}
.prose h3, .h3 {
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
}
.prose h4, .prose h5, .prose h6, .h4, .h5, .h6 {
font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height));
}
.prose a, .link {
--tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium);
text-decoration-line: underline;
text-underline-offset: 4px;
}
.prose code, .code {
position: relative;
border-radius: 0.25rem;
background-color: var(--color-muted);
padding-inline: 0.3rem;
padding-block: 0.2rem;
font-family: var(--font-mono);
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
}
.prose pre:has(> code), .code-block {
border-radius: var(--radius-md);
border-color: var(--color-border);
background-color: var(--color-muted);
}
.prose pre code, .code-block code {
display: inline-block;
padding: calc(var(--spacing) * 4);
font-family: var(--font-mono);
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
}
.prose blockquote, .quote {
border-left-style: var(--tw-border-style);
border-left-width: 4px;
border-color: var(--color-border);
padding-left: calc(var(--spacing) * 4);
}
.prose ol, .ordered-list {
margin-block: calc(var(--spacing) * 6);
margin-left: calc(var(--spacing) * 6);
list-style-type: decimal;
li {
margin-bottom: calc(var(--spacing) * 2);
}
}
.prose ul, .unordered-list {
margin-block: calc(var(--spacing) * 6);
margin-left: calc(var(--spacing) * 6);
list-style-type: disc;
li {
margin-bottom: calc(var(--spacing) * 2);
}
ul, ol {
margin-block: calc(var(--spacing) * 2);
}
}
.prose > *:first-child {
margin-top: calc(var(--spacing) * 0) !important;
}
.prose > *:last-child {
margin-bottom: calc(var(--spacing) * 0) !important;
}
.prose h1 {
margin-bottom: calc(var(--spacing) * 8);
}
.prose h2 {
margin-top: calc(var(--spacing) * 8);
margin-bottom: calc(var(--spacing) * 6);
}
.prose h3 {
margin-top: calc(var(--spacing) * 6);
margin-bottom: calc(var(--spacing) * 4);
}
.prose h4 {
margin-block: calc(var(--spacing) * 4);
}
.prose h5 {
margin-block: calc(var(--spacing) * 4);
}
.prose h6 {
margin-block: calc(var(--spacing) * 4);
}
.prose > p, .prose > blockquote, .prose > ul, .prose > ol, .prose > dl, .prose > table, .prose > pre, .prose > p {
margin-block: calc(var(--spacing) * 4);
}
.prose > *:last-child {
margin-bottom: calc(var(--spacing) * 0) !important;
}
.prose strong, .prose b {
--tw-font-weight: var(--font-weight-semibold);
font-weight: var(--font-weight-semibold);
--tw-tracking: var(--tracking-tight);
letter-spacing: var(--tracking-tight);
&:first-child {
margin-top: calc(var(--spacing) * 0);
}
}
> h3 {
margin-top: calc(var(--spacing) * 8);
margin-bottom: calc(var(--spacing) * 6);
scroll-margin: calc(var(--spacing) * 22);
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
--tw-font-weight: var(--font-weight-semibold);
font-weight: var(--font-weight-semibold);
--tw-tracking: var(--tracking-tight);
letter-spacing: var(--tracking-tight);
}
.prose {
margin-block: calc(var(--spacing) * 6);
a {
--tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium);
text-decoration-line: underline;
text-underline-offset: 4px;
}
code:not(pre > code) {
position: relative;
border-radius: 0.25rem;
background-color: var(--color-muted);
padding-inline: 0.3rem;
padding-block: 0.2rem;
font-family: var(--font-mono);
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
}
blockquote {
border-left-style: var(--tw-border-style);
border-left-width: 4px;
border-color: var(--color-border);
padding-left: calc(var(--spacing) * 4);
}
ol {
margin-left: calc(var(--spacing) * 6);
list-style-type: decimal;
}
ul {
margin-left: calc(var(--spacing) * 6);
list-style-type: disc;
}
b, strong {
--tw-font-weight: var(--font-weight-semibold);
font-weight: var(--font-weight-semibold);
}
> p, > blockquote, > ul, > ol, > dl, > table, > pre, > p {
margin-block: calc(var(--spacing) * 4);
}
> *:first-child {
margin-top: calc(var(--spacing) * 0) !important;
}
> *:last-child {
margin-bottom: calc(var(--spacing) * 0) !important;
}
}
.step {
counter-increment: step;
}
.step:before {
margin-right: calc(var(--spacing) * 2);
display: inline-flex;
height: calc(var(--spacing) * 8);
width: calc(var(--spacing) * 8);
align-items: center;
justify-content: center;
border-radius: calc(infinity * 1px);
border-style: var(--tw-border-style);
border-width: 4px;
border-color: var(--color-background);
background-color: var(--color-muted);
text-align: center;
text-indent: -1px;
font-family: var(--font-mono);
font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height));
--tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium);
@media (width >= 48rem) {
position: absolute;
}
@media (width >= 48rem) {
height: calc(var(--spacing) * 9);
}
@media (width >= 48rem) {
width: calc(var(--spacing) * 9);
}
@media (width >= 48rem) {
margin-top: -4px;
}
@media (width >= 48rem) {
margin-left: -50px;
}
content: counter(step);
}
}
@property --tw-translate-x {
+2 -3
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Accordion
description: A vertically stacked set of interactive headings that each reveal a section of content.
toc:
@@ -8,7 +8,6 @@ toc:
---
{% from "macros/code_preview.njk" import code_preview %}
{% from "macros/code_block.njk" import code_block %}
<div class="alert mb-6">
{% lucide "circle-alert" %}
@@ -68,4 +67,4 @@ toc:
<h2 id="usage"><a href="#usage">Usage</a></h2>
<p class="prose my-6">Basecoat animates <code>&lt;details&gt;</code> elements by default. The example above uses Alpine.js to handle the open/close state along with some Tailwind CSS classes.</p>
<p class="prose">Basecoat animates <code>&lt;details&gt;</code> elements by default. The example above uses Alpine.js to handle the open/close state along with some Tailwind CSS classes.</p>
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Alert Dialog
description: A modal dialog that interrupts the user with important content and expects a response.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Alert
description: Displays a callout for user attention.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Avatar
description: An image element with a fallback for representing the user.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Badge
description: Displays a badge or a component that looks like a badge.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Breadcrumb
description: Displays the path to the current resource using a hierarchy of links.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Button
description: Displays a button or a component that looks like a button.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Card
description: Displays a card with header, content, and footer.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Checkbox
description: A control that allows the user to toggle between checked and not checked.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Combobox
description: Autocomplete input and command palette with a list of suggestions.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Dialog
description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Dropdown Menu
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Input
description: Displays a form input field or a component that looks like an input field.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Input
description: Displays a form input field or a component that looks like an input field.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Label
description: Renders an accessible label associated with controls.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Pagination
description: Pagination with page navigation, next and previous links.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Popover
description: Displays rich content in a portal, triggered by a button.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Radio Group
description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Select
description: Displays a list of options for the user to pick from—triggered by a button.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Skeleton
description: Used to show a placeholder while content is loading.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Slider
description: An input where the user selects a value from within a given range.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Switch
description: A control that allows the user to toggle between checked and not checked.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Table
description: A responsive table component.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Tabs
description: A set of layered sections of content—known as tab panels—that are displayed one at a time.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Teaxtarea
description: Displays a form textarea or a component that looks like a textarea.
toc:
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Toast
description: A succinct message that is displayed temporarily.
---
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: layouts/component.njk
layout: layouts/page.njk
title: Tooltip
description: A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
toc:
+109 -3
View File
@@ -2,10 +2,116 @@
layout: layouts/page.njk
title: Installation
description: How to install Basecoat in your app.
toc:
- label: Installing the CSS
id: install-css
children:
- label: Add Tailwind CSS
id: install-css-tailwind
- label: Add Basecoat
id: install-css-basecoat
- label: Import basecoat in your CSS
id: install-css-import
- label: That's it
id: install-css-done
- label: Components with Javascript code
id: install-js
- label: Use Nunjucks or Jinja macros
id: install-macros
---
<h2 id="jinja-and-nunjucks"><a href="#jinja-and-nunjucks">CSS vs. Tailwind</a></h2>
{% from "macros/code_block.njk" import code_block %}
<h2 id="htmx"><a href="#htmx">HTML &amp; Javascript</a></h2>
<h2 id="install-css">Installing the CSS</h2>
<h2 id="jinja-and-nunjucks"><a href="#jinja-and-nunjucks">Jinja and Nunjucks</a></h2>
<ol class="[&>h3]:step steps mb-12 md:ml-4 md:border-l md:pl-8">
<li class="step">
<h3 class="mb-4 scroll-m-20 font-semibold tracking-tight" id="install-css-tailwind"><a href="#install-css-tailwind">Add Tailwind CSS</a></h3>
<div class="prose">
<p>Basecoat uses Tailwind CSS. You need to install it in your project.</p>
<p><a href="https://tailwindcss.com/docs/installation" target="_blank">Follow the Tailwind CSS installation instructions to get started.</a></p>
</div>
</li>
<li class="step mt-8">
<h3 class="mb-4 scroll-m-20 font-semibold tracking-tight" id="install-css-basecoat"><a href="#install-css-basecoat">Add Basecoat</a></h3>
<div class="prose">
<p>Add Basecoat to your Tailwind CSS file.</p>
</div>
{% set code %}npm install hunvreus/basecoat{% endset %}
{{ code_block(code, "bash") }}
</li>
<li class="step mt-8">
<h3 class="mb-4 scroll-m-20 font-semibold tracking-tight" id="install-css-import"><a href="#install-css-import">Import basecoat in your CSS</a></h3>
{% set code %}@import "tailwindcss";
@import "basecoat";{% endset %}
{{ code_block(code, "css") }}
</li>
<li class="step mt-8">
<h3 class="mb-4 scroll-m-20 font-semibold tracking-tight" id="install-css-done"><a href="#install-css-done">That's it</a></h3>
<div class="prose">
<p>You can now use any of the Basecoat classes in your project (e.g. <code>btn</code>, <code>card</code>, <code>input</code>, etc). Read the documentation about each component to get started (e.g. <a href="/components/button">button</a>, <a href="/components/card">card</a>, <a href="/components/input">input</a>, etc).</p>
</div>
</li>
</ol>
<h2 id="install-js"><a href="#install-js">Components with Javascript code</a></h2>
<div class="prose">
<p><b>Some components require Javascript code to work.</b></p>
<p>The documentation provides Alpine.js code snippets to cover that. <a href="https://alpinejs.dev/docs/installation" target="_blank">Make sure to install Alpine.js if you decide to use them.</a></p>
<p>For simple components like <a href="/components/accordion">Accordion</a> or <a href="/components/slider">Slider</a>, you will notice some inline Alpine.js code that you can just copy along with the rest of the HTML.</p>
<p>For more complex components (<a href="/components/dialog">Dialog</a>, <a href="/components/dropdown-menu">Dropdown Menu</a>, <a href="/components/popover">Popover</a>, <a href="/components/select">Select</a>, <a href="/components/tabs">Tabs</a> and <a href="/components/tooltip">Toast</a>), we provide a separate <code>&lt;script&gt;</code> code snippet that must be included anywhere <b>before</b> the HTML for the component.</p>
<p>You are also welcome to write your own Javascript.</p>
<p>All of the components try and implement WAI-ARIA standards to make them accessible.</p>
</div>
<h2 id="install-macros"><a href="#install-macros">Use Nunjucks or Jinja macros</a></h2>
<div class="prose">
<p>For more complex components, you can use <a href="https://mozilla.github.io/nunjucks/" target="_blank">Nunjucks</a> or <a href="https://jinja.palletsprojects.com" target="_blank">Jinja</a> macros to help you generate the HTML and Javascript code.</p>
<p>For example, here's how you could use the <code>select()</code> macro to generate the HTML and Javascript code for a <a href="/components/select">Select</a> component:</p>
{% set code %}{% raw %}{% call select() %}
<div role="group" aria-labelledby="fruit-options-label">
<span id="fruit-options-label" role="heading">Fruits</span>
<div role="option" data-value="apple">Apple</div>
<div role="option" data-value="banana">Banana</div>
<div role="option" data-value="blueberry">Blueberry</div>
<div role="option" data-value="pineapple">Grapes</div>
<div role="option" data-value="pineapple">Pineapple</div>
</div>
{% endcall %}{% endraw %}{% endset %}
{{ code_block(code, "jinja") }}
<p>You still need to make sure to include the Javascript code, to do so you have two options:</p>
<ul>
<li>
Set <code>include_script</code> to <code>true</code> when calling the macro. This will include the <code>&lt;script&gt;</code> code snippet directly before the component's HTML:
{% set code %}{% raw %}{% call select(include_script=true) %} {# Or `True` for Jinja #}
<div role="group" aria-labelledby="fruit-options-label">
<span id="fruit-options-label" role="heading">Fruits</span>
<div role="option" data-value="apple">Apple</div>
<div role="option" data-value="banana">Banana</div>
<div role="option" data-value="blueberry">Blueberry</div>
<div role="option" data-value="pineapple">Grapes</div>
<div role="option" data-value="pineapple">Pineapple</div>
</div>
{% endcall %}{% endraw %}{% endset %}
{{ code_block(code, "jinja") }}
</li>
<li>
Manually include the <code>&lt;script&gt;</code> code snippet anywhere before the component's HTML. You can use the relevant script partial to do this, for example:
{% set code_script %}{% raw %}{% include "select-script.njk" %}
{% call select() %}
<div role="group" aria-labelledby="fruit-options-label">
<span id="fruit-options-label" role="heading">Fruits</span>
<div role="option" data-value="apple">Apple</div>
<div role="option" data-value="banana">Banana</div>
<div role="option" data-value="blueberry">Blueberry</div>
<div role="option" data-value="pineapple">Grapes</div>
<div role="option" data-value="pineapple">Pineapple</div>
</div>
{% endcall %}{% endraw %}{% endset %}
{{ code_block(code_script, "jinja") }}
</li>
</ul>
<p>Documentation for each macro's parameters is available in the <a href="https://github.com/hunvreus/basecoat/tree/main/docs/src/_includes/components" target="_blank">source code</a>.</p>
</div>
-13
View File
@@ -1,13 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Inter&display=swap");
@import "tailwindcss";
@source './src/**/*.njk';
@import "basecoat";
@theme {
--font-sans: 'Inter';
--font-mono: 'JetBrains Mono';
}
/* @import "./theme.css"; */
-146
View File
@@ -1,146 +0,0 @@
:root {
--background: oklch(0.94 0.02 345.70);
--foreground: oklch(0.47 0 0);
--card: oklch(0.95 0.05 86.89);
--card-foreground: oklch(0.47 0 0);
--popover: oklch(1.00 0 0);
--popover-foreground: oklch(0.47 0 0);
--primary: oklch(0.62 0.18 348.14);
--primary-foreground: oklch(1.00 0 0);
--secondary: oklch(0.81 0.07 198.19);
--secondary-foreground: oklch(0.32 0 0);
--muted: oklch(0.88 0.05 212.10);
--muted-foreground: oklch(0.58 0 0);
--accent: oklch(0.92 0.08 87.67);
--accent-foreground: oklch(0.32 0 0);
--destructive: oklch(0.71 0.17 21.96);
--destructive-foreground: oklch(1.00 0 0);
--border: oklch(0.62 0.18 348.14);
--input: oklch(0.92 0 0);
--ring: oklch(0.70 0.16 350.75);
--chart-1: oklch(0.70 0.16 350.75);
--chart-2: oklch(0.82 0.08 212.09);
--chart-3: oklch(0.92 0.08 87.67);
--chart-4: oklch(0.80 0.11 348.18);
--chart-5: oklch(0.62 0.19 353.91);
--sidebar: oklch(0.91 0.04 343.09);
--sidebar-foreground: oklch(0.32 0 0);
--sidebar-primary: oklch(0.66 0.21 354.31);
--sidebar-primary-foreground: oklch(1.00 0 0);
--sidebar-accent: oklch(0.82 0.11 346.02);
--sidebar-accent-foreground: oklch(0.32 0 0);
--sidebar-border: oklch(0.95 0.03 307.17);
--sidebar-ring: oklch(0.66 0.21 354.31);
--font-sans: Poppins, sans-serif;
--font-serif: Lora, serif;
--font-mono: Fira Code, monospace;
--radius: 0.4rem;
--shadow-2xs: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 0.50);
--shadow-xs: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 0.50);
--shadow-sm: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 1.00), 3px 1px 2px -1px hsl(325.78 58.18% 56.86% / 1.00);
--shadow: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 1.00), 3px 1px 2px -1px hsl(325.78 58.18% 56.86% / 1.00);
--shadow-md: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 1.00), 3px 2px 4px -1px hsl(325.78 58.18% 56.86% / 1.00);
--shadow-lg: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 1.00), 3px 4px 6px -1px hsl(325.78 58.18% 56.86% / 1.00);
--shadow-xl: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 1.00), 3px 8px 10px -1px hsl(325.78 58.18% 56.86% / 1.00);
--shadow-2xl: 3px 3px 0px 0px hsl(325.78 58.18% 56.86% / 2.50);
}
.dark {
--background: oklch(0.25 0.03 234.16);
--foreground: oklch(0.93 0.02 349.08);
--card: oklch(0.29 0.03 233.54);
--card-foreground: oklch(0.93 0.02 349.08);
--popover: oklch(0.29 0.03 233.54);
--popover-foreground: oklch(0.93 0.02 349.08);
--primary: oklch(0.92 0.08 87.67);
--primary-foreground: oklch(0.25 0.03 234.16);
--secondary: oklch(0.78 0.08 4.13);
--secondary-foreground: oklch(0.25 0.03 234.16);
--muted: oklch(0.27 0.01 255.58);
--muted-foreground: oklch(0.78 0.08 4.13);
--accent: oklch(0.67 0.10 356.98);
--accent-foreground: oklch(0.93 0.02 349.08);
--destructive: oklch(0.67 0.18 350.36);
--destructive-foreground: oklch(0.25 0.03 234.16);
--border: oklch(0.39 0.04 242.22);
--input: oklch(0.31 0.03 232.00);
--ring: oklch(0.70 0.09 201.87);
--chart-1: oklch(0.70 0.09 201.87);
--chart-2: oklch(0.78 0.08 4.13);
--chart-3: oklch(0.67 0.10 356.98);
--chart-4: oklch(0.44 0.07 217.08);
--chart-5: oklch(0.27 0.01 255.58);
--sidebar: oklch(0.23 0.03 235.97);
--sidebar-foreground: oklch(0.97 0.00 264.54);
--sidebar-primary: oklch(0.66 0.21 354.31);
--sidebar-primary-foreground: oklch(1.00 0 0);
--sidebar-accent: oklch(0.82 0.11 346.02);
--sidebar-accent-foreground: oklch(0.28 0.03 256.85);
--sidebar-border: oklch(0.37 0.03 259.73);
--sidebar-ring: oklch(0.66 0.21 354.31);
--font-sans: Poppins, sans-serif;
--font-serif: Lora, serif;
--font-mono: Fira Code, monospace;
--radius: 0.4rem;
--shadow-2xs: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 0.50);
--shadow-xs: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 0.50);
--shadow-sm: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 1.00), 3px 1px 2px -1px hsl(206.15 28.06% 27.25% / 1.00);
--shadow: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 1.00), 3px 1px 2px -1px hsl(206.15 28.06% 27.25% / 1.00);
--shadow-md: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 1.00), 3px 2px 4px -1px hsl(206.15 28.06% 27.25% / 1.00);
--shadow-lg: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 1.00), 3px 4px 6px -1px hsl(206.15 28.06% 27.25% / 1.00);
--shadow-xl: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 1.00), 3px 8px 10px -1px hsl(206.15 28.06% 27.25% / 1.00);
--shadow-2xl: 3px 3px 0px 0px hsl(206.15 28.06% 27.25% / 2.50);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
--font-serif: var(--font-serif);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--shadow-2xs: var(--shadow-2xs);
--shadow-xs: var(--shadow-xs);
--shadow-sm: var(--shadow-sm);
--shadow: var(--shadow);
--shadow-md: var(--shadow-md);
--shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl);
--shadow-2xl: var(--shadow-2xl);
}
+2 -2
View File
@@ -16,10 +16,10 @@
},
"homepage": "https://github.com/hunvreus/basecoat#readme",
"scripts": {
"css:dev": "tailwindcss -i ./docs/styles.css -o ./docs/src/assets/styles.css --watch",
"css:dev": "tailwindcss -i ./docs/css/styles.css -o ./docs/src/assets/styles.css --watch",
"eleventy:serve": "eleventy --serve",
"dev": "concurrently \"npm:css:dev\" \"npm:eleventy:serve\"",
"build": "tailwindcss -i ./docs/styles.css -o ./docs/src/assets/styles.css --minify && eleventy"
"build": "tailwindcss -i ./docs/css/styles.css -o ./docs/src/assets/styles.css --minify && eleventy"
},
"devDependencies": {
"@11ty/eleventy": "^3.0.0",
-120
View File
@@ -906,124 +906,4 @@
}
}
}
}
/* Prose */
@layer components {
.prose h1,
.prose h2,
.prose h3,
.prose h4,
.prose h5,
.prose h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
@apply font-medium leading-tight;
}
.prose h1,
.h1 {
@apply text-2xl;
}
.prose h2,
.h2 {
@apply text-xl;
}
.prose h3,
.h3 {
@apply text-lg;
}
.prose h4,
.prose h5,
.prose h6,
.h4,
.h5,
.h6 {
@apply text-base;
}
.prose a,
.link {
@apply font-medium underline underline-offset-4;
}
.prose code,
.code {
@apply relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm;
}
.prose pre:has(> code),
.code-block {
@apply bg-muted border-border rounded-md;
}
.prose pre code,
.code-block code {
@apply inline-block p-4 text-sm font-mono;
}
.prose blockquote,
.quote {
@apply border-l-4 border-border pl-4;
}
.prose ol,
.ordered-list {
@apply my-6 ml-6 list-decimal;
li {
@apply mb-2;
}
}
.prose ul,
.unordered-list {
@apply my-6 ml-6 list-disc;
li {
@apply mb-2;
}
ul,
ol {
@apply my-2;
}
}
.prose > *:first-child {
@apply !mt-0;
}
.prose > *:last-child {
@apply !mb-0;
}
.prose h1 {
@apply mb-8;
}
.prose h2 {
@apply mt-8 mb-6;
}
.prose h3 {
@apply mt-6 mb-4;
}
.prose h4 {
@apply my-4;
}
.prose h5 {
@apply my-4;
}
.prose h6 {
@apply my-4;
}
.prose > p,
.prose > blockquote,
.prose > ul,
.prose > ol,
.prose > dl,
.prose > table,
.prose > pre,
.prose > p {
@apply my-4;
}
.prose > *:last-child {
@apply !mb-0;
}
.prose strong,
.prose b {
@apply font-semibold;
}
}