From 0c4a14816e966e04c0d18c937fca3a5b8e7207e7 Mon Sep 17 00:00:00 2001 From: Ronan Berder Date: Thu, 1 May 2025 20:53:03 +0800 Subject: [PATCH] Working on CLI --- .eleventy.js | 34 + cli/index.js | 60 ++ docs/css/custom.css | 8 +- .../_includes/components/dialog-script.njk | 55 -- .../components/dropdown-menu-script.njk | 98 --- .../_includes/components/popover-script.njk | 33 - .../_includes/components/select-script.njk | 157 ----- docs/src/_includes/components/tabs-script.njk | 71 -- .../src/_includes/components/toast-script.njk | 75 --- docs/src/_includes/layouts/base.njk | 26 +- docs/src/_includes/macros/code_preview.njk | 2 +- .../partials/kitchen-sink/alert-dialog.njk | 2 +- .../partials/kitchen-sink/breadcrumb.njk | 2 +- .../partials/kitchen-sink/combobox.njk | 2 +- .../partials/kitchen-sink/dialog.njk | 2 +- .../partials/kitchen-sink/dropdown-menu.njk | 2 +- .../partials/kitchen-sink/popover.njk | 2 +- .../partials/kitchen-sink/select.njk | 2 +- .../_includes/partials/kitchen-sink/tabs.njk | 2 +- docs/src/_includes/partials/sidebar.njk | 11 +- docs/src/assets/styles.css | 7 +- docs/src/components/alert-dialog.njk | 22 +- docs/src/components/alert.njk | 2 +- docs/src/components/avatar.njk | 2 +- docs/src/components/badge.njk | 2 +- docs/src/components/breadcrumb.njk | 18 +- docs/src/components/button.njk | 6 +- docs/src/components/card.njk | 2 +- docs/src/components/checkbox.njk | 8 +- docs/src/components/combobox.njk | 22 +- docs/src/components/dialog.njk | 24 +- docs/src/components/dropdown-menu.njk | 20 +- docs/src/components/form.njk | 2 +- docs/src/components/input.njk | 2 +- docs/src/components/label.njk | 2 +- docs/src/components/pagination.njk | 2 +- docs/src/components/popover.njk | 24 +- docs/src/components/radio-group.njk | 2 +- docs/src/components/select.njk | 24 +- docs/src/components/skeleton.njk | 2 +- docs/src/components/slider.njk | 2 +- docs/src/components/switch.njk | 2 +- docs/src/components/table.njk | 2 +- docs/src/components/tabs.njk | 20 +- docs/src/components/textarea.njk | 2 +- docs/src/components/tooltip.njk | 2 +- docs/src/fragments/toast/error.njk | 2 +- docs/src/fragments/toast/info.njk | 2 +- docs/src/fragments/toast/success.njk | 2 +- docs/src/fragments/toast/warning.njk | 2 +- docs/src/index.njk | 4 +- docs/src/installation.njk | 51 +- package-lock.json | 604 +++++++++++++++++- package.json | 37 +- src/{ => css}/basecoat.css | 0 src/jinja/dialog.html.jinja | 110 ++++ src/jinja/dropdown-menu.html.jinja | 57 ++ src/jinja/popover.html.jinja | 55 ++ src/jinja/select.html.jinja | 108 ++++ src/jinja/tabs.html.jinja | 75 +++ src/jinja/toast.html.jinja | 173 +++++ src/js/dialog.js | 54 ++ src/js/dropdown-menu.js | 91 +++ src/js/popover.js | 26 + src/js/select.js | 150 +++++ src/js/tabs.js | 64 ++ src/js/toast.js | 68 ++ .../components => src/nunjucks}/dialog.njk | 11 +- .../nunjucks}/dropdown-menu.njk | 10 +- .../components => src/nunjucks}/popover.njk | 10 +- .../components => src/nunjucks}/select.njk | 10 +- .../components => src/nunjucks}/tabs.njk | 10 +- .../components => src/nunjucks}/toast.njk | 10 +- 73 files changed, 1961 insertions(+), 706 deletions(-) create mode 100755 cli/index.js delete mode 100644 docs/src/_includes/components/dialog-script.njk delete mode 100644 docs/src/_includes/components/dropdown-menu-script.njk delete mode 100644 docs/src/_includes/components/popover-script.njk delete mode 100644 docs/src/_includes/components/select-script.njk delete mode 100644 docs/src/_includes/components/tabs-script.njk delete mode 100644 docs/src/_includes/components/toast-script.njk rename src/{ => css}/basecoat.css (100%) create mode 100644 src/jinja/dialog.html.jinja create mode 100644 src/jinja/dropdown-menu.html.jinja create mode 100644 src/jinja/popover.html.jinja create mode 100644 src/jinja/select.html.jinja create mode 100644 src/jinja/tabs.html.jinja create mode 100644 src/jinja/toast.html.jinja create mode 100644 src/js/dialog.js create mode 100644 src/js/dropdown-menu.js create mode 100644 src/js/popover.js create mode 100644 src/js/select.js create mode 100644 src/js/tabs.js create mode 100644 src/js/toast.js rename {docs/src/_includes/components => src/nunjucks}/dialog.njk (89%) rename {docs/src/_includes/components => src/nunjucks}/dropdown-menu.njk (79%) rename {docs/src/_includes/components => src/nunjucks}/popover.njk (79%) rename {docs/src/_includes/components => src/nunjucks}/select.njk (91%) rename {docs/src/_includes/components => src/nunjucks}/tabs.njk (86%) rename {docs/src/_includes/components => src/nunjucks}/toast.njk (94%) diff --git a/.eleventy.js b/.eleventy.js index 6124b88..cb91258 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -1,10 +1,36 @@ import eleventyLucideicons from "@grimlink/eleventy-plugin-lucide-icons"; import prettier from "prettier"; +import Nunjucks from "nunjucks"; +import fs from "fs"; +import path from "path"; export default async function(eleventyConfig) { eleventyConfig.setInputDirectory("./docs/src"); eleventyConfig.addPassthroughCopy({"docs/src/assets": "assets"}); + eleventyConfig.addPassthroughCopy({ "src/js": "assets/js" }); eleventyConfig.addPlugin(eleventyLucideicons); + // eleventyConfig.addShortcode("fetchCode", async function(filePath) { + // return "HELLO"; + // const absolutePath = path.resolve(process.cwd(), filePath); + // return absolutePath; + // try { + // console.log(absolutePath); + // return fs.readFileSync(absolutePath, 'utf8'); + // } catch (error) { + // console.error(`[Eleventy FetchCode Error] Failed to read: ${absolutePath}`, error); + // return ``; + // } + // }); + eleventyConfig.addShortcode("fetchCode", function(filePath) { + const absolutePath = path.resolve(process.cwd(), filePath); + try { + return fs.readFileSync(absolutePath, 'utf8'); + } catch (error) { + console.error(`[Eleventy FetchCode Error] Failed to read: ${absolutePath}`, error); + return ``; + } + }); + eleventyConfig.addNunjucksAsyncFilter("prettyHtml", async (code, callback) => { try { const formattedCode = await prettier.format(code, { @@ -20,4 +46,12 @@ export default async function(eleventyConfig) { callback(err, code); } }); + let nunjucksEnvironment = new Nunjucks.Environment( + new Nunjucks.FileSystemLoader([ + "src/nunjucks", + "docs/src/_includes" + ]), + { autoescape: true } + ); + eleventyConfig.setLibrary("njk", nunjucksEnvironment); } \ No newline at end of file diff --git a/cli/index.js b/cli/index.js new file mode 100755 index 0000000..947bc7e --- /dev/null +++ b/cli/index.js @@ -0,0 +1,60 @@ +#!/usr/bin/env node +// ^^^ Makes the script executable + +import { Command } from 'commander'; +// We'll add fs-extra and inquirer later + +const program = new Command(); + +console.log('Basecoat CLI'); + +program + .name('basecoat') + .description('Add Basecoat components to your project') + .version('0.1.0'); // TODO: Get version from package.json + +program + .command('add') + .description('Add one or more components to your project') + .argument('[components...]', 'Names of components to add') // Optional arg for now + .action(async (components) => { + if (!components || components.length === 0) { + console.log('Please specify which component(s) to add, or run add without args for a list (TODO).'); + // TODO: Implement interactive component selection if no args + return; + } + + console.log(`Attempting to add: ${components.join(', ')}`); + + for (const componentName of components) { + await addComponent(componentName); + } + + console.log('\nComponent addition process finished.'); + }); + +// Placeholder function for adding a single component +async function addComponent(componentName) { + console.log(`\nProcessing component: ${componentName}`); + + // 1. Check if config file exists (TODO) + // 2. If not, run init command/ask questions (TODO) + // 3. Read config (template engine, paths) (TODO) + // 4. Determine source file paths based on component name and config (TODO) + // 5. Check if source files exist in the package (TODO) + // 6. Copy files to destination paths using fs-extra (TODO) + + console.log(` -> Placeholder: Logic to copy ${componentName} files would go here.`); +} + +// TODO: Implement init command +// program +// .command('init') +// .description('Initialize basecoat configuration') +// .action(async () => { +// console.log('Running init...'); +// // Ask config questions +// // Save config file +// }); + +program.parse(process.argv); \ No newline at end of file diff --git a/docs/css/custom.css b/docs/css/custom.css index 1b06eea..882d322 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -23,6 +23,12 @@ ul { @apply list-disc ml-6; } + ol, + ul { + li { + @apply mt-2; + } + } b, strong { @apply font-semibold; @@ -35,7 +41,7 @@ > table, > pre, > p { - @apply my-4; + @apply my-6; } > *:first-child { @apply !mt-0; diff --git a/docs/src/_includes/components/dialog-script.njk b/docs/src/_includes/components/dialog-script.njk deleted file mode 100644 index 2c76bdd..0000000 --- a/docs/src/_includes/components/dialog-script.njk +++ /dev/null @@ -1,55 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/_includes/components/dropdown-menu-script.njk b/docs/src/_includes/components/dropdown-menu-script.njk deleted file mode 100644 index 3bc772c..0000000 --- a/docs/src/_includes/components/dropdown-menu-script.njk +++ /dev/null @@ -1,98 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/_includes/components/popover-script.njk b/docs/src/_includes/components/popover-script.njk deleted file mode 100644 index b9b330b..0000000 --- a/docs/src/_includes/components/popover-script.njk +++ /dev/null @@ -1,33 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/_includes/components/select-script.njk b/docs/src/_includes/components/select-script.njk deleted file mode 100644 index b031f61..0000000 --- a/docs/src/_includes/components/select-script.njk +++ /dev/null @@ -1,157 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/_includes/components/tabs-script.njk b/docs/src/_includes/components/tabs-script.njk deleted file mode 100644 index 5dce2be..0000000 --- a/docs/src/_includes/components/tabs-script.njk +++ /dev/null @@ -1,71 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/_includes/components/toast-script.njk b/docs/src/_includes/components/toast-script.njk deleted file mode 100644 index 315dafa..0000000 --- a/docs/src/_includes/components/toast-script.njk +++ /dev/null @@ -1,75 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/_includes/layouts/base.njk b/docs/src/_includes/layouts/base.njk index bcb07b1..9a7f08b 100644 --- a/docs/src/_includes/layouts/base.njk +++ b/docs/src/_includes/layouts/base.njk @@ -45,14 +45,24 @@ - + + + + + + + + - {% include "components/dialog-script.njk" %} - {% include "components/dropdown-menu-script.njk" %} - {% include "components/popover-script.njk" %} - {% include "components/select-script.njk" %} - {% include "components/tabs-script.njk" %} - {% include "components/toast-script.njk" %} @@ -128,7 +138,7 @@ -{% from "components/toast.njk" import toaster %} +{% from "toast.njk" import toaster %} {{ toaster() }} \ No newline at end of file diff --git a/docs/src/_includes/macros/code_preview.njk b/docs/src/_includes/macros/code_preview.njk index 0146792..7090699 100644 --- a/docs/src/_includes/macros/code_preview.njk +++ b/docs/src/_includes/macros/code_preview.njk @@ -12,7 +12,7 @@ {% endset %}
- {% from "components/tabs.njk" import tabs %} + {% from "tabs.njk" import tabs %} {% set tabsets = [ { tab: "Preview", panel: preview_panel }, { tab: "Code", panel: code_panel } diff --git a/docs/src/_includes/partials/kitchen-sink/alert-dialog.njk b/docs/src/_includes/partials/kitchen-sink/alert-dialog.njk index 2d3295d..425f194 100644 --- a/docs/src/_includes/partials/kitchen-sink/alert-dialog.njk +++ b/docs/src/_includes/partials/kitchen-sink/alert-dialog.njk @@ -1,4 +1,4 @@ -{% from "components/dialog.njk" import dialog %} +{% from "dialog.njk" import dialog %}
diff --git a/docs/src/_includes/partials/kitchen-sink/breadcrumb.njk b/docs/src/_includes/partials/kitchen-sink/breadcrumb.njk index 3b67035..679436f 100644 --- a/docs/src/_includes/partials/kitchen-sink/breadcrumb.njk +++ b/docs/src/_includes/partials/kitchen-sink/breadcrumb.njk @@ -1,4 +1,4 @@ -{% from "components/popover.njk" import popover %} +{% from "popover.njk" import popover %}
-

The Alert Dialog component uses the same Alpine.js code as the Dialog component with one small difference: we set initialCloseOnOverlayClick to false to prevent the dialog from closing when the overlay is clicked.

+

The Alert Dialog component uses the same Alpine.js code as the Dialog component with one small difference: we set initialCloseOnOverlayClick to false to prevent the dialog from closing when the overlay is clicked.

-{% from "components/tabs.njk" import tabs %} +{% from "tabs.njk" import tabs %} {% set tabsets = [ - { tab: "HTML", panel: code_block(code_html | prettyHtml) }, - { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } + { tab: "HTML", panel: code_block(code_html | prettyHtml, class="") }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml, class="") } ] %} {{ tabs(id="alert-dialog", tabsets=tabsets) }}

Jinja or Nunjucks

-

If you use Jinja (or Nunjucks), you can use the dialog() macro directly, making sure to set close_on_overlay_click and close_button to False (or false for Nunjucks). Read more about using Basecoat with Jinja and Nunjucks.

+

If you use Jinja (or Nunjucks), you can use the dialog() macro directly, making sure to set close_on_overlay_click and close_button to False (or false for Nunjucks). Read more about using Basecoat with Jinja and Nunjucks.

{% set raw_code %}{% raw %}{% set footer %} diff --git a/docs/src/components/alert.njk b/docs/src/components/alert.njk index 245f624..f8f550c 100644 --- a/docs/src/components/alert.njk +++ b/docs/src/components/alert.njk @@ -28,7 +28,7 @@ toc:

Usage

-
+

You can use one of the two classes: alert or alert-dialog with any of the following children:

  • A svg icon,
  • diff --git a/docs/src/components/avatar.njk b/docs/src/components/avatar.njk index 61687b3..2a5520e 100644 --- a/docs/src/components/avatar.njk +++ b/docs/src/components/avatar.njk @@ -20,4 +20,4 @@ toc:

    Usage

    -

    Avatars are fairly simple to implement with Tailwind. The example above shows how to implement one with Tailwind and an <img> element. More examples can be found in the kitchen sink.

    \ No newline at end of file +

    Avatars are fairly simple to implement with Tailwind. The example above shows how to implement one with Tailwind and an <img> element. More examples can be found in the kitchen sink.

    \ No newline at end of file diff --git a/docs/src/components/badge.njk b/docs/src/components/badge.njk index 578fe8d..ef1f67a 100644 --- a/docs/src/components/badge.njk +++ b/docs/src/components/badge.njk @@ -30,7 +30,7 @@ toc:

    Usage

    -
    +

    Use one of the badge classes: badge, badge-primary, badge-secondary, badge-destructive or badge-outline.

    diff --git a/docs/src/components/breadcrumb.njk b/docs/src/components/breadcrumb.njk index f60ba4c..e67f29b 100644 --- a/docs/src/components/breadcrumb.njk +++ b/docs/src/components/breadcrumb.njk @@ -9,7 +9,7 @@ toc: {% from "macros/code_preview.njk" import code_preview %} {% from "macros/code_block.njk" import code_block %} -{% from "components/dropdown-menu.njk" import dropdown_menu %} +{% from "dropdown-menu.njk" import dropdown_menu %}
    {% lucide "circle-alert" %} @@ -17,7 +17,13 @@ toc:
    {% set code_script %} -{% include "components/dropdown-menu-script.njk" %} + {% endset %} {% set code_html %} @@ -58,13 +64,13 @@ toc:

    Usage

    -
    +

    The example above uses some simple Tailwind CSS along with the Dropdown Menu.

    -{% from "components/tabs.njk" import tabs %} +{% from "tabs.njk" import tabs %} {% set tabsets = [ - { tab: "HTML", panel: code_block(code_html | prettyHtml) }, - { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } + { tab: "HTML", panel: code_block(code_html | prettyHtml, class="") }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml, class="") } ] %} {{ tabs(id="alert-dialog", tabsets=tabsets) }} \ No newline at end of file diff --git a/docs/src/components/button.njk b/docs/src/components/button.njk index d1b70e1..e814be4 100644 --- a/docs/src/components/button.njk +++ b/docs/src/components/button.njk @@ -40,7 +40,7 @@ toc:

    Usage

    -
    +

    You can use one of the btn classes to style any element as a button:

      @@ -68,9 +68,7 @@ toc:
    -
    - {{ code_block(code) }} -
    +{{ code_block(code) }}

    Examples

    diff --git a/docs/src/components/card.njk b/docs/src/components/card.njk index a59a2e0..5264879 100644 --- a/docs/src/components/card.njk +++ b/docs/src/components/card.njk @@ -47,7 +47,7 @@ toc:

    Usage

    -
    +

    Add the card class to any element and then define any of the children elements:

    • A <header> for the card header, which can contain a <h2> for the title and a <p> for the description.
    • diff --git a/docs/src/components/checkbox.njk b/docs/src/components/checkbox.njk index 14fee39..c43d6d5 100644 --- a/docs/src/components/checkbox.njk +++ b/docs/src/components/checkbox.njk @@ -27,14 +27,12 @@ toc:

      Usage

      -
      +

      Add the input class to your <input type="radio"> elements or have a parent with the form class (read more about form). You can also set the aria-invalid attribute to true to make the input invalid.

      -
      - {% set code %}{% endset %} - {{ code_block(code) }} -
      +{% set code %}{% endset %} +{{ code_block(code) }}

      Examples

      diff --git a/docs/src/components/combobox.njk b/docs/src/components/combobox.njk index 36e876b..597440d 100644 --- a/docs/src/components/combobox.njk +++ b/docs/src/components/combobox.njk @@ -21,7 +21,7 @@ toc: {% from "macros/code_preview.njk" import code_preview %} {% from "macros/code_block.njk" import code_block %} -{% from "components/select.njk" import select %} +{% from "select.njk" import select %} {% set options_frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"] %} {% set code_html %} @@ -39,7 +39,13 @@ toc: {% endset %} {% set code_script %} -{% include "components/select-script.njk" %} + {% endset %} {{ code_preview("combobox", code_script | prettyHtml ~ code_html | prettyHtml) }} @@ -56,7 +62,7 @@ toc:
      -
      +

      Combobox uses the same Alpine.js code and markup as the Select component, the only difference being the search box at the top of the listbox.

      You can set up a few additional options on the <div data-popover> element:

        @@ -66,18 +72,16 @@ toc:
      -{% from "components/tabs.njk" import tabs %} +{% from "tabs.njk" import tabs %} {% set tabsets = [ - { tab: "HTML", panel: code_block(code_html | prettyHtml) }, - { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } + { tab: "HTML", panel: code_block(code_html | prettyHtml, class="") }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml, class="") } ] %} {{ tabs(id="combobox", tabsets=tabsets) }}

      Jinja or Nunjucks

      -
      -

      If you use Jinja (or Nunjucks), you can use the select() macro directly, making sure to set is_combobox to True (or true for Nunjucks). Read more about using Basecoat with Jinja and Nunjucks.

      -
      +

      If you use Jinja (or Nunjucks), you can use the select() macro directly, making sure to set is_combobox to True (or true for Nunjucks). Read more about using Basecoat with Jinja and Nunjucks.

      {% set raw_code %}{% raw %}{% call select( listbox_attrs={"data-empty": "No framework found."}, diff --git a/docs/src/components/dialog.njk b/docs/src/components/dialog.njk index 4d466fc..54b9f24 100644 --- a/docs/src/components/dialog.njk +++ b/docs/src/components/dialog.njk @@ -19,7 +19,7 @@ toc: {% from "macros/code_block.njk" import code_block %} {% from "macros/code_preview.njk" import code_preview %} -{% from "components/dialog.njk" import dialog %} +{% from "dialog.njk" import dialog %} {% set code_html %} {% set footer %} @@ -40,7 +40,7 @@ toc:
      - +
      @@ -51,10 +51,16 @@ toc: {% endset %} {% set code_script %} -{% include "components/dialog-script.njk" %} + {% endset %} -{{ code_preview("dialog", code_script | prettyHtml ~ code_html | prettyHtml) }} +{{ code_preview("dialog", code_html | prettyHtml) }}

      Usage

      @@ -68,7 +74,7 @@ toc:
      -
      +

      The component is structured as such:

      • A <div class="dialog"> which wraps around the entire component and holds it state (e.g. open/close).
      • @@ -85,16 +91,16 @@ toc:
      -{% from "components/tabs.njk" import tabs %} +{% from "tabs.njk" import tabs %} {% set tabsets = [ - { tab: "HTML", panel: code_block(code_html | prettyHtml) }, - { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } + { tab: "HTML", panel: code_block(code_html | prettyHtml, class="") }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml, class="") } ] %} {{ tabs(id="combobox", tabsets=tabsets) }}

      Jinja or Nunjucks

      -

      If you use Jinja (or Nunjucks), you can use the dialog() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

      +

      If you use Jinja (or Nunjucks), you can use the dialog() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

      {% set raw_code %}{% raw %}{% set footer %} diff --git a/docs/src/components/dropdown-menu.njk b/docs/src/components/dropdown-menu.njk index 33f3d2c..2f10038 100644 --- a/docs/src/components/dropdown-menu.njk +++ b/docs/src/components/dropdown-menu.njk @@ -21,7 +21,7 @@ toc: {% from "macros/code_block.njk" import code_block %} {% from "macros/code_preview.njk" import code_preview %} -{% from "components/dropdown-menu.njk" import dropdown_menu %} +{% from "dropdown-menu.njk" import dropdown_menu %} {% set code_html %} {% call dropdown_menu( @@ -69,7 +69,13 @@ toc: {% endset %} {% set code_script %} -{% include "components/dropdown-menu-script.njk" %} + {% endset %} {{ code_preview("dropdown-menu", code_script | prettyHtml ~ code_html | prettyHtml) }} @@ -86,7 +92,7 @@ toc:
      -
      +

      The component is structured as such:

      • A <div class="popover"> which wraps around the entire component and holds it state (e.g. open/close).
      • @@ -109,16 +115,16 @@ toc:
      -{% from "components/tabs.njk" import tabs %} +{% from "tabs.njk" import tabs %} {% set tabsets = [ - { tab: "HTML", panel: code_block(code_html | prettyHtml) }, - { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } + { tab: "HTML", panel: code_block(code_html | prettyHtml, class="") }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml, class="") } ] %} {{ tabs(id="dropdown-menu", tabsets=tabsets) }}

      Jinja or Nunjucks

      -

      If you use Jinja (or Nunjucks), you can use the dropdown_menu() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

      +

      If you use Jinja (or Nunjucks), you can use the dropdown_menu() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

      {% set raw_code %}{% raw %}{% call dropdown_menu( id="dropdown-menu", diff --git a/docs/src/components/form.njk b/docs/src/components/form.njk index 8c18b81..c152262 100644 --- a/docs/src/components/form.njk +++ b/docs/src/components/form.njk @@ -72,7 +72,7 @@ toc:

      Usage

      -
      +

      Adding the form class to the parent of any form element (<label>, <input>, <textarea>, <select>) will automatically apply the style you would get from adding label, input, textarea, or select classes. Read more about Label, Input, Textarea, and Select.

      diff --git a/docs/src/components/input.njk b/docs/src/components/input.njk index 2b0a756..883c750 100644 --- a/docs/src/components/input.njk +++ b/docs/src/components/input.njk @@ -32,7 +32,7 @@ toc:

      Usage

      -
      +

      Simply add the input class to your <input> element or have a parent with the form class (read more about form). You can also set the aria-invalid attribute to true to make the input invalid.

      diff --git a/docs/src/components/label.njk b/docs/src/components/label.njk index b23e74d..18eeab5 100644 --- a/docs/src/components/label.njk +++ b/docs/src/components/label.njk @@ -23,7 +23,7 @@ toc:

      Usage

      -
      +

      Simply add the label class to your <label> element or have a parent with the form class (read more about form). Labels' style may be affected by the presence of a disabled peer or child element.

      diff --git a/docs/src/components/pagination.njk b/docs/src/components/pagination.njk index 206a71c..0336f23 100644 --- a/docs/src/components/pagination.njk +++ b/docs/src/components/pagination.njk @@ -41,7 +41,7 @@ toc:

      Usage

      -
      +

      A pagination is fairly simple to implement with Tailwind using the Basecoat button classes:

      diff --git a/docs/src/components/popover.njk b/docs/src/components/popover.njk index 2a054cc..d6ca2c1 100644 --- a/docs/src/components/popover.njk +++ b/docs/src/components/popover.njk @@ -14,7 +14,7 @@ toc: {% from "macros/code_preview.njk" import code_preview %} {% from "macros/code_block.njk" import code_block %} -{% from "components/popover.njk" import popover %} +{% from "popover.njk" import popover %} {% set code_html %} {% call popover( @@ -52,10 +52,16 @@ toc: {% endset %} {% set code_script %} -{% include "components/popover-script.njk" %} + {% endset %} -{{ code_preview("combobox", code_script | prettyHtml ~ code_html | prettyHtml) }} +{{ code_preview("popover", code_script | prettyHtml ~ code_html | prettyHtml) }}

      Usage

      @@ -69,7 +75,7 @@ toc:
      -
      +

      The component is structured as such:

      • A <div class="popover"> which wraps around the entire component and holds it state (e.g. open/close).
      • @@ -83,17 +89,17 @@ toc:
      -{% from "components/tabs.njk" import tabs %} +{% from "tabs.njk" import tabs %} {% set tabsets = [ - { tab: "HTML", panel: code_block(code_html | prettyHtml) }, - { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) } + { tab: "HTML", panel: code_block(code_html | prettyHtml, class="") }, + { tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml, class="") } ] %} {{ tabs(id="popover", tabsets=tabsets) }}

      Jinja or Nunjucks

      -
      -

      If you use Jinja (or Nunjucks), you can use the popover() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

      +
      +

      If you use Jinja (or Nunjucks), you can use the popover() macro directly. Read more about using Basecoat with Jinja and Nunjucks.

      {% set raw_code %}{% raw %}{% call popover( diff --git a/docs/src/components/radio-group.njk b/docs/src/components/radio-group.njk index 71f4b1f..c32019d 100644 --- a/docs/src/components/radio-group.njk +++ b/docs/src/components/radio-group.njk @@ -24,7 +24,7 @@ toc:

      Usage

      -
      +

      Simply add the input class to your <input type="radio"> elements or have a parent with the form class (read more about form). You can also set the aria-invalid attribute to true to make the input invalid.

      diff --git a/docs/src/components/select.njk b/docs/src/components/select.njk index 8239594..139cd0a 100644 --- a/docs/src/components/select.njk +++ b/docs/src/components/select.njk @@ -25,7 +25,7 @@ toc: {% from "macros/code_preview.njk" import code_preview %} {% from "macros/code_block.njk" import code_block %} -{% from "components/select.njk" import select %} +{% from "select.njk" import select %} {% set code_native %} + + {% endif %} +
      + {% if caller %}{{ caller() }}{% endif %} +
      + + {% if name is defined %} + + {% endif %} + +{% endmacro %} \ No newline at end of file diff --git a/src/jinja/tabs.html.jinja b/src/jinja/tabs.html.jinja new file mode 100644 index 0000000..e9cddb6 --- /dev/null +++ b/src/jinja/tabs.html.jinja @@ -0,0 +1,75 @@ +{# + 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. +#} +{% macro tabs( + id, + tabsets=[], + main_attrs=None, + tablist_attrs=None, + default_tab_index=1 + ) +%} +
      + + + {% for tabset in tabsets %} + {% if tabset.panel %} +
      + {{ tabset.panel | safe }} +
      + {% endif %} + {% endfor %} +
      +{% endmacro %} \ No newline at end of file diff --git a/src/jinja/toast.html.jinja b/src/jinja/toast.html.jinja new file mode 100644 index 0000000..c9828bd --- /dev/null +++ b/src/jinja/toast.html.jinja @@ -0,0 +1,173 @@ +{# + 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. +#} +{% macro toaster( + id="toaster", + toasts=[], + main_attrs=None, + is_fragment=False +) %} +{% set icons = { + 'success': '', + 'error': '', + 'info': '', + 'warning': '' +} %} + +
      +{% for toast in toasts %} +
      +
      +
      + {% if toast.category in ["error", "success", "info", "warning"] %} + {{ icons[toast.category] | safe }} + {% endif %} +
      + {% if toast.title %} +

      {{ toast.title }}

      + {% endif %} + {% if toast.description %} +

      {{ toast.description }}

      + {% endif %} +
      + {% if toast.action or toast.cancel %} +
      + {% if toast.action %} + {% if toast.action.click %} + + {% elif toast.action.url %} + {{ toast.action.label }} + {% endif %} + {% endif %} + {% if toast.cancel %} + {% if toast.cancel.click %} + + {% elif toast.cancel.url %} + {{ toast.cancel.label }} + {% endif %} + {% endif %} +
      + {% endif %} +
      +
      +
      +{% endfor %} +
      + +{% if not is_fragment %} +