手记

Picshaw(拍趣)- 款图片分享应用。

这是提交给“菠萝派挑战赛”的内容。

我建的东西

想象一下参加一场令人兴奋的活动——比如一场开发者大会——在那里你会遇到新朋友,与他们一起拍摄大量照片和视频,并留下美好的回忆。然而,当活动结束时,你却发现没有办法轻松获取所有精彩的照片。

或者考虑一个婚礼:你知道你的宾客一整天留下了许多美好瞬间,但收集这些照片意味着你得挨个儿联系每个人。这绝对不是个好办法。

Picshaw 提供了一个简单的解决方法。作为活动组织者,你可以在平台上创建一个专属的活动文件夹,生成一个可以分享的链接,并邀请你的嘉宾上传他们拍的照片。这样一来,每个人都可以从所有参与者独特视角重温活动。再也不用担心错过任何瞬间,只需轻松分享回忆。

Picshaw功能
  • 可以创建公开和私人活动。公开活动会在“发现活动页面”展示,任何人都可以查看和探索。私人活动只能通过组织者提供的分享链接访问。

请看这张图片

  • 轻松上传文件 访客可以轻松上传他们的活动照片到指定文件夹,所有美好瞬间都将汇集一处。

  • 这里有两种查看模式,可以浏览上传的照片。
    用户可以以列表模式查看照片,类似于 Instagram 的信息流,或者以网格模式查看,提供画廊式的布局。

  • 轻松分享活动链接,组织者可以生成并分享一个唯一的链接来邀请嘉宾上传照片,简化了收集照片的流程。

    发现公开活动,您可以从“发现活动”页面上浏览所有公开活动,并以新颖的方式体验他人共享的时刻。

无缝登录 用户可以快速且安全地使用 Google 登录或一次性登录链接登录,使体验顺畅且省心。

  • 支持夜间模式和日间模式
Demo

试试 Picshaw 实时:https://picshaw.vercel.app

我的程序

代码已在GitHub上发布。可以给我点个星,也可以关注我,😊

lenajeremy / hack-photobomb (GitHub上的用户名和项目链接)

请提供需要审查的文本内容。

这是一个通过create-next-app创建的Next.js项目。

开始入门

首先,运行开发服务器。

# 未提供具体命令,此处仅翻译描述部分。

你可以使用以下任何一种命令来运行开发环境:

    npm run dev
    或者,
    yarn dev
    或者,
    pnpm dev
    或者,
    bun dev

切换到全屏 退出全屏

用浏览器打开http://localhost:3000看看结果吧。

你可以通过修改app/page.tsx来开始编辑页面,并且在编辑文件时,页面会自动更新。

该项目使用next/font 自动优化并加载Geist,这是一款新的 Vercel 字体家族。

了解更多

要了解更多关于 Next.js 的内容,可以看看以下资源:

你可以去查看GitHub 仓库 - 欢迎您的反馈和贡献。

在 Vercel 上部署应用

最简单的方式来部署您的 Next.js 应用程序是使用 Vercel 平台,该平台由 Next.js 的创建者提供。

看看我们的Next.js 部署指南以获取更多信息。

在 GitHub 上查看此项目

zh: zh: (内容省略)

玩 Pinata:

与Pinata集成是项目中最顺利的部分之一。以下是实现步骤的分解:

- Do not translate the following part as it's a code segment.

注意:上述代码段无需翻译。

1. 启动Pinata SDK

我创建了一个专用文件 @/lib/pinata.ts 来管理Pinata的配置。

    import { PinataSDK } from "pinata"

    export const pinata = new PinataSDK({
        pinataJwt: `${process.env.PINATA_JWT}`,
        pinataGateway: `${process.env.NEXT_PUBLIC_GATEWAY_URL}`
    })

全屏模式 退出全屏

此处省略

2. 在我的 API 路由部分:

  • 确认用户已登录后再进行上传文件,确保操作顺利。
    const session = await auth()

    if (!session || !session.user) {
       return respondError(new Error("用户未通过认证"), "未能通过用户认证", 401)
    }
    // 未通过认证,状态码 401

