这是提交给“菠萝派挑战赛”的内容。
我建的东西想象一下参加一场令人兴奋的活动——比如一场开发者大会——在那里你会遇到新朋友,与他们一起拍摄大量照片和视频,并留下美好的回忆。然而,当活动结束时,你却发现没有办法轻松获取所有精彩的照片。
或者考虑一个婚礼:你知道你的宾客一整天留下了许多美好瞬间,但收集这些照片意味着你得挨个儿联系每个人。这绝对不是个好办法。
Picshaw 提供了一个简单的解决方法。作为活动组织者,你可以在平台上创建一个专属的活动文件夹,生成一个可以分享的链接,并邀请你的嘉宾上传他们拍的照片。这样一来,每个人都可以从所有参与者独特视角重温活动。再也不用担心错过任何瞬间,只需轻松分享回忆。
Picshaw功能- 可以创建公开和私人活动。公开活动会在“发现活动页面”展示,任何人都可以查看和探索。私人活动只能通过组织者提供的分享链接访问。
请看这张图片
- 轻松上传文件 访客可以轻松上传他们的活动照片到指定文件夹,所有美好瞬间都将汇集一处。
-
这里有两种查看模式,可以浏览上传的照片。
用户可以以列表模式查看照片,类似于 Instagram 的信息流,或者以网格模式查看,提供画廊式的布局。
-
轻松分享活动链接,组织者可以生成并分享一个唯一的链接来邀请嘉宾上传照片,简化了收集照片的流程。
发现公开活动,您可以从“发现活动”页面上浏览所有公开活动,并以新颖的方式体验他人共享的时刻。
无缝登录 用户可以快速且安全地使用 Google 登录或一次性登录链接登录,使体验顺畅且省心。
- 支持夜间模式和日间模式
试试 Picshaw 实时:https://picshaw.vercel.app
我的程序代码已在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 的内容,可以看看以下资源:
- Next.js 文档页 - 了解 Next.js 的功能和 API 详情。
- Next.js 学习 - 互动的 Next.js 教程。
你可以去查看GitHub 仓库 - 欢迎您的反馈和贡献。
在 Vercel 上部署应用最简单的方式来部署您的 Next.js 应用程序是使用 Vercel 平台,该平台由 Next.js 的创建者提供。
看看我们的Next.js 部署指南以获取更多信息。
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吧