Skip to content

Commit fd1801e

Browse files
Copilothotlong
andcommitted
Add Airtable-style view tabs to console ObjectView and viewName bindings to example navigation
- Add view type tab bar (grid/kanban/calendar/etc.) to console ObjectView header - Add VIEW_TYPE_ICONS mapping for Lucide icons per view type - CRM: Add Pipeline (kanban) and Calendar nav items with viewName binding - TODO: Add Task Board (kanban) and Calendar nav items with viewName binding Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 220b667 commit fd1801e

3 files changed

Lines changed: 67 additions & 3 deletions

File tree

apps/console/src/components/ObjectView.tsx

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* - ListView delegation for non-grid view types (kanban, calendar, chart, etc.)
1010
*/
1111

12-
import { useMemo, useState, useCallback } from 'react';
12+
import { useMemo, useState, useCallback, type ComponentType } from 'react';
1313
import { useParams, useSearchParams, useNavigate } from 'react-router-dom';
1414
import { ObjectChart } from '@object-ui/plugin-charts';
1515
import { ListView } from '@object-ui/plugin-list';
@@ -19,12 +19,24 @@ import { ObjectView as PluginObjectView } from '@object-ui/plugin-view';
1919
import '@object-ui/plugin-grid';
2020
import '@object-ui/plugin-kanban';
2121
import '@object-ui/plugin-calendar';
22-
import { Button, Empty, EmptyTitle, EmptyDescription, Sheet, SheetContent, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from '@object-ui/components';
23-
import { Plus, Table as TableIcon, Settings2, MoreVertical, Wrench } from 'lucide-react';
22+
import { cn, Button, Empty, EmptyTitle, EmptyDescription, Sheet, SheetContent, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from '@object-ui/components';
23+
import { Plus, Table as TableIcon, Settings2, MoreVertical, Wrench, KanbanSquare, Calendar, LayoutGrid, Activity, GanttChart, MapPin, BarChart3 } from 'lucide-react';
2424
import type { ListViewSchema } from '@object-ui/types';
2525
import { MetadataToggle, MetadataPanel, useMetadataInspector } from './MetadataInspector';
2626
import { useObjectActions } from '../hooks/useObjectActions';
2727

28+
/** Map view types to Lucide icons (Airtable-style) */
29+
const VIEW_TYPE_ICONS: Record<string, ComponentType<any>> = {
30+
grid: TableIcon,
31+
kanban: KanbanSquare,
32+
calendar: Calendar,
33+
gallery: LayoutGrid,
34+
timeline: Activity,
35+
gantt: GanttChart,
36+
map: MapPin,
37+
chart: BarChart3,
38+
};
39+
2840
export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
2941
const navigate = useNavigate();
3042
const { objectName, viewId } = useParams();
@@ -273,6 +285,33 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
273285
</div>
274286
</div>
275287

288+
{/* View Tabs — Airtable-style named-view switcher */}
289+
{views.length > 1 && (
290+
<div className="border-b px-3 sm:px-4 bg-background overflow-x-auto shrink-0">
291+
<div className="flex items-center gap-0.5 -mb-px">
292+
{views.map((view: any) => {
293+
const isActive = view.id === activeViewId;
294+
const ViewIcon = VIEW_TYPE_ICONS[view.type] || TableIcon;
295+
return (
296+
<button
297+
key={view.id}
298+
onClick={() => handleViewChange(view.id)}
299+
className={cn(
300+
"inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap",
301+
isActive
302+
? "border-primary text-primary"
303+
: "border-transparent text-muted-foreground hover:text-foreground hover:border-border"
304+
)}
305+
>
306+
<ViewIcon className="h-3.5 w-3.5" />
307+
{view.label}
308+
</button>
309+
);
310+
})}
311+
</div>
312+
</div>
313+
)}
314+
276315
{/* 2. Content — Plugin ObjectView with ViewSwitcher + Filter + Sort */}
277316
<div className="flex-1 overflow-hidden relative flex flex-row">
278317
<div className="flex-1 relative h-full">

examples/crm/objectstack.config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ export default defineStack({
8989
label: 'Opportunities',
9090
icon: 'trending-up'
9191
},
92+
{
93+
id: 'nav_pipeline',
94+
type: 'object',
95+
objectName: 'opportunity',
96+
viewName: 'pipeline',
97+
label: 'Pipeline',
98+
icon: 'kanban-square'
99+
},
92100
{
93101
id: 'nav_projects',
94102
type: 'object',
@@ -100,6 +108,7 @@ export default defineStack({
100108
id: 'nav_events',
101109
type: 'object',
102110
objectName: 'event',
111+
viewName: 'calendar',
103112
label: 'Calendar',
104113
icon: 'calendar'
105114
},

examples/todo/objectstack.config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ export default defineStack({
3535
label: 'All Tasks',
3636
icon: 'list-todo',
3737
},
38+
{
39+
id: 'nav_todo_board',
40+
type: 'object',
41+
objectName: 'todo_task',
42+
viewName: 'board',
43+
label: 'Task Board',
44+
icon: 'kanban-square',
45+
},
46+
{
47+
id: 'nav_todo_calendar',
48+
type: 'object',
49+
objectName: 'todo_task',
50+
viewName: 'calendar',
51+
label: 'Calendar',
52+
icon: 'calendar',
53+
},
3854
{
3955
id: 'nav_todo_help',
4056
type: 'page',

0 commit comments

Comments
 (0)