chore: add CONTRIBUTING.md for project guidelines and enhance README with author follow section
This commit is contained in:
@@ -49,7 +49,7 @@ function AppContent() {
|
||||
</ScrollArea>
|
||||
</main>
|
||||
|
||||
<Toaster />
|
||||
<Toaster richColors={true} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useSetAtom } from 'jotai'
|
||||
import {
|
||||
AlertCircle,
|
||||
CheckCircle2,
|
||||
Copy,
|
||||
ExternalLink,
|
||||
FolderOpen,
|
||||
Loader2,
|
||||
@@ -110,6 +111,25 @@ export function DownloadItem({ download }: DownloadItemProps) {
|
||||
await handleOpenFileLocation()
|
||||
}
|
||||
|
||||
const handleCopyToClipboard = async () => {
|
||||
if (!download.outputPath) {
|
||||
toast.error(t('notifications.copyFailed'))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const success = await ipcServices.fs.copyFileToClipboard(download.outputPath)
|
||||
if (!success) {
|
||||
toast.error(t('notifications.copyFailed'))
|
||||
return
|
||||
}
|
||||
toast.success(t('notifications.videoCopied'))
|
||||
} catch (error) {
|
||||
console.error('Failed to copy file to clipboard:', error)
|
||||
toast.error(t('notifications.copyFailed'))
|
||||
}
|
||||
}
|
||||
|
||||
const handleRemoveHistory = async () => {
|
||||
if (!isHistory) return
|
||||
try {
|
||||
@@ -166,11 +186,11 @@ export function DownloadItem({ download }: DownloadItemProps) {
|
||||
<div className="group relative w-full max-w-full overflow-hidden">
|
||||
<div className="flex w-full flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-start sm:gap-4">
|
||||
{/* Thumbnail */}
|
||||
<div className="shrink-0 overflow-hidden rounded-md border border-border/60 bg-background/60">
|
||||
<div className="shrink-0 overflow-hidden rounded-md border border-border/60 bg-background/60 w-32 h-20">
|
||||
<ImageWithPlaceholder
|
||||
src={thumbnailSrc}
|
||||
alt={download.title}
|
||||
className="w-32 h-18 object-cover aspect-video"
|
||||
className="w-full h-full object-cover"
|
||||
fallbackIcon={<Play className="h-6 w-6" />}
|
||||
/>
|
||||
</div>
|
||||
@@ -179,18 +199,11 @@ export function DownloadItem({ download }: DownloadItemProps) {
|
||||
<div className="flex-1 min-w-0 max-w-full space-y-3 overflow-hidden">
|
||||
<div className="flex w-full flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-start sm:justify-between sm:gap-4">
|
||||
<div className="flex-1 min-w-0 max-w-full space-y-2 overflow-hidden">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="w-full min-w-0 overflow-hidden">
|
||||
<p className="w-full wrap-break-word text-sm font-medium sm:text-base line-clamp-2">
|
||||
{download.title}
|
||||
</p>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p className="max-w-xs wrap-break-word">{download.title}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="w-full min-w-0 overflow-hidden">
|
||||
<p className="w-full wrap-break-word text-sm font-medium sm:text-base line-clamp-2">
|
||||
{download.title}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex w-full flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||
<Badge variant="outline" className="bg-muted/50 capitalize text-[11px] font-medium">
|
||||
{download.type}
|
||||
@@ -285,13 +298,13 @@ export function DownloadItem({ download }: DownloadItemProps) {
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 shrink-0"
|
||||
onClick={handleOpenFile}
|
||||
onClick={handleCopyToClipboard}
|
||||
>
|
||||
<ExternalLink className="h-4 w-4" />
|
||||
<Copy className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t('history.openFile')}</p>
|
||||
<p>{t('history.copyToClipboard')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
@@ -346,6 +359,21 @@ export function DownloadItem({ download }: DownloadItemProps) {
|
||||
<p>{t('history.openFile')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 shrink-0"
|
||||
onClick={handleCopyToClipboard}
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t('history.copyToClipboard')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
|
||||
@@ -44,7 +44,7 @@ export function ImageWithPlaceholder({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('relative', className)}>
|
||||
<div className={cn('relative w-full h-full', className)}>
|
||||
{isLoading && (
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@@ -48,6 +48,12 @@
|
||||
"shareSupport": "Recommend VidBee to your friends to support our growth and updates.",
|
||||
"shareTitle": "Spread the word",
|
||||
"shareDescription": "Share VidBee with your community in one click.",
|
||||
"followAuthorActions": {
|
||||
"follow": "Follow @nexmoex"
|
||||
},
|
||||
"followAuthorDescription": "Stay updated with the latest VidBee news and updates.",
|
||||
"followAuthorSupport": "Follow the developer on X (Twitter) to get the latest updates and news about VidBee.",
|
||||
"followAuthorTitle": "Follow the Developer",
|
||||
"shareActions": {
|
||||
"twitter": "Share on X (Twitter)",
|
||||
"facebook": "Share on Facebook",
|
||||
@@ -175,6 +181,7 @@
|
||||
"noHistory": "No download history yet",
|
||||
"noHistoryDescription": "Your completed downloads will appear here",
|
||||
"openFile": "Open File",
|
||||
"copyToClipboard": "Copy to clipboard",
|
||||
"openFileLocation": "Open File Location",
|
||||
"openFolder": "Open Folder",
|
||||
"openDownloadFolder": "Open Download Folder",
|
||||
@@ -203,6 +210,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"copyFailed": "Failed to copy to clipboard",
|
||||
"videoCopied": "Video copied to clipboard",
|
||||
"downloadCompleted": "Download completed",
|
||||
"downloadFailed": "Download failed",
|
||||
"downloadStarted": "Download started",
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
"website": "官方网站",
|
||||
"websiteDescription": "产品亮点、路线图与社区动态。"
|
||||
},
|
||||
"followAuthorActions": {
|
||||
"follow": "关注 @nexmoex"
|
||||
},
|
||||
"followAuthorDescription": "获取 VidBee 的最新消息和更新。",
|
||||
"followAuthorSupport": "在 X (Twitter) 上关注开发者,获取 VidBee 的最新更新和消息。",
|
||||
"followAuthorTitle": "关注开发者",
|
||||
"resourcesDescription": "了解 VidBee 并保持关注的实用链接。",
|
||||
"resourcesTitle": "资源",
|
||||
"sourceCode": "源代码已开放",
|
||||
|
||||
@@ -213,6 +213,29 @@ export function About() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t('about.followAuthorTitle')}</CardTitle>
|
||||
<CardDescription>{t('about.followAuthorDescription')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<p className="text-sm text-muted-foreground md:max-w-md">
|
||||
{t('about.followAuthorSupport')}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => openShareUrl('https://x.com/nexmoex')}
|
||||
className="gap-2"
|
||||
>
|
||||
<Twitter className="h-4 w-4" />
|
||||
{t('about.followAuthorActions.follow')}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t('about.shareTitle')}</CardTitle>
|
||||
|
||||
Reference in New Issue
Block a user