@vilio/media-module 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ import { NextResponse } from "next/server";
2
+ export declare function DELETE(request: Request): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ success: boolean;
6
+ }>>;
7
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/api/delete.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,wBAAsB,MAAM,CAAC,OAAO,EAAE,OAAO;;;;IAmC5C"}
@@ -0,0 +1,35 @@
1
+ import { db, getCurrentSession } from "@vilio/core/server";
2
+ import { eq } from "drizzle-orm";
3
+ import { NextResponse } from "next/server";
4
+ import { mediaTable } from "../schema";
5
+ export async function DELETE(request) {
6
+ try {
7
+ const session = await getCurrentSession();
8
+ if (!session?.user) {
9
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
10
+ }
11
+ const { searchParams } = new URL(request.url);
12
+ const id = searchParams.get("id");
13
+ if (!id) {
14
+ return NextResponse.json({ error: "No ID provided" }, { status: 400 });
15
+ }
16
+ const [item] = await db
17
+ .select()
18
+ .from(mediaTable)
19
+ .where(eq(mediaTable.id, id))
20
+ .limit(1);
21
+ if (!item) {
22
+ return NextResponse.json({ error: "Media not found" }, { status: 404 });
23
+ }
24
+ // Use filesystemService to delete from the correct provider
25
+ //await filesystemService.delete(item.url, item.provider as any);
26
+ // Remove from DB
27
+ await db.delete(mediaTable).where(eq(mediaTable.id, id));
28
+ return NextResponse.json({ success: true });
29
+ }
30
+ catch (error) {
31
+ console.error("[Media:Delete] Error:", error);
32
+ return NextResponse.json({ error: "Delete failed" }, { status: 500 });
33
+ }
34
+ }
35
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/api/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAqB,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAgB;IAC3C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,iBAAiB,EAAE,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;YACnB,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAElC,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,EAAE;aACpB,MAAM,EAAE;aACR,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aAC5B,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,4DAA4D;QAC5D,iEAAiE;QAEjE,iBAAiB;QACjB,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAEzD,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;QAC9C,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { NextResponse } from "next/server";
2
+ export declare function GET(): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ id: string;
6
+ filename: string;
7
+ url: string;
8
+ provider: "local" | "vercel-blob" | "s3";
9
+ mimeType: string;
10
+ size: number;
11
+ width: number | null;
12
+ height: number | null;
13
+ alt: string | null;
14
+ metadata: unknown;
15
+ authorId: string | null;
16
+ createdAt: Date;
17
+ updatedAt: Date | null;
18
+ }[]>>;
19
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/api/list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,wBAAsB,GAAG;;;;;;;;;;;;;;;;MAqBxB"}
@@ -0,0 +1,23 @@
1
+ import { db, getCurrentSession } from "@vilio/core/server";
2
+ import { desc } from "drizzle-orm";
3
+ import { NextResponse } from "next/server";
4
+ import { mediaTable } from "../schema";
5
+ export async function GET() {
6
+ try {
7
+ const session = await getCurrentSession();
8
+ if (!session?.user) {
9
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
10
+ }
11
+ const items = await db
12
+ .select()
13
+ .from(mediaTable)
14
+ .orderBy(desc(mediaTable.createdAt))
15
+ .limit(100);
16
+ return NextResponse.json(items);
17
+ }
18
+ catch (error) {
19
+ console.error("[Media:List] Error:", error);
20
+ return NextResponse.json({ error: "Failed to fetch media" }, { status: 500 });
21
+ }
22
+ }
23
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/api/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,iBAAiB,EAAE,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;YACnB,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,EAAE;aACnB,MAAM,EAAE;aACR,IAAI,CAAC,UAAU,CAAC;aAChB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;aACnC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEd,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;QAC5C,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAClC,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { NextResponse } from "next/server";
2
+ export declare function POST(request: Request): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ metadata: unknown;
6
+ id: string;
7
+ url: string;
8
+ size: number;
9
+ height: number | null;
10
+ width: number | null;
11
+ alt: string | null;
12
+ filename: string;
13
+ provider: "local" | "vercel-blob" | "s3";
14
+ mimeType: string;
15
+ authorId: string | null;
16
+ createdAt: Date;
17
+ updatedAt: Date | null;
18
+ }>>;
19
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/api/upload.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO;;;;;;;;;;;;;;;;IAuD1C"}
@@ -0,0 +1,50 @@
1
+ import { db, filesystemService, getCurrentSession } from "@vilio/core/server";
2
+ import { applyFilters } from "@vilio/modules/server";
3
+ import { NextResponse } from "next/server";
4
+ import { mediaTable } from "../schema";
5
+ export async function POST(request) {
6
+ try {
7
+ const session = await getCurrentSession();
8
+ if (!session?.user) {
9
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
10
+ }
11
+ const formData = await request.formData();
12
+ const file = formData.get("file");
13
+ if (!file) {
14
+ return NextResponse.json({ error: "No file provided" }, { status: 400 });
15
+ }
16
+ // Use Vilio Filesystem Service to handle upload (local, vercel-blob, etc.)
17
+ const result = await filesystemService.upload(file);
18
+ // Type guard: Check if the result is an error
19
+ if ("error" in result) {
20
+ console.error("[Media:Upload] Filesystem error:", result.error);
21
+ return NextResponse.json({ error: result.error }, { status: 500 });
22
+ }
23
+ // result is now inferred as StorageData (has url, service, etc.)
24
+ const uploaded = result;
25
+ // Ensure we have a URL before inserting into DB
26
+ if (!uploaded.url) {
27
+ console.error("[Media:Upload] Provider returned empty URL:", uploaded);
28
+ return NextResponse.json({ error: "Provider did not return a file URL" }, { status: 500 });
29
+ }
30
+ // --- HOOK: media:upload:before_db ---
31
+ // Allow other modules to modify media data before it's saved to DB
32
+ const mediaData = await applyFilters("media:upload:before_db", {
33
+ filename: uploaded.name || file.name,
34
+ url: uploaded.url,
35
+ provider: (uploaded.service || "local"),
36
+ mimeType: uploaded.type || file.type,
37
+ size: uploaded.size || file.size,
38
+ authorId: session.user.id,
39
+ metadata: uploaded.metadata || {},
40
+ });
41
+ // Insert into DB
42
+ const [media] = await db.insert(mediaTable).values(mediaData).returning();
43
+ return NextResponse.json(media);
44
+ }
45
+ catch (error) {
46
+ console.error("[Media:Upload] Unexpected Error:", error);
47
+ return NextResponse.json({ error: "Upload failed" }, { status: 500 });
48
+ }
49
+ }
50
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/api/upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from "./components/MediaPicker";
2
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC"}
package/dist/client.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./components/MediaPicker";
2
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ interface MediaItem {
3
+ id: string;
4
+ filename: string;
5
+ url: string;
6
+ mimeType: string;
7
+ size: number;
8
+ }
9
+ interface MediaPickerProps {
10
+ onSelect: (item: MediaItem) => void;
11
+ trigger?: React.ReactNode;
12
+ selectedId?: string;
13
+ }
14
+ export declare function MediaPicker({ onSelect, trigger, selectedId, }: MediaPickerProps): import("react/jsx-runtime").JSX.Element;
15
+ export {};
16
+ //# sourceMappingURL=MediaPicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaPicker.d.ts","sourceRoot":"","sources":["../../src/components/MediaPicker.tsx"],"names":[],"mappings":"AAeA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAO,EACP,UAAU,GACX,EAAE,gBAAgB,2CAyKlB"}
@@ -0,0 +1,76 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { i18n } from "@vilio/intl";
4
+ import { Button } from "@vilio/ui/components/button";
5
+ import { Card } from "@vilio/ui/components/card";
6
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@vilio/ui/components/dialog";
7
+ import { Input } from "@vilio/ui/components/input";
8
+ import { Skeleton } from "@vilio/ui/components/skeleton";
9
+ import { Check, Search, Upload } from "lucide-react";
10
+ import { useEffect, useState } from "react";
11
+ import { toast } from "sonner";
12
+ export function MediaPicker({ onSelect, trigger, selectedId, }) {
13
+ const [items, setItems] = useState([]);
14
+ const [loading, setLoading] = useState(false);
15
+ const [uploading, setUploading] = useState(false);
16
+ const [searchQuery, setSearchQuery] = useState("");
17
+ const [open, setOpen] = useState(false);
18
+ const fetchMedia = async () => {
19
+ try {
20
+ setLoading(true);
21
+ const res = await fetch("/api/media");
22
+ const data = await res.json();
23
+ if (Array.isArray(data)) {
24
+ setItems(data);
25
+ }
26
+ }
27
+ catch (error) {
28
+ toast.error("Failed to load media");
29
+ }
30
+ finally {
31
+ setLoading(false);
32
+ }
33
+ };
34
+ useEffect(() => {
35
+ if (open) {
36
+ fetchMedia();
37
+ }
38
+ }, [open]);
39
+ const handleUpload = async (e) => {
40
+ const file = e.target.files?.[0];
41
+ if (!file)
42
+ return;
43
+ const formData = new FormData();
44
+ formData.append("file", file);
45
+ try {
46
+ setUploading(true);
47
+ const res = await fetch("/api/media/upload", {
48
+ method: "POST",
49
+ body: formData,
50
+ });
51
+ if (res.ok) {
52
+ const newMedia = await res.json();
53
+ toast.success("File uploaded successfully");
54
+ // Refresh list and select the new item
55
+ await fetchMedia();
56
+ handleSelect(newMedia);
57
+ }
58
+ else {
59
+ toast.error("Upload failed");
60
+ }
61
+ }
62
+ catch (error) {
63
+ toast.error("An error occurred during upload");
64
+ }
65
+ finally {
66
+ setUploading(false);
67
+ }
68
+ };
69
+ const filteredItems = items.filter((item) => item.filename.toLowerCase().includes(searchQuery.toLowerCase()));
70
+ const handleSelect = (item) => {
71
+ onSelect(item);
72
+ setOpen(false);
73
+ };
74
+ return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [_jsx(DialogTrigger, { asChild: true, children: trigger || _jsx(Button, { variant: "outline", children: i18n("Select Media") }) }), _jsxs(DialogContent, { className: "max-w-4xl max-h-[90vh] flex flex-col p-0 overflow-hidden", children: [_jsx(DialogHeader, { className: "p-6 pb-2", children: _jsxs(DialogTitle, { className: "flex items-center justify-between", children: [_jsx("span", { children: i18n("Media Library") }), _jsx("div", { className: "flex items-center gap-2", children: _jsxs("label", { className: "cursor-pointer", children: [_jsx("input", { type: "file", className: "hidden", onChange: handleUpload, disabled: uploading }), _jsx(Button, { size: "sm", variant: "default", asChild: true, disabled: uploading, children: _jsxs("span", { children: [_jsx(Upload, { className: "mr-2 h-4 w-4" }), uploading ? i18n("Uploading...") : i18n("Upload New")] }) })] }) })] }) }), _jsx("div", { className: "px-6 py-2 border-b bg-muted/30", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), _jsx(Input, { placeholder: i18n("Search files..."), className: "pl-10 bg-background", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto p-6 min-h-[400px]", children: loading && items.length === 0 ? (_jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4", children: Array.from({ length: 12 }).map((_, i) => (_jsx(Skeleton, { className: "aspect-square rounded-lg" }, i))) })) : filteredItems.length > 0 ? (_jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4", children: filteredItems.map((item) => (_jsxs(Card, { className: `group relative aspect-square overflow-hidden cursor-pointer hover:ring-2 hover:ring-primary transition-all border-none bg-muted/50 ${selectedId === item.id ? "ring-2 ring-primary" : ""}`, onClick: () => handleSelect(item), children: [item.mimeType.startsWith("image/") ? (_jsx("img", { src: item.url, alt: item.filename, className: "h-full w-full object-cover" })) : (_jsx("div", { className: "flex h-full items-center justify-center bg-muted", children: _jsx("div", { className: "text-xs font-medium uppercase text-muted-foreground", children: item.mimeType.split("/")[1] }) })), selectedId === item.id && (_jsx("div", { className: "absolute inset-0 bg-primary/20 flex items-center justify-center", children: _jsx("div", { className: "bg-primary text-white rounded-full p-1 shadow-lg", children: _jsx(Check, { className: "h-4 w-4" }) }) })), _jsx("div", { className: "absolute inset-x-0 bottom-0 bg-black/60 p-2 opacity-0 group-hover:opacity-100 transition-opacity", children: _jsx("p", { className: "text-[10px] truncate text-white text-center font-medium", children: item.filename }) })] }, item.id))) })) : (_jsxs("div", { className: "flex flex-col items-center justify-center py-20 text-center text-muted-foreground", children: [_jsx(Upload, { className: "h-10 w-10 mb-4 opacity-20" }), _jsx("p", { className: "text-sm", children: i18n("No media found. Upload your first file!") })] })) })] })] }));
75
+ }
76
+ //# sourceMappingURL=MediaPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaPicker.js","sourceRoot":"","sources":["../../src/components/MediaPicker.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { IModule } from "@vilio/modules";
2
+ declare const module: IModule;
3
+ export default module;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAO9C,QAAA,MAAM,MAAM,EAAE,OAqCb,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,41 @@
1
+ import { i18n } from "@vilio/intl";
2
+ import localesEn from "../locales/en/global.json" with { type: "json" };
3
+ import localesPl from "../locales/pl/global.json" with { type: "json" };
4
+ import manifest from "../manifest.json";
5
+ import { apiRoutes, privateRoutes } from "./routes";
6
+ import { mediaSchema, relations } from "./schema";
7
+ const module = {
8
+ manifest,
9
+ translations: {
10
+ en: localesEn,
11
+ pl: localesPl,
12
+ },
13
+ onEnable: async () => {
14
+ console.log("[Module:Media] enabled");
15
+ },
16
+ onDisable: async () => {
17
+ console.log("[Module:Media] disabled");
18
+ },
19
+ schema: {
20
+ ...mediaSchema,
21
+ relations,
22
+ },
23
+ routes: {
24
+ private: privateRoutes,
25
+ api: apiRoutes,
26
+ },
27
+ navigation: {
28
+ admin: {
29
+ [i18n("General")]: [
30
+ {
31
+ id: "media-library",
32
+ title: i18n("Media Library"),
33
+ url: "/media",
34
+ icon: "solar:album-bold-duotone",
35
+ },
36
+ ],
37
+ },
38
+ },
39
+ };
40
+ export default module;
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,OAAO,SAAS,MAAM,2BAA2B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACxE,OAAO,SAAS,MAAM,2BAA2B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACxE,OAAO,QAAQ,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAElD,MAAM,MAAM,GAAY;IACtB,QAAQ;IACR,YAAY,EAAE;QACZ,EAAE,EAAE,SAAS;QACb,EAAE,EAAE,SAAS;KACd;IAED,QAAQ,EAAE,KAAK,IAAI,EAAE;QACnB,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACxC,CAAC;IAED,SAAS,EAAE,KAAK,IAAI,EAAE;QACpB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,EAAE;QACN,GAAG,WAAW;QACd,SAAS;KACV;IAED,MAAM,EAAE;QACN,OAAO,EAAE,aAAa;QACtB,GAAG,EAAE,SAAS;KACf;IAED,UAAU,EAAE;QACV,KAAK,EAAE;YACL,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE;gBACjB;oBACE,EAAE,EAAE,eAAe;oBACnB,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC;oBAC5B,GAAG,EAAE,QAAQ;oBACb,IAAI,EAAE,0BAA0B;iBACjC;aACF;SACF;KACF;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function MediaPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=MediaPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaPage.d.ts","sourceRoot":"","sources":["../../src/pages/MediaPage.tsx"],"names":[],"mappings":"AAgCA,MAAM,CAAC,OAAO,UAAU,SAAS,4CA+LhC"}
@@ -0,0 +1,95 @@
1
+ /** biome-ignore-all lint/correctness/useExhaustiveDependencies: <> */
2
+ /** biome-ignore-all lint/suspicious/noArrayIndexKey: <> */
3
+ /** biome-ignore-all lint/a11y/useButtonType: <> */
4
+ /** biome-ignore-all lint/performance/noImgElement: <> */
5
+ "use client";
6
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ import { useTranslation } from "@vilio/intl";
8
+ import { Button } from "@vilio/ui/components/button";
9
+ import { Card } from "@vilio/ui/components/card";
10
+ import { Input } from "@vilio/ui/components/input";
11
+ import { Skeleton } from "@vilio/ui/components/skeleton";
12
+ import { ExternalLink, Grid, List as ListIcon, Search, Trash2, Upload, } from "lucide-react";
13
+ import { useEffect, useState } from "react";
14
+ import { toast } from "sonner";
15
+ export default function MediaPage() {
16
+ const [items, setItems] = useState([]);
17
+ const [loading, setLoading] = useState(true);
18
+ const [uploading, setUploading] = useState(false);
19
+ const [searchQuery, setSearchQuery] = useState("");
20
+ const { t } = useTranslation();
21
+ const fetchMedia = async () => {
22
+ try {
23
+ setLoading(true);
24
+ const res = await fetch("/api/media");
25
+ const data = await res.json();
26
+ if (Array.isArray(data)) {
27
+ setItems(data);
28
+ }
29
+ }
30
+ catch (_e) {
31
+ toast.error("Failed to load media");
32
+ }
33
+ finally {
34
+ setLoading(false);
35
+ }
36
+ };
37
+ useEffect(() => {
38
+ fetchMedia();
39
+ }, []);
40
+ const handleUpload = async (e) => {
41
+ const file = e.target.files?.[0];
42
+ if (!file)
43
+ return;
44
+ const formData = new FormData();
45
+ formData.append("file", file);
46
+ try {
47
+ setUploading(true);
48
+ const res = await fetch("/api/media/upload", {
49
+ method: "POST",
50
+ body: formData,
51
+ });
52
+ if (res.ok) {
53
+ toast.success(t("File uploaded successfully"));
54
+ fetchMedia();
55
+ }
56
+ else {
57
+ toast.error(t("Upload failed"));
58
+ }
59
+ }
60
+ catch (_e) {
61
+ toast.error(t("An error occurred during upload"));
62
+ }
63
+ finally {
64
+ setUploading(false);
65
+ }
66
+ };
67
+ const handleDelete = async (id) => {
68
+ if (!confirm(t("Are you sure you want to delete this file?")))
69
+ return;
70
+ try {
71
+ const res = await fetch(`/api/media/delete?id=${id}`, {
72
+ method: "DELETE",
73
+ });
74
+ if (res.ok) {
75
+ toast.success(t("File deleted successfully"));
76
+ setItems((prev) => prev.filter((item) => item.id !== id));
77
+ }
78
+ else {
79
+ toast.error(t("Delete failed"));
80
+ }
81
+ }
82
+ catch (_e) {
83
+ toast.error(t("An error occurred during deletion"));
84
+ }
85
+ };
86
+ const filteredItems = items.filter((item) => item.filename.toLowerCase().includes(searchQuery.toLowerCase()));
87
+ return (_jsxs("div", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-bold tracking-tight", children: t("Media Library") }), _jsx("p", { className: "text-muted-foreground", children: t("Manage your images and files.") })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "icon", children: _jsx(Grid, { className: "h-4 w-4" }) }), _jsx(Button, { variant: "outline", size: "icon", children: _jsx(ListIcon, { className: "h-4 w-4" }) }), _jsxs("label", { className: "cursor-pointer", children: [_jsx("input", { type: "file", className: "hidden", onChange: handleUpload, disabled: uploading }), _jsx(Button, { asChild: true, disabled: uploading, children: _jsxs("span", { children: [_jsx(Upload, { className: "mr-2 h-4 w-4" }), uploading ? t("Uploading...") : t("Upload")] }) })] })] })] }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), _jsx(Input, { placeholder: t("Search files..."), className: "pl-10 max-w-sm", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) })] }), loading ? (_jsx("div", { className: "grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4", children: Array.from({ length: 12 }).map((_, i) => (_jsx(Skeleton, { className: "aspect-square rounded-xl" }, i))) })) : filteredItems.length > 0 ? (_jsx("div", { className: "grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4", children: filteredItems.map((item) => (_jsxs(Card, { className: "group relative aspect-square overflow-hidden border-none bg-muted hover:ring-2 hover:ring-primary transition-all", children: [item.mimeType.startsWith("image/") ? (_jsx("img", { src: item.url, alt: item.filename, className: "h-full w-full object-cover transition-transform group-hover:scale-105" })) : (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsx("div", { className: "text-xs font-medium uppercase text-muted-foreground", children: item.mimeType.split("/")[1] }) })), _jsxs("div", { className: "absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex flex-col justify-end p-2 text-white", children: [_jsx("p", { className: "text-[10px] truncate font-medium", children: item.filename }), _jsxs("div", { className: "flex justify-between mt-1", children: [_jsx("button", { className: "hover:text-primary", onClick: (e) => {
88
+ e.stopPropagation();
89
+ window.open(item.url, "_blank");
90
+ }, children: _jsx(ExternalLink, { className: "h-3 w-3" }) }), _jsx("button", { className: "hover:text-destructive", onClick: (e) => {
91
+ e.stopPropagation();
92
+ handleDelete(item.id);
93
+ }, children: _jsx(Trash2, { className: "h-3 w-3" }) })] })] })] }, item.id))) })) : (_jsxs("div", { className: "flex flex-col items-center justify-center py-20 text-center", children: [_jsx("div", { className: "bg-muted p-4 rounded-full mb-4", children: _jsx(Upload, { className: "h-8 w-8 text-muted-foreground" }) }), _jsx("h3", { className: "text-lg font-semibold", children: t("No files found") }), _jsx("p", { className: "text-muted-foreground max-w-xs", children: t("Start by uploading your first file to the media library.") })] }))] }));
94
+ }
95
+ //# sourceMappingURL=MediaPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaPage.js","sourceRoot":"","sources":["../../src/pages/MediaPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ApiRouteDefinition, PrivateRouteDefinition } from "@vilio/modules";
2
+ export declare const privateRoutes: PrivateRouteDefinition[];
3
+ export declare const apiRoutes: ApiRouteDefinition[];
4
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,gBAAgB,CAAC;AAGxB,eAAO,MAAM,aAAa,EAAE,sBAAsB,EAKjD,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,kBAAkB,EAsBzC,CAAC"}
package/dist/routes.js ADDED
@@ -0,0 +1,31 @@
1
+ import MediaPage from "./pages/MediaPage";
2
+ export const privateRoutes = [
3
+ {
4
+ path: "/media",
5
+ component: MediaPage,
6
+ },
7
+ ];
8
+ export const apiRoutes = [
9
+ {
10
+ path: "/api/media",
11
+ handler: async (request) => {
12
+ const { GET } = await import("./api/list");
13
+ return GET();
14
+ },
15
+ },
16
+ {
17
+ path: "/api/media/upload",
18
+ handler: async (request) => {
19
+ const { POST } = await import("./api/upload");
20
+ return POST(request);
21
+ },
22
+ },
23
+ {
24
+ path: "/api/media/delete",
25
+ handler: async (request) => {
26
+ const { DELETE: delHandler } = await import("./api/delete");
27
+ return delHandler(request);
28
+ },
29
+ },
30
+ ];
31
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAIA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,MAAM,CAAC,MAAM,aAAa,GAA6B;IACrD;QACE,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,SAAS;KACrB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAyB;IAC7C;QACE,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,KAAK,EAAE,OAAgB,EAAE,EAAE;YAClC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;YAC3C,OAAO,GAAG,EAAE,CAAC;QACf,CAAC;KACF;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,KAAK,EAAE,OAAgB,EAAE,EAAE;YAClC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;YAC9C,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;KACF;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,KAAK,EAAE,OAAgB,EAAE,EAAE;YAClC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;YAC5D,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;KACF;CACF,CAAC"}