ZZY 73917d6001 dev feat(markcard, static): 实现书签卡片功能和静态资源获取
- 书签卡片相关的组件和页面
- 实现书签数据的获取、添加、编辑和删除功能
- 添加用户验证和权限控制
- 优化页面布局和样式
2024-12-22 15:21:07 +08:00

87 lines
3.1 KiB
TypeScript

import React from "react"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { ChevronDown, ExternalLink, Edit } from 'lucide-react'
import { MarkCardI, MarkLinkI, getBasePath } from '@/lib/markcard/card'
interface CardProps {
card: MarkCardI
canEdit: boolean
// userId?: string
baseUrl: string
onEdit?: (id: string, origin: MarkCardI) => void
}
export default function MarkCard({ card, canEdit, baseUrl, onEdit }: CardProps) {
const { id, title, shortDescription, detailedDescription, links, publicUrl } = card
// const baseUrl = await getBasePath(userId)
const realLinks = links.map(link => {
if (link.url.startsWith('$')) {
return { ...link, url: `${baseUrl}/${link.url.substring(1)}` }
}
return link
})
const getALink = (link: MarkLinkI) => {
return (
<a href={link.url} target={link.blank ? '_blank' : ''} rel="noopener noreferrer" className="flex items-center">
{link.title}
<ExternalLink className="ml-2 h-4 w-4" />
</a>
)
}
return (
<Card className="w-full max-w-md shadow-lg hover:shadow-xl transition-shadow duration-300">
<CardHeader>
<CardTitle className="text-2xl font-bold">{title}</CardTitle>
<CardDescription>{shortDescription}</CardDescription>
</CardHeader>
<CardContent>
{detailedDescription && <p className="text-sm text-gray-600 mb-4">{detailedDescription}</p>}
{publicUrl && (
<div className="mb-4">
<span className="text-sm font-semibold">Public URL: </span>
<a href={`${baseUrl}/${publicUrl}`} className="text-blue-500 hover:underline" target="_blank" rel="noopener noreferrer">
{`${baseUrl}/${publicUrl}`}
</a>
</div>
)}
</CardContent>
<CardFooter className="flex justify-between items-center">
<div className="flex space-x-2">
{ realLinks.length > 0 && (
<Button asChild variant="outline">
{getALink(realLinks[0])}
</Button>)}
{realLinks.length > 1 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">
Open Link <ChevronDown className="ml-2 h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
{realLinks.slice(1).map((link, index) => (
<DropdownMenuItem key={index} asChild>
{getALink(link)}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
{canEdit && onEdit && (
<Button variant="ghost" onClick={() => onEdit(id, card)}>
<Edit className="mr-2 h-4 w-4" />
Edit
</Button>
)}
</CardFooter>
</Card>
)
}