feat(17): restyle discussion view and planning page in backend/
- discussion.templ: #discussion-messages uses .ui-card; DiscussionMessageRow uses .message-row/.message-other/.message-bubble/.message-meta classes; day separator gets data-day-separator attribute - planning.templ: wraps content in .overview-section; heading uses .overview-section-heading with h1; empty state uses .ui-card - app.css: add Section 26 .message-* bubble classes; extend .overview-section-heading selector to include h1 Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e3596ff753
commit
56194cfdb5
3 changed files with 77 additions and 20 deletions
|
|
@ -352,6 +352,7 @@
|
|||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.overview-section-heading h1,
|
||||
.overview-section-heading h3,
|
||||
.tasks-section-header h3 {
|
||||
color: var(--color-surface-muted-inverse);
|
||||
|
|
@ -700,3 +701,61 @@
|
|||
font-style: italic;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Section 26 — Discussion message bubbles (Phase 17)
|
||||
============================================================ */
|
||||
|
||||
.message-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.message-row.message-own {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.message-row.message-other {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.message-meta {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.message-author {
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.message-timestamp {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.message-bubble {
|
||||
border-radius: 0.25rem 0.75rem 0.75rem 0.75rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
max-width: 70%;
|
||||
padding: 0.75rem 1rem;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-words;
|
||||
}
|
||||
|
||||
.message-row.message-own .message-bubble {
|
||||
background-color: rgba(128, 78, 236, 0.10);
|
||||
border-radius: 0.75rem 0.75rem 0.25rem 0.75rem;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.message-row.message-other .message-bubble {
|
||||
background-color: var(--color-surface-default, #ffffff);
|
||||
border: 1px solid var(--color-border-default, #e2e8f0);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,18 +15,16 @@ templ DiscussionTabFragment(tablo sqlc.Tablo, data DiscussionTabData, form Discu
|
|||
<p class="mt-1 text-sm text-slate-600">1 participant</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="discussion-messages" class="rounded border border-slate-200 bg-white">
|
||||
<div id="discussion-messages" class="ui-card">
|
||||
if len(data.Messages) == 0 {
|
||||
@DiscussionEmptyState()
|
||||
} else {
|
||||
<div class="divide-y divide-slate-100">
|
||||
for i, message := range data.Messages {
|
||||
if DiscussionShowDaySeparator(data.Messages, i) {
|
||||
@DiscussionDaySeparator(message.CreatedAt)
|
||||
}
|
||||
@DiscussionMessageRow(message)
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@DiscussionComposer(tablo, form, errs, csrfToken)
|
||||
|
|
@ -34,25 +32,25 @@ templ DiscussionTabFragment(tablo sqlc.Tablo, data DiscussionTabData, form Discu
|
|||
}
|
||||
|
||||
templ DiscussionEmptyState() {
|
||||
<div class="bg-slate-50 px-4 py-8 text-center">
|
||||
<div class="ui-card-body py-8 text-center">
|
||||
<h3 class="text-xl font-semibold leading-snug text-slate-800">No messages yet</h3>
|
||||
<p class="mt-2 text-base text-slate-600">Start the discussion for this tablo.</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ DiscussionDaySeparator(createdAt time.Time) {
|
||||
<div class="bg-slate-50 px-4 py-3 text-center text-sm text-slate-500">
|
||||
<div class="bg-slate-50 px-4 py-2 text-center text-sm text-slate-500" data-day-separator="true">
|
||||
{ DiscussionDateLabel(createdAt) }
|
||||
</div>
|
||||
}
|
||||
|
||||
templ DiscussionMessageRow(message DiscussionMessageView) {
|
||||
<article id={ "discussion-message-" + message.ID.String() } data-message-id={ message.ID.String() } class="px-4 py-3">
|
||||
<div class="flex flex-wrap items-baseline gap-x-2 gap-y-1">
|
||||
<span class="text-sm font-semibold text-slate-900">{ message.AuthorEmail }</span>
|
||||
<time class="text-xs text-slate-500" datetime={ message.CreatedAt.Format(time.RFC3339) }>{ DiscussionTimestampLabel(message.CreatedAt) }</time>
|
||||
<article id={ "discussion-message-" + message.ID.String() } data-message-id={ message.ID.String() } class="message-row message-other">
|
||||
<div class="message-meta">
|
||||
<span class="message-author">{ message.AuthorEmail }</span>
|
||||
<time class="message-timestamp" datetime={ message.CreatedAt.Format(time.RFC3339) }>{ DiscussionTimestampLabel(message.CreatedAt) }</time>
|
||||
</div>
|
||||
<p class="mt-2 whitespace-pre-wrap break-words text-base leading-6 text-slate-900">{ message.Body }</p>
|
||||
<div class="message-bubble">{ message.Body }</div>
|
||||
</article>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import (
|
|||
|
||||
templ PlanningPage(user *auth.User, csrfToken string, activePath string, tablos []sqlc.Tablo, agenda PlanningAgenda) {
|
||||
@AppLayout("Planning - Xtablo", user, csrfToken, activePath, tablos) {
|
||||
<div class="space-y-6">
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
<section class="overview-section">
|
||||
<div class="overview-section-heading">
|
||||
<div>
|
||||
<h1 class="text-[28px] font-semibold leading-tight">Planning</h1>
|
||||
<h1>Planning</h1>
|
||||
<p class="mt-1 text-sm text-slate-600">{ agenda.RangeLabel }</p>
|
||||
</div>
|
||||
<nav class="flex flex-wrap items-center gap-2" aria-label="Planning navigation">
|
||||
|
|
@ -27,7 +27,7 @@ templ PlanningPage(user *auth.User, csrfToken string, activePath string, tablos
|
|||
</nav>
|
||||
</div>
|
||||
if len(agenda.Events) == 0 {
|
||||
<div class="border border-slate-200 bg-slate-50 px-4 py-12">
|
||||
<div class="ui-card ui-card-body py-12 text-center">
|
||||
<h2 class="text-xl font-semibold leading-snug text-slate-800">No events in this range</h2>
|
||||
<p class="mt-2 text-base text-slate-600">Use the navigation controls to browse another 14-day window.</p>
|
||||
</div>
|
||||
|
|
@ -38,7 +38,7 @@ templ PlanningPage(user *auth.User, csrfToken string, activePath string, tablos
|
|||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue