Skip to content

Bot Command Card

A card documenting a slash command, its owning bot and its typed options.

A card documenting a slash command, its owning bot and its typed options. Compose it from the exported registry parts so local content and behaviour stay in the application while the visual contract stays token-driven.

Root class newt-command-card
import { Badge } from "@/registry/bases/newt/ui/badge"
import {
  BotCommandCard,
  BotCommandCardDescription,
  BotCommandCardHeader,
  BotCommandCardName,
  BotCommandCardOption,
  BotCommandCardOptions,
} from "@/registry/bases/newt/ui/bot-command-card"

export default function BotCommandCardDemo() {
  return (
    <BotCommandCard className="w-full">
      <BotCommandCardHeader>
        <BotCommandCardName>command</BotCommandCardName>
        <Badge variant="brand">bot-name</Badge>
      </BotCommandCardHeader>
      <BotCommandCardDescription>
        Command description goes here.
      </BotCommandCardDescription>
      <BotCommandCardOptions>
        <BotCommandCardOption
          name="option"
          type="STRING"
          required
          description="Option description"
        />
        <BotCommandCardOption
          name="user"
          type="USER"
          description="Member to target"
        />
      </BotCommandCardOptions>
    </BotCommandCard>
  )
}
<script setup lang="ts">
import { Badge } from "~~/registry/bases/newt/ui/badge"
import {
  BotCommandCard,
  BotCommandCardDescription,
  BotCommandCardHeader,
  BotCommandCardName,
  BotCommandCardOption,
  BotCommandCardOptions,
} from "~~/registry/bases/newt/ui/bot-command-card"
</script>

<template>
  <BotCommandCard class="w-full">
    <BotCommandCardHeader>
      <BotCommandCardName>command</BotCommandCardName>
      <Badge variant="brand">bot-name</Badge>
    </BotCommandCardHeader>
    <BotCommandCardDescription>
      Command description goes here.
    </BotCommandCardDescription>
    <BotCommandCardOptions>
      <BotCommandCardOption
        name="option"
        type="STRING"
        required
        description="Option description"
      />
      <BotCommandCardOption
        name="user"
        type="USER"
        description="Member to target"
      />
    </BotCommandCardOptions>
  </BotCommandCard>
</template>

Installation

pnpm dlx newtui@latest add bot-command-card
npx newtui@latest add bot-command-card
yarn dlx newtui@latest add bot-command-card
bunx newtui@latest add bot-command-card

Add the components it builds on

Copy the source into your project

import * as React from "react"

import { cn } from "@/lib/utils"

const BotCommandCard = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      "max-w-[480px] rounded-md border border-newt-border bg-newt-bg-elevated p-4",
      className
    )}
    {...props}
  />
))
BotCommandCard.displayName = "BotCommandCard"

const BotCommandCardHeader = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("mb-2 flex items-center justify-between gap-3", className)}
    {...props}
  />
))
BotCommandCardHeader.displayName = "BotCommandCardHeader"

export interface BotCommandCardNameProps extends React.ComponentProps<"span"> {
  /** Render the muted leading slash. Defaults to true. */
  slash?: boolean
}

const BotCommandCardName = React.forwardRef<
  HTMLSpanElement,
  BotCommandCardNameProps
>(({ className, slash = true, children, ...props }, ref) => (
  <span
    ref={ref}
    className={cn(
      "inline-flex items-center gap-1 font-mono text-sm font-semibold text-newt-text-link",
      className
    )}
    {...props}
  >
    {slash ? (
      <span className="font-normal text-newt-text-secondary">/</span>
    ) : null}
    {children}
  </span>
))
BotCommandCardName.displayName = "BotCommandCardName"

const BotCommandCardDescription = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      "mb-3 text-[13px] leading-normal text-newt-text-secondary",
      className
    )}
    {...props}
  />
))
BotCommandCardDescription.displayName = "BotCommandCardDescription"

const BotCommandCardOptions = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex flex-col gap-1.5", className)}
    {...props}
  />
))
BotCommandCardOptions.displayName = "BotCommandCardOptions"

export interface BotCommandCardOptionProps extends Omit<
  React.ComponentProps<"div">,
  "children"
> {
  /** Option name, rendered in monospace. */
  name: string
  /** Option type, e.g. `STRING`, `USER`, `INTEGER`. */
  type?: string
  /** Marks the option as required. */
  required?: boolean
  /** Label used for the required marker. */
  requiredLabel?: string
  /** Human readable description. */
  description?: React.ReactNode
}

const BotCommandCardOption = React.forwardRef<
  HTMLDivElement,
  BotCommandCardOptionProps
>(
  (
    {
      className,
      name,
      type,
      required = false,
      requiredLabel = "required",
      description,
      ...props
    },
    ref
  ) => (
    <div
      ref={ref}
      className={cn("flex items-baseline gap-2.5 text-xs", className)}
      {...props}
    >
      <span className="shrink-0 font-mono font-semibold text-newt-text-primary">
        {name}
      </span>
      {type ? (
        <span className="shrink-0 font-mono text-[11px] text-newt-text-secondary">
          {type}
        </span>
      ) : null}
      {required ? (
        <span className="shrink-0 text-[11px] font-bold text-newt-text-secondary">
          {requiredLabel}
        </span>
      ) : null}
      {description ? (
        <span className="text-newt-text-secondary">{description}</span>
      ) : null}
    </div>
  )
)
BotCommandCardOption.displayName = "BotCommandCardOption"

