AI Suite #

A complete set of UI patterns for building AI-powered features. Drop-in markup for chat interfaces, image generation, content writing, prompt management, and usage analytics.

Frontend only

Admindek's AI Suite ships frontend markup and styles only — wire up your own backend (OpenAI, Anthropic, self-hosted, mock) by replacing the placeholder fetch calls. The page-level JavaScript is structured so you can plug in any provider with minimal changes.

Page catalog #

PageFilePurpose
AI Chatapplication/ai-chat.htmlConversation interface with message bubbles
AI Image Generatorapplication/ai-image.htmlPrompt → image with results gallery
AI Content Writerapplication/ai-writer.htmlLong-form generation with templates
AI Dashboardapplication/ai-dashboard.htmlUsage metrics and cost tracking
Prompt Libraryapplication/ai-prompts.htmlCategorized prompt templates

AI Chat #

A conversation interface modeled on ChatGPT and Claude — sidebar of past conversations, message thread, input area.

File: src/html/application/ai-chat.html

Features #

  • Conversation sidebar — list of past chats grouped by Today / Yesterday / Last 7 days / Older
  • Search for past conversations
  • New chat button
  • Message thread with user vs. assistant bubbles
  • Code blocks with copy button (Prism.js syntax highlighting)
  • Markdown rendering in assistant responses
  • Streaming response support — append-to-bubble pattern ready
  • Regenerate / edit controls on user messages
  • Stop generation button while streaming
  • Mobile: sidebar collapses, hamburger toggle

Markup snippet #

<div class="ai-chat-wrapper">
  <aside class="ai-chat-sidebar" id="ai-chat-sidebar">
    <button class="btn btn-primary w-100" id="ai-new-chat">
      <i class="ti ti-plus"></i> New Chat
    </button>
 
    <div class="input-group input-group-sm">
      <span class="input-group-text"><i class="ti ti-search"></i></span>
      <input type="text" class="form-control" placeholder="Search conversations…" />
    </div>
 
    <div class="flex-grow-1 overflow-auto">
      <small class="text-muted text-uppercase">Today</small>
      <ul class="ai-conversation-list">
        <li class="ai-conversation-item active">
          <i class="ti ti-message"></i>
          <div>
            <div class="text-truncate">REST API with Express.js</div>
            <small class="text-muted">2 min ago</small>
          </div>
        </li>
      </ul>
    </div>
  </aside>
 
  <main class="ai-chat-main">
    <div class="ai-chat-messages" id="ai-messages">
      <div class="ai-message ai-message-user">
        <div class="ai-message-avatar">JD</div>
        <div class="ai-message-bubble">How do I set up an Express server?</div>
      </div>
      <div class="ai-message ai-message-assistant">
        <div class="ai-message-avatar"><i class="ti ti-sparkles"></i></div>
        <div class="ai-message-bubble">
          <p>Here's a minimal Express setup:</p>
          <pre><code class="language-javascript">const express = require('express')
const app = express()
app.listen(3000)</code></pre>
        </div>
      </div>
    </div>
 
    <div class="ai-chat-input">
      <textarea placeholder="Send a message…" rows="1"></textarea>
      <button class="btn btn-primary"><i class="ti ti-send"></i></button>
    </div>
  </main>
</div>

Wiring up a backend #

Replace the demo handler in ai-chat.js with your fetch / SSE call:

async function sendMessage(text) {
  appendMessage('user', text)
 
  const response = await fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message: text, conversationId: currentId }),
  })
 
  // For streaming, use ReadableStream
  const reader = response.body.getReader()
  const decoder = new TextDecoder()
  const bubble = appendMessage('assistant', '')
 
  while (true) {
    const { value, done } = await reader.read()
    if (done) break
    bubble.textContent += decoder.decode(value)
  }
}

AI Image Generator #

Prompt-based image generation with a results grid and history.

File: src/html/application/ai-image.html

