Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ROADMAP.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -132,6 +132,18 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind
- [x] i18n for all 11 locales (en, zh, ja, de, fr, es, ar, ru, pt, ko)
- [ ] Conditional formatting rules

### P1.9 Console — Content Area Layout & Responsiveness

- [x] Add `min-w-0` / `overflow-hidden` to flex layout chain (SidebarInset → AppShell → ObjectView → PluginObjectView) to prevent content overflow
- [x] Fix Gantt task list width — responsive sizing (120px mobile, 200px tablet, 300px desktop) instead of hardcoded 300px
- [x] Fix Kanban board overflow containment (`min-w-0` on swimlane and flat containers)
- [x] Fix Calendar header responsive wrapping and date label sizing
- [x] Fix Map container overflow containment via `cn()` merge
- [x] Fix Timeline container `min-w-0` to prevent overflow
- [x] Fix ListView container `min-w-0 overflow-hidden` to prevent overflow
- [ ] Mobile/tablet end-to-end testing for all view types
- [ ] Dynamic width calculation for Gantt task list and Kanban columns based on container width

---

## 🧩 P2 — Polish & Advanced Features
Expand Down
4 changes: 2 additions & 2 deletions apps/console/src/components/ObjectView.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -388,7 +388,7 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
}), [objectDef.name, onEdit, activeView?.showSearch, activeView?.showFilters]);

