mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 17:29:45 +00:00
feat(inbox): WhatsApp-style doodle background in the chat area
Adds a subtle, repeating SVG pattern behind the message thread and the "select a conversation" empty state — same visual language WhatsApp uses in their own chat UI, themed for a CRM (message bubble, phone, mail, calendar, lightbulb, briefcase, trophy, dollar sign, percent, etc). Asset: public/inbox-doodle.svg, 6 KB, 240×240 tile that repeats seamlessly. Icon shapes are taken verbatim from lucide-react (already a dependency, every other icon in the UI uses it) so the doodle reads as part of the same visual system, not a separate clip-art import. Stroke is slate-500 at 22% opacity over bg-slate-950 — visible but not competing with message text. Wiring: a single DOODLE_BG_CLASSES constant in message-thread.tsx applied to both the empty-state and active-thread containers, so they can't drift. The header keeps bg-slate-900 (solid) and the composer keeps its own background, so the doodle only shows in the actual message scroll area — exactly like WhatsApp. No JS, no perf hit beyond a one-off 6 KB asset fetch that's then browser-cached forever (it's served from /public with Next's default caching). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3de2da6cca
commit
598ac7e66d
139
public/inbox-doodle.svg
Normal file
139
public/inbox-doodle.svg
Normal file
@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
WhatsApp-style doodle background for the inbox message area.
|
||||
|
||||
Design notes:
|
||||
- 240x240 tile, repeats seamlessly via CSS background-repeat. Icons stay
|
||||
inside a (10, 10) → (217, 217) safe zone so the tile boundary always
|
||||
falls in empty space; no icon is ever cut in half by a seam.
|
||||
- Icon shapes are taken verbatim from lucide-react (which the app already
|
||||
ships) so they sit visually consistent with every other icon in the UI.
|
||||
- Stroke color is slate-500 (#64748b) at 22% opacity — visible against
|
||||
bg-slate-950 (#020617) without competing with message text.
|
||||
- All shapes use stroke + fill:none + round caps to match the lucide
|
||||
line-art style.
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="240" viewBox="0 0 240 240" fill="none" stroke="#64748b" stroke-opacity="0.22" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
|
||||
<!-- 1. MessageSquare @ (30,22) s=0.95 -->
|
||||
<g transform="translate(30 22) scale(0.95)">
|
||||
<path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"/>
|
||||
</g>
|
||||
|
||||
<!-- 2. Phone @ (95,18) s=0.85 r=-12 -->
|
||||
<g transform="translate(95 18) scale(0.85) rotate(-12 12 12)">
|
||||
<path d="M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384"/>
|
||||
</g>
|
||||
|
||||
<!-- 3. Star @ (160,28) s=0.75 -->
|
||||
<g transform="translate(160 28) scale(0.75)">
|
||||
<path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"/>
|
||||
</g>
|
||||
|
||||
<!-- 4. Heart @ (200,28) s=0.7 r=8 -->
|
||||
<g transform="translate(200 28) scale(0.7) rotate(8 12 12)">
|
||||
<path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"/>
|
||||
</g>
|
||||
|
||||
<!-- 5. Calendar @ (50,70) s=0.9 r=5 -->
|
||||
<g transform="translate(50 70) scale(0.9) rotate(5 12 12)">
|
||||
<path d="M8 2v4"/>
|
||||
<path d="M16 2v4"/>
|
||||
<rect width="18" height="18" x="3" y="4" rx="2"/>
|
||||
<path d="M3 10h18"/>
|
||||
</g>
|
||||
|
||||
<!-- 6. Lightbulb @ (130,60) s=0.85 r=-8 -->
|
||||
<g transform="translate(130 60) scale(0.85) rotate(-8 12 12)">
|
||||
<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/>
|
||||
<path d="M9 18h6"/>
|
||||
<path d="M10 22h4"/>
|
||||
</g>
|
||||
|
||||
<!-- 7. BarChart @ (198,70) s=0.85 -->
|
||||
<g transform="translate(198 70) scale(0.85)">
|
||||
<path d="M5 21v-6"/>
|
||||
<path d="M12 21V9"/>
|
||||
<path d="M19 21V3"/>
|
||||
</g>
|
||||
|
||||
<!-- 8. Users @ (25,115) s=0.85 -->
|
||||
<g transform="translate(25 115) scale(0.85)">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
||||
<path d="M16 3.128a4 4 0 0 1 0 7.744"/>
|
||||
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
|
||||
<circle cx="9" cy="7" r="4"/>
|
||||
</g>
|
||||
|
||||
<!-- 9. DollarSign @ (90,110) s=0.8 r=-5 -->
|
||||
<g transform="translate(90 110) scale(0.8) rotate(-5 12 12)">
|
||||
<line x1="12" x2="12" y1="2" y2="22"/>
|
||||
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
||||
</g>
|
||||
|
||||
<!-- 10. Trophy @ (152,118) s=0.85 -->
|
||||
<g transform="translate(152 118) scale(0.85)">
|
||||
<path d="M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978"/>
|
||||
<path d="M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978"/>
|
||||
<path d="M18 9h1.5a1 1 0 0 0 0-5H18"/>
|
||||
<path d="M4 22h16"/>
|
||||
<path d="M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z"/>
|
||||
<path d="M6 9H4.5a1 1 0 0 1 0-5H6"/>
|
||||
</g>
|
||||
|
||||
<!-- 11. Smile @ (205,108) s=0.7 r=10 -->
|
||||
<g transform="translate(205 108) scale(0.7) rotate(10 12 12)">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<path d="M8 14s1.5 2 4 2 4-2 4-2"/>
|
||||
<line x1="9" x2="9.01" y1="9" y2="9"/>
|
||||
<line x1="15" x2="15.01" y1="9" y2="9"/>
|
||||
</g>
|
||||
|
||||
<!-- 12. Globe @ (45,158) s=0.85 -->
|
||||
<g transform="translate(45 158) scale(0.85)">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/>
|
||||
<path d="M2 12h20"/>
|
||||
</g>
|
||||
|
||||
<!-- 13. Mail @ (115,152) s=0.9 r=8 -->
|
||||
<g transform="translate(115 152) scale(0.9) rotate(8 12 12)">
|
||||
<rect x="2" y="4" width="20" height="16" rx="2"/>
|
||||
<path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7"/>
|
||||
</g>
|
||||
|
||||
<!-- 14. Briefcase @ (178,165) s=0.85 r=-4 -->
|
||||
<g transform="translate(178 165) scale(0.85) rotate(-4 12 12)">
|
||||
<path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
|
||||
<rect width="20" height="14" x="2" y="6" rx="2"/>
|
||||
</g>
|
||||
|
||||
<!-- 15. CheckCircle @ (25,200) s=0.8 r=-10 -->
|
||||
<g transform="translate(25 200) scale(0.8) rotate(-10 12 12)">
|
||||
<path d="M21.801 10A10 10 0 1 1 17 3.335"/>
|
||||
<path d="m9 11 3 3L22 4"/>
|
||||
</g>
|
||||
|
||||
<!-- 16. Percent @ (90,208) s=0.75 -->
|
||||
<g transform="translate(90 208) scale(0.75)">
|
||||
<line x1="19" x2="5" y1="5" y2="19"/>
|
||||
<circle cx="6.5" cy="6.5" r="2.5"/>
|
||||
<circle cx="17.5" cy="17.5" r="2.5"/>
|
||||
</g>
|
||||
|
||||
<!-- 17. ShoppingCart @ (152,205) s=0.8 r=5 -->
|
||||
<g transform="translate(152 205) scale(0.8) rotate(5 12 12)">
|
||||
<circle cx="8" cy="21" r="1"/>
|
||||
<circle cx="19" cy="21" r="1"/>
|
||||
<path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12"/>
|
||||
</g>
|
||||
|
||||
<!-- 18. Rocket @ (208,198) s=0.7 r=15 -->
|
||||
<g transform="translate(208 198) scale(0.7) rotate(15 12 12)">
|
||||
<path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/>
|
||||
<path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09"/>
|
||||
<path d="M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z"/>
|
||||
<path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
@ -110,6 +110,18 @@ const STATUS_OPTIONS: { label: string; value: ConversationStatus; color: string
|
||||
{ label: "Closed", value: "closed", color: "text-slate-400" },
|
||||
];
|
||||
|
||||
/**
|
||||
* WhatsApp-style doodle background applied to the chat area (both the
|
||||
* active thread and the empty state). The SVG tile lives at
|
||||
* `/public/inbox-doodle.svg`; the slate-950 colour sits underneath so
|
||||
* the doodles read as a subtle pattern rather than a stark grid.
|
||||
*
|
||||
* Defined once at module scope so the two render paths can't drift —
|
||||
* if we ever switch the asset, both spots update together.
|
||||
*/
|
||||
const DOODLE_BG_CLASSES =
|
||||
"bg-slate-950 bg-[url('/inbox-doodle.svg')] bg-repeat";
|
||||
|
||||
export function MessageThread({
|
||||
conversation,
|
||||
contact,
|
||||
@ -629,10 +641,12 @@ export function MessageThread({
|
||||
[conversation, onAssignChange],
|
||||
);
|
||||
|
||||
// Empty state
|
||||
// Empty state — same WhatsApp-style doodle background as the active
|
||||
// thread below, so swapping between empty/selected doesn't change the
|
||||
// pattern under the user's eye.
|
||||
if (!conversation || !contact) {
|
||||
return (
|
||||
<div className="flex flex-1 flex-col items-center justify-center bg-slate-950">
|
||||
<div className={cn("flex flex-1 flex-col items-center justify-center", DOODLE_BG_CLASSES)}>
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-slate-800">
|
||||
<MessageSquare className="h-8 w-8 text-slate-600" />
|
||||
</div>
|
||||
@ -658,8 +672,9 @@ export function MessageThread({
|
||||
: "Assign";
|
||||
|
||||
return (
|
||||
<div className="flex flex-1 flex-col bg-slate-950">
|
||||
{/* Header */}
|
||||
<div className={cn("flex flex-1 flex-col", DOODLE_BG_CLASSES)}>
|
||||
{/* Header — solid bg-slate-900 sits on top of the doodle so the
|
||||
name/avatar/dropdowns stay legible. */}
|
||||
<div className="flex items-center justify-between gap-2 border-b border-slate-800 bg-slate-900 px-3 py-3 sm:px-4">
|
||||
<div className="flex min-w-0 items-center gap-2 sm:gap-3">
|
||||
{/* Back-to-list button — mobile only. Hidden on lg+ where the
|
||||
|
||||
Loading…
Reference in New Issue
Block a user