进入全屏模式 退出全屏模式

  • 验证请求内容:我确认了事件的存在,并且保证文件上传未超出限制
    const form = await request.formData()
    const files = Array.from(form.values())
    const eventSlug = params["event-slug"]

    try {
        const event = await prisma.event.findUnique({ where: { slug: eventSlug } })

        if (!event) {
            return respondError("活动未找到", undefined, 404)
        }

        if (files.length > 50) {
            return respondError("每个请求最多只能上传50个文件", "上传的文件数超过上限", 400)
        } else if (files.length === 0) {
            return respondError("至少需要上传一个文件", "未上传任何文件", 400)
        }

全屏/退出全屏

下一步就是把文件上传到Pinata了。

// 该代码片段主要用于处理文件的上传以及获取上传文件的公共URL。首先,它过滤并上传非字符串类型的文件,然后获取成功上传的文件列表。接下来,为每个成功上传的文件生成一个带有有效期限的公共URL。
const res = await Promise.all(files.filter(f => typeof f !== 'string').map(f => pinata.upload.file(f)))
            const successfulUploads = res.filter(r => r.status === "fulfilled")

            const uploadsWithPublicURL = await Promise.all(successfulUploads.map(async r => {
                const publicURL = await pinata.gateways.createSignedURL({ cid: r.value.cid, expires: 60 * 60 * 24 * 365 })
                return { ...r.value, publicURL }
            }))

点击进入全屏模式。点击退出全屏模式。

提示:更好的实现方式应该包括上传失败的检测,这样用户就能知道哪些文件上传失败,并尝试重新上传。

  • 将上传的数据最终保存到数据库,我使用 Prisma 完成了这一操作。
    const dbUpload = await prisma.upload.create({
                data: {
                    text: `${session.user.name} 上传了 ${files.length} 张图片到 ${event?.name}`,
                    ownerId: session.user?.id ?? "",
                    eventId: event?.id ?? "",
                    files: {
                        createMany: {
                            data: uploadsWithPublicURL.map(file => {
                                return {
                                    ownerId: session.user?.id ?? "",
                                    eventId: event?.id ?? "",
                                    cid: file.id,
                                    publicURL: file.publicURL,
                                }
                            })
                        }
                    }
                }
            })

            return respondSuccess(dbUpload, "成功上传", 201)

全屏观看,退出全屏


这个流程确保活动照片安全高效地上传至Pinata,成功的上传会被追踪并存储在数据库里,以便以后方便访问。

在浏览器中渲染上传的图片

1. 调整 next.config.js 文件以进行必要的配置更改

更新 next.config.js 文件中的 images 字段配置,以使 NextJS 能优化来自远程 URL 的图片。

    /** @type {{import('next').NextConfig}} */
    const nextConfig = {
      images: {
        remotePatterns: [
          {
            hostname: "sapphire-obliged-canidae-626.mypinata.cloud",
            protocol: "https",
          },
        ],
      },
    };

    export default nextConfig;

点击全屏 点击退出全屏

2. 查看事件信息

在我的应用里,我使用一个自定义钩子useFetch来获取所选事件的详情。

     const params = useParams();
      const eventSlug = params["event-slug"];
      const [viewMode, setViewMode] = React.useState<"网格视图" | "列表视图">("网格视图");
      const router = useRouter();

      const {
        loading,
        data,
        trigger: getEventDetails,
      } = useFetch<void, GetUploadsResponse>(`/api/e/${eventSlug}`, undefined, {
        fetchOnRender: true, // 在渲染时触发数据获取
      });

点击这里切换到全屏模式;点击这里切换回正常模式

3. 图像渲染

我把获取到的图片显示在一个自适应的网格布局中

      <div className="grid grid-cols-3 md:grid-cols-4 gap-1 my-6">
            {photos.map((file) => (
              <Image
                key={file.id}
                src={file.publicURL}
                width={400}
                height={400}
                alt=""
                className="aspect-square object-cover"
              />
          ))}
     </div>
这是一个网格布局,包含多张图片。每张图片由photos数组中的一个对象来表示。通过映射函数,我们将photos数组中的每个对象转换为一个图片元素。每个图片元素的宽度和高度都是400像素,且保持正方形比例。

全屏。退出全屏。

改进建议

为了进一步改进这款应用,有必要添加一些内容过滤功能。这可以确保用户不会在公共组中发布不适宜公开的内容。我开始尝试使用Google Cloud Vision,但由于时间紧迫,未能在截止日期前完成。

总结

将Pinata的文件API集成到Picshaw中大大提升了图像上传和管理的体验。Pinata的无缝性能,其直观的API让实现变得简单,让我能够专注于构建应用的核心功能,同时放心地让Pinata高效处理文件存储和分发。

总体上来说,Pinata已成为构建稳定且流畅的图片管理系统的重要工具。

我还特别喜欢做Picshaw。

关注我在X @jeremiahlena13

0人推荐
随时随地看视频
慕课网APP