return (
<div className="h-full flex flex-col bg-background">
<div className="h-full flex flex-col bg-background min-w-0 overflow-hidden">
{/* 1. Header with breadcrumb + description */}
<div className="flex justify-between items-center py-2.5 sm:py-3 px-3 sm:px-4 border-b shrink-0 bg-background z-10">
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
Expand DownExpand Up@@ -517,7 +517,7 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {

{/* 2. Content — Plugin ObjectView with ViewSwitcher + Filter + Sort */}
<div className="flex-1 overflow-hidden relative flex flex-row">
<div className="flex-1 relative h-full flex flex-col">
<div className="flex-1 min-w-0 relative h-full flex flex-col">
<div className="flex-1 relative overflow-auto p-3 sm:p-4">
<PluginObjectView
key={refreshKey}
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/ui/sidebar.tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/layout/src/AppShell.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -140,7 +140,7 @@ export function AppShell({
<div className="w-px h-4 bg-border mx-1 sm:mx-2" />
{navbar}
</header>
<main className={cn("flex-1 overflow-auto p-3 sm:p-4 md:p-6", className)}>
<main className={cn("flex-1 min-w-0 overflow-auto p-3 sm:p-4 md:p-6", className)}>
{children}
</main>
</SidebarInset>
Expand Down
6 changes: 3 additions & 3 deletions packages/plugin-calendar/src/CalendarView.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,9 +237,9 @@ function CalendarView({
}

return (
<div role="region" aria-label="Calendar" className={cn("flex flex-col h-full bg-background", className)}>
<div role="region" aria-label="Calendar" className={cn("flex flex-col h-full bg-background min-w-0 overflow-hidden", className)}>
{/* Header */}
<div className="flex items-center justify-between p-4 border-b">
<div className="flex flex-wrap items-center justify-between gap-2 p-2 sm:p-4 border-b min-w-0">
<div className="flex items-center gap-4">
<div className="flex items-center bg-muted/50 rounded-lg p-1 gap-1">
<Button variant="ghost" size="sm" onClick={handleToday} className="h-8" aria-label="Go to today">
Expand DownExpand Up@@ -272,7 +272,7 @@ function CalendarView({
variant="ghost"
aria-label={`Current date: ${getDateLabel()}`}
className={cn(
"text-xl font-semibold h-auto px-3 py-1 hover:bg-muted/50 transition-colors",
"text-base sm:text-xl font-semibold h-auto px-2 sm:px-3 py-1 hover:bg-muted/50 transition-colors",
"flex items-center gap-2"
)}
>
Expand Down
11 changes: 9 additions & 2 deletions packages/plugin-gantt/src/GanttView.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,13 @@ function getResponsiveColumnWidth() {
return 60;
}

function getResponsiveTaskListWidth() {
const w = typeof window !== 'undefined' ? window.innerWidth : 1024;
if (w < 640) return 120;
if (w < 1024) return 200;
return 300;
}

export interface GanttTask {
id: string | number
title: string
Expand DownExpand Up@@ -138,7 +145,7 @@ export function GanttView({
return cols;
}, [timelineRange]);

const taskListWidth = 300;
const taskListWidth = getResponsiveTaskListWidth();

const headerRef = React.useRef<HTMLDivElement>(null);
const listRef = React.useRef<HTMLDivElement>(null);
Expand DownExpand Up@@ -170,7 +177,7 @@ export function GanttView({
};

return (
<div className={cn("flex flex-col h-full bg-background border rounded-lg overflow-hidden", className)}>
<div className={cn("flex flex-col h-full bg-background border rounded-lg overflow-hidden min-w-0", className)}>
{/* Toolbar */}
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 p-2 border-b bg-card">
<div className="flex items-center gap-2">
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-kanban/src/KanbanImpl.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -515,7 +515,7 @@ function KanbanBoardInner({ columns, onCardMove, onCardClick, className, dnd, qu

{swimlanes ? (
/* Swimlane (2D) layout */
<div className={cn("flex flex-col gap-1 p-2 sm:p-4", className)} role="region" aria-label="Kanban board with swimlanes">
<div className={cn("flex flex-col gap-1 p-2 sm:p-4 min-w-0 overflow-hidden", className)} role="region" aria-label="Kanban board with swimlanes">
{/* Column headers */}
<div className="flex gap-3 sm:gap-4 pl-36 sm:pl-44 overflow-x-auto">
{boardColumns.map(col => (
Expand DownExpand Up@@ -572,7 +572,7 @@ function KanbanBoardInner({ columns, onCardMove, onCardClick, className, dnd, qu
</div>
) : (
/* Standard flat layout */
<div className={cn("flex gap-3 sm:gap-4 overflow-x-auto snap-x snap-mandatory p-2 sm:p-4 bg-muted/10 rounded-lg [-webkit-overflow-scrolling:touch]", className)} role="region" aria-label="Kanban board">
<div className={cn("flex gap-3 sm:gap-4 overflow-x-auto snap-x snap-mandatory p-2 sm:p-4 bg-muted/10 rounded-lg [-webkit-overflow-scrolling:touch] min-w-0", className)} role="region" aria-label="Kanban board">
{boardColumns.map((column) => (
<KanbanColumnView
key={column.id}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-list/src/ListView.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -785,7 +785,7 @@ export const ListView: React.FC<ListViewProps> = ({
return (
<div
ref={pullRef}
className={cn('flex flex-col h-full bg-background relative', className)}
className={cn('flex flex-col h-full bg-background relative min-w-0 overflow-hidden', className)}
{...(schema.aria?.label ? { 'aria-label': schema.aria.label } : {})}
{...(schema.aria?.describedBy ? { 'aria-describedby': schema.aria.describedBy } : {})}
{...(schema.aria?.live ? { 'aria-live': schema.aria.live } : {})}
Expand Down
8 changes: 4 additions & 4 deletions packages/plugin-map/src/ObjectMap.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@
import React, { useEffect, useState, useMemo } from 'react';
import type { ObjectGridSchema, DataSource, ViewData } from '@object-ui/types';
import { useNavigationOverlay } from '@object-ui/react';
import { NavigationOverlay } from '@object-ui/components';
import { NavigationOverlay, cn } from '@object-ui/components';
import { z } from 'zod';
import MapGL, { NavigationControl, Marker, Popup } from 'react-map-gl/maplibre';
import maplibregl from 'maplibre-gl';
Expand DownExpand Up@@ -501,7 +501,7 @@ export const ObjectMap: React.FC<ObjectMapProps> = ({

if (loading) {
return (
<div className={className}>
<div className={cn("min-w-0 overflow-hidden", className)}>
<div className="flex items-center justify-center h-96 bg-muted rounded-lg border">
<div className="text-muted-foreground">Loading map...</div>
</div>
Expand All@@ -511,7 +511,7 @@ export const ObjectMap: React.FC<ObjectMapProps> = ({

if (error) {
return (
<div className={className}>
<div className={cn("min-w-0 overflow-hidden", className)}>
<div className="flex items-center justify-center h-96 bg-muted rounded-lg border">
<div className="text-destructive">Error: {error.message}</div>
</div>
Expand All@@ -520,7 +520,7 @@ export const ObjectMap: React.FC<ObjectMapProps> = ({
}

return (
<div className={className}>
<div className={cn("min-w-0 overflow-hidden", className)}>
{invalidCount > 0 && (
<div className="mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded">
{`${invalidCount} record${invalidCount !== 1 ? 's' : ''} with missing or invalid coordinates excluded from the map.`}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-timeline/src/ObjectTimeline.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -185,7 +185,7 @@ export const ObjectTimeline: React.FC<ObjectTimelineProps> = ({
}

return (
<div ref={pullRef} className="relative overflow-auto h-full">
<div ref={pullRef} className="relative overflow-auto h-full min-w-0">
{pullDistance > 0 && (
<div
className="flex items-center justify-center text-xs text-muted-foreground"
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-view/src/ObjectView.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -914,7 +914,7 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
: layout;

return (
<div className={cn('flex flex-col h-full', className)}>
<div className={cn('flex flex-col h-full min-w-0 overflow-hidden', className)}>
{/* Title and description */}
{(schema.title || schema.description) && (
<div className="mb-4 shrink-0">
Expand All@@ -933,7 +933,7 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
</div>

{/* Content */}
<div className="flex-1 min-h-0">
<div className="flex-1 min-h-0 min-w-0 overflow-hidden">
{renderContent()}
</div>

Expand Down