Better responsive design (#62)

This commit is contained in:
Matt Rubens 2025-05-31 22:20:33 -04:00 committed by GitHub
parent 55526e4437
commit 65e38dee4d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 90 additions and 42 deletions

34
.roomodes Normal file
View file

@ -0,0 +1,34 @@
customModes:
- slug: designer
name: 🎨 Designer
roleDefinition: >-
You are Roo, a UI/UX expert specializing in design systems, user interface design, and frontend development. Your expertise includes:
- Creating and maintaining design systems and component libraries
- Implementing responsive and accessible web interfaces
- Working with CSS, HTML, Tailwind CSS, and modern frontend frameworks like React and Next.js
- Ensuring consistent user experiences across platforms and devices
- Optimizing user flows and interaction patterns
- Creating visually appealing and functional interfaces
- Following modern design principles and accessibility standards
whenToUse: >-
Use this mode when creating or modifying UI components, implementing design systems,
working on visual design improvements, ensuring responsive web interfaces, or focusing
on user experience enhancements. This mode is especially effective for CSS styling,
component design, layout improvements, and frontend framework implementations.
groups:
- read
- edit
- browser
- command
- mcp
customInstructions: >-
When working in Designer mode, prioritize:
- User experience and accessibility
- Responsive design principles
- Consistent design patterns and component reusability
- Modern CSS practices and Tailwind CSS utilities
- Clean, semantic HTML structure
- Performance optimization for frontend assets
- Cross-browser compatibility
- Design system consistency
Always consider the visual impact and user interaction flow when making changes.

View file

@ -59,7 +59,7 @@ export const Tasks = ({
}
return (
<div className="space-y-3">
<div className="space-y-3 sm:space-y-4">
{tasks.map((task) => (
<TaskCard
key={task.taskId}

View file

@ -27,15 +27,16 @@ export const Usage = () => {
return (
<>
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-4 sm:gap-6">
<UsageCard />
<div className="flex gap-2">
<div className="flex flex-wrap gap-2">
{viewModes.map((mode) => (
<Button
key={mode}
variant={viewMode === mode ? 'default' : 'secondary'}
size="sm"
onClick={() => setViewMode(mode)}
className="min-w-[80px]"
>
{t(`view_mode_${mode}`)}
</Button>

View file

@ -8,12 +8,12 @@ type MetricProps = {
};
export const Metric = ({ label, value, isPending }: MetricProps) => (
<div className="flex flex-col gap-1 rounded-lg border border-secondary bg-background px-3 py-2">
<div className="text-xs text-muted-foreground">{label}</div>
<div className="font-mono font-semibold text-2xl h-8">
<div className="flex flex-col gap-1 rounded-lg border border-secondary bg-background px-2 py-2 sm:px-3 sm:py-3">
<div className="text-xs text-muted-foreground line-clamp-1">{label}</div>
<div className="font-mono font-semibold text-lg sm:text-xl md:text-2xl h-6 sm:h-7 md:h-8">
{isPending ? (
<div>
<Skeleton className="h-6 w-12 my-1" />
<Skeleton className="h-5 w-10 my-1" />
</div>
) : typeof value === 'number' ? (
formatNumber(value)

View file

@ -1,8 +1,4 @@
import {
formatNumber,
formatCurrency,
formatTimestamp,
} from '@/lib/formatters';
import { formatNumber, formatCurrency } from '@/lib/formatters';
import { generateFallbackTitle } from '@/lib/taskUtils';
import { Card, CardContent, Button } from '@/components/ui';
@ -16,6 +12,27 @@ type TaskCardProps = {
onTaskSelected: (task: TaskWithUser) => void;
};
// Helper function for elegant timestamp display
const formatElegantTime = (timestamp: number): string => {
const date = new Date(timestamp * 1000);
const now = new Date();
// Check if it's today
if (date.toDateString() === now.toDateString()) {
return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
}
// Check if it's yesterday
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
if (date.toDateString() === yesterday.toDateString()) {
return 'Yesterday';
}
// Otherwise return a short date format
return date.toLocaleDateString([], { month: 'short', day: 'numeric' });
};
export const TaskCard = ({ task, onFilter, onTaskSelected }: TaskCardProps) => {
return (
<Card
@ -23,19 +40,23 @@ export const TaskCard = ({ task, onFilter, onTaskSelected }: TaskCardProps) => {
onClick={() => onTaskSelected(task)}
>
<CardContent className="p-0">
<div className="px-4 py-2">
{/* First line - Title and Status */}
<div className="flex items-center justify-between gap-2 mb-1">
<div className="px-4 py-2.5">
{/* Line 1: Title and Status */}
<div className="flex items-center justify-between gap-2 mb-1.5">
<h3 className="font-medium text-sm truncate flex-1 leading-none">
{task.title || generateFallbackTitle(task)}
</h3>
<Status completed={task.completed} />
</div>
{/* Second line - All metadata */}
<div className="flex items-center justify-between gap-3 text-xs text-muted-foreground">
<div className="flex items-center gap-3">
<span>{formatTimestamp(task.timestamp)}</span>
{/* Line 2: All metadata in a single line with bullet separators between items */}
<div className="flex items-center justify-between text-xs text-muted-foreground">
{/* Left side: Date, User, and Mode (if present) with bullet separators */}
<div className="flex items-center">
<span className="whitespace-nowrap">
{formatElegantTime(task.timestamp)}
</span>
<div className="mx-2 text-muted-foreground/30"></div>
<Button
variant="link"
size="sm"
@ -51,33 +72,24 @@ export const TaskCard = ({ task, onFilter, onTaskSelected }: TaskCardProps) => {
>
{task.user.name}
</Button>
{/* Mode (if present) */}
{task.mode && (
<span className="px-2 py-1 bg-muted rounded text-xs font-medium">
{task.mode}
</span>
<>
<div className="mx-2 text-muted-foreground/30"></div>
<span className="text-xs font-medium text-muted-foreground">
{task.mode}
</span>
</>
)}
<Button
variant="link"
size="sm"
onClick={(e) => {
e.stopPropagation();
onFilter({
type: 'model',
value: task.model,
label: task.model,
});
}}
className="px-0 h-auto text-xs font-normal font-mono text-muted-foreground hover:text-foreground"
>
{task.model}
</Button>
</div>
{/* Metrics on the right */}
<div className="flex items-center gap-3">
{/* Right side: Tokens and Cost with bullet separator */}
<div className="flex items-center whitespace-nowrap">
<span className="font-medium">
{formatNumber(task.tokens)} tokens
</span>
<div className="mx-2 text-muted-foreground/30"></div>
<span className="font-medium">{formatCurrency(task.cost)}</span>
</div>
</div>

View file

@ -64,20 +64,21 @@ export const UsageCard = () => {
)}
</CardHeader>
<CardContent>
<div className="flex flex-col gap-4">
<div className="flex flex-row gap-2">
<div className="flex flex-col gap-3">
<div className="flex flex-row flex-wrap gap-1.5">
{timePeriods.map((period) => (
<Button
key={period}
variant={period === timePeriod ? 'default' : 'secondary'}
size="sm"
onClick={() => setTimePeriod(period)}
className="text-xs px-2.5 h-8"
>
{t(`analytics_period_${period}_days`)}
</Button>
))}
</div>
<div className="grid grid-cols-2 gap-4 md:grid-cols-5">
<div className="grid grid-cols-2 gap-3 lg:grid-cols-5">
<Metric
label={t('analytics_active_developers')}
value={usage[TelemetryEventName.TASK_CREATED]?.users}