Features #

  • Prompt input with character counter and prompt-enhancement suggestions
  • Style presets: Photorealistic, Anime, Sketch, Watercolor, 3D Render, Pixel Art
  • Aspect ratio selector: 1:1, 16:9, 9:16, 4:3, 3:2
  • Quality / step controls
  • Negative prompt input (advanced)
  • Results gallery with hover actions: Download, Copy URL, Variations, Use as base
  • History panel of past generations
  • Lightbox preview (GLightbox)

Layout #

<div class="ai-image-wrapper row g-3">
  <aside class="col-lg-4 ai-image-controls">
    <div class="card">
      <div class="card-body">
        <label class="form-label">Prompt</label>
        <textarea class="form-control" rows="4" placeholder="A serene lake at sunset…"></textarea>
 
        <label class="form-label mt-3">Style</label>
        <div class="ai-style-presets">
          <button class="ai-style-preset active">Photorealistic</button>
          <button class="ai-style-preset">Anime</button>
          <button class="ai-style-preset">3D Render</button>
        </div>
 
        <label class="form-label mt-3">Aspect ratio</label>
        <div class="btn-group w-100">
          <input type="radio" name="ratio" id="r-1-1" checked /><label for="r-1-1" class="btn btn-outline-secondary">1:1</label>
          <input type="radio" name="ratio" id="r-16-9" /><label for="r-16-9" class="btn btn-outline-secondary">16:9</label>
        </div>
 
        <button class="btn btn-primary w-100 mt-3">
          <i class="ti ti-sparkles"></i> Generate
        </button>
      </div>
    </div>
  </aside>
 
  <main class="col-lg-8 ai-image-results">
    <div class="row g-2">
      <div class="col-6">
        <a href="/generated/1.jpg" class="glightbox ai-image-result">
          <img src="/generated/1.jpg" alt="" />
          <div class="ai-image-actions">
            <button title="Download"><i class="ti ti-download"></i></button>
            <button title="Variations"><i class="ti ti-refresh"></i></button>
          </div>
        </a>
      </div>
    </div>
  </main>
</div>

AI Content Writer #

Long-form text generation with template prompts and inline editing.

File: src/html/application/ai-writer.html

Features #

  • Template gallery — Blog post, Email, Product description, Social caption, Landing page, Code docs
  • Template form with structured inputs (e.g., for Blog: topic, tone, target length, audience)
  • Quill rich text editor for the generated output
  • Inline regenerate — select text and click "Regenerate" to rewrite just that section
  • Tone adjuster — Friendly / Formal / Confident / Casual
  • Length adjuster — Shorter / Same / Longer
  • Export — Markdown, HTML, PDF, DOCX
<div class="ai-writer row g-3">
  <aside class="col-lg-4">
    <div class="card">
      <div class="card-body">
        <h6>Templates</h6>
        <ul class="list-unstyled ai-writer-templates">
          <li class="ai-template active"><i class="ti ti-article"></i> Blog post</li>
          <li class="ai-template"><i class="ti ti-mail"></i> Email</li>
          <li class="ai-template"><i class="ti ti-shopping-bag"></i> Product description</li>
          <li class="ai-template"><i class="ti ti-brand-twitter"></i> Social caption</li>
        </ul>
 
        <hr />
 
        <form class="ai-template-form">
          <label class="form-label">Topic</label>
          <input type="text" class="form-control" />
 
          <label class="form-label mt-3">Tone</label>
          <select class="form-select">
            <option>Friendly</option>
            <option>Formal</option>
            <option>Confident</option>
          </select>
 
          <label class="form-label mt-3">Length</label>
          <input type="range" class="form-range" min="300" max="2000" step="100" />
 
          <button class="btn btn-primary w-100 mt-3">Generate</button>
        </form>
      </div>
    </div>
  </aside>
 
  <main class="col-lg-8">
    <div class="card">
      <div class="card-header d-flex justify-content-between">
        <h6 class="mb-0">Editor</h6>
        <div class="btn-group">
          <button class="btn btn-sm btn-outline-secondary"><i class="ti ti-refresh"></i> Regenerate</button>
          <button class="btn btn-sm btn-outline-secondary"><i class="ti ti-download"></i> Export</button>
        </div>
      </div>
      <div class="card-body">
        <div id="ai-writer-editor"></div>
      </div>
    </div>
  </main>
