mirror of
https://github.com/beilunyang/moemail.git
synced 2025-11-02 11:34:03 +08:00
208 lines
7.4 KiB
TypeScript
208 lines
7.4 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { EmailList } from "./email-list"
|
|
import { MessageListContainer } from "./message-list-container"
|
|
import { MessageView } from "./message-view"
|
|
import { SendDialog } from "./send-dialog"
|
|
import { cn } from "@/lib/utils"
|
|
import { useCopy } from "@/hooks/use-copy"
|
|
import { useSendPermission } from "@/hooks/use-send-permission"
|
|
import { Copy } from "lucide-react"
|
|
|
|
interface Email {
|
|
id: string
|
|
address: string
|
|
}
|
|
|
|
export function ThreeColumnLayout() {
|
|
const [selectedEmail, setSelectedEmail] = useState<Email | null>(null)
|
|
const [selectedMessageId, setSelectedMessageId] = useState<string | null>(null)
|
|
const [selectedMessageType, setSelectedMessageType] = useState<'received' | 'sent'>('received')
|
|
const [refreshTrigger, setRefreshTrigger] = useState(0)
|
|
const { copyToClipboard } = useCopy()
|
|
const { canSend: canSendEmails } = useSendPermission()
|
|
|
|
const columnClass = "border-2 border-primary/20 bg-background rounded-lg overflow-hidden flex flex-col"
|
|
const headerClass = "p-2 border-b-2 border-primary/20 flex items-center justify-between shrink-0"
|
|
const titleClass = "text-sm font-bold px-2 w-full overflow-hidden"
|
|
|
|
// 移动端视图逻辑
|
|
const getMobileView = () => {
|
|
if (selectedMessageId) return "message"
|
|
if (selectedEmail) return "emails"
|
|
return "list"
|
|
}
|
|
|
|
const mobileView = getMobileView()
|
|
|
|
const copyEmailAddress = () => {
|
|
copyToClipboard(selectedEmail?.address || "")
|
|
}
|
|
|
|
const handleMessageSelect = (messageId: string | null, messageType: 'received' | 'sent' = 'received') => {
|
|
setSelectedMessageId(messageId)
|
|
setSelectedMessageType(messageType)
|
|
}
|
|
|
|
const handleSendSuccess = () => {
|
|
setRefreshTrigger(prev => prev + 1)
|
|
}
|
|
|
|
return (
|
|
<div className="pb-5 pt-20 h-full flex flex-col">
|
|
{/* 桌面端三栏布局 */}
|
|
<div className="hidden lg:grid grid-cols-12 gap-4 h-full min-h-0">
|
|
<div className={cn("col-span-3", columnClass)}>
|
|
<div className={headerClass}>
|
|
<h2 className={titleClass}>我的邮箱</h2>
|
|
</div>
|
|
<div className="flex-1 overflow-auto">
|
|
<EmailList
|
|
onEmailSelect={(email) => {
|
|
setSelectedEmail(email)
|
|
setSelectedMessageId(null)
|
|
}}
|
|
selectedEmailId={selectedEmail?.id}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={cn("col-span-4", columnClass)}>
|
|
<div className={headerClass}>
|
|
<h2 className={titleClass}>
|
|
{selectedEmail ? (
|
|
<div className="w-full flex justify-between items-center gap-2">
|
|
<div className="flex items-center gap-2">
|
|
<span className="truncate min-w-0">{selectedEmail.address}</span>
|
|
<div className="shrink-0 cursor-pointer text-primary" onClick={copyEmailAddress}>
|
|
<Copy className="size-4" />
|
|
</div>
|
|
</div>
|
|
{selectedEmail && canSendEmails && (
|
|
<SendDialog
|
|
emailId={selectedEmail.id}
|
|
fromAddress={selectedEmail.address}
|
|
onSendSuccess={handleSendSuccess}
|
|
/>
|
|
)}
|
|
</div>
|
|
) : (
|
|
"选择邮箱查看消息"
|
|
)}
|
|
</h2>
|
|
</div>
|
|
{selectedEmail && (
|
|
<div className="flex-1 overflow-auto">
|
|
<MessageListContainer
|
|
email={selectedEmail}
|
|
onMessageSelect={handleMessageSelect}
|
|
selectedMessageId={selectedMessageId}
|
|
refreshTrigger={refreshTrigger}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className={cn("col-span-5", columnClass)}>
|
|
<div className={headerClass}>
|
|
<h2 className={titleClass}>
|
|
{selectedMessageId ? "邮件内容" : "选择邮件查看详情"}
|
|
</h2>
|
|
</div>
|
|
{selectedEmail && selectedMessageId && (
|
|
<div className="flex-1 overflow-auto">
|
|
<MessageView
|
|
emailId={selectedEmail.id}
|
|
messageId={selectedMessageId}
|
|
messageType={selectedMessageType}
|
|
onClose={() => setSelectedMessageId(null)}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 移动端单栏布局 */}
|
|
<div className="lg:hidden h-full min-h-0">
|
|
<div className={cn("h-full", columnClass)}>
|
|
{mobileView === "list" && (
|
|
<>
|
|
<div className={headerClass}>
|
|
<h2 className={titleClass}>我的邮箱</h2>
|
|
</div>
|
|
<div className="flex-1 overflow-auto">
|
|
<EmailList
|
|
onEmailSelect={(email) => {
|
|
setSelectedEmail(email)
|
|
}}
|
|
selectedEmailId={selectedEmail?.id}
|
|
/>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{mobileView === "emails" && selectedEmail && (
|
|
<div className="h-full flex flex-col">
|
|
<div className={cn(headerClass, "gap-2")}>
|
|
<button
|
|
onClick={() => {
|
|
setSelectedEmail(null)
|
|
}}
|
|
className="text-sm text-primary shrink-0"
|
|
>
|
|
← 返回邮箱列表
|
|
</button>
|
|
<div className="flex-1 flex justify-between items-center gap-2 min-w-0">
|
|
<div className="flex items-center gap-2">
|
|
<span className="truncate min-w-0 flex-1 text-right">{selectedEmail.address}</span>
|
|
<div className="shrink-0 cursor-pointer text-primary" onClick={copyEmailAddress}>
|
|
<Copy className="size-4" />
|
|
</div>
|
|
</div>
|
|
{canSendEmails && (
|
|
<SendDialog
|
|
emailId={selectedEmail.id}
|
|
fromAddress={selectedEmail.address}
|
|
onSendSuccess={handleSendSuccess}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 overflow-auto">
|
|
<MessageListContainer
|
|
email={selectedEmail}
|
|
onMessageSelect={handleMessageSelect}
|
|
selectedMessageId={selectedMessageId}
|
|
refreshTrigger={refreshTrigger}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{mobileView === "message" && selectedEmail && selectedMessageId && (
|
|
<div className="h-full flex flex-col">
|
|
<div className={headerClass}>
|
|
<button
|
|
onClick={() => setSelectedMessageId(null)}
|
|
className="text-sm text-primary"
|
|
>
|
|
← 返回消息列表
|
|
</button>
|
|
<span className="text-sm font-medium">邮件内容</span>
|
|
</div>
|
|
<div className="flex-1 overflow-auto">
|
|
<MessageView
|
|
emailId={selectedEmail.id}
|
|
messageId={selectedMessageId}
|
|
messageType={selectedMessageType}
|
|
onClose={() => setSelectedMessageId(null)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|