feat: initialize aivideo project

This commit is contained in:
2026-04-17 18:33:05 +08:00
commit 14b18d67fe
162 changed files with 26251 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
"use client";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { api } from "@/lib/api";
import type { AssetItem } from "@/lib/types";
export default function AssetsPage() {
const [mediaType, setMediaType] = useState("image");
const assetsQuery = useQuery({
queryKey: ["asset-list"],
queryFn: () => api.get<AssetItem[]>("/api/v1/assets"),
});
const uploadMutation = useMutation({
mutationFn: async (file: File) => {
const formData = new FormData();
formData.append("file", file);
formData.append("mediaType", mediaType);
return api.post("/api/v1/assets", formData);
},
onSuccess: () => assetsQuery.refetch(),
});
const deleteMutation = useMutation({
mutationFn: (assetId: number) => api.del(`/api/v1/assets/${assetId}`),
onSuccess: () => assetsQuery.refetch(),
});
return (
<div className="two-col-grid">
<section className="panel">
<h3></h3>
<div className="form-stack">
<label className="field-label">
<select value={mediaType} onChange={(event) => setMediaType(event.target.value)}>
<option value="image"></option>
<option value="video"></option>
<option value="audio"></option>
</select>
</label>
<label className="field-label">
<input
type="file"
onChange={(event) => {
const file = event.target.files?.[0];
if (file) {
uploadMutation.mutate(file);
}
}}
/>
</label>
</div>
</section>
<section className="panel">
<h3></h3>
<div className="list-grid">
{assetsQuery.data?.map((asset) => (
<div className="list-item" key={asset.id}>
<strong>{asset.originalFilename}</strong>
<div className="muted">
{asset.mediaType} · {Math.round(asset.fileSize / 1024)} KB
</div>
<div className="row" style={{ marginTop: 12 }}>
<a className="ghost-button" href={asset.publicUrl} target="_blank">
</a>
<button
className="danger-button"
onClick={() => deleteMutation.mutate(asset.id)}
>
</button>
</div>
</div>
))}
</div>
</section>
</div>
);
}