Move permission badge and share button to list title line
- Created ListHeader component with permission and share on same line as title - Permission badge and share button now appear to the right of the title - Removed permission/share section from ListDetailView - More compact header layout with better use of space
This commit is contained in:
@@ -7,6 +7,7 @@ import Link from 'next/link'
|
|||||||
import { ArrowLeft } from 'lucide-react'
|
import { ArrowLeft } from 'lucide-react'
|
||||||
import InlineItemCreate from '@/components/InlineItemCreate'
|
import InlineItemCreate from '@/components/InlineItemCreate'
|
||||||
import ListDetailView from '@/components/ListDetailView'
|
import ListDetailView from '@/components/ListDetailView'
|
||||||
|
import ListHeader from '@/components/ListHeader'
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic'
|
export const dynamic = 'force-dynamic'
|
||||||
export const revalidate = 0
|
export const revalidate = 0
|
||||||
@@ -36,27 +37,22 @@ export default async function ListDetailPage({ params }: { params: { id: string
|
|||||||
return (
|
return (
|
||||||
<main className="container mx-auto px-4 sm:px-6 py-6 sm:py-8 max-w-6xl">
|
<main className="container mx-auto px-4 sm:px-6 py-6 sm:py-8 max-w-6xl">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="mb-6 sm:mb-8">
|
<ListHeader
|
||||||
<Link
|
listId={list.id}
|
||||||
href="/"
|
listTitle={list.title}
|
||||||
className="inline-flex items-center gap-2 text-gray-600 hover:text-gray-900 active:text-black mb-4 transition-colors tap-target-sm text-sm sm:text-base"
|
listColor={list.color}
|
||||||
>
|
completedCount={completedItems.length}
|
||||||
<ArrowLeft size={20} className="flex-shrink-0" />
|
totalCount={list.items.length}
|
||||||
<span>Back to Lists</span>
|
permission={permission}
|
||||||
</Link>
|
canShare={canShare}
|
||||||
|
ownerId={list.ownerId}
|
||||||
<div className="flex items-center gap-2 sm:gap-3 mb-2">
|
ownerName={list.owner?.name}
|
||||||
<div
|
ownerEmail={list.owner?.email || ''}
|
||||||
className="w-5 h-5 sm:w-6 sm:h-6 rounded-full flex-shrink-0"
|
collaborators={list.collaborators.map(c => ({
|
||||||
style={{ backgroundColor: list.color }}
|
...c,
|
||||||
/>
|
permission: c.permission as 'editor' | 'viewer'
|
||||||
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold text-gray-900 truncate">{list.title}</h1>
|
}))}
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
<p className="text-gray-600 text-sm sm:text-base">
|
|
||||||
{completedItems.length} of {list.items.length} tasks completed
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Inline Item Creation - only show if user can edit */}
|
{/* Inline Item Creation - only show if user can edit */}
|
||||||
{canEdit && (
|
{canEdit && (
|
||||||
|
|||||||
@@ -156,26 +156,6 @@ export default function ListDetailView({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Permission Badge and Share Button */}
|
|
||||||
{(permission || canShare) && (
|
|
||||||
<div className="flex items-center justify-between gap-4">
|
|
||||||
{permission && (
|
|
||||||
<div>
|
|
||||||
<PermissionBadge permission={permission} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{canShare && (
|
|
||||||
<button
|
|
||||||
onClick={() => setIsShareModalOpen(true)}
|
|
||||||
className="ml-auto flex items-center gap-2 px-4 py-2 bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white rounded-lg transition-colors text-sm font-medium"
|
|
||||||
>
|
|
||||||
<Share2 size={16} />
|
|
||||||
Share
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Search Bar */}
|
{/* Search Bar */}
|
||||||
<SearchBar
|
<SearchBar
|
||||||
onSearch={handleSearchCallback}
|
onSearch={handleSearchCallback}
|
||||||
|
|||||||
98
components/ListHeader.tsx
Normal file
98
components/ListHeader.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState } from 'react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { ArrowLeft, Share2 } from 'lucide-react'
|
||||||
|
import PermissionBadge from './PermissionBadge'
|
||||||
|
import ShareListModal from './ShareListModal'
|
||||||
|
|
||||||
|
interface ListHeaderProps {
|
||||||
|
listId: string
|
||||||
|
listTitle: string
|
||||||
|
listColor: string
|
||||||
|
completedCount: number
|
||||||
|
totalCount: number
|
||||||
|
permission: 'owner' | 'editor' | 'viewer'
|
||||||
|
canShare: boolean
|
||||||
|
ownerId: string
|
||||||
|
ownerName: string | null | undefined
|
||||||
|
ownerEmail: string
|
||||||
|
collaborators: Array<{
|
||||||
|
id: string
|
||||||
|
permission: 'editor' | 'viewer'
|
||||||
|
user: {
|
||||||
|
id: string
|
||||||
|
name: string | null
|
||||||
|
email: string
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ListHeader({
|
||||||
|
listId,
|
||||||
|
listTitle,
|
||||||
|
listColor,
|
||||||
|
completedCount,
|
||||||
|
totalCount,
|
||||||
|
permission,
|
||||||
|
canShare,
|
||||||
|
ownerId,
|
||||||
|
ownerName,
|
||||||
|
ownerEmail,
|
||||||
|
collaborators
|
||||||
|
}: ListHeaderProps) {
|
||||||
|
const [isShareModalOpen, setIsShareModalOpen] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="mb-6 sm:mb-8">
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="inline-flex items-center gap-2 text-gray-600 hover:text-gray-900 active:text-black mb-4 transition-colors tap-target-sm text-sm sm:text-base"
|
||||||
|
>
|
||||||
|
<ArrowLeft size={20} className="flex-shrink-0" />
|
||||||
|
<span>Back to Lists</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between gap-3 mb-2">
|
||||||
|
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
|
||||||
|
<div
|
||||||
|
className="w-5 h-5 sm:w-6 sm:h-6 rounded-full flex-shrink-0"
|
||||||
|
style={{ backgroundColor: listColor }}
|
||||||
|
/>
|
||||||
|
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold text-gray-900 truncate">{listTitle}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 flex-shrink-0">
|
||||||
|
<PermissionBadge permission={permission} />
|
||||||
|
{canShare && (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsShareModalOpen(true)}
|
||||||
|
className="flex items-center gap-2 px-3 py-1.5 bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white rounded-lg transition-colors text-sm font-medium"
|
||||||
|
>
|
||||||
|
<Share2 size={16} />
|
||||||
|
<span className="hidden sm:inline">Share</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-600 text-sm sm:text-base">
|
||||||
|
{completedCount} of {totalCount} tasks completed
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ShareListModal
|
||||||
|
isOpen={isShareModalOpen}
|
||||||
|
onClose={() => setIsShareModalOpen(false)}
|
||||||
|
listId={listId}
|
||||||
|
listTitle={listTitle}
|
||||||
|
isOwner={permission === 'owner'}
|
||||||
|
ownerId={ownerId}
|
||||||
|
ownerName={ownerName}
|
||||||
|
ownerEmail={ownerEmail}
|
||||||
|
initialCollaborators={collaborators}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user