From 7be0181034dad3d85e25a74bfd15167bc5b48e88 Mon Sep 17 00:00:00 2001 From: corgifist Date: Thu, 24 Jul 2025 19:35:27 +0300 Subject: [PATCH] added pwa manifest and icons & barebones project properties dropdown --- package-lock.json | 142 ++++++++++++++ package.json | 1 + public/web-app-manifest-192x192.png | Bin 0 -> 4645 bytes public/web-app-manifest-512x512.png | Bin 0 -> 15070 bytes src/app/apple-icon.png | Bin 3619 -> 3639 bytes src/app/favicon.ico | Bin 5391 -> 15086 bytes src/app/icon0.svg | 3 + src/app/icon1.png | Bin 0 -> 2040 bytes src/app/layout.tsx | 1 + src/app/manifest.json | 21 ++ src/app/page.tsx | 44 ++++- src/app/persistence-provider.tsx | 4 +- src/components/dashboard/Dashboard.tsx | 6 +- src/components/ui/dropdown-menu.tsx | 257 +++++++++++++++++++++++++ src/lib/db.ts | 2 +- src/types/Thumbnail.ts | 8 + 16 files changed, 478 insertions(+), 11 deletions(-) create mode 100644 public/web-app-manifest-192x192.png create mode 100644 public/web-app-manifest-512x512.png create mode 100644 src/app/icon0.svg create mode 100644 src/app/icon1.png create mode 100644 src/app/manifest.json create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/types/Thumbnail.ts diff --git a/package-lock.json b/package-lock.json index ecf1946..6d1815a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@radix-ui/react-aspect-ratio": "^1.1.7", "@radix-ui/react-checkbox": "^1.3.2", "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", @@ -1149,6 +1150,32 @@ } } }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -1215,6 +1242,21 @@ } } }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-dismissable-layer": { "version": "1.1.10", "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", @@ -1242,6 +1284,35 @@ } } }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz", + "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", @@ -1323,6 +1394,46 @@ } } }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz", + "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", @@ -1426,6 +1537,37 @@ } } }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-separator": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", diff --git a/package.json b/package.json index 9f5644a..b837c2b 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@radix-ui/react-aspect-ratio": "^1.1.7", "@radix-ui/react-checkbox": "^1.3.2", "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", diff --git a/public/web-app-manifest-192x192.png b/public/web-app-manifest-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..172590e3c56d39fb72c8c1fdf663b5df0606ebb9 GIT binary patch literal 4645 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 C;9r~o literal 0 HcmV?d00001 diff --git a/src/app/apple-icon.png b/src/app/apple-icon.png index c5e7c667c0775e918074175b6e0ff0c2af1dc3b3..81d1d56f288181d6e479b80e47bd84361af1b69f 100644 GIT binary patch literal 3639 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 diff --git a/src/app/favicon.ico b/src/app/favicon.ico index d37e877aec4062a3cadf0d76c0a10fa1847e8b02..7cd65b8a2c395b65c8ad4cc0dc347b2df99fd964 100644 GIT binary patch literal 15086 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 vQE)tJHy`{Hf&C3* diff --git a/src/app/icon0.svg b/src/app/icon0.svg new file mode 100644 index 0000000..0a04b3b --- /dev/null +++ b/src/app/icon0.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/app/icon1.png b/src/app/icon1.png new file mode 100644 index 0000000000000000000000000000000000000000..6d395a87a78d8c267c995557646958ee9f2bbea1 GIT binary patch literal 2040 zcmVPx+vPnciRCr$PoH>u=R1n9j-n8wRzGjzWkyb(=kPzRHgcL#&0#XQx_yh#RkP;A( zGJ7zyeYsulM$bLdZMT+JFIZ`Vt&Mv<<@(q4du1DMzWOo(^KXw6T1}>xxt|3npOeuB6qzzH6?wKzgGJHH}y4VKI~OR>x-+r{iyuv;?inWWq;RUMeE5` z6#?@0UnKkU*Gh(?2yoCZhyde2mJAs9LrT!e8B&7ID!%l9dxuC9J}aTpgij8UDQFNJ zGKP*bMaIyF68g5r(0{)EqT@)0u%cHg4`Kk|SCgsLkcTI&CbYhoRe=GS)nrPeP4Jkoq6<>P5ag38DJd6!#!UJ!}6f|^(jG?0VNGjfK_(;) z(5h;3*V9nx4PI4%sB*vSQ<&LK^&Ehu9FXUj2oTnIWewJh{S&=WS5-unwLeX9R03kp zzWbCV;grJL$gCt$g&m|D$O~X%rMCwV%ih2?&ZvYW{{>zE12t`#01AL%3$p}bYyj;r ztt9jIZ(v5IfaLM{_n#Dya7DYwkT58p1h5QA8mMRoJPB{(lnn4Bd0QX=K}{|2_HUE@ zF;Bv!_HSTHw!nT7;JD9FUIZ941<8OB2}=ojaEFwjv(ZUaKITCz)@gQUo()x@jnl*dS&&H})*d(@4`N|P98)A!ZzB(4Hi1~2XYG#( z#KP3tm?vQil};cAk+C1(K`d0H-JHLHBtXFpY|MKs2`BrBu|IJD*#we#rzJ79<3Y0P?JsybS_C-g zCjy+s@gaiv6qXD)I!;Q^FovWA4cS9_z{wj{n((ODqBLP?!mk}8r3s(aP~m`sL*6(C z{QK);9>iQj#xful(QC7?o+Dvjk+$=+Q_X&FN9zUof-$u1-e*C~xtfg4uT&EUXg#%o z`J3L?WXzo1=q3A0#%L4)PCY;b7%qV%0|uj`l%S(Cqy(K+eCYuX4v{823Jqz(19!+2 zG;oHOF?4(sA!F#<9z%b-W>=D_^J|j_8HmaoGq=v=&+tR2$?61R`46A=HPrL_fUW?< zylco317fJW(R1s4{(DCuG^BM}spjoBdP%`I{O4+Je_ya9>}*3$^CWC(VFTl|;A?WU zU{{j1TaYghK<_?aN!Z((oaRZ`b;=vL5xZUj1v~61f80& zl%U}exb%RNH>3%ld?8KvZ03 zUa=$`6Nq*B8;B8uPXhS70Krx|bjt){+1FJ4enG+UBx%?DN;3F{+@2Fa1>enWa833t z$!Kfsx&enC(WKqA0>*%krLrW?tC;TgV^prbc}l%R2{NDmlr zfHdL3>47xi!SR7iK?7&V7&_hw-~C+|ftYU@kO37!n>Zj(lF>Fg?E5*I0kI`T!-JS# z@gNr6B?Zp@h#~BkHkv$0#zgY_WrYzK`>zR10f@c2nXpF@Q8yGhk_<_JrA6)rOs%0^ zutyPLdreS4lJV7t>`F4|hM;9YGGK2%SVjO->)0+TjQQ^!#db+x`2fOKHxrhG`y1c{ z0Q7O&-$4G$RHh+pc@loJ0$irQnJ4+6eAq24FeD#MU1WdUi2$eBU5fxmXGF<>aTAsj zbng!-LE~O3Jz)4Ki8SFs36&;1N|mxPRGP3f;s2o(yjvqn!b;Z!+egfUrs#3Aw4fRK zvkk#+SwYBe#9(_(XfFAOTVL`UG0+X+E)QZDm5;ju`%Ob?$3NQ&o5zGDB)r-K3t~VG z;g-9BdjXi^1MHo_uk>)8P@X4A_3{Zz!a$d#c07pn0mOhL>N@#?T}i_Fnv^XFAQ9j+ zhKc}#Se6VJCbpEIqc@}komG740S}LLL}|jK*pMbXaEDAmCuhhQI + diff --git a/src/app/manifest.json b/src/app/manifest.json new file mode 100644 index 0000000..5e1d9e4 --- /dev/null +++ b/src/app/manifest.json @@ -0,0 +1,21 @@ +{ + "name": "ClipFusion Video Editor", + "short_name": "ClipFusion", + "icons": [ + { + "src": "/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index aad5970..c2550fb 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -5,7 +5,7 @@ import { useLiveQuery } from "dexie-react-hooks"; import { db } from "@/lib/db"; import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; -import { ListCheckIcon, PlusIcon } from "lucide-react"; +import { CopyIcon, EllipsisIcon, InfoIcon, LetterTextIcon, ListCheckIcon, PencilIcon, PlusIcon, TextIcon, TextQuoteIcon, TrashIcon } from "lucide-react"; import { Toggle } from "@/components/ui/toggle"; import Search from "@/components/search"; import { useIsMobile } from "@/hooks/use-mobile"; @@ -20,6 +20,7 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Textarea } from "@/components/ui/textarea"; import { generateUUID } from "@/lib/uuid"; +import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; const NewProjectFormSchema = z.object({ title: z.string().nonempty("Title cannot be empty"), @@ -33,9 +34,42 @@ const ProjectContainer = ({ }): ReactNode => { return ( - -

{project.title}

- {project.description &&

{project.description}

} + +
+
+
+

{project.title}

+ {project.creationDate &&

{new Date(project.creationDate).toLocaleDateString()}

} +
+
+ + + {project.title} additional options + + + {project.title} + + + Rename + + + Edit + + + Duplicate + + + Delete + + + + Properties + + + + +
+
) @@ -133,7 +167,7 @@ export default function Home(): ReactNode { setSearch(e.target.value)}/>
-
+
{projects && projects.map((project) => )}
{(projects != undefined && projects.length == 0) && ( diff --git a/src/app/persistence-provider.tsx b/src/app/persistence-provider.tsx index ef66c76..c1a14cf 100644 --- a/src/app/persistence-provider.tsx +++ b/src/app/persistence-provider.tsx @@ -29,7 +29,7 @@ const PersistenceProvider = ({ const isPersistent = await isStoragePersisted(); console.log(isPersistent); if (!isPersistent) { - if (localStorage.getItem('persistence-status') != "persisted" && localStorage.getItem('persistence-status') == undefined) { + if ((localStorage.getItem('persistence-status') != "persisted" && localStorage.getItem('persistence-status') == undefined) || localStorage.getItem('persistence-status') === "") { const persistenceStatus = await tryPersistWithoutPromtingUser(); localStorage.setItem("persistence-status", persistenceStatus); if (persistenceStatus == "never") { @@ -49,7 +49,7 @@ const PersistenceProvider = ({ const persistResult = await persist(); if (persistResult === false) { toast("Failed to Enable Persistent Storage", { - description: "Try again later" + description: "Browser denied request for persistent storage" }) return; } diff --git a/src/components/dashboard/Dashboard.tsx b/src/components/dashboard/Dashboard.tsx index cd1b2a3..54fd6d5 100644 --- a/src/components/dashboard/Dashboard.tsx +++ b/src/components/dashboard/Dashboard.tsx @@ -87,14 +87,14 @@ export const Dashboard = (): ReactNode => { - Socials + Link
- ClipFusion GitHub Repository + ClipFusion GitHub Repository @@ -104,7 +104,7 @@ export const Dashboard = (): ReactNode => { - ClipFusion Git Mirror + ClipFusion Git Mirror diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..ec51e9c --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,257 @@ +"use client" + +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: "default" | "destructive" +}) { + return ( + + ) +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +} diff --git a/src/lib/db.ts b/src/lib/db.ts index a63802a..9bca7ce 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -44,7 +44,7 @@ export async function showEstimatedQuota(): Promise "persisted" In case this call successfully silently persisted the storage, or if it was already persisted. */ -export async function tryPersistWithoutPromtingUser() { +export async function tryPersistWithoutPromtingUser(): Promise<"never" | "prompt" | "persisted"> { if (!navigator.storage || !navigator.storage.persisted) { return "never"; } diff --git a/src/types/Thumbnail.ts b/src/types/Thumbnail.ts new file mode 100644 index 0000000..7a49e56 --- /dev/null +++ b/src/types/Thumbnail.ts @@ -0,0 +1,8 @@ +import { Entity } from "dexie"; +import EditorDB from "./EditorDB"; + +export default class Thumbnail extends Entity { + uuid!: string; + blob!: Blob; + createdAt!: Date; +} \ No newline at end of file