mirror of
https://github.com/FranP-code/format_twitter_projects_accounts_tweets.git
synced 2025-10-13 00:32:19 +00:00
Fix table overflow and add checkbox for seen status
This commit is contained in:
committed by
GitHub
parent
6438fcb12f
commit
13d7866faa
@@ -66,7 +66,7 @@ export function ProjectCard({ project, onSeenStatusChange }: ProjectCardProps) {
|
|||||||
|
|
||||||
{/* Project Actions */}
|
{/* Project Actions */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<>
|
<div className="flex items-center space-x-4">
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
{/* Project URL */}
|
{/* Project URL */}
|
||||||
{project.project_url && (
|
{project.project_url && (
|
||||||
@@ -95,26 +95,24 @@ export function ProjectCard({ project, onSeenStatusChange }: ProjectCardProps) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Seen Toggle */}
|
</div>
|
||||||
<Button
|
|
||||||
variant={seen ? "secondary" : "outline"}
|
{/* Seen Checkbox */}
|
||||||
size="sm"
|
<div className="flex items-center space-x-2">
|
||||||
onClick={toggleSeen}
|
<input
|
||||||
className="ml-auto"
|
type="checkbox"
|
||||||
|
id={`seen-${project.id}`}
|
||||||
|
className="w-4 h-4 rounded border-border bg-background"
|
||||||
|
checked={seen}
|
||||||
|
onChange={toggleSeen}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor={`seen-${project.id}`}
|
||||||
|
className="text-sm text-muted-foreground cursor-pointer"
|
||||||
>
|
>
|
||||||
{seen ? (
|
Seen
|
||||||
<>
|
</label>
|
||||||
<X className="w-4 h-4 mr-1" />
|
</div>
|
||||||
Mark Unseen
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Check className="w-4 h-4 mr-1" />
|
|
||||||
Mark Seen
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Engagement Stats */}
|
{/* Engagement Stats */}
|
||||||
|
|||||||
@@ -68,6 +68,36 @@ export function ProjectsTable({ projects, title, showUrlColumn = true, onSeenSta
|
|||||||
};
|
};
|
||||||
|
|
||||||
const columns = useMemo(() => [
|
const columns = useMemo(() => [
|
||||||
|
columnHelper.display({
|
||||||
|
id: 'seen',
|
||||||
|
header: ({ table }) => (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="w-4 h-4 rounded border-border bg-background"
|
||||||
|
checked={table.getIsAllRowsSelected()}
|
||||||
|
indeterminate={table.getIsSomeRowsSelected()}
|
||||||
|
onChange={table.getToggleAllRowsSelectedHandler()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const projectId = row.original.id;
|
||||||
|
const isSeen = seenProjects.has(projectId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="w-4 h-4 rounded border-border bg-background"
|
||||||
|
checked={isSeen}
|
||||||
|
onChange={() => toggleSeen(projectId)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
size: 60,
|
||||||
|
}),
|
||||||
columnHelper.accessor('author_name', {
|
columnHelper.accessor('author_name', {
|
||||||
header: ({ column }) => (
|
header: ({ column }) => (
|
||||||
<Button
|
<Button
|
||||||
@@ -96,7 +126,7 @@ export function ProjectsTable({ projects, title, showUrlColumn = true, onSeenSta
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
size: 240,
|
size: 200,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('project_description', {
|
columnHelper.accessor('project_description', {
|
||||||
header: ({ column }) => (
|
header: ({ column }) => (
|
||||||
@@ -120,7 +150,7 @@ export function ProjectsTable({ projects, title, showUrlColumn = true, onSeenSta
|
|||||||
<p className="text-sm leading-relaxed line-clamp-3 pr-2">{row.original.project_description}</p>
|
<p className="text-sm leading-relaxed line-clamp-3 pr-2">{row.original.project_description}</p>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
size: 400,
|
size: 350,
|
||||||
}),
|
}),
|
||||||
...(showUrlColumn ? [
|
...(showUrlColumn ? [
|
||||||
columnHelper.accessor('project_url', {
|
columnHelper.accessor('project_url', {
|
||||||
@@ -262,38 +292,6 @@ export function ProjectsTable({ projects, title, showUrlColumn = true, onSeenSta
|
|||||||
),
|
),
|
||||||
size: 140,
|
size: 140,
|
||||||
}),
|
}),
|
||||||
columnHelper.display({
|
|
||||||
id: 'actions',
|
|
||||||
header: 'Actions',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const projectId = row.original.id;
|
|
||||||
const isSeen = seenProjects.has(projectId);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-full flex justify-center">
|
|
||||||
<Button
|
|
||||||
variant={isSeen ? "secondary" : "outline"}
|
|
||||||
size="sm"
|
|
||||||
onClick={() => toggleSeen(projectId)}
|
|
||||||
className="h-8"
|
|
||||||
>
|
|
||||||
{isSeen ? (
|
|
||||||
<>
|
|
||||||
<X className="w-3 h-3 mr-1" />
|
|
||||||
Unseen
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Check className="w-3 h-3 mr-1" />
|
|
||||||
Seen
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
size: 120,
|
|
||||||
}),
|
|
||||||
], [showUrlColumn, seenProjects]);
|
], [showUrlColumn, seenProjects]);
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
@@ -327,7 +325,7 @@ export function ProjectsTable({ projects, title, showUrlColumn = true, onSeenSta
|
|||||||
}, [projects]);
|
}, [projects]);
|
||||||
|
|
||||||
// Calculate total width
|
// Calculate total width
|
||||||
const totalWidth = table.getHeaderGroups()[0]?.headers.reduce((acc, header) => acc + header.getSize(), 0) || 1000;
|
const totalWidth = table.getHeaderGroups()[0]?.headers.reduce((acc, header) => acc + header.getSize(), 0) || 800;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
@@ -367,36 +365,37 @@ export function ProjectsTable({ projects, title, showUrlColumn = true, onSeenSta
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Table Container */}
|
{/* Table Container */}
|
||||||
<div className="border rounded-lg overflow-hidden bg-card">
|
<div className="border rounded-lg bg-card">
|
||||||
<div className="w-full" style={{ minWidth: `${totalWidth}px` }}>
|
<div className="overflow-x-auto">
|
||||||
|
<div className="w-full" style={{ minWidth: `${totalWidth}px` }}>
|
||||||
{/* Fixed Header */}
|
{/* Fixed Header */}
|
||||||
<div className="sticky top-0 z-10 bg-muted/50 border-b">
|
<div className="sticky top-0 z-10 bg-muted/50 border-b">
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<div key={headerGroup.id} className="grid" style={{ gridTemplateColumns: headerGroup.headers.map(h => `${h.getSize()}px`).join(' ') }}>
|
<div key={headerGroup.id} className="grid" style={{ gridTemplateColumns: headerGroup.headers.map(h => `${h.getSize()}px`).join(' ') }}>
|
||||||
{headerGroup.headers.map((header) => (
|
{headerGroup.headers.map((header) => (
|
||||||
<div
|
<div
|
||||||
key={header.id}
|
key={header.id}
|
||||||
className="px-4 py-3 text-left font-medium border-r border-border last:border-r-0 flex items-center"
|
className="px-4 py-3 text-left font-medium border-r border-border last:border-r-0 flex items-center"
|
||||||
>
|
>
|
||||||
{header.isPlaceholder
|
{header.isPlaceholder
|
||||||
? null
|
? null
|
||||||
: flexRender(header.column.columnDef.header, header.getContext())}
|
: flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Virtual Scrollable Body */}
|
{/* Virtual Scrollable Body */}
|
||||||
<div
|
<div
|
||||||
ref={parentRef}
|
ref={parentRef}
|
||||||
className="h-[600px] overflow-auto relative"
|
className="h-[600px] overflow-auto relative"
|
||||||
>
|
>
|
||||||
<div style={{ height: `${virtualizer.getTotalSize()}px` }}>
|
<div style={{ height: `${virtualizer.getTotalSize()}px` }}>
|
||||||
{virtualizer.getVirtualItems().map((virtualRow) => {
|
{virtualizer.getVirtualItems().map((virtualRow) => {
|
||||||
const row = rows[virtualRow.index];
|
const row = rows[virtualRow.index];
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={row.id}
|
key={row.id}
|
||||||
className={`absolute w-full border-b border-border hover:bg-muted/50 transition-colors grid ${seenProjects.has(row.original.id) ? 'opacity-60 bg-muted/30' : ''}`}
|
className={`absolute w-full border-b border-border hover:bg-muted/50 transition-colors grid ${seenProjects.has(row.original.id) ? 'opacity-60 bg-muted/30' : ''}`}
|
||||||
style={{
|
style={{
|
||||||
@@ -404,22 +403,24 @@ export function ProjectsTable({ projects, title, showUrlColumn = true, onSeenSta
|
|||||||
transform: `translateY(${virtualRow.start}px)`,
|
transform: `translateY(${virtualRow.start}px)`,
|
||||||
gridTemplateColumns: row.getVisibleCells().map(cell => `${cell.column.getSize()}px`).join(' ')
|
gridTemplateColumns: row.getVisibleCells().map(cell => `${cell.column.getSize()}px`).join(' ')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{row.getVisibleCells().map((cell) => (
|
{row.getVisibleCells().map((cell) => (
|
||||||
<div
|
<div
|
||||||
key={cell.id}
|
key={cell.id}
|
||||||
className="px-4 py-3 border-r border-border last:border-r-0 flex items-center overflow-hidden"
|
className="px-4 py-3 border-r border-border last:border-r-0 flex items-center overflow-hidden"
|
||||||
>
|
>
|
||||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user