</div>
import Quill from 'quill'
 
new Quill('#ai-writer-editor', {
  theme: 'snow',
  placeholder: 'Generated content will appear here…',
})

AI Dashboard #

Usage analytics for AI features — tokens consumed, cost, latency, model breakdown.

File: src/html/application/ai-dashboard.html

Widgets #

  • Total spend (this month) with month-over-month delta
  • Tokens consumed — input vs. output split
  • Active users — users who used AI features in the period
  • P95 latency per model
  • Cost by model — donut chart (GPT-4, GPT-3.5, Claude, etc.)
  • Tokens over time — area chart
  • Top users — table with consumption ranking
  • Error rate — line chart of failed completions
  • Recent generations — activity feed

Same widget primitives as the main dashboards — KPI cards, ApexCharts, DataTables.


Prompt Library #

Searchable, taggable prompt templates organized by use case.

File: src/html/application/ai-prompts.html

Features #

  • Category sidebar: Writing, Coding, Marketing, Research, Customer support, Translation, etc.
  • Search bar with full-text search across prompt titles and bodies
  • Tag filter — filter by tags (multi-select)
  • Sort: Most used, Recently added, Alphabetical, Rating
  • Prompt card with title, category, tags, copy button, "Use this prompt" button
  • Prompt detail modal — full prompt body, variables ({{topic}}, {{audience}}), example outputs
  • Variables form — when "Use this prompt" is clicked, fill in {{variables}} then send to AI Chat or Writer
  • Personal vs. team library — toggle between your saved prompts and your team's shared library
  • Add prompt — form to save your own prompts with title, body, category, tags, variables

Markup #

<div class="ai-prompts-wrapper row g-3">
  <aside class="col-lg-3">
    <div class="card">
      <div class="card-body">
        <h6>Categories</h6>
        <ul class="list-unstyled ai-prompt-categories">
          <li class="active">All <span class="badge bg-light text-dark ms-auto">128</span></li>
          <li>Writing <span class="badge">42</span></li>
          <li>Coding <span class="badge">31</span></li>
          <li>Marketing <span class="badge">19</span></li>
        </ul>
      </div>
    </div>
  </aside>
 
  <main class="col-lg-9">
    <div class="d-flex gap-2 mb-3">
      <input type="search" class="form-control" placeholder="Search prompts…" />
      <select class="form-select w-auto">
        <option>Most used</option>
        <option>Recent</option>
        <option>Alphabetical</option>
      </select>
    </div>
 
    <div class="row g-3">
      <div class="col-md-6 col-xl-4">
        <article class="ai-prompt-card">
          <div class="d-flex justify-content-between align-items-start mb-2">
            <span class="badge bg-info">Writing</span>
            <button class="btn btn-sm btn-link" title="Copy"><i class="ti ti-copy"></i></button>
          </div>
          <h6 class="ai-prompt-title">Blog post outline</h6>
          <p class="ai-prompt-preview text-muted small">
            Create a detailed outline for a blog post about {{topic}}…
          </p>
          <div class="ai-prompt-tags">
            <span class="badge">blog</span>
            <span class="badge">seo</span>
          </div>
          <button class="btn btn-primary btn-sm w-100 mt-3">Use this prompt</button>
        </article>
      </div>
    </div>
  </main>
</div>

Wiring it all together #

The AI Suite pages are designed to share state. A common pattern:

  1. User browses Prompt Library → clicks "Use this prompt"
  2. Variables form opens (modal or sidebar) → user fills in {{topic}}, {{audience}}
  3. User picks a destination: AI Chat or AI Content Writer
  4. The selected page loads with the prompt prefilled

You can implement this with a shared client-side store (localStorage, Zustand, or a vanilla JS event bus) — the markup is independent.


See also #