Alert
Message Alert
A notification about a message from a person: initials tinted from the name, up to three lines of text and a reply. It shows the start of a conversation, not the conversation.
- alert
- message
- notification
- avatar
Preview
Use it with AI
- 1. Copy the link.
- 2. Write to your agent in your own words and drop the link into the sentence.
- 3. The agent opens the link and installs the component from the registry.
put this in the header: https://vibeui.ru/c/alert-007?lang=en
Show the full instructions
What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.
# Install and place "alert-007" (Message Alert) from VibeUI
## 1. Install first — do not skip, do not recreate
Run this exact command before writing any code:
npx shadcn@latest add https://vibeui.ru/r/alert-007.json
Registry item: https://vibeui.ru/r/alert-007.json
Installs to: components/vibeui/alert-007.tsx (the exact path follows this project's components.json aliases).
npm dependencies: none.
Registry dependencies: none.
Install it from the registry. Do not recreate it from the description,
do not substitute a similar component from another library, and do not
rewrite it to match the project's existing style.
## 2. What it is
A notification about a message from a person: initials tinted from the name, up to three lines of text and a reply. It shows the start of a conversation, not the conversation.
A message notification: initials on a tinted circle, name, role, time, up to three lines of text and the Reply and Dismiss actions. The avatar hue is derived from the name, so the author is recognised by colour before the name is read. Zero dependencies, one file, its own palette.
## 3. How to use it
import { Alert007 } from "@/components/vibeui/alert-007"
<Alert007
name="Anna Kovalyova"
role="Art director"
message="Move the pricing block above the testimonials."
time="12 minutes ago"
onReply={openThread}
/>
Read the installed file for the full prop list.
## 4. Where to place it
This is a small inline component. Put it exactly where the user asked,
inside the existing markup. Do not create a new page, section or
wrapper for it. If a similar control already sits in that spot,
replace it instead of adding a second one.
Placement: ___
(The user fills this line in. If it is still blank, ask where to put it
instead of guessing.)
## 5. Keep exactly as installed
- the local --vibeui-alert-007-* palette — do not swap it for your theme tokens (bg-muted, text-primary and the like)
- deriving the hue from the name: a random colour would change on every render and stop identifying the person
- clamping the text to three lines: a notification shows the start of a conversation, not the thread
- initials instead of a photo: an avatar rarely ships with the notification, and a silhouette placeholder is worse than two letters
- the time on the right and its wrapping in a narrow column
- Reply in the accent colour and Dismiss muted: they carry different weight
- the <style> block inside the component — it holds the palette and the layout
## 6. You may change
- name and role — the author; the colour comes from the name too
- message — the text; the overflow clamps itself
- time — a string formatted by the caller
- the onReply and onDismiss handlers
- width and outer spacing through className
## 7. Rules
- The component neither opens the thread nor marks anything read — that is the caller's job in onReply.
- Do not pass markup in message: the line clamp works on text and nested blocks break it.
- For a system message with no author use alert-001, where an avatar would be an empty circle.
- Do not lift the CSS variables into globals.css: the component has to stay a single file.
## 8. Verify
- it renders with no console errors;
- it looks like the preview on the VibeUI page you copied this from;
- if it does not, you changed something listed in section 5 — put it back.For developers
npx shadcn@latest add https://vibeui.ru/r/alert-007.jsonhttps://vibeui.ru/r/alert-007.jsonКомпонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-alert-007-*. Оттенок аватара считается из имени детерминированной функцией и подставляется в --vibeui-alert-007-hue: тот же приём, что в avatar-001, поэтому один человек всегда одного цвета. Текст сообщения обрезается тремя строками через -webkit-line-clamp. Время прижимается вправо через margin-left:auto и переносится в узкой колонке.
Component source
The same file your agent installs. Here in case you would rather copy it by hand.
import type { ComponentPropsWithoutRef, CSSProperties } from "react"
export type Alert007Props = Omit<
ComponentPropsWithoutRef<"div">,
"children"
> & {
name?: string
role?: string
message?: string
time?: string
replyLabel?: string
onReply?: () => void
onDismiss?: () => void
accent?: string
}
// Идея компонента: уведомление о сообщении от человека. Слева инициалы с
// оттенком, выведенным из имени, — тот же приём, что в аватаре: один человек
// всегда одного цвета. Текст сообщения показывается целиком до трёх строк и
// дальше обрывается многоточием, потому что уведомление — не переписка.
const STYLES = `
:where([data-vibeui-block="alert-007"]){
--vibeui-alert-007-fg:oklch(0.22 0.014 265);
--vibeui-alert-007-muted:oklch(0.5 0.014 265);
--vibeui-alert-007-bg:oklch(1 0 0);
--vibeui-alert-007-border:oklch(0.9 0.006 265);
--vibeui-alert-007-accent:oklch(0.55 0.2 262);
--vibeui-alert-007-hue:250;
--vibeui-alert-007-radius:0.875rem;
--vibeui-alert-007-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
container-type:inline-size;
}
[data-vibeui-block="alert-007"]{
display:flex;align-items:flex-start;gap:0.75rem;
width:100%;box-sizing:border-box;
padding:0.875rem 1rem;
border:1px solid var(--vibeui-alert-007-border);
border-radius:var(--vibeui-alert-007-radius);
background:var(--vibeui-alert-007-bg);color:var(--vibeui-alert-007-fg);
font-family:var(--vibeui-alert-007-font);
}
/* Инициалы: оттенок выводится из имени, поэтому автор узнаётся по цвету. */
[data-vibeui-block="alert-007"] [data-part="avatar"]{
display:flex;align-items:center;justify-content:center;flex:none;
width:2.25rem;height:2.25rem;border-radius:9999px;
background:oklch(0.92 0.05 var(--vibeui-alert-007-hue));
color:oklch(0.38 0.09 var(--vibeui-alert-007-hue));
font-size:0.75rem;font-weight:650;
}
[data-vibeui-block="alert-007"] [data-part="text"]{display:flex;flex-direction:column;gap:0.1875rem;flex:1 1 auto;min-width:0}
[data-vibeui-block="alert-007"] [data-part="head"]{display:flex;align-items:baseline;gap:0.5rem;flex-wrap:wrap}
[data-vibeui-block="alert-007"] [data-part="name"]{font-size:0.875rem;font-weight:600}
[data-vibeui-block="alert-007"] [data-part="role"]{font-size:0.75rem;color:var(--vibeui-alert-007-muted)}
[data-vibeui-block="alert-007"] [data-part="time"]{margin-left:auto;font-size:0.75rem;color:var(--vibeui-alert-007-muted);white-space:nowrap}
/* До трёх строк: уведомление показывает начало сообщения, а не переписку. */
[data-vibeui-block="alert-007"] [data-part="message"]{
font-size:0.875rem;line-height:1.55;color:var(--vibeui-alert-007-muted);
display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
}
[data-vibeui-block="alert-007"] [data-part="actions"]{display:flex;align-items:center;gap:0.75rem;margin-top:0.4375rem}
[data-vibeui-block="alert-007"] button{
appearance:none;cursor:pointer;font:inherit;font-size:0.8125rem;font-weight:600;
border:0;background:none;padding:0;
}
[data-vibeui-block="alert-007"] [data-part="reply"]{color:var(--vibeui-alert-007-accent)}
[data-vibeui-block="alert-007"] [data-part="dismiss"]{color:var(--vibeui-alert-007-muted);font-weight:500}
[data-vibeui-block="alert-007"] [data-part="dismiss"]:hover{color:var(--vibeui-alert-007-fg)}
[data-vibeui-block="alert-007"] button:focus-visible{outline:2px solid var(--vibeui-alert-007-accent);outline-offset:2px;border-radius:0.25rem}
@container (max-width: 22rem){
[data-vibeui-block="alert-007"] [data-part="time"]{margin-left:0}
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="alert-007"] *{animation:none!important;transition:none!important}}
`
/** Оттенок из имени: один человек всегда одного цвета. */
function hueOf(name: string): number {
let sum = 0
for (let index = 0; index < name.length; index += 1) {
sum = (sum + name.charCodeAt(index) * (index + 1)) % 360
}
return sum
}
function initialsOf(name: string): string {
return name
.trim()
.split(/\s+/)
.slice(0, 2)
.map((word) => word.charAt(0).toUpperCase())
.join("")
}
/**
* Уведомление о сообщении: инициалы, текст до трёх строк и ответ.
* Один файл, ноль зависимостей, собственная палитра.
*/
export function Alert007({
name = "Анна Ковалёва",
role = "Арт-директор",
message = "Посмотрела главную — блок с тарифами лучше поднять выше отзывов. И на мобильном заголовок переносится некрасиво, гляньте.",
time = "12 минут назад",
replyLabel = "Ответить",
onReply,
onDismiss,
accent,
className,
style,
...props
}: Alert007Props) {
const palette = {
"--vibeui-alert-007-hue": hueOf(name),
...(accent ? { "--vibeui-alert-007-accent": accent } : null),
...style,
} as CSSProperties
return (
<>
<style href="vibeui-alert-007" precedence="medium">
{STYLES}
</style>
<div
{...props}
data-vibeui-block="alert-007"
role="status"
className={className}
style={palette}
>
<span data-part="avatar" aria-hidden="true">
{initialsOf(name)}
</span>
<span data-part="text">
<span data-part="head">
<span data-part="name">{name}</span>
{role ? <span data-part="role">{role}</span> : null}
{time ? <span data-part="time">{time}</span> : null}
</span>
<span data-part="message">{message}</span>
<span data-part="actions">
{replyLabel ? (
<button data-part="reply" type="button" onClick={onReply}>
{replyLabel}
</button>
) : null}
{onDismiss ? (
<button data-part="dismiss" type="button" onClick={onDismiss}>
Скрыть
</button>
) : null}
</span>
</span>
</div>
</>
)
}