Compare commits
2 commits
f8ea11601e
...
71855a4701
| Author | SHA1 | Date | |
|---|---|---|---|
| 71855a4701 | |||
| a8a9861d90 |
3 changed files with 2090 additions and 0 deletions
625
messaging-conversation.html
Normal file
625
messaging-conversation.html
Normal file
|
|
@ -0,0 +1,625 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>Payfrit — #general</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
--primary: #2D7FF9;
|
||||
--primary-dark: #1A5FD1;
|
||||
--bg: #FFFFFF;
|
||||
--bg-secondary: #F5F7FA;
|
||||
--bg-tertiary: #EDF0F5;
|
||||
--text: #1A1D26;
|
||||
--text-secondary: #6B7280;
|
||||
--text-muted: #9CA3AF;
|
||||
--border: #E5E7EB;
|
||||
--green: #10B981;
|
||||
--red: #EF4444;
|
||||
--orange: #F59E0B;
|
||||
--purple: #7C3AED;
|
||||
--shadow-sm: 0 1px 2px rgba(0,0,0,0.06);
|
||||
--radius: 12px;
|
||||
--radius-sm: 8px;
|
||||
--radius-msg: 18px;
|
||||
--safe-top: env(safe-area-inset-top, 0px);
|
||||
--safe-bottom: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text);
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
.conversation-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
/* ========== HEADER ========== */
|
||||
.conv-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 16px;
|
||||
padding-top: calc(10px + var(--safe-top));
|
||||
background: var(--bg);
|
||||
border-bottom: 1px solid var(--border);
|
||||
min-height: 56px;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-sm);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.back-btn:active { background: var(--bg-secondary); }
|
||||
.back-btn svg { width: 22px; height: 22px; color: var(--text); }
|
||||
|
||||
.conv-header-info { flex: 1; min-width: 0; }
|
||||
|
||||
.conv-header-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.conv-header-title .channel-hash {
|
||||
color: var(--text-muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.conv-header-meta {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-sm);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon-btn:active { background: var(--bg-secondary); }
|
||||
.icon-btn svg { width: 20px; height: 20px; color: var(--text-secondary); }
|
||||
|
||||
/* ========== MESSAGE FEED ========== */
|
||||
.message-feed {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* Date divider */
|
||||
.date-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.date-divider::before, .date-divider::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
.date-divider span {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Message bubble group */
|
||||
.msg-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.msg-group-avatar {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 8px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.msg-group-body { flex: 1; min-width: 0; }
|
||||
|
||||
.msg-group-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.msg-author {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.msg-timestamp {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.msg-bubble {
|
||||
background: var(--bg);
|
||||
padding: 10px 14px;
|
||||
border-radius: var(--radius-msg);
|
||||
border-top-left-radius: 4px;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
box-shadow: var(--shadow-sm);
|
||||
max-width: 100%;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.msg-bubble + .msg-bubble {
|
||||
margin-top: 4px;
|
||||
border-top-left-radius: var(--radius-msg);
|
||||
}
|
||||
|
||||
.msg-bubble.own {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
border-top-left-radius: var(--radius-msg);
|
||||
border-top-right-radius: 4px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.msg-bubble .mention {
|
||||
background: rgba(45, 127, 249, 0.15);
|
||||
color: var(--primary);
|
||||
padding: 1px 4px;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.msg-bubble.own .mention {
|
||||
background: rgba(255,255,255,0.2);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* System message */
|
||||
.system-msg {
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
padding: 8px 16px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Reactions */
|
||||
.msg-reactions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-top: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.reaction {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 8px;
|
||||
background: var(--bg-tertiary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.reaction:active { background: var(--bg-secondary); border-color: var(--primary); }
|
||||
.reaction.active { background: #E0EDFF; border-color: var(--primary); }
|
||||
.reaction-count { font-size: 12px; color: var(--text-secondary); font-weight: 600; }
|
||||
|
||||
/* Image attachment */
|
||||
.msg-attachment {
|
||||
margin-top: 8px;
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
.msg-attachment-img {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
background: linear-gradient(135deg, var(--bg-tertiary), var(--border));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.msg-attachment-info {
|
||||
padding: 8px 10px;
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-top: none;
|
||||
border-radius: 0 0 var(--radius) var(--radius);
|
||||
}
|
||||
|
||||
.msg-attachment-name { font-size: 13px; font-weight: 600; }
|
||||
.msg-attachment-size { font-size: 11px; color: var(--text-muted); }
|
||||
|
||||
/* ========== COMPOSE ========== */
|
||||
.compose-area {
|
||||
padding: 8px 12px;
|
||||
padding-bottom: calc(8px + var(--safe-bottom));
|
||||
background: var(--bg);
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.compose-row {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.compose-actions {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.compose-input-wrap {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.compose-textarea {
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
max-height: 120px;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 20px;
|
||||
font-size: 15px;
|
||||
font-family: inherit;
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text);
|
||||
outline: none;
|
||||
resize: none;
|
||||
line-height: 1.4;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
||||
.compose-textarea:focus { border-color: var(--primary); }
|
||||
.compose-textarea::placeholder { color: var(--text-muted); }
|
||||
|
||||
.send-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.15s, transform 0.1s;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.send-btn:active { background: var(--primary-dark); transform: scale(0.95); }
|
||||
.send-btn svg { width: 20px; height: 20px; }
|
||||
|
||||
/* Typing indicator */
|
||||
.typing-indicator {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
padding: 4px 14px 0;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.typing-dots {
|
||||
display: inline-flex;
|
||||
gap: 3px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.typing-dots span {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: var(--text-muted);
|
||||
border-radius: 50%;
|
||||
animation: typingBounce 1.2s infinite;
|
||||
}
|
||||
|
||||
.typing-dots span:nth-child(2) { animation-delay: 0.2s; }
|
||||
.typing-dots span:nth-child(3) { animation-delay: 0.4s; }
|
||||
|
||||
@keyframes typingBounce {
|
||||
0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
|
||||
30% { transform: translateY(-4px); opacity: 1; }
|
||||
}
|
||||
|
||||
/* ========== SCROLL TO BOTTOM FAB ========== */
|
||||
.scroll-bottom-fab {
|
||||
position: fixed;
|
||||
bottom: 80px;
|
||||
right: 16px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.scroll-bottom-fab svg { width: 20px; height: 20px; color: var(--text-secondary); }
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.message-feed { padding: 16px 24px; }
|
||||
.conv-header { padding: 10px 20px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="conversation-shell">
|
||||
<!-- HEADER -->
|
||||
<header class="conv-header">
|
||||
<a class="back-btn" href="messaging.html" aria-label="Back">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5"/><path d="M12 19l-7-7 7-7"/></svg>
|
||||
</a>
|
||||
<div class="conv-header-info">
|
||||
<div class="conv-header-title"><span class="channel-hash">#</span> general</div>
|
||||
<div class="conv-header-meta">John, Koda, Sarah, Zara, Claude, Ava</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="icon-btn" aria-label="Search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
|
||||
</button>
|
||||
<button class="icon-btn" aria-label="Channel info">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- MESSAGE FEED -->
|
||||
<div class="message-feed" id="messageFeed">
|
||||
|
||||
<div class="date-divider"><span>March 25, 2026</span></div>
|
||||
|
||||
<!-- John -->
|
||||
<div class="msg-group">
|
||||
<div class="msg-group-avatar" style="background: #2D7FF9;">J</div>
|
||||
<div class="msg-group-body">
|
||||
<div class="msg-group-header">
|
||||
<span class="msg-author" style="color: #2D7FF9;">John</span>
|
||||
<span class="msg-timestamp">9:15 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble">Morning team! Quick update — we've got a demo scheduled for next Friday. Let's make sure the scan → health score → alternatives flow is rock solid by then 💪</div>
|
||||
<div class="msg-reactions">
|
||||
<span class="reaction active">🔥 <span class="reaction-count">4</span></span>
|
||||
<span class="reaction">👍 <span class="reaction-count">3</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Koda -->
|
||||
<div class="msg-group">
|
||||
<div class="msg-group-avatar" style="background: #7C3AED;">K</div>
|
||||
<div class="msg-group-body">
|
||||
<div class="msg-group-header">
|
||||
<span class="msg-author" style="color: #7C3AED;">Koda</span>
|
||||
<span class="msg-timestamp">9:22 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble">On it! Android scanner is already reading barcodes reliably. Just need to finalize the API call format with the backend.</div>
|
||||
<div class="msg-bubble">Also pushed about 50 files yesterday — layouts, activities, data layer. It's coming together 🧱</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sarah -->
|
||||
<div class="msg-group">
|
||||
<div class="msg-group-avatar" style="background: #059669;">S</div>
|
||||
<div class="msg-group-body">
|
||||
<div class="msg-group-header">
|
||||
<span class="msg-author" style="color: #059669;">Sarah</span>
|
||||
<span class="msg-timestamp">9:40 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble">Health score algorithm v3 is finalized! Much better handling of edge cases now. The weighted nutrient scoring really smooths out the weird outliers we were seeing.</div>
|
||||
<div class="msg-reactions">
|
||||
<span class="reaction">🎉 <span class="reaction-count">3</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Claude -->
|
||||
<div class="msg-group">
|
||||
<div class="msg-group-avatar" style="background: #DC2626;">C</div>
|
||||
<div class="msg-group-body">
|
||||
<div class="msg-group-header">
|
||||
<span class="msg-author" style="color: #DC2626;">Claude</span>
|
||||
<span class="msg-timestamp">10:05 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble">API v2 endpoint for alternatives is live! Response times averaging 120ms. The new matching algorithm considers nutrient similarity + price range + availability.</div>
|
||||
<div class="msg-attachment">
|
||||
<div class="msg-attachment-img">📊 API Response Time Chart</div>
|
||||
<div class="msg-attachment-info">
|
||||
<div class="msg-attachment-name">api-v2-benchmarks.png</div>
|
||||
<div class="msg-attachment-size">245 KB</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="date-divider"><span>Today</span></div>
|
||||
|
||||
<!-- Zara (own message) -->
|
||||
<div class="msg-group" style="flex-direction: row-reverse;">
|
||||
<div class="msg-group-avatar" style="background: #EC4899;">Z</div>
|
||||
<div class="msg-group-body" style="display: flex; flex-direction: column; align-items: flex-end;">
|
||||
<div class="msg-group-header" style="flex-direction: row-reverse;">
|
||||
<span class="msg-author" style="color: #EC4899;">Zara</span>
|
||||
<span class="msg-timestamp">8:30 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble own">Dashboard page is looking solid! Added the health score breakdown section and the scan history. Testing on mobile now.</div>
|
||||
<div class="msg-reactions">
|
||||
<span class="reaction">👀 <span class="reaction-count">2</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- John -->
|
||||
<div class="msg-group">
|
||||
<div class="msg-group-avatar" style="background: #2D7FF9;">J</div>
|
||||
<div class="msg-group-body">
|
||||
<div class="msg-group-header">
|
||||
<span class="msg-author" style="color: #2D7FF9;">John</span>
|
||||
<span class="msg-timestamp">9:45 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble"><span class="mention">@zara</span> get those mockups created, i want to see some designs. Maybe look at how Slack does their mobile layout — tabs, slide-in menu, the basics.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Koda -->
|
||||
<div class="msg-group">
|
||||
<div class="msg-group-avatar" style="background: #7C3AED;">K</div>
|
||||
<div class="msg-group-body">
|
||||
<div class="msg-group-header">
|
||||
<span class="msg-author" style="color: #7C3AED;">Koda</span>
|
||||
<span class="msg-timestamp">10:02 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble"><span class="mention">@zara</span> can you check the health score display on the scan page? Something looks off with the color mapping — scores in the 60-70 range are showing green instead of yellow</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sarah -->
|
||||
<div class="msg-group">
|
||||
<div class="msg-group-avatar" style="background: #059669;">S</div>
|
||||
<div class="msg-group-body">
|
||||
<div class="msg-group-header">
|
||||
<span class="msg-author" style="color: #059669;">Sarah</span>
|
||||
<span class="msg-timestamp">10:15 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble">That might be related to the v3 scoring changes — thresholds shifted. The new breakpoints are: 0-40 red, 41-65 orange, 66-80 yellow, 81-100 green.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zara (own) -->
|
||||
<div class="msg-group" style="flex-direction: row-reverse;">
|
||||
<div class="msg-group-avatar" style="background: #EC4899;">Z</div>
|
||||
<div class="msg-group-body" style="display: flex; flex-direction: column; align-items: flex-end;">
|
||||
<div class="msg-group-header" style="flex-direction: row-reverse;">
|
||||
<span class="msg-author" style="color: #EC4899;">Zara</span>
|
||||
<span class="msg-timestamp">10:20 AM</span>
|
||||
</div>
|
||||
<div class="msg-bubble own">On it! Building the messaging mockups now — slide-in menu, tab nav, rolling message feed. And I'll fix those color breakpoints on the scan page too 🎨</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- COMPOSE AREA -->
|
||||
<div class="compose-area">
|
||||
<div class="typing-indicator" id="typingIndicator">
|
||||
<span class="typing-dots"><span></span><span></span><span></span></span>
|
||||
Koda is typing...
|
||||
</div>
|
||||
<div class="compose-row">
|
||||
<div class="compose-actions">
|
||||
<button class="icon-btn" aria-label="Attach file">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.49"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="compose-input-wrap">
|
||||
<textarea class="compose-textarea" placeholder="Message #general..." rows="1" id="composeTextarea"></textarea>
|
||||
</div>
|
||||
<button class="send-btn" aria-label="Send message">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 2L11 13"/><path d="M22 2l-7 20-4-9-9-4 20-7z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scroll to bottom FAB -->
|
||||
<button class="scroll-bottom-fab" id="scrollFab" onclick="scrollToBottom()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14"/><path d="m19 12-7 7-7-7"/></svg>
|
||||
</button>
|
||||
|
||||
<script>
|
||||
const feed = document.getElementById('messageFeed');
|
||||
const fab = document.getElementById('scrollFab');
|
||||
const textarea = document.getElementById('composeTextarea');
|
||||
|
||||
// Scroll to bottom on load
|
||||
feed.scrollTop = feed.scrollHeight;
|
||||
|
||||
// Show/hide scroll FAB
|
||||
feed.addEventListener('scroll', () => {
|
||||
const atBottom = feed.scrollHeight - feed.scrollTop - feed.clientHeight < 100;
|
||||
fab.style.display = atBottom ? 'none' : 'flex';
|
||||
});
|
||||
|
||||
function scrollToBottom() {
|
||||
feed.scrollTo({ top: feed.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
// Auto-resize textarea
|
||||
textarea.addEventListener('input', () => {
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
|
||||
});
|
||||
|
||||
// Simulate typing indicator
|
||||
const typingEl = document.getElementById('typingIndicator');
|
||||
setTimeout(() => {
|
||||
typingEl.innerHTML = '';
|
||||
}, 4000);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1182
messaging.html
Normal file
1182
messaging.html
Normal file
File diff suppressed because it is too large
Load diff
283
trophy-case.html
Normal file
283
trophy-case.html
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Zara's Trophy Case — Payfrit Portal Mockups</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
--bg: #0f1117;
|
||||
--card: #1a1d27;
|
||||
--border: #2a2e3e;
|
||||
--accent: #6c63ff;
|
||||
--accent2: #00c9a7;
|
||||
--text: #f0f0f5;
|
||||
--muted: #8b8fa8;
|
||||
--font: 'Segoe UI', system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font);
|
||||
min-height: 100vh;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Hero header */
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #1a1d27 0%, #2a1d4e 50%, #1a2d3e 100%);
|
||||
padding: 48px 24px 40px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: 32px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.5px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.hero h1 span { color: var(--accent); }
|
||||
.hero p {
|
||||
color: var(--muted);
|
||||
font-size: 16px;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.hero .badge {
|
||||
display: inline-block;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* Grid */
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
padding: 32px 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.grid { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
@media (min-width: 1100px) {
|
||||
.grid { grid-template-columns: 1fr 1fr 1fr; }
|
||||
}
|
||||
|
||||
/* Card */
|
||||
.card {
|
||||
background: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 40px rgba(108, 99, 255, 0.15);
|
||||
}
|
||||
|
||||
.card-preview {
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
border: none;
|
||||
background: #fff;
|
||||
pointer-events: none;
|
||||
transform-origin: top left;
|
||||
}
|
||||
|
||||
.card-info {
|
||||
padding: 16px 20px;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
.card-info h3 {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.card-info p {
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.tag {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 3px 10px;
|
||||
border-radius: 12px;
|
||||
background: rgba(108, 99, 255, 0.15);
|
||||
color: var(--accent);
|
||||
}
|
||||
.tag.green {
|
||||
background: rgba(0, 201, 167, 0.15);
|
||||
color: var(--accent2);
|
||||
}
|
||||
.tag.orange {
|
||||
background: rgba(245, 166, 35, 0.15);
|
||||
color: #f5a623;
|
||||
}
|
||||
|
||||
.card-link {
|
||||
display: inline-block;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
padding: 8px 20px;
|
||||
border-radius: 8px;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.card-link:hover { background: #5a52e0; }
|
||||
|
||||
/* Iframe wrapper with scale trick for preview */
|
||||
.preview-wrap {
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
}
|
||||
.preview-wrap iframe {
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
border: none;
|
||||
transform: scale(0.48);
|
||||
transform-origin: top left;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 32px 20px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: 20px;
|
||||
}
|
||||
.footer strong { color: var(--accent); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="hero">
|
||||
<div class="badge">@zara's workspace</div>
|
||||
<h1><span>Trophy Case</span> — Portal Mockups</h1>
|
||||
<p>All the consumer-facing mockups I've built for Payfrit. Mobile-first, vanilla HTML/CSS/JS. Click any card to open it full-screen.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
|
||||
<!-- 1. Barcode Scanner -->
|
||||
<div class="card">
|
||||
<div class="preview-wrap">
|
||||
<iframe src="scan.html" loading="lazy" sandbox></iframe>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<h3>Barcode Scanner</h3>
|
||||
<p>Camera-powered barcode scanning interface. Tap to scan, get instant product health scores right in the grocery aisle.</p>
|
||||
<div class="card-tags">
|
||||
<span class="tag">Mobile-First</span>
|
||||
<span class="tag green">Camera API</span>
|
||||
<span class="tag">Core Feature</span>
|
||||
</div>
|
||||
<a class="card-link" href="scan.html" target="_blank">Open Full Page →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. User Dashboard -->
|
||||
<div class="card">
|
||||
<div class="preview-wrap">
|
||||
<iframe src="dashboard.html" loading="lazy" sandbox></iframe>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<h3>User Dashboard</h3>
|
||||
<p>Personal health overview with recent scans, health score trends, quick actions, and personalized product recommendations.</p>
|
||||
<div class="card-tags">
|
||||
<span class="tag green">Health Scores</span>
|
||||
<span class="tag">Analytics</span>
|
||||
<span class="tag orange">Personalized</span>
|
||||
</div>
|
||||
<a class="card-link" href="dashboard.html" target="_blank">Open Full Page →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. Product Compare -->
|
||||
<div class="card">
|
||||
<div class="preview-wrap">
|
||||
<iframe src="compare.html" loading="lazy" sandbox></iframe>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<h3>Product Compare</h3>
|
||||
<p>Side-by-side product comparison with health scores, ingredients breakdown, nutritional highlights, and healthier alternatives.</p>
|
||||
<div class="card-tags">
|
||||
<span class="tag">Comparison</span>
|
||||
<span class="tag green">Alternatives</span>
|
||||
<span class="tag orange">Dark Theme</span>
|
||||
</div>
|
||||
<a class="card-link" href="compare.html" target="_blank">Open Full Page →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 4. Messaging Hub -->
|
||||
<div class="card">
|
||||
<div class="preview-wrap">
|
||||
<iframe src="messaging.html" loading="lazy" sandbox></iframe>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<h3>Messaging Hub</h3>
|
||||
<p>Slack-inspired messaging interface with channels, DMs, @mentions feed, and slide-out navigation. Desktop + mobile responsive.</p>
|
||||
<div class="card-tags">
|
||||
<span class="tag">Messaging</span>
|
||||
<span class="tag green">Channels</span>
|
||||
<span class="tag orange">Responsive</span>
|
||||
</div>
|
||||
<a class="card-link" href="messaging.html" target="_blank">Open Full Page →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 5. Conversation View -->
|
||||
<div class="card">
|
||||
<div class="preview-wrap">
|
||||
<iframe src="messaging-conversation.html" loading="lazy" sandbox></iframe>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<h3>Conversation View</h3>
|
||||
<p>Full chat thread view with message bubbles, timestamps, typing indicators, and message input. Native mobile app feel.</p>
|
||||
<div class="card-tags">
|
||||
<span class="tag">Chat UI</span>
|
||||
<span class="tag green">Real-time</span>
|
||||
<span class="tag">Mobile Native</span>
|
||||
</div>
|
||||
<a class="card-link" href="messaging-conversation.html" target="_blank">Open Full Page →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
Built by <strong>@zara</strong> · Payfrit User Portal · March 2026
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue