Skip to content

Commit

Permalink
Merge pull request #97 from besscroft/feature-issues-91
Browse files Browse the repository at this point in the history
Feature issues 91
  • Loading branch information
besscroft authored Jul 4, 2024
2 parents 81101cb + a8ccc9a commit 017f4d3
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 59 deletions.
12 changes: 12 additions & 0 deletions app/api/open/get-image-blob/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'server-only'
import { NextRequest } from 'next/server'

export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url)
const imageUrl = searchParams.get('imageUrl')
// @ts-ignore
const blob = await fetch(imageUrl).then(res => res.blob())
return new Response(blob)
}

export const revalidate = 0
12 changes: 2 additions & 10 deletions components/BlurImage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
'use client'

import React, { useState } from 'react'
import React from 'react'
import { useButtonStore } from '~/app/providers/button-store-Providers'
import { Image } from '@nextui-org/image'
import { cn } from '~/utils'

export default function BlurImage({ photo }: { photo: any }) {
const [isLoading, setIsLoading] = useState(true)
const { setMasonryView, setMasonryViewData } = useButtonStore(
(state) => state,
)
Expand All @@ -26,13 +24,7 @@ export default function BlurImage({ photo }: { photo: any }) {
setMasonryView(true)
setMasonryViewData(photo)
}}
className={cn(
'duration-700 ease-in-out group-hover:opacity-75 cursor-pointer transition-all will-change-transform hover:scale-[1.01]',
isLoading
? 'scale-110 blur-2xl grayscale opacity-50'
: 'scale-100 blur-0 grayscale-0'
)}
onLoad={() => setIsLoading(false)}
className="duration-700 ease-in-out group-hover:opacity-75 cursor-pointer transition-all will-change-transform hover:scale-[1.01]"
/>
</div>
)
Expand Down
136 changes: 99 additions & 37 deletions components/MasonryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@ import {
} from '~/components/ui/Dialog'
import { useButtonStore } from '~/app/providers/button-store-Providers'
import { CopyrightType, DataProps, ImageType } from '~/types'
import { Image, Tabs, Tab, Card, CardHeader, CardBody, CardFooter, Button, Chip, Link, Avatar } from '@nextui-org/react'
import { Aperture, Camera, Image as ImageIcon, Languages, CalendarDays, X, SunMedium, MoonStar, Copyright, Crosshair, Timer, CircleGauge, Copy, Share2 } from 'lucide-react'
import { Image, Tabs, Tab, Card, CardHeader, CardBody, CardFooter, Button, Chip, Link, Avatar, Tooltip } from '@nextui-org/react'
import { Aperture, Camera, Image as ImageIcon, Images, Link as LinkIcon, ImageDown, Languages, CalendarDays, X, SunMedium, MoonStar, Copyright, Crosshair, Timer, CircleGauge, Share2 } from 'lucide-react'
import * as React from 'react'
import { useTheme } from 'next-themes'
import { useRouter } from 'next-nprogress-bar'
import ExifView from '~/components/ExifView'
import { toast } from 'sonner'
import { usePathname } from 'next/navigation'
import useSWR from 'swr'

export default function MasonryItem() {
const router = useRouter()
const pathname = usePathname()
const { MasonryView, MasonryViewData, setMasonryView, setMasonryViewData } = useButtonStore(
(state) => state,
)
const {data: download = false, mutate: setDownload} = useSWR(['masonry/download', MasonryViewData.url], null)
const { theme, setTheme } = useTheme()

const props: DataProps = {
Expand All @@ -44,6 +46,30 @@ export default function MasonryItem() {
}
}

async function downloadImg() {
setDownload(true)
try {
toast.warning('开始下载,原图较大,请耐心等待!', { duration: 1500 })
await fetch(`/api/open/get-image-blob?imageUrl=${MasonryViewData.url}`)
.then((response) => response.blob())
.then((blob) => {
const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement("a");
link.href = url;
const parsedUrl = new URL(MasonryViewData.url);
const filename = parsedUrl.pathname.split('/').pop();
link.download = filename || "downloaded-file";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
} catch (e) {
toast.error('下载失败!', { duration: 500 })
} finally {
setDownload(false)
}
}

return (
<Dialog
defaultOpen={false}
Expand All @@ -57,52 +83,37 @@ export default function MasonryItem() {
>
<DialogContent className="flex flex-col">
<div className="flex items-center">
<div className="flex-1">
<div className="flex-1 overflow-hidden whitespace-nowrap">
<p>{MasonryViewData.title}</p>
</div>
<div className="flex items-center space-x-4">
{
navigator.canShare && typeof navigator.canShare === 'function' &&
<Tooltip content="分享">
<Button
isIconOnly
variant="shadow"
size="sm"
aria-label="分享"
className="bg-white dark:bg-gray-800"
onClick={() => handleOnClick()}
>
<Share2 size={20}/>
</Button>
</Tooltip>
}
<Tooltip content="切换主题">
<Button
isIconOnly
variant="shadow"
size="sm"
aria-label="分享"
aria-label="切换主题"
className="bg-white dark:bg-gray-800"
onClick={() => handleOnClick()}
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
>
<Share2 size={20}/>
{theme === 'light' ? <SunMedium size={20} /> : <MoonStar size={20} />}
</Button>
}
<Button
isIconOnly
variant="shadow"
size="sm"
aria-label="复制直链"
className="bg-white dark:bg-gray-800"
onClick={async () => {
try {
const url = window.location.origin + (pathname === '/' ? '/preview/' : pathname + '/preview/') + MasonryViewData.id
// @ts-ignore
await navigator.clipboard.writeText(url);
toast.success('复制直链成功!', { duration: 500 })
} catch (error) {
toast.error('复制直链失败!', { duration: 500 })
}
}}
>
<Copy size={20}/>
</Button>
<Button
isIconOnly
variant="shadow"
size="sm"
aria-label="切换主题"
className="bg-white dark:bg-gray-800"
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
>
{theme === 'light' ? <SunMedium size={20} /> : <MoonStar size={20} />}
</Button>
</Tooltip>
<Button
isIconOnly
variant="shadow"
Expand All @@ -124,7 +135,7 @@ export default function MasonryItem() {
<Image
className="object-contain md:max-h-[90vh]"
alt={MasonryViewData.detail}
src={MasonryViewData.url}
src={MasonryViewData.preview_url || MasonryViewData.url}
radius="none"
loading="lazy"
/>
Expand All @@ -141,6 +152,57 @@ export default function MasonryItem() {
}
>
<div className="flex flex-col space-y-2">
<div className="flex space-x-2">
<Button
color="primary"
variant="bordered"
aria-label="复制图片链接"
size="sm"
startContent={<Images size={20}/>}
onClick={async () => {
try {
const url = MasonryViewData.url
// @ts-ignore
await navigator.clipboard.writeText(url);
toast.success('复制图片链接成功!', { duration: 500 })
} catch (error) {
toast.error('复制图片链接失败!', { duration: 500 })
}
}}
>
复制图片链接
</Button>
<Button
color="primary"
variant="bordered"
aria-label="复制直链"
size="sm"
startContent={<LinkIcon size={20}/>}
onClick={async () => {
try {
const url = window.location.origin + (pathname === '/' ? '/preview/' : pathname + '/preview/') + MasonryViewData.id
// @ts-ignore
await navigator.clipboard.writeText(url);
toast.success('复制直链成功!', { duration: 500 })
} catch (error) {
toast.error('复制直链失败!', { duration: 500 })
}
}}
>
复制直链
</Button>
<Button
color="primary"
variant="bordered"
aria-label="下载原图"
size="sm"
startContent={<ImageDown size={20}/>}
onClick={() => downloadImg()}
isLoading={download}
>
下载原图
</Button>
</div>
{MasonryViewData?.exif?.model && MasonryViewData?.exif?.f_number
&& MasonryViewData?.exif?.exposure_time && MasonryViewData?.exif?.focal_length
&& MasonryViewData?.exif?.iso_speed_rating &&
Expand Down
2 changes: 1 addition & 1 deletion components/admin/list/ImageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default function ImageView() {
<Image
isBlurred
isZoomed
src={imageViewData.url}
src={imageViewData.preview_url || imageViewData.url}
alt={imageViewData.detail}
/>
{imageViewData?.labels &&
Expand Down
13 changes: 2 additions & 11 deletions components/admin/list/ListImage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
'use client'

import React, { useState } from 'react'
import React from 'react'
import { Image } from '@nextui-org/image'
import { cn } from '~/utils'

export default function ListImage({ image }: { image: any }) {
const [isLoading, setIsLoading] = useState(true)

return (
<Image
src={image.preview_url || image.url}
Expand All @@ -15,13 +12,7 @@ export default function ListImage({ image }: { image: any }) {
removeWrapper
disableSkeleton
radius="none"
className={cn(
'duration-700 ease-in-out group-hover:opacity-75 object-cover',
isLoading
? 'scale-110 blur-2xl grayscale'
: 'scale-100 blur-0 grayscale-0'
)}
onLoad={() => setIsLoading(false)}
className="duration-700 ease-in-out group-hover:opacity-75 object-cover"
/>
)
}

0 comments on commit 017f4d3

Please sign in to comment.