Project “Mimir”, icon: bird
AI Chatbot App, with OpenRouter integration & support for multiple models
Chat History + Search + Bookmarks
Attachments: Upload PDF or Images with chat
Ability to Chat with multiple models at once! (Upto 3)
Analytics to track costs, tokens, etc.
Ability to generate public sharable URL’s for chats
Prompt Library + Enhance Prompt
Beautiful Glassmorphic UI with light & dark modes
We’ll use OpenRouter (openai js sdk) to enable AI models
Microtasks: Generate title when first role=assistatn message comes, generate audio transcripts
All data must persist to Supabase DB except API Keys
Use Shadcn components, select components:
Standard:
Combobox: https://ui.shadcn.com/docs/components/combobox
Tabs: https://ui.shadcn.com/docs/components/tabs
Typography https://ui.shadcn.com/docs/components/typography
AI Message Input Box Inspiration:
https://21st.dev/preetsuthar17/ai-chat-input/default
https://21st.dev/kokonutd/v0-ai-chat/default
https://21st.dev/rafa-porto/ai-assistant-interface/default
https://ui.shadcn.com/docs/components/combobox < for all Model Selection drop-down
https://animate-ui.com/docs/radix/sidebar < Sidebar
Sonner/Toast: https://ui.shadcn.com/docs/components/sonner
Dialogue: https://animate-ui.com/docs/headless/dialog
Icon Button; https://animate-ui.com/docs/buttons/icon
New Chat Page Background: https://21st.dev/nubmaster4568/sign-in-flow-1/default
Effects:
Shimmering text: https://21st.dev/preetsuthar17/shining-text/default
Sine Border Effect: https://magicui.design/docs/components/shine-border
Ripple: https://magicui.design/docs/components/ripple
Stars Background: https://animate-ui.com/docs/backgrounds/stars
Primary Colour: #0bb2cd
Primary Gradient: #0bb2cd, #37d8b7, transparent, #b8f284, #00c6c8, transparent, #b8f284, #f9f871
Font: Source Sans 3 from Google Fonts
For , etc. - Fira Code
Icons from: https://lucide.dev/icons/
Animated Icons from: https://animate-ui.com/docs/icons
Common Layout:
Sticky header navigation:
Left side:
Logo (inside Ripple Effect)
Right Side:
New Chat button > New Chat View
Settings
Switch — for appearance - Dark/Light/System (default)
On left side of page, show sidebar:
“Hide sidebar” icon + button
New Chat < icon + button > New Chat View
Search Chats < icon + buttons, turns into a search input box
On click, open Command component: https://ui.shadcn.com/docs/components/command
Search functionality described later
Icon: calendar + Calendar View > Calendar View
Time-wise groups (ordered by recent first) list of Chat Cards, groups: Today, Yesterday, Last 7 days, 1 group for each month
Chat Cards:
Title (truncate after 50 characters), below it:
Metadata: icon: clock {updated at relative shorthand}, icon: message-entered {message_count}, ${xx.xx}
Infinite loading pattern: Initially, only load 50 items, as user scrolls to the end of list — load 50 more and so on
New Chat View (Default)
Empty state:
App logo
Most Popular/recently used prompts from prompt library x 3 cards
Error Banner: (if OpenRouter Keys are missing)
icon: warning You must generate and set OpenRouter API keys to start using the app. [Instructions](opens instructions component)
Layout bottom: floating Message Input Box (Described later in details)
When a new message is sent from Message Input, animate it to Chat Detail View:
Animate in columns (if multiple models were selected) - fade in move to top, show skeleton state for message inside
User message + Placeholder response card is animated in in all column(s)
Placeholder card starts to animate in text as LLM starts streaming responses
Once first message/response from LLM with role=assistant has arrived, we must generate a title (described later) — once title is available, animate it in the header
Transition to Chat Detail View
Chat Detail View:
Header:
Title: generated or {Local Date @ Localtime}
Metdata:
Created at (icon: clock) : {relative timestamp shorthand} · Updated at: {Relative timestamp shorthand}
Message count, icon: message-square
Models: {count int comma seperation}, icon: bot
Tokens: {count intl comma seperation), icon: text-cursor-input
Cost: ${0.0000}, on hover show tooltip:
Total Input Cost ${XX.XX}
Total Output Cost ${XX.XX}
Other Cost ${XX.XX} (micro asks)
Bookmark active/regular state, icon: bookmark
Share icon, icon: share-2 (Opens dialogue, described later)
Message History timeline —
Columns:
would have x columns, 1 for each model, max 3. Scroll all 3 columns together
Each column shows title of the {icon: bot} {model} + enable/disable switch + info icon (icon: info) — on hover, show tooltip with content
Model: {model}
On mobile/narrow devices — show only 1 column at a time, with next column slight appearing from left — allow swipe to change columns
Message Card:
Each message contained in a card, process markdown — new message content from LLM/AI/OpenRouter must be streamed in!
Before the message content — show any attachment icons — as described in Message Input Box
Inside the message card, after main content show action icons (right alined):
Copy (icon button), icon: copy
Regenerate (icon button), icon: refresh-cw
Opens dropdown:
Regenerate with {model), where model is same as the one that was used
Select Model: Opens combobox for Model Selection
On the left side, outside the card, show icons in circles to depict user/assistant:
User, icon: circle-user
Assistant, icon: bot
Below the message card (outside of it), show message metadata [right aligned]
Model: {slug}, icon: brain - only if message.role=assistant
[Created at]: icon: clock {relative timestamp shorthand}, icon: clock
Icon: case-sensitive {character count in message.content - into comma formatted}
Tokens: {count}, icon: text-cursor-input, on hover show full breakdown - only if message.role=assistant
Icon: braces - on hover, show tooltip “Click to view raw json response) - only if message.role=assistant, on click open Dialogue:
Response for Message ID: {id}
raw_response in
Actions: “Copy” “Close”
Have ample bottom-padding for timeline/columns so content does not hide behind floating message input
If user opens this page, auto scroll to the latest message
Allow setting a custom target message using url param message={id}, if set - scroll to that particular message
Websocket connection for:
Generating & Updating title (microtasks)
Transcription (microtasks)
Metadata updates in header
New Messages/responses streamed
Messages
Message Tokens Breakdown tooltip:
Input
- Text: {tokens} * ${price}/tok = ${cost}
- Text (Cached): {tokens} * ${price}/tok = ${cost}
- Audio: {tokens} * ${price}/tok = {cost}
- Audio (Cached): {tokens} * ${price}/tok} = ${cost}
- Image: {tokens} * ${price}/tok= {cost}
- Image (Cached): {tokens} * ${price}/tok = ${cost}
Output
- Text: {tokens} * {price} = ${cost}
- Reasoning: {tokens} * {price} = ${cost}
- Audio: {tokens} * {price} = ${cost}
- Image: {tokens} * {price} = ${cost}
Total {tokens} · ${total_cost}
Message Input Box:
For all states:
Once message is typed, save it every 5 seconds to localstorage so it is not lost of page is navigated away
Always keep send CTA enabled, even if message is empty — show error state if user tries to submit empty
Top Aligned
Left: Attachments icon (PDF and/or Images) — max 5
For each attachment show a badge above the message box with [icon {filename} X icon button], clicking on “X” removes attachment
PDF, icon: file-text
Image, icon: image
Show loading state for badge till uploading
Right: (both rounded buttons)
Record Icon buton, icon: mic
Send Icon button, animated icon: from library, animate on hover
Bottom aligned:
[New Chat Page only!] Model Selector with default selection, once 1 model is selected show a + icon in circle to allow adding up to 2 more (3 total)
As each model gets added, show pricing below the message box, left aligned
This only appears for Initial State on New Chat Page!!!
Prompt Library, icon: list-plus, on click open a dropdown:
Show 5 most recently used prompts, and More button > More opens Prompt Library side-panel sheet
If a Prompt is selected, the text is added at the spot cursor was at / or at the end of existing content in Message box
Below Message Inbox Box:
Left Aligned:
Cost, icon: receipt: for each model show {icon: brain} {input cost in usd} / {output cost in usd} · (as divider)
If model.is_expensive, show in red
Advanced Settings, icon: flask-conical > opens dialogue: For each selected LLM - allow changing model, temperature, max tokens
Check App Limits: If budget_max_24h is exceeded, show a warning dialogue with actions “Cancel”, “Dangerous Override”
Initial State - New Chat Page (3 lines fro text area for focus state)
https://21st.dev/preetsuthar17/ai-chat-input/default
Instead of “Think” — give model selector powered by OpenRouter
Allow selecting upto 3 models
Show pricing of selected models (Input/Output per token) below the Message Input Box (for each selected model) + warning if model.is_expensive = True
If thinking/reasoning model show “icon: brain {Reasoning Model}”
Mic icon — activates Recorder (described later) — enables speech to text, Only if transcription is enabled in settings
When typing, allow text area to expand in height to upto 5 lines
On Submit, submitting state
Submitting State:
Animate back to 3 lines, disable changes to input, text fades-off within
Show shimmer effect on text
On Failure:
Show a sonner with error message, allow click to copy for error, dismissible
Content remains inside message box, so user can retry — text area is enabled again
If Max 24h Budget is exceeded, show a dialogue:
Max 24h Budget Exceeded!
Your Budget {amount} Current Spending: {amount}
CTA:
Cancel: goes back to initial state with content intact
Dangerous Override: creates a chat anyway!
On Success - transition to Generating Response State
Generating Response State
On Success:
Animate columns appearing if > 1 model was selected (fade-in move up) — in each column following animation will happen
Animate message card appearing — stream content into them
Message box becomes empty (local storage is cleared off) — Send icon becomes “Stop” icon, clicking on it will stop stream responses
Once streaming is finished, switch to Initial State - Chat Detail Page
Behind the scenes, OpenAI will stream to backend. Backend must debounce and save to DB && stream to client as is in parallel!
Initial State — Chat Detail Page
Same as usual, however, no model selector
Mic icon / transcription still present
When typing, allow text area to expand in height upto 5 lines
On Submit, Submitting State > Generating Response / Failure States
Context Window Warning (above message box):
Among the model(s) selected — find the lowest context_length (chat_max_context_length)
Check the last message with role=assistants, and add input+output tokens = total_tokens
If total_tokens > 70%*chat_max_context_length = Start showing warning: You’re approaching context window limit for {model}, please summarise this & start a new chat
"summarise this” is linked, if clicked appends following in the message input box content “Please summarise all we spoke about so I can resume it elsewhere”
If total_tokens > 95%*chat_max_context_length = Disable Input Message box, show error above: “You’ve reached the context window limit for {model}”
Icon for both: message-square-warning
Recorder:
In Input Message box, if mic icon is clicked, animate to “Active Recorder State”:
Active Recorder State:
Message Input box shrinks in height to 1 line (other controls disappear)
Left Side: Pause icon button (icon: circle-pause), Stop Icon Button (icon: circle-stop), Timer 0:00 > 0:01
Waveform of audio being recorded via mic
At the end: Max duration countdown — 10:00
Pause icon — pauses recording, timers, and enables “Resume” icon (icon: circle-play) — which resumes timers and recordings
Stop Icon — starts the process of transcription > Recorder Processing State
If Max duration is arrived, recording automatically stops and begins processing > Recorder Processing State
Recorder Processing State > Success / Failure
The controls + waveform become grayscale and fade off
Below the recorder component we see shimmering text “Transcribing…”
We must process all transcription via Microtask setup! Populate thread_if if available!
If failed, ensure recording is kept as it is — active recorder state is restored with “paused” state
Failure message appears in a sonner, click to copy, needs to be dismissed
Retry Button
If successful:
The Recorder components fade off
Message input box expands again, controls re-enabled
Transcription fades-in (persisted to localstorage right away)
Transcription requires OpenAI or HuggingFace Key, with selected model
For OpenAI we use transcription API via their SDK:
For HuggingFace details here:
Search
When search icon is clicked open Command element Command (for Search) https://21st.dev/shadcn/command/dense
As user types (debounce, etc.) — and search across chats — fuzz, case-insensitive, sub-string, matching algo that forgives typo’s
Show list of chart cards appear below , ordered by recent first
Search in: title, message content, date, cost, model, etc.
Allow using filters like:
before:DD-MM-YYYY
after:DD-MM-YYYY
title_has: string
On click of a card — open that Chat detail view. On esc, close command
Also trigger, with keyboard shortcuts:
Ctrl+K on Windows
Cmd+K on Mac
Settings Page:
All data must be read from & persisted to DB
Each card must have “Save” button — do NOT autosave/auto-update — user must explicitly click save
Card: API Keys
OpenRouter API Key:
Password field, is not stored in DB but in localstorage only!!!
Instructions link that opens dialogue with instructions to Sign Up + Generate keys
OpenAI API Key (same as OpenRouter API Key - password + instructions)
Password field, is not stored in DB but in localstorage only!!!
Instructions link that opens dialogue with instructions to Sign Up + Generate keys
HuggingFace API Key
Password field, is not stored in DB but in localstorage only!!!
Instructions link that opens dialogue with instructions to Sign Up + Generate keys
Note: API Keys are like passwords + wallet (because they contain money). For now, we will NOT save them to database. You can override this but at your own risk!
Button: Dangerously Save to Database > saves API Keys to database, givens a warning dialogue where user must enter “I understand” before proceeding
Card: System Defaults
Note: Chaining this will only affect new chats/messages
Chats Using: OpenRouter/OpenAI (initially OpenRouter, OpenAI to be supported later) - readonly
System Prompt: text area
Default Temperature: 0.5
Min 0, max 1.5
Default Model:
4.1-mini > must be a selection from OpenRouter
Warn user if they selected a model where is_expensive = True
Max Output Tokens: 0 for no limit
Card: Utility Settings
Transcriptions
Enable/Disable switch < don’t allow enabling till OpenAI or HuggingFace key is present, error “Please enter OpenAI or HuggingFace API Keys”
Provider: the corresponding key must be present above, else show error sonner when selected (and revert)
HuggingFace (Free but unreliable)
OpenAI (Best but Paid)
Transcription Model (based on provider selected)
For HuggingFace
tiny
base
small
medium
large
large-v2
large-v3 (Default)
For OpenAI — ensure only following models are enlisted/allowed to be selected for transcription for OpenAI!
Whisper (whisper-1),
Cost:
Input: Audio -, Text: N/A
Output: Text $.006/MTok
Max Duration: 10mins
Max File Size: 25MB
GPT-4o Transcribe (gpt-4o-transcribe)
Cost:
Input: Audio $6/Mtok, Text $2.50/Mtok
Output: Text: $10/Mtok
Context Window: 16,000
Max Output Tokens: 2,000
GPT-4o mini Transcribe (gpt-4o-mini-transcribe) [Default if OpenAI is selected]
Cost:
Input: Audio $3/Mtok, Text $1.25/Mtok
Output: Text: $5/Mtok
Context Window: 16,000
Max Output Tokens: 2,000
For Audio use icon: headphones, for text use: clipboard-type
Divider
Model for Generating Title: {Combobox - model selection), default anthropic/claude-3-haiku
Card: Cost Control
Affordable Input Token Price: Default 0.000002, allow editing
Affordable Output Token Price: Default 0.000004, allow editing
If either of these costs/prices exceed for any selected model — it is deemed “expensive” or model.is_expensive = True
Max 24h Budget: $0.00
Explanation below field 0 = unlimited. You can set this limit to ensure you do not overspend
Usage (last 24h) - calculated using Total Cost of Messages + Microtasks in last 24hrs
Export Data
Export & Download Button: initiates a zip with all data (SQL db dump, file attachments, etc.) - initiates download
Microtasks:
Generating title — when first response is received from LLM with role=assistant trigger generating title via microtasks
Fallback - if for some reason it fails, attempt regenerating every time Thread Detail View is opened
Generating transcripts - in message input box as described
Preserve the audio till transcript is successful, on success it can be deleted
Background Chat Completed:
If a user was having a chat, and app was in middle of streaming responses — but user navigates away — trigger a sonner once streaming is finished:
“Completed: {Title}” > click to open Thread View
Auto fades/disimisses in 5 seconds
===
Database
app_settings (only 1 row allowed)
use_keys_from: localstorage (default), database
dangeours_openai_api_key < only in DB, for localstorage use regular string/name
dangeours_openrouter_api_key
dangeours_huggingface_api_key
system_prompt: text, required
Default: You are a helpful assistant who’s always eager to help & be proactive. Keep language crisp and to the point. Use bullets & sub-sections whenever helpful. Avoid overusing emojis.
default_temperature=0.5
default_model=
max_output_tokens=0
chat_using: openrouter (default), openai
utility_transcription_enabled: Bool
utility_transcription_provider: openai/huggingface
utility_transcription_model: model slug
utility_title_model: anthropic/claude-3-haiku
budget_input_token_cost: 0.000002
budget_output_token_cost: 0.000004
budget_max_24h: 0
Constraints: Only 1 row must exist in this table!
table: threads
id
title (nullable, max 120 chars)
created_at
updated_at
Index: created_at, updated_at, title
Calculated: For a thread, following “fields” or properties are calculated, summed from messages associated with the thread
total_tokens
total_input_tokens
cached_tokens
cached_tokens_percentage (of total_input tokens)
total_output_tokens
total_cost
total_input_cost
total_output_cost
other_costs (from microtasks - title generation & transcription of audio)
table: thread_errors < Capture all thread associated errors here
id
thread_id
error_code
error_message
raised_by
created_at
Index: thread_id, created_at
table: messages (use id, created_at to sort always!)
id
created_at
thread_id=FK
column: 0, 1 ,2
role=system, user, assistant, tool
content={content}
tool_call={tool_call}
model=
provider=openrouter/openai
external_id (from OpenAI/OpenRouter)
raw_output JSONB - store LLM response as it i
Cost Fields: To be stamped with message, at the time of creation of message when role=assistant, data available via OpenRouter. All prices in per token, may go upto 12 decimal places!
input_token_price (text)
input_cached_token_price (text)
input_audio_token_price
input_cached_audio_token_price
input_image_token_price
input_cached_image_token_price
output_token_price
output_audio_token_price
output_image_token_price
output_reasoning_token_price
Usage Fields: Available with EVERY OpenRouter Response — must be persisted with every message where role=assistant!
input_tokens (text)
input_cached_tokens
input_audio_tokens
input_cached_audio_tokens
input_image_tokens
input_cached_image_tokens
output_tokens
output_audio_tokens
output_image_tokens
output_reasoning_tokens
Index: thread_id, created_at, updated_at, role, content, model
Calculated fields/props:
If Caching Enabled/Used: If (input_cached_token_price || input_cached_audio_token_price || input_cached_image_token_price) and (input_cached_tokens || input_cached_audio_tokens || input_cached_image_tokens)
Total Cached Cost:
input_cached_cost (text) = input_cached_token_price * input_cached_tokens
Input_cached_audio_cost = input_cached_audio_token_price * input_cached_audio_tokens
input_cached_image_cost = input_cached_image_token_price * input_cached_image_tokens
total_cached_cost = input_cached_cost + Input_cached_audio_cost + input_cached_image_cost
NonCached Cost: < If Caching is not used or enabled, directly use this)
input_cost = input_tokens * input_token_price
input_audio_cost = input_audio_tokens * input_audio_token_price
input_image_cost = input_image_tokens * output_image_token_price
noncahced_input_cost = input_cost + input_audio_cost + input_image_cost
total_input_cost = noncahced_input_cost + total_cached_cost
Total Output Cost:
output_cost = output_tokens * output_token_price
output_reasoning_cost = output_reasoning_tokens * output_reasoning_token_price
output_audio_tokens = output_audio_tokens * output_audio_token_price
output_image_tokens = output_image_tokens * output_image_token_price
total_output_cost = output_cost + output_reasoning_cost + output_audio_tokens + output_image_tokens
Total Cost
total_cost = total_input_cost + total_output_cost + other_cost
table: microtasks
task_type=transcribe, generate_title
status= pending, running, failed, done (default pending)
model= < picked from
temperature= defualt 0.5
created_at
updated_at
started_at
completed_at
input_data (JSONB, whatever we were sending)
output_data (JSONB, whatever model/LLM returned)
thread_id nullable
retry_count = default 0
error_code
error_message
Cost Fields + Usage Fields like messages table
Calculated fields like messages table
index: status, thread_id, task_type, created_at, completed_at, started_at, model
Changes:
Settings Page, 2nd card:
Personal Settings
Name:
Profession/Designation
System Health Page:
Design
Animated Icons: https://animate-ui.com/docs/icons
Message Input Box - send icon button use ‘send-horizontal’, animate on hover
icon: loader
CSS Classes (Reusable)
Brand Mesh Gradient - change to RGBA, animate position, spread, intensity, placement on hover or active
--_gradient-blend-mode: normal;
--_gradient-blur: 140px;
background: radial-gradient(at 7% 41%, #0AB2CC 0px, transparent 50%), radial-gradient(at 18% 9%, #00C4C7 0px, transparent 50%), radial-gradient(at 83.5% 76.5149111675127%, #36D9B8 0px, transparent 50%), radial-gradient(at 47.083333333333336% 59.129124365482234%, #79E89E 0px, transparent 50%), radial-gradient(at 87.83333333333333% 29.05298223350254%, #B8F285 0px, transparent 50%), radial-gradient(at 17.666666666666668% 86.15958121827411%, #32a08d 0px, transparent 50%) #fff;;
mix-blend-mode: var(--_gradient-blend-mode);
.frosted-backdrop {
backdrop-filter: blur(var(--_gradient-blur)) contrast(100%) brightness(100%);
-webkit-backdrop-filter: blur(var(--_gradient-blur)) contrast(100%) brightness(100%);
}
Glass 0
.glass-card {
width: 240px;
height: 360px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.5),
inset 0 -1px 0 rgba(255, 255, 255, 0.1),
inset 0 0 12px 6px rgba(255, 255, 255, 0.6);
position: relative;
overflow: hidden;
}
.glass-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.8),
transparent
);
}
.glass-card::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 100%;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.8),
transparent,
rgba(255, 255, 255, 0.3)
);
}
Glass 1
.glass-card {
width: 240px;
height: 360px;
background: rgba(255, 255, 255, 0.14);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.5),
inset 0 -1px 0 rgba(255, 255, 255, 0.1),
inset 0 0 22px 11px rgba(255, 255, 255, 1.1);
position: relative;
overflow: hidden;
}
.glass-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.8),
transparent
);
}
.glass-card::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 100%;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.8),
transparent,
rgba(255, 255, 255, 0.3)
);
}
Glass 2
.glass-card {
width: 240px;
height: 360px;
background: rgba(255, 255, 255, 0.22);
backdrop-filter: blur(29px);
-webkit-backdrop-filter: blur(29px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.5),
inset 0 -1px 0 rgba(255, 255, 255, 0.1),
inset 0 0 34px 17px rgba(255, 255, 255, 1.7);
position: relative;
overflow: hidden;
}
.glass-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.8),
transparent
);
}
.glass-card::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 100%;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.8),
transparent,
rgba(255, 255, 255, 0.3)
);
}
Fixes
- Clcikcing on search icon loads command but also throws an error:
"
DialogContent
requires a DialogTitle
for the component to be accessible for screen reader users. If you want to hide the DialogTitle
, you can wrap it with our VisuallyHidden component. For more information, see https://radix-ui.com/primitives/docs/components/dialog"
- Message box - not as per spec. Advacned Settings outside message box, below it right aligned. Models and pricing inside message box 2nd line
- Mesagebox send icon button animated background and + New CHat button background - initial state - use timings 5s to change between transitions, add easy ease - 2.5s when hovere. ADd text shadow and shadow for icon outline sso it is legible - or change line and ext colour to black?
- Logo icon center of page and in logo in nav — remove the horrendous zoom /resizing animation on hover!
Install and use this:
npx shadcn@latest add "https://animate-ui.com/r/icon.json"
npx shadcn@latest add "https://animate-ui.com/r/loader-pinwheel-icon.json"
loader-pinwheel
animate on hover
- Remove the inner shadow treatments from sidebar - want just pure blurring
- Sidebar, remove "+ New Chat", make "icon + Search firs" and Calendar opens Calendar but the width should fit the Calendar componet
Also remove "Start a new conversation" change the message icon thickness to 1.25px
- Move "Finish Setup to Start using Mimir. Configure in Settings" to above the icon
- Put loco icon + Finish Setup to Start using Mimir. Configure in Settings in same horizontal line, below it implement particles https://21st.dev/aceternity/sparkles/default
- Move Settings as last fixed item in Sidebar towards the bottom, put Appearance Settings above it - remove from header nav
- Move logo+name inside the Sidebar as first item
- Move open close sidebar, at top left of the page and remove it from header, remove the static nav header from dashboard
—
Duplicate
—
Context:
We've had a detailed conversation focusing on enhancing the Mimir AI Chatbot's user interface and experience.
Initially, we established design principles emphasizing a production-ready, beautiful aesthetic using existing libraries like Tailwind CSS, shadcn/ui, React hooks, and Lucide React.
The subsequent discussions involved numerous specific UI/UX modifications across the application, including:
Navigation and Sidebar: Redesigning the header and sidebar layout, moving elements like the logo, settings, and theme toggle, and implementing dynamic sidebar collapse/expand functionality. This also included refining the visual "glassmorphism" effects (glass-0, glass-1) and updating icon styles.
Chat Interface: Overhauling the new chat page layout, adjusting the message input box, and integrating advanced settings (model selection, temperature, max tokens) within or around it.
Animations and Visuals: A significant focus was placed on incorporating animated icons (from animate-ui.com) for elements like the bot logo and send button, along with custom CSS keyframe animations for mesh gradients and glow effects on interactive elements.
New Features: Implementing a calendar view in the sidebar that filters chats by date and displays chat activity with visual indicators. A comprehensive search command was also added, accessible via a keyboard shortcut, allowing fuzzy and filtered searches across chat data.
Settings Page: Streamlining the settings page by removing certain sections and consolidating others, such as API key management, budget controls, transcription settings, and data export options.
Accessibility and Refinements: Addressing accessibility concerns, such as ensuring proper DialogTitle for the search command, and making various minor adjustments to spacing, sizing, and visual consistency throughout the application.
Particles Background: Integrating a dynamic particles background effect on the new chat view for a more engaging visual experience.
The conversation has progressed through several iterations of these changes, with each step building upon the previous one to refine the application's look and feel.
Changes:
- Remove the glass treatment from around the opne sidebar icon
- Sidebar: Move "Mihir" logo to next line, after close sidebar icon - make it clickable so it takes us to dashboard
- Remove the redundant "Appearance" and give "moon/sun" label "Dark/Light/System" — give, both Settings, and theme icon same treatment
- Remove the glass treatment from sidebar, message, advanced settings popup, input box — instead we wll' use the following glass treatment:
/* Glassmorphism card effect */
.card {
backdrop-filter: blur(16px) saturate(84%);
-webkit-backdrop-filter: blur(16px) saturate(84%);
background-color: rgba(17, 59, 57, 0.22);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.125);
}
- Send icon button in Message box - change icon line to dark, and change animation speed to take 5-7s
- The particle are scatteredon the entire background right now, make sure they are concentrated around the icon in center of page and fade off radially as we go more distant
- Model Selection badge - on hover show a preview card: https://animate-ui.com/docs/base/preview-card With Model details available from OpenRouter/OpenAI
- In center of the page currently icon + Hello there! Let's chat? are stacked - put them in the same horizontal line like icon + greeting
===
ontext:
We've had a detailed conversation focusing on enhancing the Mimir AI Chatbot's user interface and experience.
Initially, we established design principles emphasizing a production-ready, beautiful aesthetic using existing libraries like Tailwind CSS, shadcn/ui, React hooks, and Lucide React.
The subsequent discussions involved numerous specific UI/UX modifications across the application, including:
Navigation and Sidebar: Redesigning the header and sidebar layout, moving elements like the logo, settings, and theme toggle, and implementing dynamic sidebar collapse/expand functionality. This also included refining the visual "glassmorphism" effects (glass-0, glass-1) and updating icon styles.
Chat Interface: Overhauling the new chat page layout, adjusting the message input box, and integrating advanced settings (model selection, temperature, max tokens) within or around it.
Animations and Visuals: A significant focus was placed on incorporating animated icons (from animate-ui.com) for elements like the bot logo and send button, along with custom CSS keyframe animations for mesh gradients and glow effects on interactive elements.
New Features: Implementing a calendar view in the sidebar that filters chats by date and displays chat activity with visual indicators. A comprehensive search command was also added, accessible via a keyboard shortcut, allowing fuzzy and filtered searches across chat data.
Settings Page: Streamlining the settings page by removing certain sections and consolidating others, such as API key management, budget controls, transcription settings, and data export options.
Accessibility and Refinements: Addressing accessibility concerns, such as ensuring proper DialogTitle for the search command, and making various minor adjustments to spacing, sizing, and visual consistency throughout the application.
Particles Background: Integrating a dynamic particles background effect on the new chat view for a more engaging visual experience.
The conversation has progressed through several iterations of these changes, with each step building upon the previous one to refine the application's look and feel.
Changes:
Remove the glass treatment from around the opne sidebar icon
Sidebar: Move "Mihir" logo to next line, after close sidebar icon - make it clickable so it takes us to dashboard
Remove the redundant "Appearance" and give "moon/sun" label "Dark/Light/System" — give, both Settings, and theme icon same treatment
Remove the glass treatment from sidebar, message, advanced settings popup, input box — instead we wll' use the following glass treatment:
/* Glassmorphism card effect */
.card {
backdrop-filter: blur(16px) saturate(84%);
-webkit-backdrop-filter: blur(16px) saturate(84%);
background-color: rgba(17, 59, 57, 0.22);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.125);
}
Send icon button in Message box - change icon line to dark, and change animation speed to take 5-7s
The particle are scatteredon the entire background right now, make sure they are concentrated around the icon in center of page and fade off radially as we go more distant
Model Selection badge - on hover show a preview card: https://animate-ui.com/docs/base/preview-card With Model details available from OpenRouter/OpenAI 7.1 When just 1 model is selected - allow clicking on the badge to open selection dropdown again (reuse component) and change it
In center of the page currently icon + Hello there! Let's chat? are stacked - put them in the same horizontal line like icon + greeting
Limit max file attachments to 5, above it show an error sonner
Move Settings temperature, max output tokens outside the dialogue to below the message box replacing advanced settigns, initial state, display values: icon: thermometer {temperature} · icon: text-cursor-input {max output tokens} - on click allow edit.
—
Fixes:
Sidebar logo + icon - make it same size as other nav items, the icon is an animated icon should animate on hover
Move "sun/moon/system" icon for theme from below sidebar to top of sidebar on right side of close sidebar icon - make all 3 visible, show selected
Model Selection batch, hover preivew card is showing randomly on the page, it show show below or above the badge
Temperature and Max tokens settings below Mesage box, change them to badages with icon + data. Align them to the right , reduce space between items. On click open dialogue where these can be changed - add tooltips on hover with content: "Temperature: 0.7". On hover, both, icon + data should show hover state.
Hide the particles (or make them very dim and slow), make them appear like they are coming form behin dmessage box when mesasge box is in focs
Currently on the send icon button in mesage box has an animation on hover and without hover - slow down the non-hover animation to 7s! Change the glow/box shadow colour to primary colour
THe icon before "Hello there!..." - reduce the size and vertically align it to the text
Change Finish Setup to Start using Mimir. Configure in Settings to THis special aniamted button (npm and link below) with text "Finish Setup, Experience Magic" (and make it appear near the top of page - on click take to Settings page with OpenRouter API key input box selected.
pnpm dlx shadcn@latest add "https://magicui.design/r/rainbow-button"
https://magicui.design/docs/components/rainbow-button
Badge Example:
import { ZapIcon } from "lucide-react"
import { Badge } from "@/components/ui/badge"
export default function Component() {
return (
Badge
)
}
—
Now properly implement the schema, setup the tables, and wire up everything so it all works and persist to db. We are using supabase!
Ensure when settings are saved there are persisted to db!
—
Implement integration with OpenRouter, standardise certain reusable patterns/integrations:
Getting list of models for various drop-down (in Settings with inside message input box) etc
Running a thread with OpenRouter -
—
Critical:
Please remove auth and login layer? I did not ask for it!
- Sidebar:
- Theme icons in sidebar should be right aligned, not left.
- Selected state in dark theme has dark fill and dark icon - make the icon line fill white. In white mode the active one has fill white, change it to dark
- "Icon + Mihir", move this in same horizontal line as "close sidebar" icon and theme icons - between them, left aligned. Resize to match the icons/sizes!
- Mihir icon: loader-pinwheel - change line thickness to 1px - keep it in animated sate (no hover required)
- New Chat Page:
- Remove “Configure your OpenRouter API key to start using Mimir.”
- When Message Input is in focus - make the parties in background more visible, concentrate them behind the message box
- In the icon + headline/greeting - change icon from bot to aniamted icon: loader-pinwheel like we use in Sidebar, this one animates only on hover
- Temperature + Tokens below Message inbox box, remove · Add tooltip with Label: {value} content
- Move Model Selector to top of page in the same horizontal line as open sidebar icon, after it , from selected model badge remove the popover card and use a tooltip to display info (example code shown below)
- Finish Setup button is not implemented properly! Please use this component: npx shadcn@latest add "https://magicui.design/r/rainbow-button"
import { RainbowButton } from "@/components/magicui/rainbow-button"; export function RainbowButtonDemo() { return <RainbowButton>Get Unlimited Access</RainbowButton>;}
- Input Message Box, send icon button has background animated all the time, ti should only animate on hover! Fix this
Settings Page
Nothing should automatically save! Give Save button in each card on settings page, only persist to DB once save is clicked. Show sonner with success/error
Storage Settings would be below all API Keys in API Keys card, it should only impact where API Keys are stored
API Keys:
Add field in db and expose it here for OpenAI API Key
Example of Tooltip with Stats, use glass treatment for tooltip
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
export default function Component() {
return (
Stats
-
Status
Completed
-
Code Coverage
94.3%
-
Last Deploy
Today at 15:42
-
Performance Score
98/100
)
}
—
Model Selector (Top of page) should be left aligned not center
Ensure at least one model is always selected (Default from settings)
this should be Combobox component
Message Input Box
Move prompt selector to 2nd line in Input box
Remove “Configure your OpenRouter API key to start using Mimir.” Warning please!!!
Even though OpenRouter key is present, Model selector is not opening/wroking! Cosn’t of selected models and tooltip card with details do nto appear either!
Message Box - Send button background animation - remove!!! For heaven’s sake
Reduce space between icon + greention and message box (Bring the box up!)
Please pay careful attention to this:
Close sidebar icon inside Sidebar and Mimir + logo are overlapping, Logo should appear after the close sidebar icon
In the same horizontal line, but right-aligned should be the 3 theme icons - please move them here
Settings Page:
Save button should be at the end of each card after the fields
Remove “available models” card, we should have Default Model: in System Defaults card! This should be persisted to correct db field, and New Chat Page model selector should pick this by default! — this should be Combobox component
Same with other system defaults like temperature (0.5) and max token output (0) — must be in DB and that’s where we should pick it up from. The dialogue box on new Chat page allows us to override this
Data Management
“Clear All Data” button - should open a dialogue that requires user to type “Delete” in input field to confirm this action
—
Model Selector in Header on New Chat Page:
There is a default model set in Settings - badge for that should always show, if not found select Sonnet 3.5
The new model selector should be triggered by a + icon inside a circle (clickable) opening the combobox
Combobox model card:
Title (Company)
{slug}
Input Modalities: (using icons) icon: letter-text for text, icon: image for image, icon: headphones for audio then for Output modalities
Cost: Input Tokens / Output Tokens, then details by modalities, cached, etc
Max Context Length: { }
Supported Parameters: { }
Sidebar - close sidebar icon and Mimir icon _ logo are still overlapping, fix this pls!
There are several app default fields created but not exposed on Frontend! Fix all the fields - data must be gotten and shown from db and persisted back there!
System Prompt is broken
Default Model is missing!
Max output tokens not tied to db
Utility title model not exposed
Budets not shown!
Use the following gradient has box shadow for Message Input Box when hovered (shown later, example 1 ) and animate it using CSS like shown in example 2
Example 1:
.box:before {
content: "";
z-index: -1;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: linear-gradient(-45deg, #03E5B7 0%, #037ADE 100% );
transform: translate3d(0px, 20px, 0) scale(0.98);
filter: blur(20px);
opacity: var(0.7);
transition: opacity 0.3s;
border-radius: inherit;
}
/*
- Prevents issues when the parent creates a
- stacking context. (For example, using the transform
- property )
*/
.box::after {
content: "";
z-index: -1;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: inherit;
border-radius: inherit;
}
INSTRUCITONS:
Change the linear gradient to: #0bb2cd, #37d8b7, transparent, #b8f284, #00c6c8, transparent, #b8f284, #f9f871
On hover animate their position as well!
Example 2:
:root {
--gradient-shadow: linear-gradient(
45deg,
#fb0094,
#0000ff,
#00ff00,
#ffff00,
#ff0000,
#fb0094,
#0000ff,
#00ff00,
#ffff00,
#ff0000
);
}
body {
margin: 0;
padding: 0;
background: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.shadow {
display: flex;
justify-content: center;
align-items: center;
position: relative;
color: #fff;
text-align: center;
font-size: 50px;
font-weight: bold;
width: 400px;
height: 250px;
background: linear-gradient(0deg, #000, #262626);
}
.shadow:before,
.shadow:after {
content: "";
position: absolute;
top: -2px;
left: -2px;
background: var(--gradient-shadow);
background-size: 400%;
width: calc(100% + 4px);
height: calc(100% + 4px);
z-index: -1;
animation: animate 20s linear infinite;
}
.shadow:after {
filter: blur(20px);
}
@keyframes animate {
0% {
background-position: 0 0;
}
50% {
background-position: 300% 0;
}
100% {
background-position: 0 0;
}
}
INSTRUCTIONS: Save this as reusable style!
—
Fixes:
Message box has file attachment badges that appear before it:
Truncate the name from start so max 10 characters are shown (last 10 chars)
New Chat Page top header, change “Model:” to “Chat with:” [Default Model Badge] [+ circular icon that opens combobox to select models]
Clicking on [Default Model Badge] or selected model badge should also, again, open Model combobox so user can select and change it
Model Selector - should allow adding up to 3 models! Clicking + circluar button should do that, currently its only updating the first model
Use a button with icon to show a selected model (upto 3), icon: brain {name}, on hover show tooltip with all details
If model.is_expensive =true, give model button a red outline, on hover show reason in tooltip
Use this as add 1 more model button: circle-plus
Sidebar
Add additional space between close sidebar icon and icon + Mimir, reduce space between icon + Mimir. The icon is animated icon, should animate by default
Message box focus background/box shadow animation:
Only go in one direction continuously, reduce the speed of animation to 20% of current speed
In dark mode, increase the darkness (and in light mode the light/whiteness) of the background glass treatment of the message box input
There are several app default fields created but not exposed on Frontend! Fix all the fields - data must be gotten and shown from db and persisted back there!
System Prompt is broken
Default Model is missing!
Max output tokens not tied to db
Utility title model not exposed
Budets not shown!
—
Message box focus background/box shadow animation:
Reduce transparency of all colours to randomly between 5% to MAX 30%!
On hover/focus - in dark mode - give it a bright outline (255, 255, 255, 0.3), opposite (dark 30%) in white mode
White mode message box background has too much grey, change that to white
Model Selector - should allow adding up to 3 models! Clicking + circluar button should do that, currently its only updating the first model
No default model is showing! Make sure you pick it up from settings
Remove icon: brain from each button
If model.is_expensive =true, give model button a red outline, on hover show reason in tooltip
On hover, tooltip is shown but content not legible, use dark colour for background, grey for labels, white for data
Input & Output costs, remove the “tokens” part for data
For input & output cost, before the cost show a coloured dot - green if below budget, red if more than budget
Show inputoutput modalities using icons
On clock, currently the model gets removed, instead:
Clicking button representing model should open the dropdown again, allowing to select another model in it’s place
Add a x icon at the end - clicking on it will remove the model + button
Entry animation: Make new model buttons appear, animated moving towards right, and fading in
Exit animation: Fade off (0.3s)
Fields still not connected to DB:
System Prompt
budget_max_24h
Title Generation model, should be a dropdown powered by OpenRouter like Default Model combobox is
Top Header:
Open Sidebar icon, show tooltip on hover “Open Sidebar”
When Sidebar is open, there is extra space on left of “Chat with” likely due to some component not getting removed or wrong styling, please fix it
Sidebar:
Close sidebar icon to have a tooltip on hover “Close Sidebar”
===
There is still “x” icon inside sidebar, remove it!
Model Selectors in header:
Implement Hover tooltip on entire card
Clicking “x” does nothing, should remove the model
There should only be 1 model by default from settings!!
Message box active/focus state:
Particles, Keep the particles concentrated behind the message box, don’t make them respond to cursor/clicks
Message box background/glass treatment fill in light mode - reduce opacity further!
Settings
System prompt fields still not populatedfyom db, / saved to db
Check all other fields!
24-hr budget also not from db
Max output tokens also not from DB!
Model Selector - should allow adding up to 3 models! Clicking + circluar button should do that, currently its only updating the first model
No default model is showing! Make sure you pick it up from settings
Remove icon: brain from each button
If model.is_expensive =true, give model button a red outline, on hover show reason in tooltip
On hover, tooltip is shown but content not legible, use dark colour for background, grey for labels, white for data
Input & Output costs, remove the “tokens” part for data
For input & output cost, before the cost show a coloured dot - green if below budget, red if more than budget
Show inputoutput modalities using icons
Updating Default Model in settings does not save it!
System prompt Stil not connected to db!
Max output tokens still not connected to db
Model Selector in header on new chat page:
On hover, tooltip is shown but content not correct, not from OpenRouter
On light mode, tooltip background colour should be black/dark
When just 1 selected model is left, do not show remove (x icon)
Clicking on circle-plus icon button should open combobox for model selector from open router - implement
Remove the container around circle-plus icon the icon should be the button itself
On selection, add that model as the n option
Max 3
Settings still not connected with db, alll data is fake since db is empty! Fix this!
Sidebar
Close sidebar icon and icon + Mimir logo are overlapping, add space between them!
Chat card - reduce roundedness
Do not show … menu on card, use full space
Change nav items Search & Calendar to just icons, in same horizontal line
WHen search is clicked command opens
When calendar is clicked, Calendar opens in sidebar like today
Even though there are chats / threads in DB - sidebar does not show it upfront!
Implement relative time shorthand, eg: 5 minutes ago > 5m
Less than a min ago > now
X mins ago > Xm
Hours ago > Xh
Days ago. > d
Months ago > m
Message box - add a character limit (max 500) show left character count on top right corner when less than 20% left / allow typing beyond but show errror state and do not allow sending
Send button icon — in light mode make line colour if icon white, in dark mode make it dark
There are particles behind - increase their spread and numbers by a bit
Model Selector circle-plus icon
Opens the combobox dropdown, but no models are populated! Populate them like we do in settings for model comboboxes
Selected model button/tab — tooltip opens but data is incorrect!
Use this in sidebar chat card and chat detail view header and under messages! And also in search command chat cards
Sidebar
Above the Chat cards list add a title “Chat History”, on it’s right — Move/align Search icon, calendar on left side - currently center aligned. Add bookmark icon - clicking it shows only bookmarked items
Reduce width of “settings” to half, in other half right aligned show the system theme icons (move them here from top of sidebar)
When calendar icon is clicked instead of opening a calendar in sidebar open a new dialogue with two columns - left calendar - with dots below dates where at least 1 chat exists . Same setup as calendar in sidebar
On right panel/column show list of chat cards for selected date . Allow scrolling if required
Cost in the chat card - remove colour coding
Selected Chat card - in sidebar has a bright sky blue border - change that to 1px solid rgba(255, 255, 255, 0.6)
Search Combobox:
Fix the list of chat cards:
Remove chat/message icon
Reduce size of icons in metadata 12x12, Remove $ icon
Remove the title “Chats”
Chat detail view -
message with role system should be collapsed like an accordion with title System Prompt . On click open the card and reveal content , icon for system message : laptop-minimal
User icon or any other icon do not fill with colour! Remove the colour fill
Default title should be : MMM DD at HH:MM AM/PM - replace when microtasks generate a proper title
When generating an LLm response fails thread_error table should populate with appropriate details. An alert should appear at end of timeline with retry button - stays if fails again, alert goes away and message appears if it worked!
Change character count icon to: case-lower
Change icon for tokens in header and under messages from whatever it is to text-cursor-input
Remove dollar icon from costs metadata
Header, metadata:
keep icon + {count}, remove the words “messages, models, tokens,
Implement hover on each icon+data set: on hover, both, icon and text change colour to white/black (Css animate), show tooltip (with black aground for both light and dark themes)
Implement the same tooltips and details for similar metadata below message cards
Tool tip for messagesd:
Total Messages: {count}
Assistant: {count}
User: {count}
Models
Show all models, 1 each line. Below model show input output pricing
Tokens tooltip, show breakdown
Input {count}
- Text {count}
- Text Cached {count}
- Audio {count}
- Audio Cached {count}
- Image {count}
- Image Cached {count}
Output {count}
- Text {count}
- Audio {count}
- Image {count}
- Reasoning {count}
Cost tooltip:
Input Cost:
Output Cost:
Microtasks costs:
Message card, at the end has action items - Copy, etc. move that to outside the message card - in the same horizontal line as the message metadata, before metadata
Actions should be left aligned to message card, and metadata to the right
There is a random 0 appearing below every message card - remove it
Parse and render markdown in message content
table: threads
Add column is_bookmarked: bool, default False
Using this implement bookmark in Thread Detail View
table: app_default add
user_name: string, allow blank - if filled, use this to generate app greetings
Templates for Greetings:
“Howdy, {name}?”
“Namaste, {name}!”
“How’s the day, {name}?”
“Let’s chat, {name}?”
“{name}, sup?”
Default: "Hello there! Let's chat?”]
The app_greeting microtask is not yet fully implemented. The infrastructure is in place (microtasks table, proper cost tracking, etc.), but the actual background job that runs every 4 hours to generate personalized greetings and prompts based on chat history needs to be implemented as a separate background service or cron job. Currently, the system uses static prompts as placeholders.
Micro task: app_greeting, every 4 hrs (if there are > 5 chats in DB) generate the following using structured responses in micro tasks (same model as title)
greenting: “String”
Name of the User: {user_name} - you must generate a 3-4 word greeting with name included. Examples.. Try to include to a pun or keyword from recent chats
prompts: [ “Prompt1”, “Prompt 2”, “Prompt 3” ]
Suggest 3x1 sentences conversation starters/prompts the user might be interested in, looking at chat history — predict what prompt/quesiton they are likely to ask or should be asking.
Prompt: “You are a helpful UI copy assistant, only respond with required JSON. Name of the User: {user_name}. …
Here are some recent snippets of user’s conversations based on which you can make suggestions
{message.content for role=user in the last 4hours, 8hrs (if 4 was zero), 24 hrs if 8hrs count was zero
Once generated, they are used on New Chat Page - greeting to replace the templates
Prompts display as a button below Message Input box, on click - content of button is the prompt. On click, fill the prompt in the chat.
Chat Command Search, shows chat cards:
Reduce icon size to 8x8px in metadata
Chat Calendar dialogue:
Reduce width of column for calendar, reduce calendar card width so it fits the calendar
The right panel is not showing chat cards for teh select date - today even though they exist in db!
Chat Detail View:
Fixed header
background - give it glass treatment
Messages metadata tooltip background should be black - also for tooltip for costs, and tokens
Message role icons for user and assistant - reduce circle border size to 1px
Message card metadata:
Contain it in the same width / bounds on left and right as the width of the message card associated with it, right now it is overrun on either side
Use regular font weight, icon line thickness 1px
For role=assistant show:
icon: brain, remove model slug
icon: braces, hover tooltip: “See Raw JSON response”, on click open Dialogue with message.raw_response content in allow click to copy
icon: tags, on hover show tooltip:
temperature (Add to messages table if not present, ensure we populate it going forward)
For all ensure created icon clock + relative timestamp is the last metadata in the list
System Prompt
accordion, change arrow icon at the end to chevron-down, when open change it to chevron-up
Border - make it solid
When clicked it opens - the content card and title appear disconnected, make sure they are connected visually
New Chat Page:
Move the prompt suggestions from below and outside message box to inside it in 2nd line after “Prompt Library”. Truncate content to fit them in same line max 30 chars
When clicked - currently they start a new chat with that prompt . Instead they should fill the full text of suggested prompt in Message Input Box
Circle-plus icon opens combobox but doesn’t show model - make sure we always show models from OpenRouter
Chat with: “Selected model” button has a hover tooltip - however data is not populated other than name, plate it from OpenRouter
Chat Calendar dialogue:
Reduce card containing calendar more, make it fit calendar
The date dot -should be middle aligned
On right Chat cards - remove model from cards, reuse what we have in sidebar
Sidebar
Chat Card: if chat is bookmarked, show bookmark icon after updated at metadata separated by another ·
Icon + Mimir logo hover tooltip content: append “by @kingsidharth for Outskill” link Outskill to https://outskill.com/
Chat Detail View
Message card metadata:
Contain it in the same width / bounds on left and right as the width of the message card associated with it, right now it is overrun on either side
Fixed header - last metadata icon tags - hover tooltip “See associated data”, on click open dialogue
List of micro tasks + cost + type + status
Also confirm if “Micro task: app_greeting” is implemented?
—
Still not working:
Circle-plus icon opens combobox but doesn’t show model - make sure we always show models from OpenRouter
Chat with: “Selected model” button has a hover tooltip - however data is not populated other than name, plate it from OpenRouter
Sidebar & Chat Calendar Chat Card:
Make updated at metadata the first in 2nd line, add tokens with icon: text-cursor-input {count, into comma separation}
Message card metadata on Chat Detail View
Contain it in the same width / bounds on left and right as the width of the message card associated with it, right now it is overrun on either side
Add to start of metadata: icon: brain, hover tooltip show model details
Tokens tooltip, show breakdown
Input {count}
- Text {count}
- Text Cached {count}
- Audio {count}
- Audio Cached {count}
- Image {count}
- Image Cached {count}
Output {count}
- Text {count}
- Audio {count}
- Image {count}
- Reasoning {count}
Search command box has chart card in list below search - search card has metadata with icons. Reduce the size of those icons! Set it to 10pxx10px
New Chat Page:
Model Selector Dropdown, change design to have the following in this order:
{name}
{canonical_slug} · {MMM DD, YY from created_at}
Modailities
Input: {icons} · Output: {icons} · Context: {22k} [icons: text: letter-text, audio: icon: headphones, image: icon: eye]
Price. Icon: arrow-up (for input} $X.XX/Mtok / icon: arrow-down $X.XX/Mtok · Input: {colour_dot} {modality icon} ${X.XX}/Mtok Cached: {cost}/Mtok · Output: {colour_dot} {modality icon} ${X.XX}/Mtok {cost}/Mtok · as separator for all modalities . Colour dot = green if price is < budget input/output else red
Show cost in $/Million Toklens or MToks by multiplying the price from OpenRouter/db with 1000000
Selected Model card after Chat with:
Add a red outline to button if either input or output cost is beyond budget
It shows a tooltip card, add/change content:
Remove Input/Output Cost and show single line:
Cost: Icon: arrow-up (for input} $X.XX/Mtok / icon: arrow-down $X.XX/Mtok (Mtok prices are in million tokens i..e multiply db or openroter pricing with 1000000, colour the arrow red if beyond budget, green if not)
Badge “{red dot} Expensive” below if model.is_expensive = true
Input: {modalities icons} Output: {modalities}
Chat Detail View:
Header
Header background - add transparency, blur, etc. to give it glassmorphic feel
Metadata:
Tokens tooltip - none of the counts are actual, use real data here!
Cost tooltip: Right align prices, show “Total Cost: $X.XX at end
Created tooltio, change content to: Created: {MMM DD, YY HH:MM AM/PM}
Updated tooltip: change content to: Created: {MMM DD, YY HH:MM AM/PM}
With multiple columns, we show a fixed header for each column with icon + model name, modify to:
Reduce font size to 12px, font-weight regular, change icon to brain
Show icon: brain, in same horizontal line right alined, [after it show icon + token count · ${cost}
For model name: On Hover, show tooltip, content:
{Model Name}
Icon: arrow-up (for input} $X.XX/Mtok / icon: arrow-down $X.XX/Mtok [colour icons red if that price is > budget, else green]
For model name: on click Open Dialogue:
When other metadata’s are hovered, show what we show in header with same metadata
Message card: has spacing left on its left side or right side (or gap), however the message metadata does not respect this gap!
For message role=user
Action icons should come first, left alined: Clip to Copy
Then Metadata, right aligned: {created} · {character count}
For message role=assistant
It is mostly correct, but needs to leave gap on right like role=assistant message card does
For all message metadata below cards, update tooltips:
brain/model:
{Model Name}
arrow-up (for input} $X.XX/Mtok / icon: arrow-down $X.XX/Mtok [colour arrow green if below budget, else red]
characters: {count international commas} characters
tokens: show full breakdown like we do in tokens metadata hover tooltip card in header
Created: {MMM DD, YY HH:MM AM/PM}
—
Fixes
Sidebar
Chat Card:
Metadata: put created at icon + shorthand as first metadata in 2nd row
After that message count will follow, after that (separated by ·) show icon: text-cursor-input {token count, comma operated, into commas}
Hover:
Change border colour to rgba(255, 255, 255, 0.4)
Selected sate, light mode:
Add border - 1px solid primary colour
When we click a Chat Card in sidebar, we are taken to that page - ensure we:
update URLs for each thread, settings, page
Sidebar should close
When Bookmark icon is clicked, cards change instantly. Instead animate it:
Previous cards: fade-off 0.5s
New cards: fade-in 0.5s, move up 10x 0.7s
Reverse when undone
Logo: icon + Mimir - aniamted icon should animate when either icon or name is hovered. On hover, also add text/box shadow to give it a glow effect
Change Mimir font-weight to bold
Close sidebar icon, tooltip - background colour should be black
Chat Calendar Dialogue
Calendar is within Calendar card, however there is extra space left on right side of calendar - make sure calendar and container hug each other. Appropriately, reduce width of first column
When a date is hovered, show tooltip:
{MMM DD}
Chats: {count}
Search Command Box - has search and list of chat cards below
In those chat cards there is metadata, fix things there:
Reduce icon size to 12x12px
Remove model name from metadata!
New Chat Page:
Model selector in header. If selected model is expensive= true, the model card/button gets a red outline. Change this to: Outline colour remains normal (remove red treatment), instead show this icon in red after the model name within the button. Icon: circle-dollar-sign
When this button is hovered, it shows a tooltip, in that tooltip put Input & Output Modalities in same line! Use title “Modalities” and arrow-right to depict border so {input modalities icons} {icon: chevron-right} {output modalities icons}
circle-plus icon and clicking on selected model card opens a combobox dropdown, fixes:
Model Name should be primary, right now we are seeing the company
Change Input & Output modalities to: {input modalities icons} {icon: chevron-right} {output modalities icons}
Cost: our multiplication is wrong, price coming from openrouter should be multiplied with 1000x not 1000000. Move them to same line as pervious metadata separated by ·
Message Box Input
Prompt suggestions generated are shown in 2nd line inside the message box after Prompt Library card. Changes:
Remove them from 2nd line and inside message box
Move them to below message box (outside) - below the temperature/max output token badges - show as cards
Show equal sized 3-cards next to each other - aligned with left and right side of message box
Cards “glow” on hover
On click, take the content of the prompt and fill it in Message Input Box (do not auto start the chat!)
On focus, we animate particles in the background:
Reduce the size, match the size of particles we use before focus
Ensure particles are more gathered behind message box
Remove the box-gradient with multiple colour gradient
Ensure they fade-off radially
Ensure particles are visible on light mode as well ! Use primary colour for this
Max character count, increase to 2000 characters
Chat Detail View
Header:
Change fixed header background to translucent give it glassmorphic treatment
On scroll, reduce height of fixed header by hiding/fading-off metadata and reducing font-size of title to 14px
Metadata:
For light mode, on hover - the icon + metadata colour should change to primary colour
Ensure all icons have 1px line thickness
Tooltip for Tokens: Ensure real counts are used here from database!
Tooltip for Cost: Ensure real counts are used here from database!
System Prompt Accordion
Open State - add an overall container for tab + content, when opening - animate it’s visibility + increase spacing between tittle + content
Remove action buttons/icons from below system prompt
Message Card
Contain it in the same width / bounds on left and right as the width of the message card associated with it, right now it is overrun on either side
message.role=assistant, add additional metadata, at the start of metadata:
token tooltip show all the breakdown
Tokens count and character count, use international comma’s to format
Change icon in circle to brain - line thickness 1.25px
For role=user, remove the user icon on right
Action icons should come first, left alined: Clip to Copy
Then Metadata, right aligned: {created} · {character count}
New Chat Page:
Prompt suggestions below message box, left align content
Set opacity of cards to 80%, animate to 100% on hover
Search Command Box - has search and list of chat cards below — Reduce icon size in metadata by half, ensure we are using 1px thickness for icon lines
Change sequence of metadata: updated, messages, tokens, count
See Chat cards in Sidebar for inspiration
Sidebar
Chat Card, metadata icons - set line thickness to 1px
Close sidebar icon has a tooltip, change tooltip background colour to black
Open Sidebar icon has a tooltip, change tooltip background colour to black
Message Box Input, on focus we animate particles behind:
Increase their range / visible area
Increase numbers
Model Selector on top
selected model card/button - on click it should, again, open the model selector combobox like we do for circle-plus button
On hover, show glow on selected model card/button
There is still blank section between name and close/x icon! Remove it!
We still do not see icon: badge-dollar-sign in read after name if model is expensive!
circle-plus icon is not vertically aligned in the circle - ensure it is in middle vertically
The model card inside combobox, modify:
Reduce spacing between {icon} {cost}/MTok | {icon} {cost}/MTok [retainign arrow icons and colour coding]
Reduce space between divider and “icon + metadata”
Ensure cost is in $/Mtok - what we get from OpenRouter, multiply it by 1000 for this
Remove {created} date after name, instead show “Context: {count}”. Remove context from below/metadata line
Additional metadata (After ·) Cached: {modality icon} ${X.XX}/Mtok
Chat Detail View:
Header:
Change fixed header background to translucent give it glassmorphic treatment
On scroll, reduce height of fixed header by hiding/fading-off metadata and reducing font-size of title to 14px
System prompt accordion - when clicked, page scrolls to bottom. It should not!
message.role=assistant
Metadata, fixes:
STILL NOT FIXED: - you need to leave gap on right side of metadata, so it aligns with message box!!
For tokens use icon: text-cursor-input
Add a new icon before existing metadata, icon: brain, hover tooltip: Model Name
Character count, tooltip content: “{count, comma separated} characters”
{Created}, tooltip content: {MMM DD HH:MM AM/PM}
Tags icon - from hover tooltip content, remove everything - only Temperature should be there!
Action icon fixes:
Copy icon, tooltip “Copy Message Content”
Regenerate icon, on click open dropdown
{model name from messages record, same as the one response was generated with}
More… - open model selector
Response JSON icon, when clicked - open a dialogue
Title: Thread ID {id} | Message {id}
Raw JSON from messages db wrapped in
CTA: Copy, Close
There is an icon in circle on the left, change that icon to brain, lien thickness 1px
Fix chat turn: Starting Chat
When a chat starts, first system message must be created, then user message - then and only then should we try to generate llm response -ensure this sequence is followed
Microtasks:
When a task is created, model is known — all the price fields must be populated from OpenRouter models endpoint
started_at is not being set! Fix this!
Message card metadata:
When attempting to start a chat, it failed : Unexpected token ':', ": OPENROUT"... is not valid JSON
"Error sending message:"{stack: "SyntaxError: Unexpected token ':', ": OPENROUT"... is not valid JSON", message: "Unexpected token ':', ": OPENROUT"... is not valid JSON", name: "SyntaxError"}
New Chat Page: Entry Animation:
Use the animation code for which is shown at the bottom — applies to Message Box + components. And Icon + Greeting on New Chat page
You are given a task to integrate an existing React component in the codebase
The codebase should support:
- shadcn project structure
- Tailwind CSS
- Typescript
If it doesn't, provide instructions on how to setup project via shadcn CLI, install Tailwind or Typescript.
Determine the default path for components and styles.
If default path for components is not /components/ui, provide instructions on why it's important to create this folder
Copy-paste this component to /components/ui folder:
blur-fade.tsx
"use client"
import { useRef } from "react"
import {
AnimatePresence,
motion,
useInView,
UseInViewOptions,
Variants,
} from "framer-motion"
type MarginType = UseInViewOptions["margin"]
interface BlurFadeProps {
children: React.ReactNode
className?: string
variant?: {
hidden: { y: number }
visible: { y: number }
}
duration?: number
delay?: number
yOffset?: number
inView?: boolean
inViewMargin?: MarginType
blur?: string
}
export function BlurFade({
children,
className,
variant,
duration = 0.4,
delay = 0,
yOffset = 6,
inView = false,
inViewMargin = "-50px",
blur = "6px",
}: BlurFadeProps) {
const ref = useRef(null)
const inViewResult = useInView(ref, { once: true, margin: inViewMargin })
const isInView = !inView || inViewResult
const defaultVariants: Variants = {
hidden: { y: yOffset, opacity: 0, filter: `blur(${blur})` },
visible: { y: -yOffset, opacity: 1, filter: `blur(0px)` },
}
const combinedVariants = variant || defaultVariants
return (
<AnimatePresence>
<motion.div
ref={ref}
initial="hidden"
animate={isInView ? "visible" : "hidden"}
exit="hidden"
variants={combinedVariants}
transition={{
delay: 0.04 + delay,
duration,
ease: "easeOut",
}}
className={className}
>
{children}
</motion.div>
</AnimatePresence>
)
}
demo.tsx
import { BlurFade } from "@/components/ui/blur-fade"
export function BlurFadeTextDemo() {
return (
<section id="header">
<BlurFade delay={0.25} inView>
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl xl:text-6xl/none">
Hello World 👋
</h2>
</BlurFade>
<BlurFade delay={0.25 * 2} inView>
<span className="text-xl text-pretty tracking-tighter sm:text-3xl xl:text-4xl/none">
Nice to meet you
</span>
</BlurFade>
</section>
)
}
Install NPM dependencies:
framer-motion
Implementation Guidelines
- Analyze the component structure and identify all required dependencies
- Review the component's argumens and state
- Identify any required context providers or hooks and install them
- Questions to Ask
- What data/props will be passed to this component?
- Are there any specific state management requirements?
- Are there any required assets (images, icons, etc.)?
- What is the expected responsive behavior?
- What is the best place to use this component in the app?
Steps to integrate
- Copy paste all the code above in the correct directories
- Install external dependencies
- Fill image assets with Unsplash stock images you know exist
- Use lucide-react icons for svgs or logos if component requires them
Implement Chat Turns:
When a new chat is created, String chat:
Creating a thread
Add system prompt as the first message, this should always be the first message
role=system
Add user’s input as 2nd message in thread, role=user
At this point, using chat completion and openai sdk, we ping OpenRouter to generate response
Stream this response, do BOTH in parallel
Debounced save to db
Stream to client (using websockets)
Repeats:
Now system wait’s for user’s message, when received - we’ll again repeat the process (append role=user message, generate response from LLM) till:
We reach 90% of context_length of any of the model’s
Error handling, record failures in theard_errors table
Show error in sonner in FE, click to copy
If generating LLM response fails, and max retries are reached - show an error alert box in thread detail view in place of message and show a button to “Retry”
If Retry successful - error alert is removed and chat continues as is
If fails, state remains
If Handing multiple models:
Starting chat:
Once for thread: system message, user message
For each model:
System + user message = generate response
Stored with appropriate column to identify later. We spend the role=assistant message with corrected column
Repeat:
Once user responds (We append it once)
Then for each model: we combine system, user, and role=assistant message where column matches! CRITICAL
We spend the role=assistant message with corrected column
Chat Detail View:
Header:
Title: generated or {Local Date @ Localtime}
Metdata:
Created at (icon: clock) : {relative timestamp shorthand} · Updated at: {Relative timestamp shorthand}
Message count, icon: message-square
Models: {count int comma seperation}, icon: bot
Tokens: {count intl comma seperation), icon: text-cursor-input
Cost: ${0.0000}, on hover show tooltip:
Total Input Cost ${XX.XX}
Total Output Cost ${XX.XX}
Other Cost ${XX.XX} (micro asks)
Bookmark active/regular state, icon: bookmark
Share icon, icon: share-2 (Opens dialogue, described later)
Message History timeline —
Columns:
would have x columns, 1 for each model, max 3. Scroll all 3 columns together
Each column shows title of the {icon: bot} {model} + enable/disable switch + info icon (icon: info) — on hover, show tooltip with content
Model: {model}
On mobile/narrow devices — show only 1 column at a time, with next column slight appearing from left — allow swipe to change columns
Message Card:
Each message contained in a card, process markdown — new message content from LLM/AI/OpenRouter must be streamed in!
Before the message content — show any attachment icons — as described in Message Input Box
Inside the message card, after main content show action icons (right alined):
Copy (icon button), icon: copy
Regenerate (icon button), icon: refresh-cw
Opens dropdown:
Regenerate with {model), where model is same as the one that was used
Select Model: Opens combobox for Model Selection
On the left side, outside the card, show icons in circles to depict user/assistant:
User, icon: circle-user
Assistant, icon: bot
Below the message card (outside of it), show message metadata [right aligned]
Model: {slug}, icon: brain - only if message.role=assistant
[Created at]: icon: clock {relative timestamp shorthand}, icon: clock
Icon: case-sensitive {character count in message.content - into comma formatted}
Tokens: {count}, icon: text-cursor-input, on hover show full breakdown - only if message.role=assistant
Icon: braces - on hover, show tooltip “Click to view raw json response) - only if message.role=assistant, on click open Dialogue:
Response for Message ID: {id}
raw_response in
Actions: “Copy” “Close”
Have ample bottom-padding for timeline/columns so content does not hide behind floating message input
If user opens this page, auto scroll to the latest message
Allow setting a custom target message using url param message={id}, if set - scroll to that particular message
Websocket connection for:
Generating & Updating title (microtasks)
Transcription (microtasks)
Metadata updates in header
New Messages/responses streamed
——
New Chat Page
Move “temperature”,max tokens badges to 2nd line of message box inside it - right alined
Sidebar
Logo:
Icon only animates when icon is hovered, it should animate even when “Mimir” text is hovered
By default keep icon + text opacity to 0.8, animate to 1 on hover
Chat History - reduce transparency of text
Model Selector on top:
Selected model button - you fucked it up. Implement as a proper button, show model name inside. If model.is_expensive = true, after the name show icon: badge-dollar-sign in red
If more than 1 card is present, show “x” to remove
Model selection dropdown, Model card:
Move “Context: {count}k” to after the title, in first line separated by name with ·
Move Input/Output Modalities, Input Cost, Output Cost, Cached {price} - all in 1 line separated by ·
Chat Detail View
Header: There is a fixed header with title + metadata:
Change fixed header background to translucent give it glassmorphic treatment
On scroll, reduce height of fixed header by hiding/fading-off metadata and reducing font-size of title to 14px
Metadata: ensure all icons are 14x14, ensure font size of all data is same
Message role=assistant
Metadata - reduce extra space on right - make sure it aligns with the message card
Metadata icon tag - show tooltip content: “Temperature {data}”
Use · to separate sets of “icons + data”
Message role=user, below the message card outside of it
Action bar with copy icon - ensure it leaves enough gap on the left so ti aligns with message card
Metadata should appear after action bar, in same horizontal line but right aligned
Use · to separate sets of “icons + data”
When System Prompt is clicked, ensure no scroll animation happens!
Search Command Box > Search Cards list
Reimplement metdata icon + data set in 2nd line, copy what we have in Sidebar Chat Cards
When typing starts, ensure we search across
Message content
Date, Model, etc.
Placeholder: Search chats…/ Remove tip
Footer
Bottom right: © @kingsidharth | Stats where Stats will link to stats page
—
Settings:
API Keys card:
OpenRouter API Key field, reduce width to half, after it show:
We’ll use OpenRouters to get access to AI Models
OpenAI API Key field, reduce with to half, after it show:
Required for voice to prompt
System Configuration
System prompt - remove the redundant “Current:…” from below the field
Default Temperature, remove “Current: …”
Max Output Tokens, remove “Current: …”, show tooltip below “0 = no limits!
Default Model, remove “Current”, reduce width to half so next field can fit in same line
Chat Provider, reduce width to half
Budget Management
Fit all 3 fields in 1 line!
24-hour Budget Limit (USD), change label to 24h Budget. Remove “Current: …” below. Show helper text below
Input Token Cost (per token) to “Input Cost/Token”
Output Token Cost (per token) to “Output Cost/Token”
New Chat Page:
Input Message box, has a focus state, change box shadows to:
Box shadows
We animate particles in the background - ensure they are more visible
Model Selection dropdown in header:
Reduce width of model card, and the combobox dropdown
If Cost = 0.000000, replace with “Free”, both for input & output tokens
If Cached Cost is 0.00000, hide “Cached: {icon} {cost}”
Chat Detail View:
Header - I’ve asked you 10 times! Why is the background of fixed header nav does not have glass treatment? Why is it not shrinking in height as we scroll???!!
Change fixed header background to translucent give it glassmorphic treatment
On scroll, reduce height of fixed header by hiding/fading-off metadata and reducing font-size of title to 14px
Header Metadata, before tags - add another metadata
icon: scan-text XX.X% (input + output tokens from last message with role = assistant)/model’s context length
If multiple show overall %age outside and on hover, show tooltip with content: (in this case only consider message with role=user if model is same!)
[For Each Model]
[Model Name] [LAst input + output tokens] [Context Length] [XX.X% Used]
Remove “Created at” metadata + icon, instead show this in tooltip for Updated at:
Created: {MMM DD HH:MM AM/PM}
Updated: {MMM DD HH:MM AM/PM}
Tokens tooltip content — line items where count = 0, reduce their opacity to 0.75. Ensure token counts are right alined and formatter with Fira Code
Message role = user: action bar is too far out left, add gap/padding from left so it aligns with user role message card. Ensure that for these messages the copy icon has enough gap/spacing from left so it aligns with message box!
Message role=assistant, raw response json dialogue is not implemented!
All messages, metadata outside & below message card:
Increase space between · divider and “icon + data” sets
Header, icon button tags - on clicks opens a dialogue, modify:
{Title}
ID: {thread_id}
Below it show task cards:
{Type} {status}
{icon: clock + created relative shorthand} · {icon: clock + completed/updated relative shorthand like 3m} · {icon: brain + model} · $X.XX
Icon buttons: braces - on click, open another dialogue with content
Task: {id} {task type}
{Created} · {updated} · {thread id}
Request: raw json from db in
Response: raw json from db in
Buttons: Copy, Close
Header:
Bookmark icon - if selected/bookmark is on - add a glow to the icon: 0px 11px 24px 0px rgba(246,255,47,0.77) + 0px 15px 30px 0px rgba(246,255,47,0.5)
On hover, animate with css: 0px 15px 30px 0px rgba(246,255,47,0.85) + 0px 15px 30px 0px rgba(246,255,47,0.6)
Move context Usage as 2nd last metadata
Hover tooltip content:
[input + output token from last role=assistant message] / Context Length of model
Token tooltip: {labels} should be aligned left, amounts/counts on right. All non-zero items should have white colour (this isn’t the case rn). Add “Total Tokens {count}” at the end. Make Total Tokens, Input Tokens, Output Tokens line bold
Cost tooltip
Move tables on left, amounts on right
Change labels: Input Cost > Input, Output Cost > Output, Microtasks Cost > Microtasks, Total Cost > Total
System Prompt accordion - clicking on it still scrolls! Remove such code associated with this accordion!
Chat Calendar Dialogue:
On right panel, put {selected date} {x chats} in same horizontal line
Date left aligned, count right aligned
Below it for list of Chats, reuse cards that we use in Sidebar
Reduce overall width of this dialogue
===
New Chat Page:
Message User box
On focus animates particles behind
increase time of animation/transition - so it takes about 1.5s to transiton to active state for particles
also reduce size of particles just by a bit
Inside bottom right of message box is temperature & max output tokens badges, changes:
On hover show tooltip, but nearby the badges - right now placement is off
If max output token is 0, show it as infinity symbol. Tooltip: “Max Output Tokens: No limits”
If Transcription is enabled & model is specified & openai key is present
Show round icon button inside message box with icon: mic before the send message button
On click it needs to record & transcribe, process described below
Suggested Prompt cards below Message input. Currently, clicking on them does nothing. Expected: content of prompt suggestion will be filled in message input box. Currently, clicking them only selected user input message box but does not fill the content!
Greeting above Message box:
Icon is an animated icon, on hover animate it!
Model Selector in header:
Selected model button: If model.is_expensive i.e. either input or output cost is beyond budget set in settings > show icon: circle-dollar-sign in red after the model name so in button “{name} {icon in red}”.
On hover, we show a tooltip, make adujustments:
Increase top & bottom padding
For Cost - reduce spacing between {cost}/{cost}
Sidebar
Chat Card, on hover in light mode: Outline with 50% primary colour
In metadata, deepen the colour in light mode for the stats/count/data (not the icon) and in dark mode - make it closer to white
When a link/item is clicked in Sidebar and we navigate to that page (Settings, Chat), close the sidebar once we reach there!
Remove divider below “Chat History” and above the list of Chat Cards
Footer, bottom right show © @kingsidharth | Stats | Outskill
Where @kingsidharth links to https://x.com/kingsidharth, Stats to a new Stats page, and Outsell to outskill.com
Colour for this in dark mode: rgba(255, 255, 255, 0.5), on hover animate to rgba(255, 255, 255, 0.7). On light mode begin with light grey and animate to darker grey
Command Box - Search Chats
It has a list of chat cards, which have a 2nd line of metadata + icons. REMOVE ALL THE ICONS!
Chat Detail View:
Header
Metadata - on hover - change icon colour from existing to primary, change text colour from existing to darker (light mode) or lighter (dark mode)
For all metadata, we have hover tooltips: Use regular/our decided font for all copy except - cost, counts, %ages - for these numbers use Fira Code
Try to follow this pattern:
{Label}: {metric}
with ample space between them(min 1rem)
On hover, using css animate
Light mode: icon turns blue, text turns darker grey
Dark mode: icon turns blue, text turns white
There is too much empty space below the metadata, reduce it!
Reduce font size of the title in header
On Scroll Header animation:
Scroll down:
When user scrolls the page - animate the font-size of title going smaller to 16px!
Also animate metadata fading off
Overall height of header/fixed/sticky reducing!
Scroll up: maintain till header is reached, at that point animate back to initial state:
Font-size increases
Metadata fadesin
Header size/height expands
The above described animation should be smooth, eased, use performant CSS or motion.dev if needed!
Message timeline/main body: Columns: (when columns > 1)
There is too much space blocked out on top, reclaim it!
would have x columns, 1 for each model, max 3. Scroll all 3 columns together
Each column shows title of the {icon: bot} {model} + info icon (icon: info)
On mobile/narrow devices — show only 1 column at a time, with next column slight appearing from left — allow swipe to change columns
Message Card:
Before the message content — show any attachment icons — as described in Message Input Box
Metadata - below and outside message card - each has an icon + data set:
Ensure icons have line thickness of at least 1 px.
On hover - both icon and data/text should animate to white (in dark mode) and darker grey (in light mode)
Icon size (for both action bar and metadata) - 14px x 14px
Font-size: 14px
role=assistant - there is a brain icon in circle depicting that, on hover - using css, animate - line colour of icon changes to pink, subtle pink glow
Message Input box > Audio Recorder > Back
Message Input Box:
For all states:
Once message is typed, save it every 5 seconds to localstorage so it is not lost of page is navigated away
Always keep send CTA enabled, even if message is empty — show error state if user tries to submit empty
Top Aligned
Left: Attachments icon (PDF and/or Images) — max 5
For each attachment show a badge above the message box with [icon {filename} X icon button], clicking on “X” removes attachment
PDF, icon: file-text
Image, icon: image
Show loading state for badge till uploading
Right: (both rounded buttons)
Record Icon buton, icon: mic
Send Icon button, animated icon: from library, animate on hover
Bottom aligned:
[New Chat Page only!] Model Selector with default selection, once 1 model is selected show a + icon in circle to allow adding up to 2 more (3 total)
As each model gets added, show pricing below the message box, left aligned
This only appears for Initial State on New Chat Page!!!
Prompt Library, icon: list-plus, on click open a dropdown:
Show 5 most recently used prompts, and More button > More opens Prompt Library side-panel sheet
If a Prompt is selected, the text is added at the spot cursor was at / or at the end of existing content in Message box
Below Message Inbox Box:
Left Aligned:
Cost, icon: receipt: for each model show {icon: brain} {input cost in usd} / {output cost in usd} · (as divider)
If model.is_expensive, show in red
Advanced Settings, icon: flask-conical > opens dialogue: For each selected LLM - allow changing model, temperature, max tokens
Check App Limits: If budget_max_24h is exceeded, show a warning dialogue with actions “Cancel”, “Dangerous Override”
Initial State - New Chat Page (3 lines fro text area for focus state)
https://21st.dev/preetsuthar17/ai-chat-input/default
Instead of “Think” — give model selector powered by OpenRouter
Allow selecting upto 3 models
Show pricing of selected models (Input/Output per token) below the Message Input Box (for each selected model) + warning if model.is_expensive = True
If thinking/reasoning model show “icon: brain {Reasoning Model}”
Mic icon — activates Recorder (described later) — enables speech to text, Only if transcription is enabled in settings
When typing, allow text area to expand in height to upto 5 lines
On Submit, submitting state
Submitting State:
Animate back to 3 lines, disable changes to input, text fades-off within
Show shimmer effect on text
On Failure:
Show a sonner with error message, allow click to copy for error, dismissible
Content remains inside message box, so user can retry — text area is enabled again
If Max 24h Budget is exceeded, show a dialogue:
Max 24h Budget Exceeded!
Your Budget {amount} Current Spending: {amount}
CTA:
Cancel: goes back to initial state with content intact
Dangerous Override: creates a chat anyway!
On Success - transition to Generating Response State
Generating Response State
On Success:
Animate columns appearing if > 1 model was selected (fade-in move up) — in each column following animation will happen
Animate message card appearing — stream content into them
Message box becomes empty (local storage is cleared off) — Send icon becomes “Stop” icon, clicking on it will stop stream responses
Once streaming is finished, switch to Initial State - Chat Detail Page
Behind the scenes, OpenAI will stream to backend. Backend must debounce and save to DB && stream to client as is in parallel!
Initial State — Chat Detail Page
Same as usual, however, no model selector
Mic icon / transcription still present
When typing, allow text area to expand in height upto 5 lines
On Submit, Submitting State > Generating Response / Failure States
Context Window Warning (above message box):
Among the model(s) selected — find the lowest context_length (chat_max_context_length)
Check the last message with role=assistants, and add input+output tokens = total_tokens
If total_tokens > 70%*chat_max_context_length = Start showing warning: You’re approaching context window limit for {model}, please summarise this & start a new chat
"summarise this” is linked, if clicked appends following in the message input box content “Please summarise all we spoke about so I can resume it elsewhere”
If total_tokens > 95%*chat_max_context_length = Disable Input Message box, show error above: “You’ve reached the context window limit for {model}”
Icon for both: message-square-warning
Recorder:
In Input Message box, if mic icon is clicked, animate to “Active Recorder State”:
Active Recorder State:
Message Input box shrinks in height to 1 line (other controls disappear)
Left Side: Pause icon button (icon: circle-pause), Stop Icon Button (icon: circle-stop), Timer 0:00 > 0:01
Waveform of audio being recorded via mic
At the end: Max duration countdown — 10:00
Pause icon — pauses recording, timers, and enables “Resume” icon (icon: circle-play) — which resumes timers and recordings
Stop Icon — starts the process of transcription > Recorder Processing State
If Max duration is arrived, recording automatically stops and begins processing > Recorder Processing State
Recorder Processing State > Success / Failure
The controls + waveform become grayscale and fade off
Below the recorder component we see shimmering text “Transcribing…”
We must process all transcription via Microtask setup! Populate thread_if if available!
If failed, ensure recording is kept as it is — active recorder state is restored with “paused” state
Failure message appears in a sonner, click to copy, needs to be dismissed
Retry Button
If successful:
The Recorder components fade off
Message input box expands again, controls re-enabled
Transcription fades-in (persisted to localstorage right away)
Transcription requires OpenAI or HuggingFace Key, with selected model
For OpenAI we use transcription API via their SDK:
For HuggingFace details here:
====
New Chat page:
Message Input Box
Mic recording icon - the circle around it should be same size as the one with Send message icon button!
On click change Message box to recorder sate (described later)
Implement proper transcription using micro tasks + openaisdk + openai api key - using their transcribe API https://platform.openai.com/docs/guides/speech-to-text
Send message icon button
Use animated icon send-horizontal from https://animate-ui.com/docs/icons , animate on hover
npx shadcn@latest add "https://animate-ui.com/r/send-horizontal-icon.json"
In light mode, use white colour lines to render the icon. In dark mode, use dark colour to render it.
On hover, show box-shadow glow with primary color -using css animate opacity, blur, etc.
Once in focus, we animate particles behind
in light mode they are not visible - darken their colour and increase opacity if needed to make them visible - we need to increase visibility here by 50%
In dark mode, increase their brightness, increasing visibility by 20%
There is a divider inside message box - in dark mode render it with rgba(255, 255, 255, 0.3) and in dark mode with super light grey
Below the message box we show suggested prompts:
By default use text colour at 80% opacity, animate to 100% on hover
===
Removed disabled state - button only appears when fully functional
WHY WOULD YOU DO THAT?? Bring it back! I want the disabled state.
Open AI key is set, Transcription provider is selected, transcription model is selected, enabled transcriotn still nto seeing the mic icon!
2. Sidebar Auto-close - FIXED
NOT WORKING!
2. Sidebar Auto-close - FIXED
NOPE LIES!
——
Recorder States of User Input Box:
Active Recorder State:
To transition to this state from initial state:
Animate height of message box reducing
Other icons fade off - like attachment, prompt library, send icon button, etc.
New Recording UI elements fade-in
Between pause/stop icon and max duration at end - in between you need to render waveform using https://wavesurfer.xyz/
Recorder Processing State:
Retain the same elements as previous state - but fade them out so they look disabled
Animate overlayed text “Transcribing…”
If failed, ensure recording is kept as it is — active recorder state is restored with “paused” state
Failure message appears in a sonner, click to copy, needs to be dismissed
Retry Button
If success, animate:
Recording elements like pause, stop, waveform, timer fade-off
Message box grows back to it’s regular height
Transcribed words appear in the message box input
Recorder:
In Input Message box, if mic icon is clicked, animate to “Active Recorder State”:
Active Recorder State:
Message Input box shrinks in height to 1 line (other controls disappear)
Left Side: Pause icon button (icon: circle-pause), Stop Icon Button (icon: circle-stop), Timer 0:00 > 0:01
Waveform of audio being recorded via mic
At the end: Max duration countdown — 10:00
Pause icon — pauses recording, timers, and enables “Resume” icon (icon: circle-play) — which resumes timers and recordings
Stop Icon — starts the process of transcription > Recorder Processing State
If Max duration is arrived, recording automatically stops and begins processing > Recorder Processing State
Recorder Processing State > Success / Failure
The controls + waveform become grayscale and fade off
Below the recorder component we see shimmering text “Transcribing…”
We must process all transcription via Microtask setup! Populate thread_if if available!
If failed, ensure recording is kept as it is — active recorder state is restored with “paused” state
Failure message appears in a sonner, click to copy, needs to be dismissed
Retry Button
If successful:
The Recorder components fade off
Message input box expands again, controls re-enabled
Transcription fades-in (persisted to localstorage right away)
Transcription requires OpenAI or HuggingFace Key, with selected model
For OpenAI we use transcription API via their SDK:
For HuggingFace details here:
Sidebar:
Implement auto-close: When a link/item is clicked in Sidebar and we navigate to that page (Settings, Chat), close the sidebar once we reach there!
Chat Card: metadata icon - set line thickness to 1px
On hover, animate border colour to primary colour
Theme icons (light/dark/system)
Increase size of icons to match the size of gears icon in settings button before it
Set line thickness for icons to 1px
New Chat Page:
Greeting text:
letter-spacing: -1px;
On hover - for greeting text - animate the icon
User Message Input Box
Recording icon - on hover shows a circle that circle is not matching dimensions/diamtere of circle around send message icon button - grow recording icon circle to match!
Send message icon button
Use animated icon send-horizontal from https://animate-ui.com/docs/icons , animate on hover
npx shadcn@latest add "https://animate-ui.com/r/send-horizontal-icon.json"
In light mode, use white colour lines to render the icon. In dark mode, use dark colour to render it.
On hover, show box-shadow glow with primary color -using css animate opacity, blur, etc.
Audio Recording for Transcription states:
Active State:
Circle pause icon, thickness 1px, colour grey. Reduce space before & after it
On hover, reveal bounded box with grey colour super light - rounded corners, tooltip “Pause Recording”
Circle stop icon, thickness 1px, colour red. Reduce space before & after it
On hover, reveal bounded box with red colour super light - rounded corners, tooltip “Stop & Process Recording”
{MM:SS} timer count up, then “Recording…” after it in horizontal line, currently they are stacked
Waveform - implement properly -
Increase width to cover more span
Render using bars (example later)
Waveform colour use primary colour
{count down timer}, remove “Remanining”
Add icon: trash-2 - on hover - “Delete / Cancel” - on click open confirmation dialogue
There are “Prompt Suggestions” cards below, apply Glass 0 effect to them
Model Selector in top nav:
Once selected, shows a button/card for a model with model’s name as content
If model.is_expensive i.e either of input or output cost is beyond our budget - add this icon after the name of the model within the button: circle-dollar-sign - use red for strokes
Footer:
Copyright, etc. centre align
Waveform Bars
// SoundCloud-style bars
import WaveSurfer from 'wavesurfer.js'
const wavesurfer = WaveSurfer.create({
container: document.body,
waveColor: 'rgb(200, 0, 200)',
progressColor: 'rgb(100, 0, 100)',
url: '/examples/audio/audio.wav',
// Set a bar width
barWidth: 2,
// Optionally, specify the spacing between bars
barGap: 1,
// And the bar radius
barRadius: 2,
})
wavesurfer.once('interaction', () => {
wavesurfer.play()
})
Chat Detail View:
On Scroll Header animation:
Scroll down:
When user scrolls the page - animate the font-size of title going smaller to 16px!
Also animate metadata fading off
Overall height of header/fixed/sticky reducing!
Scroll up: maintain till header is reached, at that point animate back to initial state:
Font-size increases
Metadata fadesin
Header size/height expands
The above described animation should be smooth, eased, use performant CSS or motion.dev if needed!
New Chat Page:
Mic/recording icon in Message box, on hover
Fill - grey, icon - primary colour (dark mode), black (white mode)
Fix Active Recording State in white mode:
Pause/Play icon should be in greay
Refactor:
Components/chat/chat-header.tsx
chat/message-input.tsx
Find all other files that are larger than 300 lines of code
Refactor 2
chat-header.tsx
new-chat-view.tsx
Refactor 3:
app-store.ts (~400+ lines) - Could be split into separate stores
model-selector.tsx (~300+ lines) - Could be further modularized
settings-page.tsx (~250+ lines) - Well organized with components
Do not create any files > 150 lines of code during this process!
2. User Message Input Box
1. Recording icon - on hover shows a circle that circle is not matching dimensions/diamtere of circle around send message icon button - grow recording icon circle to match!
2. Send message icon button
1. Use animated icon send-horizontal from https://animate-ui.com/docs/icons , animate on hover
1. npx shadcn@latest add "https://animate-ui.com/r/send-horizontal-icon.json"
2. In light mode, use white colour lines to render the icon. In dark mode, use dark colour to render it.
3. On hover, show box-shadow glow with primary color -using css animate opacity, blur, etc.
3. Audio Recording for Transcription states:
1. Active State:
1. Circle pause icon, thickness 1px, colour grey. Reduce space before & after it
1. On hover, reveal bounded box with grey colour super light - rounded corners, tooltip “Pause Recording”
2. Circle stop icon, thickness 1px, colour red. Reduce space before & after it
1. On hover, reveal bounded box with red colour super light - rounded corners, tooltip “Stop & Process Recording”
3. {MM:SS} timer count up, then “Recording…” after it in horizontal line, currently they are stacked
4. Waveform - implement properly -
1. Increase width to cover more span
2. Render using bars (example later)
3. Waveform colour use primary colour
5. {count down timer}, remove “Remanining”
6. Add icon: trash-2 - on hover - “Delete / Cancel” - on click open confirmation dialogue
This is still not fixed!
Recording.. still appears below count up timer instead of after it.
Waveform not implemented like in example!!! Waveform width still too less
Delete iocn not implemented!
Still too much spacing between pause/play and stop icons
Hover tooltips are missing!
Still not implemented:
Implement auto-close: When a link/item is clicked in Sidebar and we navigate to that page (Settings, Chat), close the sidebar once we reach there!
Chat Card: metadata icon - set line thickness to 1px
On hover, animate border colour to primary colour
Theme icons (light/dark/system)
Increase size of icons to match the size of gears icon in settings button before it
Set line thickness for icons to 1px
New Chat Page:
Message Inbut Box should be right below the greeting, not at the page bottom!
When in focus, we animate the particles in background - the shift is too sudden - add animation to fade in the parties
Why is the mic icon disabled?! Enable it!! - Get into active recording sate when that happens — BE VERY CAREFUL. CODE FOR THIS ALREADY EXISTS. FIND IT AND USE IT
Suggested Prompt cards should appear below the Message Input Box
Fix 2:
Move the attachment icon to the left!!!
Increase space above the Greeting
Reduce space between Greeting and Message User Input Box [so Greeting + Message Input come vertically in middle of the page]
Message User Input Box
On hover, we show particles in background. Ensure particles are spread across the page - their visibility/opacity dropping radially as well go away from Message Input box
Add animation transition from inactive to active state - fading them in
It has an actual input box inside - remove all border/outlines and animations for it from this input
Between line 1 - attachment, user input, record and send icon buttons. And Line 2 : Prompt Library…. Add a horizontal divider
In dark mode, colour twitch rgba(255,255,255,0.6)
For light mode, colour it light grey
Mic icon hover
in dark mode change icon line colour to white, with 15% opacity white fill as background
In light mode change icon line colour to black, with 1% opacity grey fill as background
Active Recording State, fix waveform! See reference screenshot for design reference! It still does not take width it can, we want bars to me vertically aligned middle, height of bars is not enough!!
The shift from initial to Active Recording sate is sudden, animate it
Reduce height of original message box (0.5s)
Make all elements fade-off (0.5s)
Make recording state icon buttons appear with fade-in (0.7s) + move from right to left (10px in 0.5s), also the same for count up timer
Waveform simply should fade-in
Change border to white + box shadow glow
For transcribing state - make text & overlay fade in - border+glow turns/aniamtes to primary
Transcribing state - remove the pulsating dot before “Transcribing…”
Sidebar:
When we click a Chat card in Sidebar, it goes to the page and Sidebar autocross
Same should happen (auto close sidebar) - when Logo is clicked
Mimir has an aniamted icon in the logo — currently only animates on hover, keep it animating by default
Chat History action icons - search, calendar, bookmark. On hover/click:
Change icon colour to primary, except for bookmark which uses its signature yellow
Theme Icons after Settings - on hover, show tooltip like “Dark” “Light” “System”
New Chat Page: Message Input Box
There are 2 paperclip icons - the one on left is correct, remove the one before mic/readoing icon
There are 2 dividers, the one that goes edge to edge is correct - remove the smaller fainter one!
On focus, we have a nice glow coming out of the message box - but it cuts off at a distance (maybe overflow hidden or something) ensure ti goes to the edges of the page smoothly
Inside there is an actual input or text area field - remove any borders/outlines from it
Suggested Prompt cards - give it Glass 1 treatment - the background
Footer - move all the text to center
New Chat Page: Message Input Box
On focus, we animate particles - ensure they are visible wider than the message box
The glow effect still getting cut off at top/bottom - ensure full smooth spread
Active Recording State:
Reduce the width of the waveform, now delete icon is out of view port box, reduce it by 150px
Chat Detail View:
Messages
Metadata:
Change icon for character cont to icon: case-upper
On Scroll Header animation:
Scroll down:
When user scrolls the page - animate the font-size of title going smaller to 16px!
Also animate metadata fading off
Overall height of header/fixed/sticky reducing!
Scroll up: maintain till header is reached, at that point animate back to initial state:
Font-size increases
Metadata fadesin
Header size/height expands
The above described animation should be smooth, eased, use performant CSS or motion.dev if needed!
New Chat Page:
Reduce spacing between Greeting and Message Input Box by bringing greeting more down
New Message Input Box, on focus - we animate particles in background. But particles are only visible above the box - ensure they are also visible below it and on either sides … fading off as we go further
Particles should be faintly visible even in non-focus state - with reduced opacity and colour and speed
Chat Detail View:
Header
As we scroll 2 open sidebar icons appear! Make sure there is only one!
Below message card:
Metadata + Action icons- data - use colour white 70% opacity, same for action button icons
On hover, css animate - both Icon + data to white 100% for metadata, and for action icons - the icon line
Ensure all icons are 14px x 14px, 1 px line thickness - vertically middle aligned
Increase space on either side of · divider for Metadata
Change sequence to:
Model
Tags
Character
Token
Created at
New Message Input Box
Has a glow on focus state, reduce it’s spread/area - so it doesn’t overpower messages above
New Chat Page:
Reduce spacing between Greeting and Message Input Box by bringing greeting more down
Move entire Greeting + Message box unit down by 2rem
Increase spacing between Suggested Prompts and Message box
The suggested prompts should have Glass 0 treatment! And and use.
Stats Page:
Implement a special page dedicated to Stats
You must query real data from DB to populate this dashboard - no placeholder/dummy/backup/fallback/test data!
Time filters as tabs: 24h, 7d, 30d — for each, we’ll use predefined “bins” - 24h x 1hr =24bins, 7d/6hr bin = 28 bins, 30d/12hr bin=60 bins
All charts, tables on the page must respect / respond to these filters
Card “Chats”: using bar charts
Show total count on top-left
Show bar chart below
Card “Tokens”: using stacked bar charts
Input tokens = blue, output tokens = orange
Below the chart show:
Progress Bar 1: a fill type for each type of token (text token, text cached, tokens, … etc.) fill representing %age of total tokens. On hover, show tooltip with all breakdowns + %ages
Progress Bar 2: Fill %age = Cached Tokens / Total Input Tokens, below the bar on left side {X}% Cached
Card “Microtasks” - using stacked area chart, each area represents task type
Below it show breakdown: Total {count} · {Task Type}: {count}
Below it show a table with: Task Type, Total Count, Success Count, Total Cost, Avg. Cost
Card “Cost”: using stacked area charts
Has 3 tabs inside card, left aligned - Overall, Chats, Microtasks
Overall, shows stacked area charts of input & output cost - where we see cost across chats & microtasks
Chats shows, shows stacked area charts of input & output cost - only for chats (excluding microtasks)
Microtasks, show stacked area chart of cost by Task Type
Below the chart show stats:
Avg. ${X.X}/Chat
Avg. ${X.X}/Microtask
Card “Models”,
shows a progress bar with each fill%age representing model, club all below 1% into a single “Others”
On hover show breakdown by Model & Cost & no. of chats
Below it, a table: Model Name | Input Cost | Output Cost | Total Cost
• 8. Ensure this page is linked from Footer