HextaUI

Saved prompts with variables that drop straight into the composer. Handles fill-in forms, slash commands, version history and shared, view-only prompts.

Kategori
Yapay zekâ
Kullanılan bileşenler
21
Dosyalar
12
Kullanım örnekleri
3
Erişim
HextaUI Pro (55 blok)
Kaynak kod güncellendi
Open in new tab

HextaUI Pro’nun parçası, 55 bloğun tamamı, $49 tek seferlik, Planları karşılaştır

Everyone on a team ends up with the same few prompts in a notes app: write release notes, summarize a PR, draft a support reply. Each time they paste it, they hunt for the parts to change. Prompt Library keeps those prompts next to the chat, marks the parts that change as {{variables}}, and fills them in with a short form before the prompt goes into the composer.

Each variable gets its own color, by its order in the prompt, and keeps it everywhere: the highlight in the editor, the chip in the list, the dot beside its field and the filled-in text in the preview. You can see at a glance which answer goes where. The list stays quiet: each row shows the title, the prompt itself with its variables as chips, who shared it and when it was last used.

The editor highlights variables as you type and suggests them after {{. A name with spaces or symbols gets an inline error with a suggestion, like {{customer_name}}. Each variable is one line that opens to set its name, type (text, long text, options or number), default, hint and whether it can be left empty, and renaming rewrites every place it appears. A live preview fills in sample values, and a prompt can switch the model or override the system prompt.

Search, then press Enter to use the top match. Use opens a form with only the variables the prompt uses, starting at the first one without a default. Enter moves to the next field and submits from the last, and the preview fills in, in each variable’s color, as you type. Type / in Prompt Input to get the same flow from the composer, through Prompt Input’s own menu.

Saving keeps the old text as a version, and History in the editor shows what changed since each one, line by line, with Restore. Duplicate, move, favorite and delete all update at once, and delete offers Undo for five seconds. Import and export use plain JSON. Shared prompts carry their author, and the ones you can’t edit open view only.

  1. HextaUI Pro'yu alın

    Tek bir ödeme, gelecekte eklenecekler dahil tüm blokların kilidini açar. Fiyatları görün.

  2. Pro registry'yi components.json dosyasına ekleyin

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  3. Token'ınızı ekleyin

    Hesap sayfanızda bir token oluşturun ve .env.local dosyasına HEXTAUI_PRO_TOKEN olarak ekleyin.

  4. Bloğu ekleyin

    pnpm dlx shadcn@latest add @hextaui-pro/prompt-library

Store prompts in your database

Pass the prompts and folders you load, and return the saved prompt from onSave. Favorites, moves and deletes update at once and roll back with a message if your API throws. A failed save keeps the editor open with the draft as typed.

"use client"

import * as React from "react"

import {
  PromptLibrary,
  PromptLibrarySkeleton,
  type Prompt,
  type PromptDraft,
  type PromptFolder,
} from "@/components/blocks/prompt-library/prompt-library"

async function request<T>(input: string, init?: RequestInit) {
  const response = await fetch(input, {
    ...init,
    headers: { "content-type": "application/json", ...init?.headers },
  })
  if (!response.ok) {
    const body = (await response.json().catch(() => ({}))) as { error?: string }
    throw new Error(body.error ?? "Something went wrong.")
  }
  return (response.status === 204 ? null : await response.json()) as T
}

export function PromptsPage({ onInsert }: { onInsert: (text: string) => void }) {
  const [prompts, setPrompts] = React.useState<Prompt[] | null>(null)
  const [folders, setFolders] = React.useState<PromptFolder[]>([])

  React.useEffect(() => {
    request<{ prompts: Prompt[]; folders: PromptFolder[] }>("/api/prompts").then((data) => {
      setPrompts(data.prompts)
      setFolders(data.folders)
    })
  }, [])

  const replace = (saved: Prompt) =>
    setPrompts((current) => {
      const list = current ?? []
      return list.some((prompt) => prompt.id === saved.id)
        ? list.map((prompt) => (prompt.id === saved.id ? saved : prompt))
        : [saved, ...list]
    })

  const save = async (draft: PromptDraft) => {
    const saved = await request<Prompt>(draft.id ? `/api/prompts/${draft.id}` : "/api/prompts", {
      method: draft.id ? "PUT" : "POST",
      body: JSON.stringify(draft),
    })
    replace(saved)
    return saved
  }

  const patch = async (prompt: Prompt, body: Partial<Prompt>) =>
    replace(await request<Prompt>(`/api/prompts/${prompt.id}`, { method: "PATCH", body: JSON.stringify(body) }))

  if (!prompts) return <PromptLibrarySkeleton />

  return (
    <PromptLibrary
      className="h-svh"
      prompts={prompts}
      folders={folders}
      onSave={save}
      onDelete={async (prompt) => {
        await request(`/api/prompts/${prompt.id}`, { method: "DELETE" })
        setPrompts((current) => current?.filter((item) => item.id !== prompt.id) ?? null)
      }}
      onMove={(prompt, folder) => patch(prompt, { folder })}
      onFavorite={(prompt, favorite) => patch(prompt, { favorite })}
      onUse={(prompt, { text }) => {
        onInsert(text)
        void patch(prompt, { lastUsedAt: new Date().toISOString() })
      }}
    />
  )
}

Type / in Prompt Input

Put PromptLibraryMenu inside PromptInput and saved prompts join your slash commands in Prompt Input’s own menu. A prompt with variables asks for them first, then lands at the caret, ready to send. Use onUse to switch to the prompt’s model.

"use client"

import { IconTrash } from "@tabler/icons-react"

import {
  PromptInput,
  PromptInputActions,
  PromptInputBody,
  PromptInputSubmit,
  PromptInputTextarea,
  type PromptMessage,
} from "../prompt-input/prompt-input"
import type { PromptMenuItem } from "../prompt-input/prompt-menu"
import type { Prompt } from "@/components/blocks/prompt-library/prompt-library"
import { PromptLibraryMenu } from "@/components/blocks/prompt-library/prompt-library-menu"

const commands: PromptMenuItem[] = [
  { value: "clear", label: "clear", description: "Start a new chat", icon: <IconTrash />, insert: "" },
]

export function Composer({
  prompts,
  onSend,
  onClear,
  onModelChange,
}: {
  prompts: Prompt[]
  onSend: (message: PromptMessage) => void
  onClear: () => void
  onModelChange: (model: string) => void
}) {
  return (
    <PromptInput onSubmit={onSend}>
      <PromptInputBody>
        <PromptInputTextarea placeholder="Ask anything. Type / for saved prompts" />
        <PromptInputActions>
          <PromptInputSubmit />
        </PromptInputActions>
      </PromptInputBody>
      <PromptLibraryMenu
        prompts={prompts}
        items={commands}
        onSelect={(item) => {
          if (item.value === "clear") onClear()
        }}
        onUse={(prompt) => {
          if (prompt.model) onModelChange(prompt.model)
        }}
      />
    </PromptInput>
  )
}

A team library with permissions

Mark team prompts shared and set canEdit per prompt. Prompts you can’t edit open view only, with Duplicate to edit instead of Save, and readOnly turns off every change for viewers.

"use client"

import type { Prompt, PromptDraft, PromptFolder } from "@/components/blocks/prompt-library/prompt-library"
import { PromptLibrary } from "@/components/blocks/prompt-library/prompt-library"

type Role = "owner" | "editor" | "viewer"

type TeamPrompt = Prompt & { ownerId: string; teamId: string | null }

function withPermissions(prompts: TeamPrompt[], userId: string, role: Role): Prompt[] {
  return prompts.map((prompt) => ({
    ...prompt,
    shared: prompt.teamId !== null,
    canEdit: prompt.ownerId === userId || (prompt.teamId !== null && role !== "viewer"),
  }))
}

export function TeamPrompts({
  prompts,
  folders,
  userId,
  role,
  onSave,
  onDelete,
  onUse,
}: {
  prompts: TeamPrompt[]
  folders: PromptFolder[]
  userId: string
  role: Role
  onSave: (draft: PromptDraft) => Promise<Prompt>
  onDelete: (prompt: Prompt) => Promise<void>
  onUse: (text: string) => void
}) {
  return (
    <PromptLibrary
      prompts={withPermissions(prompts, userId, role)}
      folders={folders}
      readOnly={role === "viewer"}
      onSave={onSave}
      onDelete={onDelete}
      onUse={(_, { text }) => onUse(text)}
    />
  )
}

Yapı

Dıştan içe doğru birleştirdiğiniz parçalar.

ParçaAçıklama
PromptLibraryFolders and tags in HextaUI’s Sidebar (a sheet on phones), search, the prompt list, the editor, history, the Use form and import and export.
PromptLibraryMenuAdds saved prompts to Prompt Input’s / menu and inserts them filled in.
UsePromptDialogThe fill-in form on its own, for using a prompt from anywhere.
PromptPreviewA prompt with values filled in, each in its variable’s color.
PromptLibrarySkeletonA loading placeholder shaped like the library.
usePromptVariablesReads a prompt’s variables, unknown and invalid names, and returns fill().

PromptLibrary

Also accepts every div prop.

PropTürVarsayılan
prompts{ id, title, body, variables?, tags?, folder?, model?, system?, favorite?, shared?, canEdit?, author?, updatedAt?, lastUsedAt?, versions? }.
Prompt[]–
folders{ id, name, shared? }. Shown in the sidebar and the Move to menu.
PromptFolder[]–
onSaveCreate when draft.id is missing, update when it’s set. Also used for duplicates, starters and restores. Throw to keep the editor open with your message.
(draft: PromptDraft) => Promise<Prompt | void>–
onDeleteRuns after the undo window. Throw and the prompt comes back.
(prompt) => void | Promise<void>–
onUseCalled with the filled-in text. Put it in your composer.
(prompt, { text, values }) => void–
onMoveAdds Move to. The card moves at once and goes back if this throws.
(prompt, folder: string | null) => void | Promise<void>–
onFavoriteAdds the star. It fills at once and goes back if this throws.
(prompt, favorite: boolean) => void | Promise<void>–
onImportSaves an imported file in one call. Without it, each prompt goes through onSave.
(drafts: PromptDraft[]) => void | Promise<void>–
readOnlyTurns off creating, editing, moving, deleting and importing. Use and export still work.
booleanfalse
modelsAdds a Model picker to the editor.
{ value, label }[]–
startersThe three prompts offered when the library is empty.
PromptDraft[]–
footerShown under the list, like a composer. Hidden while editing.
ReactNode–
undoTimeoutHow long Undo is offered after deleting, in ms. 0 deletes at once.
number5000
nowFixes the time used for “used 2h ago”, for tests and screenshots.
Date–

PromptLibraryMenu

Render inside PromptInput.

PropTürVarsayılan
promptsThe prompts to offer after /.
Prompt[]–
itemsYour own slash commands, listed before the prompts.
PromptMenuItem[]–
onSelectCalled when one of your own commands is picked.
(item) => void–
onUseCalled after a prompt is inserted, to record use or switch models.
(prompt, { text, values }) => void–

PromptVariable

One entry in a prompt’s variables.

PropTürVarsayılan
nameLetters, numbers and _, not starting with a number.
string–
typeThe field shown in the Use form.
"text" | "longText" | "select" | "number""text"
defaultUsed when the field is left empty. Options default to the first.
string–
optionsThe choices for select.
string[]–
descriptionA hint under the field.
string–
optionalLets the form submit with the field empty.
booleanfalse

usePromptVariables

Returns { names, variables, unknown, unused, issues, tokens, fill }.

PropTürVarsayılan
bodyThe prompt text.
string–
definitionsSaved definitions. Names in the body without one count as text.
PromptVariable[]–
TuşAction
EnterIn search, uses the top match. The match is highlighted in the list.
{{In the editor, suggests variables. ↑ and ↓ move, Enter or Tab picks, Escape closes.
EnterIn the Use form, moves to the next field, and inserts from the last one. Shift+Enter adds a line in long text.
⌘EnterIn the Use form, inserts from any field. Ctrl+Enter on Windows and Linux.
⌘SSaves the prompt in the editor.
/In Prompt Input with PromptLibraryMenu, lists saved prompts.
EscapeClears the search. In the editor, a variable’s name goes back to what it was.
⌘BShows or hides the folders and tags sidebar. Ctrl+B on Windows and Linux.
  • Each row is a list item whose title is a button that uses the prompt, described by its text, owner and last use. Star and actions sit beside it.
  • Variable colors always come with the variable’s name, so nothing depends on color alone, and they turn into underlines in Windows high contrast mode.
  • The editor is a combobox while suggesting variables, with the active suggestion announced. Invalid names are listed under the field in a polite live region.
  • Each variable row in the editor is a button with aria-expanded that opens its settings. Rows with an error open on their own.
  • Saving, using, favoriting, moving, deleting, restoring and importing are announced. Failures show as alerts or toasts with what happened.
  • Folders and tags use HextaUI’s Sidebar, with the open filter marked as the current page and counts read out as “3 prompts”. On phones it opens as a sheet. Picking a filter while a draft is unsaved asks before leaving it.
  • Text fields are 16px on touch screens so iOS doesn’t zoom, and touch targets grow to 44px. With reduced motion, nothing slides.

Şunlarla geliştirildi

Prompt Library bloğunun yapıldığı ücretsiz HextaUI bileşenleri. Her biri tek başına yüklenir.

Kod

12 dosya, components/blocks/prompt-library konumuna eklendi.