feat(ui): mobile UX improvements, comment attachments, and cost breakdown
Add PWA meta tags for iOS home screen. Fix mobile properties drawer with safe area insets. Add image attachment button to comment thread. Improve sidebar with collapsible sections, project grouping, and mobile bottom nav. Show token and billing type breakdown on costs page. Fix inbox loading state to show content progressively. Various mobile overflow and layout fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import { useCompany } from "../context/CompanyContext";
|
||||
import { useBreadcrumbs } from "../context/BreadcrumbContext";
|
||||
import { queryKeys } from "../lib/queryKeys";
|
||||
import { EmptyState } from "../components/EmptyState";
|
||||
import { formatCents } from "../lib/utils";
|
||||
import { formatCents, formatTokens } from "../lib/utils";
|
||||
import { Identity } from "../components/Identity";
|
||||
import { StatusBadge } from "../components/StatusBadge";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
@@ -177,7 +177,7 @@ export function Costs() {
|
||||
{data.byAgent.map((row) => (
|
||||
<div
|
||||
key={row.agentId}
|
||||
className="flex items-center justify-between text-sm"
|
||||
className="flex items-start justify-between text-sm"
|
||||
>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<Identity
|
||||
@@ -188,9 +188,21 @@ export function Costs() {
|
||||
<StatusBadge status="terminated" />
|
||||
)}
|
||||
</div>
|
||||
<span className="font-medium shrink-0 ml-2">
|
||||
{formatCents(row.costCents)}
|
||||
</span>
|
||||
<div className="text-right shrink-0 ml-2">
|
||||
<span className="font-medium block">{formatCents(row.costCents)}</span>
|
||||
<span className="text-xs text-muted-foreground block">
|
||||
in {formatTokens(row.inputTokens)} / out {formatTokens(row.outputTokens)} tok
|
||||
</span>
|
||||
{(row.apiRunCount > 0 || row.subscriptionRunCount > 0) && (
|
||||
<span className="text-xs text-muted-foreground block">
|
||||
{row.apiRunCount > 0 ? `api runs: ${row.apiRunCount}` : null}
|
||||
{row.apiRunCount > 0 && row.subscriptionRunCount > 0 ? " | " : null}
|
||||
{row.subscriptionRunCount > 0
|
||||
? `subscription runs: ${row.subscriptionRunCount} (${formatTokens(row.subscriptionInputTokens)} in / ${formatTokens(row.subscriptionOutputTokens)} out tok)`
|
||||
: null}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -326,12 +326,12 @@ export function Inbox() {
|
||||
showStaleSection ? "stale_work" : null,
|
||||
].filter((key): key is SectionKey => key !== null);
|
||||
|
||||
const isLoading =
|
||||
isJoinRequestsLoading ||
|
||||
isApprovalsLoading ||
|
||||
isDashboardLoading ||
|
||||
isIssuesLoading ||
|
||||
isRunsLoading;
|
||||
const allLoaded =
|
||||
!isJoinRequestsLoading &&
|
||||
!isApprovalsLoading &&
|
||||
!isDashboardLoading &&
|
||||
!isIssuesLoading &&
|
||||
!isRunsLoading;
|
||||
|
||||
const showSeparatorBefore = (key: SectionKey) => visibleSections.indexOf(key) > 0;
|
||||
|
||||
@@ -397,11 +397,14 @@ export function Inbox() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isLoading && <p className="text-sm text-muted-foreground">Loading...</p>}
|
||||
{approvalsError && <p className="text-sm text-destructive">{approvalsError.message}</p>}
|
||||
{actionError && <p className="text-sm text-destructive">{actionError}</p>}
|
||||
|
||||
{!isLoading && visibleSections.length === 0 && (
|
||||
{!allLoaded && visibleSections.length === 0 && (
|
||||
<p className="text-sm text-muted-foreground">Loading...</p>
|
||||
)}
|
||||
|
||||
{allLoaded && visibleSections.length === 0 && (
|
||||
<EmptyState
|
||||
icon={InboxIcon}
|
||||
message={tab === "new" ? "You're all caught up!" : "No inbox items match these filters."}
|
||||
|
||||
@@ -813,7 +813,7 @@ export function IssueDetail() {
|
||||
|
||||
{/* Mobile properties drawer */}
|
||||
<Sheet open={mobilePropsOpen} onOpenChange={setMobilePropsOpen}>
|
||||
<SheetContent side="bottom" className="max-h-[85vh]">
|
||||
<SheetContent side="bottom" className="max-h-[85dvh] pb-[env(safe-area-inset-bottom)]">
|
||||
<SheetHeader>
|
||||
<SheetTitle className="text-sm">Properties</SheetTitle>
|
||||
</SheetHeader>
|
||||
|
||||
Reference in New Issue
Block a user