export {
  BotCommandCard,
  BotCommandCardHeader,
  BotCommandCardName,
  BotCommandCardDescription,
  BotCommandCardOptions,
  BotCommandCardOption,
}
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div
    :class="
      cn(
        'max-w-[480px] rounded-md border border-newt-border bg-newt-bg-elevated p-4',
        props.class
      )
    "
  >
    <slot />
  </div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div :class="cn('mb-2 flex items-center justify-between gap-3', props.class)">
    <slot />
  </div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = withDefaults(
  defineProps<{
    /** Render the muted leading slash. Defaults to true. */
    slash?: boolean
    class?: HTMLAttributes["class"]
  }>(),
  { slash: true }
)
</script>

<template>
  <span
    :class="
      cn(
        'inline-flex items-center gap-1 font-mono text-sm font-semibold text-newt-text-link',
        props.class
      )
    "
  >
    <span v-if="props.slash" class="font-normal text-newt-text-secondary"
      >/</span
    >
    <slot />
  </span>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div
    :class="
      cn(
        'mb-3 text-[13px] leading-normal text-newt-text-secondary',
        props.class
      )
    "
  >
    <slot />
  </div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div :class="cn('flex flex-col gap-1.5', props.class)">
    <slot />
  </div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = withDefaults(
  defineProps<{
    /** Option name, rendered in monospace. */
    name: string
    /** Option type, e.g. `STRING`, `USER`, `INTEGER`. */
    type?: string
    /** Marks the option as required. */
    required?: boolean
    /** Label used for the required marker. */
    requiredLabel?: string
    /** Human readable description. */
    description?: string
    class?: HTMLAttributes["class"]
  }>(),
  { required: false, requiredLabel: "required" }
)
</script>

<template>
  <div :class="cn('flex items-baseline gap-2.5 text-xs', props.class)">
    <span class="shrink-0 font-mono font-semibold text-newt-text-primary">
      {{ props.name }}
    </span>
    <span
      v-if="props.type"
      class="shrink-0 font-mono text-[11px] text-newt-text-secondary"
    >
      {{ props.type }}
    </span>
    <span
      v-if="props.required"
      class="shrink-0 text-[11px] font-bold text-newt-text-secondary"
    >
      {{ props.requiredLabel }}
    </span>
    <span
      v-if="props.description || $slots.default"
      class="text-newt-text-secondary"
    >
      <slot>{{ props.description }}</slot>
    </span>
  </div>
</template>
export { default as BotCommandCard } from "./BotCommandCard.vue"
export { default as BotCommandCardHeader } from "./BotCommandCardHeader.vue"
export { default as BotCommandCardName } from "./BotCommandCardName.vue"
export { default as BotCommandCardDescription } from "./BotCommandCardDescription.vue"
export { default as BotCommandCardOptions } from "./BotCommandCardOptions.vue"
export { default as BotCommandCardOption } from "./BotCommandCardOption.vue"

Update the import paths

The files import @/lib/utils and sibling components through the aliases in your components.json. Point them at wherever those live in your project.

Usage

import { BotCommandCard } from "@/components/ui/bot-command-card"

export function Example() {
  return <BotCommandCard />
}
<script setup lang="ts">
import { BotCommandCard, BotCommandCardHeader, BotCommandCardName, BotCommandCardDescription, BotCommandCardOptions, BotCommandCardOption } from "@/components/ui/bot-command-card"
</script>

<template>
  <BotCommandCard />
</template>

API reference

BotCommandCardName

PropType
slash?boolean | undefined

Render the muted leading slash. Defaults to true.

Typeboolean | undefined

BotCommandCardOption

PropType
name?string

Option name, rendered in monospace.

Typestring
type?string | undefined

Option type, e.g. `STRING`, `USER`, `INTEGER`.

Typestring | undefined
required?boolean | undefined

Marks the option as required.

Typeboolean | undefined
requiredLabel?string | undefined

Label used for the required marker.

Typestring | undefined
description?React.ReactNode | undefined

Human readable description.

TypeReact.ReactNode | undefined

The registry exports BotCommandCard, BotCommandCardHeader, BotCommandCardName, BotCommandCardDescription, BotCommandCardOptions, BotCommandCardOption. Parts without a table accept the native attributes for the element they render; React uses className, while Vue uses class and fallthrough attributes.

Accessibility

Preserve the native semantics of the rendered elements and pass through ARIA attributes when the surrounding context needs a label or description. Any interactive child needs a visible focus indicator, and meaning must not rely on colour alone.

Tokens

Bot Command Card reads its colours, radii and motion from the --newt-* tokens installed with the library. Override a token and every component that reads it follows, including this one — see the token layer. In the plain HTML and CSS distribution the same component is newt-command-card.