@mevdragon/vidfarm-devcli 0.18.1 → 0.19.1
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.
- package/.agents/skills/editor-capabilities/SKILL.md +166 -0
- package/.agents/skills/editor-capabilities/references/re-theme-walkthrough.md +58 -0
- package/.agents/skills/vidfarm-media/SKILL.md +2 -0
- package/SKILL.director.md +174 -16
- package/SKILL.platform.md +7 -3
- package/demo/dist/app.css +1 -1
- package/demo/dist/app.js +79 -75
- package/dist/src/account-pages-legacy.js +1 -1
- package/dist/src/app.js +1694 -217
- package/dist/src/cli.js +1365 -105
- package/dist/src/config.js +8 -0
- package/dist/src/devcli/clips.js +3 -0
- package/dist/src/devcli/composition-edit.js +401 -10
- package/dist/src/devcli/local-backend.js +123 -0
- package/dist/src/devcli/migrate-local.js +140 -0
- package/dist/src/devcli/sync.js +311 -0
- package/dist/src/devcli/timeline-edit.js +208 -1
- package/dist/src/editor-chat.js +37 -18
- package/dist/src/frontend/file-directory.js +271 -20
- package/dist/src/frontend/homepage-view.js +3 -3
- package/dist/src/frontend/template-editor-chat.js +6 -3
- package/dist/src/page-shell.js +1 -1
- package/dist/src/primitive-context.js +31 -2
- package/dist/src/primitive-registry.js +409 -4
- package/dist/src/reskin/chat-page.js +103 -15
- package/dist/src/reskin/discover-page.js +247 -10
- package/dist/src/reskin/document.js +147 -10
- package/dist/src/reskin/inpaint-clipper-page.js +649 -0
- package/dist/src/reskin/inpaint-page.js +2459 -452
- package/dist/src/reskin/inpaint-video-page.js +1339 -0
- package/dist/src/reskin/library-page.js +324 -82
- package/dist/src/reskin/portfolio-page.js +687 -0
- package/dist/src/reskin/theme.js +36 -11
- package/dist/src/services/billing.js +4 -0
- package/dist/src/services/clip-curation/hunt.js +2 -0
- package/dist/src/services/clip-records.js +28 -0
- package/dist/src/services/file-directory.js +6 -3
- package/dist/src/services/hyperframes.js +535 -86
- package/dist/src/services/serverless-jobs.js +3 -1
- package/dist/src/services/serverless-records.js +43 -0
- package/dist/src/services/storage.js +24 -2
- package/dist/src/template-editor-pages.js +1 -1
- package/package.json +1 -1
- package/public/assets/file-directory-app.js +2 -2
- package/public/assets/homepage-client-app.js +1 -1
- package/public/assets/page-runtime-client-app.js +2 -2
- package/public/assets/placeholders/scene-placeholder.png +0 -0
|
@@ -17,7 +17,7 @@ const dynamodb = config.RECORDS_DRIVER === "local"
|
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
19
|
const sfn = new SFNClient({});
|
|
20
|
-
const ACTIVE_ROOT_JOB_STATUSES = ["queued", "running", "waiting_for_provider", "waiting_for_child", "waiting_for_human"];
|
|
20
|
+
const ACTIVE_ROOT_JOB_STATUSES = ["queued", "running", "waiting_for_provider", "waiting_for_render", "waiting_for_child", "waiting_for_human"];
|
|
21
21
|
const ACTIVE_JOB_STATUSES = new Set(ACTIVE_ROOT_JOB_STATUSES);
|
|
22
22
|
export class ServerlessJobsService {
|
|
23
23
|
async createRootJob(input) {
|
|
@@ -282,6 +282,7 @@ export class ServerlessJobsService {
|
|
|
282
282
|
"#status = :queuedStatus",
|
|
283
283
|
"#status = :runningStatus",
|
|
284
284
|
"#status = :waitingForProviderStatus",
|
|
285
|
+
"#status = :waitingForRenderStatus",
|
|
285
286
|
"#status = :waitingForChildStatus",
|
|
286
287
|
"#status = :waitingForHumanStatus"
|
|
287
288
|
].join(" OR ")
|
|
@@ -293,6 +294,7 @@ export class ServerlessJobsService {
|
|
|
293
294
|
expressionAttributeValues[":queuedStatus"] = "queued";
|
|
294
295
|
expressionAttributeValues[":runningStatus"] = "running";
|
|
295
296
|
expressionAttributeValues[":waitingForProviderStatus"] = "waiting_for_provider";
|
|
297
|
+
expressionAttributeValues[":waitingForRenderStatus"] = "waiting_for_render";
|
|
296
298
|
expressionAttributeValues[":waitingForChildStatus"] = "waiting_for_child";
|
|
297
299
|
expressionAttributeValues[":waitingForHumanStatus"] = "waiting_for_human";
|
|
298
300
|
}
|
|
@@ -625,6 +625,12 @@ class ServerlessRecordsServiceImpl {
|
|
|
625
625
|
title: input.title ?? null,
|
|
626
626
|
caption: input.caption ?? "",
|
|
627
627
|
pinnedComment: input.pinnedComment ?? null,
|
|
628
|
+
// Self-file into a tracer-derived Approved subfolder (canonical
|
|
629
|
+
// `/approved/<slug>`), mirroring how raws default into a source folder. An
|
|
630
|
+
// explicit folderPath (incl. "" for the root) always wins.
|
|
631
|
+
folderPath: input.folderPath !== undefined
|
|
632
|
+
? normalizeFolder(input.folderPath ?? "")
|
|
633
|
+
: (input.tracer ? slugFolderSegment(input.tracer) : ""),
|
|
628
634
|
mediaAssets: input.mediaAssets ?? [],
|
|
629
635
|
sharePasswordHash: input.sharePasswordHash ?? null,
|
|
630
636
|
zipStorageKey: input.zipStorageKey ?? null,
|
|
@@ -654,6 +660,23 @@ class ServerlessRecordsServiceImpl {
|
|
|
654
660
|
const updated = await this.putRecord("ready_post", { ...post, status: "deleted", deletedAt: nowIso(), updatedAt: nowIso() });
|
|
655
661
|
return updated;
|
|
656
662
|
}
|
|
663
|
+
// Move one approved post into a folder (canonical /approved/<folderPath>); ""
|
|
664
|
+
// returns it to the root. Mirrors updateClipFolder for raws.
|
|
665
|
+
async setReadyPostFolder(customerId, postId, folderPath) {
|
|
666
|
+
const post = await this.getReadyPost(postId);
|
|
667
|
+
if (!post || post.customerId !== customerId)
|
|
668
|
+
return null;
|
|
669
|
+
return this.putRecord("ready_post", {
|
|
670
|
+
...post,
|
|
671
|
+
folderPath: normalizeFolder(folderPath),
|
|
672
|
+
updatedAt: nowIso()
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
// Rename an approved folder by re-pointing every post inside it (the folder-rename
|
|
676
|
+
// primitive for the /approved directory root).
|
|
677
|
+
async moveReadyPostFolder(customerId, fromFolder, toFolder) {
|
|
678
|
+
await this.moveCollectionFolder("ready_post", customerId, fromFolder, toFolder);
|
|
679
|
+
}
|
|
657
680
|
async setReadyPostMedia(input) {
|
|
658
681
|
const post = await this.getReadyPost(input.postId);
|
|
659
682
|
if (!post || post.customerId !== input.customerId)
|
|
@@ -861,6 +884,8 @@ class ServerlessRecordsServiceImpl {
|
|
|
861
884
|
storageKey: input.storageKey,
|
|
862
885
|
folderPath: normalizeFolder(input.folderPath),
|
|
863
886
|
publicUrl: input.publicUrl ?? null,
|
|
887
|
+
thumbnailStorageKey: input.thumbnailStorageKey ?? null,
|
|
888
|
+
thumbnailUrl: input.thumbnailUrl ?? null,
|
|
864
889
|
notes: input.notes ?? null,
|
|
865
890
|
notesEmbedding: input.notesEmbedding ?? null,
|
|
866
891
|
notesEmbeddingModel: input.notesEmbeddingModel ?? null,
|
|
@@ -870,6 +895,12 @@ class ServerlessRecordsServiceImpl {
|
|
|
870
895
|
async updateUserAttachmentNotes(customerId, attachmentId, patch) {
|
|
871
896
|
return this.mergeByIdForCustomer("user_attachment", customerId, attachmentId, patch);
|
|
872
897
|
}
|
|
898
|
+
// Rename a My Files entry. Only the record's display name changes — the S3
|
|
899
|
+
// storageKey (and therefore the durable view URL) is untouched, so this is a
|
|
900
|
+
// cheap metadata-only rename that keeps every existing link working.
|
|
901
|
+
async renameUserAttachment(customerId, attachmentId, fileName) {
|
|
902
|
+
return this.mergeByIdForCustomer("user_attachment", customerId, attachmentId, { fileName });
|
|
903
|
+
}
|
|
873
904
|
async listUserAttachments(customerId) {
|
|
874
905
|
return this.listByCustomer("user_attachment", customerId);
|
|
875
906
|
}
|
|
@@ -913,6 +944,10 @@ class ServerlessRecordsServiceImpl {
|
|
|
913
944
|
if (existing)
|
|
914
945
|
await this.deleteById("user_temporary_file", fileId);
|
|
915
946
|
}
|
|
947
|
+
// Rename a temp file (display name only; storageKey/view URL untouched).
|
|
948
|
+
async renameUserTemporaryFile(customerId, fileId, fileName) {
|
|
949
|
+
return this.mergeByIdForCustomer("user_temporary_file", customerId, fileId, { fileName });
|
|
950
|
+
}
|
|
916
951
|
async deleteExpiredUserTemporaryFiles() {
|
|
917
952
|
const now = nowIso();
|
|
918
953
|
const files = (await this.scanCollection("user_temporary_file"))
|
|
@@ -1445,6 +1480,14 @@ function normalizeFolder(value) {
|
|
|
1445
1480
|
return "";
|
|
1446
1481
|
return value.trim().replace(/^\/+|\/+$/g, "");
|
|
1447
1482
|
}
|
|
1483
|
+
// Slugify a single folder-name segment (e.g. a tracer → an /approved subfolder).
|
|
1484
|
+
function slugFolderSegment(value) {
|
|
1485
|
+
return String(value ?? "")
|
|
1486
|
+
.toLowerCase()
|
|
1487
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
1488
|
+
.replace(/^-+|-+$/g, "")
|
|
1489
|
+
.slice(0, 60);
|
|
1490
|
+
}
|
|
1448
1491
|
function isExpiredUserTemporaryFileRecord(record) {
|
|
1449
1492
|
return typeof record.id === "string"
|
|
1450
1493
|
&& record.id.length > 0
|
|
@@ -13,6 +13,19 @@ function isS3NotFoundError(error) {
|
|
|
13
13
|
const httpStatusCode = typeof metadata?.httpStatusCode === "number" ? metadata.httpStatusCode : undefined;
|
|
14
14
|
return name === "NoSuchKey" || code === "NoSuchKey" || name === "NotFound" || httpStatusCode === 404;
|
|
15
15
|
}
|
|
16
|
+
// Media objects live at stable, content-addressed-ish keys and are the
|
|
17
|
+
// heavy bytes browsers re-fetch on every /discover visit today (S3 objects
|
|
18
|
+
// currently ship no Cache-Control). Give media a 1-day fresh window with a
|
|
19
|
+
// week-long stale-while-revalidate tail so it caches hard but still self-heals
|
|
20
|
+
// if a key is ever overwritten in place. NON-media (json records, composition
|
|
21
|
+
// html, text) stays uncached — those are mutable and must never go stale.
|
|
22
|
+
function cacheControlForContentType(contentType) {
|
|
23
|
+
const ct = (contentType || "").toLowerCase();
|
|
24
|
+
if (ct.startsWith("video/") || ct.startsWith("image/") || ct.startsWith("audio/")) {
|
|
25
|
+
return "public, max-age=86400, stale-while-revalidate=604800";
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
16
29
|
export class StorageService {
|
|
17
30
|
localRoot = path.join(config.VIDFARM_DATA_DIR, "storage");
|
|
18
31
|
s3 = config.STORAGE_DRIVER === "s3"
|
|
@@ -98,7 +111,8 @@ export class StorageService {
|
|
|
98
111
|
Bucket: config.AWS_S3_BUCKET,
|
|
99
112
|
Key: key,
|
|
100
113
|
Body: value,
|
|
101
|
-
ContentType: contentType
|
|
114
|
+
ContentType: contentType,
|
|
115
|
+
CacheControl: cacheControlForContentType(contentType)
|
|
102
116
|
}));
|
|
103
117
|
return { key, url: this.getPublicUrl(key) };
|
|
104
118
|
}
|
|
@@ -127,7 +141,8 @@ export class StorageService {
|
|
|
127
141
|
Key: key,
|
|
128
142
|
Body: createReadStream(localPath),
|
|
129
143
|
ContentLength: statSync(localPath).size,
|
|
130
|
-
ContentType: contentType
|
|
144
|
+
ContentType: contentType,
|
|
145
|
+
CacheControl: cacheControlForContentType(contentType)
|
|
131
146
|
}));
|
|
132
147
|
return { key, url: this.getPublicUrl(key) };
|
|
133
148
|
}
|
|
@@ -354,6 +369,13 @@ export function joinStorageKey(...parts) {
|
|
|
354
369
|
.filter(Boolean)
|
|
355
370
|
.join("/");
|
|
356
371
|
}
|
|
372
|
+
// Shared process-wide StorageService instance. StorageService binds its driver
|
|
373
|
+
// (s3 vs local fs) + data dir from `config` at construction, so importing this
|
|
374
|
+
// singleton must happen AFTER any env that flips RECORDS_DRIVER/STORAGE_DRIVER/
|
|
375
|
+
// VIDFARM_DATA_DIR has been set (the in-process devcli local path arranges that
|
|
376
|
+
// via withLocalBackend before it imports any service). app.ts, the extracted
|
|
377
|
+
// directory/clip-scan services, and the devcli all share this one instance.
|
|
378
|
+
export const storage = new StorageService();
|
|
357
379
|
function normalizeStorageKey(key) {
|
|
358
380
|
const normalized = key.replace(/^\/+/, "");
|
|
359
381
|
if (!normalized ||
|
|
@@ -1925,7 +1925,7 @@ export function renderCustomInpaintPage(input) {
|
|
|
1925
1925
|
}
|
|
1926
1926
|
|
|
1927
1927
|
function isPendingJobStatus(status) {
|
|
1928
|
-
return ["queued", "running", "waiting_for_provider", "waiting_for_child", "waiting_for_human"].includes(String(status || ""));
|
|
1928
|
+
return ["queued", "running", "waiting_for_provider", "waiting_for_render", "waiting_for_child", "waiting_for_human"].includes(String(status || ""));
|
|
1929
1929
|
}
|
|
1930
1930
|
|
|
1931
1931
|
function pendingHistoryItemKey(jobId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mevdragon/vidfarm-devcli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Local bridge for the Vidfarm Trackpad Editor. `vidfarm serve <template_id>` boots the FULL editor on localhost (disk-backed records/storage, free in-process render); edit composition.html on disk (Claude Code, Codex, etc.) and the browser live-morphs it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var re=[{key:"files",label:"My Files",description:"Durable personal files \u2014 brand assets, characters, saved context. Vector-searchable via notes."},{key:"temp",label:"Temp",description:"Scratch space, auto-organized by date (YYYY-MM-DD) and auto-deleted after 30 days."},{key:"raws",label:"Raws",description:"The reusable clip / source-footage library, organized into folders by source."}];function Ie(o){return o==="files"||o==="temp"||o==="raws"}function oe(o){return String(o??"").split("/").map(n=>n.trim()).filter(Boolean).join("/")}function $(o){let n=String(o??"").split("/").map(v=>v.trim()).filter(Boolean);if(n.length===0)return{root:null,folderPath:"",segments:[]};let[l,...i]=n;return Ie(l)?{root:l,folderPath:i.join("/"),segments:i}:{root:null,folderPath:"",segments:n}}function ee(o,n,l){let i=[o,oe(n)];return l&&i.push(String(l).trim()),"/"+i.filter(Boolean).join("/")}var He="/api/v1/user/me";function s(o,n,l){let i=document.createElement(o);return n&&(i.className=n),l!=null&&(i.textContent=l),i}function Ae(o){if(!o||o<=0)return"";let n=["B","KB","MB","GB"],l=o,i=0;for(;l>=1024&&i<n.length-1;)l/=1024,i++;return(l>=10||i===0?Math.round(l):l.toFixed(1))+" "+n[i]}function Oe(o){if(typeof o!="number"||!(o>0))return"";o=Math.round(o);let n=Math.floor(o/60),l=o%60;return n+":"+(l<10?"0"+l:l)}function ye(o){let n=s("span","rk-aichat-fic "+(o.kind==="folder"?"rk-aichat-fic-folder":"rk-aichat-fic-file"));if(o.kind==="folder")return n.textContent="/",n;if(o.thumbUrl){let i=s("img");return i.src=o.thumbUrl,i.alt="",i.loading="lazy",n.appendChild(i),n}let l=o.contentType||"";if(o.viewUrl&&l.indexOf("image/")===0){let i=s("img");return i.src=o.viewUrl,i.alt="",i.loading="lazy",n.appendChild(i),n}if(o.viewUrl&&l.indexOf("video/")===0){let i=s("video");return i.src=o.viewUrl,i.muted=!0,i.playsInline=!0,n.appendChild(i),n}return n.textContent=(o.name.split(".").pop()||o.name.slice(0,1)||"?").slice(0,3).toUpperCase(),n}var ie;function be(o){let n=document.getElementById("rk-dir-toast");n||(n=s("div"),n.id="rk-dir-toast",n.className="rk-dir-toast",document.body.appendChild(n)),n.textContent=o,n.classList.add("is-on"),ie&&window.clearTimeout(ie),ie=window.setTimeout(()=>n&&n.classList.remove("is-on"),1800)}function Ue(o){return navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(o):new Promise((n,l)=>{try{let i=s("textarea");i.value=o,i.style.position="fixed",i.style.opacity="0",document.body.appendChild(i),i.select(),document.execCommand("copy"),document.body.removeChild(i),n()}catch(i){l(i)}})}var F=null;function we(o,n){F&&F();let l=s("div","rk-dir-menu");n.forEach(h=>{let H=s("button","rk-dir-menuitem"+(h.danger?" is-danger":""),h.label);H.type="button",H.addEventListener("click",D=>{D.stopPropagation(),y(),h.run()}),l.appendChild(H)}),document.body.appendChild(l);let i=o instanceof HTMLElement?o.getBoundingClientRect():o,v=l.offsetWidth,R=l.offsetHeight,j=i.bottom+4,E=i.right-v;E<8&&(E=i.left),j+R>window.innerHeight-8&&(j=Math.max(8,i.top-R-4)),l.style.top=j+"px",l.style.left=Math.max(8,E)+"px";function y(){l.remove(),document.removeEventListener("click",I,!0),document.removeEventListener("keydown",N,!0),window.removeEventListener("scroll",y,!0),F===y&&(F=null)}function I(h){l.contains(h.target)||y()}function N(h){h.key==="Escape"&&y()}setTimeout(()=>{document.addEventListener("click",I,!0),document.addEventListener("keydown",N,!0),window.addEventListener("scroll",y,!0)},0),F=y}function ve(o,n={}){let l=n.apiBase||He,i=n.roots&&n.roots.length?n.roots:["files","temp","raws"],v=i.length===1?i[0]:null,R=n.mode||"attach",j=n.showSearch!==!1,E=n.showMultiSelect!==!1,y=n.showUpload!=null?n.showUpload:R==="attach",I=n.primaryClick||"copyPath",N=window.__rkDirectoryHost||{},h=e=>(n.onAttach||N.onAttach||(()=>be("Attached "+e.length+" item(s)")))(e),H=(e,t)=>{let r=n.onPreview||N.onPreview;r?r(e,t):e[t]&&e[t].viewUrl&&window.open(e[t].viewUrl,"_blank","noopener")},D=e=>(n.onToast||N.onToast||be)(e),A=e=>Ue(e).then(()=>D("Copied "+e)).catch(()=>D("Couldn't copy path")),m=Ce(n.initialPath,v),b="idle",K=[],w=[],q=null,z=!1,g=new Map,J=!1,O=[],V="idle",L=!1;function Ce(e,t){let r=$(e||"");return r.root?ee(r.root,r.folderPath):t?"/"+t:"/"}o.classList.add("rk-dir"),o.innerHTML="";let ae=s("div","rk-dir-search"),Y=s("input","rk-dir-search-input");Y.type="search",Y.placeholder="Search files \u2014 meaning, name, or path\u2026",ae.appendChild(Y);let x=s("div","rk-aichat-crumbs rk-dir-crumbs"),T=s("div","rk-dir-selbar");T.hidden=!0;let p=s("div","rk-aichat-files-body rk-dir-body"),u=s("label","rk-aichat-drop rk-dir-drop");u.hidden=!0;let X=s("span","rk-aichat-drop-text","Drop files here"),M=s("input");M.type="file",M.multiple=!0,M.hidden=!0,u.appendChild(X),u.appendChild(M),j&&o.appendChild(ae),o.appendChild(x),E&&o.appendChild(T),o.appendChild(p),y&&o.appendChild(u);function le(e,t){let r=new URL(l+"/directory",window.location.href);return r.searchParams.set("path",e),t&&r.searchParams.set("offset",String(t)),r.toString()}function W(e){if(!L){if(!e&&b==="ready"){f();return}b="loading",f(),fetch(le(m),{credentials:"same-origin",headers:{accept:"application/json"}}).then(t=>{if(t.status===401||t.status===403)return b="auth",null;if(!t.ok)throw new Error("http "+t.status);return t.json()}).then(t=>{if(!L){if(!t){f();return}K=Ee(t.folders||[]),w=t.files||[],q=typeof t.next_offset=="number"?t.next_offset:null,b="ready",f()}}).catch(()=>{L||(b="error",f())})}}function Ee(e){return m!=="/"?e:e.filter(t=>i.indexOf(t.root)!==-1)}function De(){q==null||z||(z=!0,f(),fetch(le(m,q),{credentials:"same-origin",headers:{accept:"application/json"}}).then(e=>e.ok?e.json():null).then(e=>{if(z=!1,L||!e){f();return}w=w.concat(e.files||[]),q=typeof e.next_offset=="number"?e.next_offset:null,f()}).catch(()=>{z=!1,f()}))}let te;function Le(){let e=Y.value.trim();if(te&&window.clearTimeout(te),!e){J=!1,O=[],f();return}te=window.setTimeout(()=>xe(e),260)}function xe(e){J=!0,V="loading",f();let t=v?"/"+v:m!=="/"?m:"";fetch(l+"/directory/search",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:e,path:t,mode:"auto",limit:40})}).then(r=>r.ok?r.json():null).then(r=>{L||(O=r&&r.results||[],V="ready",f())}).catch(()=>{L||(V="error",f())})}function S(e){let t=$(e);m=t.root?ee(t.root,t.folderPath):"/",b="idle",J=!1,Y.value="",W(!0)}function U(){return $(m).root}function G(){return $(m).folderPath}function Q(e){let t=U();if(!t){D("Open a root (/files, /temp, /raws) first");return}let r=(window.prompt("New folder name")||"").trim();if(!r)return;let d=oe(e??G()),c=ee(t,d?d+"/"+r:r);fetch(l+"/directory/folders",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:c})}).then(a=>a.ok?a.json():a.json().then(k=>Promise.reject(new Error(k.error||"http "+a.status)))).then(a=>{S(a.path||(t===U()?m:"/"+t)),D("Created "+(a.path||r))}).catch(a=>D(a.message||"Couldn't create folder"))}function Te(e,t){t?g.set(e.path,e):g.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(g.values())),ce();let r=p.querySelector('[data-path="'+_e(e.path)+'"]');r&&r.classList.toggle("is-selected",t)}function se(){g.clear(),(n.onSelectionChange||(()=>{}))([]),f()}function ne(e,t,r){let d=s("button","rk-aichat-crumb"+(t?" is-current":""),e);return d.type="button",d.addEventListener("click",r),d}function Me(){x.innerHTML="";let e=U(),t=G();if(v||x.appendChild(ne("Files",m==="/",()=>S("/"))),!e)return;let r=(re.find(a=>a.key===e)||{label:e}).label;v||x.appendChild(de()),x.appendChild(ne(r,!t,()=>S("/"+e)));let d="";t.split("/").filter(Boolean).forEach((a,k,C)=>{x.appendChild(de()),d=d?d+"/"+a:a;let B="/"+e+"/"+d;x.appendChild(ne(a,k===C.length-1,()=>S(B)))});let c=s("button","rk-dir-newfolder","+ Folder");c.type="button",c.title="New folder here (or right-click)",c.addEventListener("click",()=>Q()),x.appendChild(c)}function de(){return s("span","rk-aichat-crumb-sep","/")}function ce(){if(!E)return;let e=g.size;if(T.hidden=e===0,e===0)return;if(T.innerHTML="",T.appendChild(s("span","rk-dir-selcount",e+" selected")),R==="attach"){let d=s("button","rk-dir-selbtn","Attach");d.type="button",d.addEventListener("click",()=>{h(Array.from(g.values())),se()}),T.appendChild(d)}let t=s("button","rk-dir-selbtn","Copy paths");t.type="button",t.addEventListener("click",()=>A(Array.from(g.values()).map(d=>d.path).join(`
|
|
2
|
-
`)));let r=s("button","rk-dir-selbtn is-ghost","Clear");r.type="button",r.addEventListener("click",se),T.appendChild(t),T.appendChild(r)}function pe(e){let t=s("input","rk-dir-check");return t.type="checkbox",t.checked=g.has(e.path),t.setAttribute("aria-label","Select "+e.name),t.addEventListener("click",r=>r.stopPropagation()),t.addEventListener("change",()=>Te(e,t.checked)),t}function ue(e){let t=s("div","rk-aichat-frow rk-dir-row"+(g.has(e.path)?" is-selected":""));t.setAttribute("data-path",e.path),E&&t.appendChild(pe(e));let r=s("button","rk-aichat-fmainbtn");r.type="button",r.title="Copy path "+e.path,r.appendChild(ye(e));let d=s("span","rk-aichat-fmain");d.appendChild(s("span","rk-aichat-fname",e.name));let c=e.meta&&typeof e.meta.description=="string"?e.meta.description:"";d.appendChild(s("span","rk-aichat-fmeta",c||"folder")),r.appendChild(d),r.addEventListener("click",()=>A(e.path)),t.appendChild(r);let a=s("button","rk-aichat-fadd rk-dir-open","Open \u203A");return a.type="button",a.title="Open folder",a.addEventListener("click",k=>{k.stopPropagation(),S(e.path)}),t.appendChild(a),t.appendChild(he(e,[{label:"Open folder",run:()=>S(e.path)},{label:"New subfolder",run:()=>Q(e.folderPath)},{label:"Copy path",run:()=>A(e.path)}])),t}function fe(e,t,r,d){let c=s("div","rk-aichat-frow rk-dir-row"+(g.has(e.path)?" is-selected":""));c.setAttribute("data-path",e.path),E&&c.appendChild(pe(e));let a=s("button","rk-aichat-fmainbtn");a.type="button";let k=I==="copyPath"?"Copy path ":I==="attach"?"Attach ":"Preview ";a.title=k+e.name,a.appendChild(ye(e));let C=s("span","rk-aichat-fmain");C.appendChild(s("span","rk-aichat-fname",e.name));let B=d?e.path:Oe(e.durationSec)||Ae(e.sizeBytes)||e.contentType||"file";C.appendChild(s("span","rk-aichat-fmeta",B)),a.appendChild(C),a.addEventListener("click",()=>{I==="attach"?h([e]):I==="preview"?H(t,r):A(e.path)}),c.appendChild(a);let P=[];return R==="attach"&&P.push({label:"Attach",run:()=>h([e])}),e.viewUrl&&P.push({label:"View",run:()=>window.open(e.viewUrl,"_blank","noopener")}),e.viewUrl&&P.push({label:"Preview",run:()=>H(t,r)}),P.push({label:"Copy path",run:()=>A(e.path)}),c.appendChild(he(e,P)),c}function he(e,t){let r=s("button","rk-dir-kebab","\u22EF");return r.type="button",r.setAttribute("aria-label","More actions"),r.addEventListener("click",d=>{d.stopPropagation(),we(r,t)}),r}function _(e,t,r){let d=s("div","rk-aichat-fstate");if(d.appendChild(s("div",void 0,e)),t){let c=s("a");c.href=t.href,c.textContent=t.label,d.appendChild(c)}if(r){let c=s("button",void 0,"Try again");c.type="button",c.addEventListener("click",()=>W(!0)),d.appendChild(c)}return d}function f(){if(!L){if(Me(),ce(),Pe(),p.innerHTML="",J){Se();return}if(b==="loading"&&!w.length&&!K.length){p.appendChild(_("Loading your files\u2026"));return}if(b==="auth"){p.appendChild(_("Sign in to browse your files.",{href:"/login",label:"Sign in"}));return}if(b==="error"){p.appendChild(_("Couldn't reach your files.",void 0,!0));return}if(!K.length&&!w.length){p.appendChild(_(m==="/"?"No files yet.":"This folder is empty."));return}if(K.forEach(e=>p.appendChild(ue(e))),w.forEach((e,t)=>p.appendChild(fe(e,w,t))),q!=null){let e=s("button","rk-aichat-loadmore",z?"Loading\u2026":"Load more");e.type="button",e.disabled=z,e.addEventListener("click",De),p.appendChild(e)}}}function Se(){if(V==="loading"&&!O.length){p.appendChild(_("Searching\u2026"));return}if(V==="error"){p.appendChild(_("Search failed."));return}if(!O.length){p.appendChild(_("No matches."));return}let e=O.filter(t=>t.kind!=="folder");O.forEach((t,r)=>{t.kind==="folder"?p.appendChild(ue(t)):p.appendChild(fe(t,e,e.indexOf(t),!0))})}let Z=!1;function me(){let e=U();return e==="files"?l+"/attachments/upload":e==="temp"?l+"/temporary-files/upload":null}function Pe(){if(!y)return;let e=me();if(u.hidden=!e||b==="auth",!u.hidden&&!Z){let t=G(),r=U()?(re.find(d=>d.key===U())||{label:""}).label:"";X.textContent="Drop files into "+r+(t?" / "+t:"")}}function ge(e){let t=me();if(!t||Z||!e||!e.length)return;Z=!0;let r=G(),d=Array.from(e),c=0,a=0;X.textContent="Uploading "+d.length+" file(s)\u2026";let k=C=>{if(C>=d.length){Z=!1,a&&D(a+" of "+d.length+" failed"),W(!0);return}let B=new FormData;B.append("file",d[C]),B.append("folder_path",r),fetch(t,{method:"POST",credentials:"same-origin",body:B}).then(P=>{if(!P.ok)throw new Error("http "+P.status);c++}).catch(()=>{a++}).then(()=>k(C+1))};k(0)}function Re(e){return K.concat(w,O).find(t=>t.path===e)}return p.addEventListener("contextmenu",e=>{let t=!!U(),r=e.target.closest(".rk-dir-row"),d={top:e.clientY,bottom:e.clientY,left:e.clientX,right:e.clientX},c=[],a=r?Re(r.getAttribute("data-path")||""):void 0;a&&a.kind==="folder"?(c.push({label:"Open folder",run:()=>S(a.path)}),t&&c.push({label:"New subfolder",run:()=>Q(a.folderPath)}),c.push({label:"Copy path",run:()=>A(a.path)})):a&&(R==="attach"&&c.push({label:"Attach",run:()=>h([a])}),a.viewUrl&&c.push({label:"View",run:()=>window.open(a.viewUrl,"_blank","noopener")}),a.viewUrl&&c.push({label:"Preview",run:()=>H(w,w.indexOf(a))}),c.push({label:"Copy path",run:()=>A(a.path)})),t&&c.push({label:"New folder here",run:()=>Q()}),c.length&&(e.preventDefault(),we(d,c))}),Y.addEventListener("input",Le),u.addEventListener("click",e=>{(e.target===u||e.target===X)&&M.click()}),M.addEventListener("change",()=>{ge(M.files),M.value=""}),u.addEventListener("dragover",e=>{e.preventDefault(),u.classList.add("is-drag")}),u.addEventListener("dragleave",e=>{e.target===u&&u.classList.remove("is-drag")}),u.addEventListener("drop",e=>{e.preventDefault(),u.classList.remove("is-drag"),e.dataTransfer&&e.dataTransfer.files&&ge(e.dataTransfer.files)}),W(!0),{refresh:()=>W(!0),navigate:S,getSelection:()=>Array.from(g.values()),destroy:()=>{L=!0,F&&F(),o.innerHTML=""}}}function _e(o){return window.CSS&&window.CSS.escape?window.CSS.escape(o):o.replace(/["\\]/g,"\\$&")}function Be(o){let n=o.dataset,l=(n.roots||"").split(",").map(i=>i.trim()).filter(Boolean);return{roots:l.length?l:void 0,initialPath:n.initialPath||void 0,mode:n.mode==="standalone"?"standalone":"attach",showSearch:n.showSearch!=="false",showMultiSelect:n.showMultiselect!=="false",showUpload:n.showUpload!=null?n.showUpload==="true":void 0,primaryClick:n.primaryClick||"copyPath"}}function ke(){Array.prototype.slice.call(document.querySelectorAll("[data-rk-directory]")).forEach(n=>{n.getAttribute("data-rk-dir-mounted")!=="1"&&(n.setAttribute("data-rk-dir-mounted","1"),window.__rkDirectoryInstance=ve(n,Be(n)))})}window.__vidfarmDirectory={mount:ve};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ke):ke();window.dispatchEvent(new CustomEvent("vidfarm:directory-ready"));export{ve as createDirectoryExplorer};
|
|
1
|
+
var Me=["files","temp","raws","projects","approved"],pe=[{key:"files",label:"My Files",description:"Durable personal files \u2014 brand assets, characters, saved context. Vector-searchable via notes."},{key:"temp",label:"Temp",description:"Scratch space, auto-organized by date (YYYY-MM-DD) and auto-deleted after 30 days."},{key:"raws",label:"Raws",description:"The reusable clip / source-footage library, organized into folders by source."},{key:"projects",label:"Projects",description:"Your video-editing projects \u2014 one folder per fork, holding that composition's working files (composition.html/json, cast, media) and saved versions. Read-only: browse to reference or study another fork."},{key:"approved",label:"Approved",description:"Finished, ready-to-post cuts, organized into folders (defaults to a folder per tracer/campaign)."}];function qe(r){return r==="files"||r==="temp"||r==="raws"||r==="projects"||r==="approved"}function ue(r){return String(r??"").split("/").map(n=>n.trim()).filter(Boolean).join("/")}function J(r){let n=String(r??"").split("/").map(h=>h.trim()).filter(Boolean);if(n.length===0)return{root:null,folderPath:"",segments:[]};let[s,...a]=n;return qe(s)?{root:s,folderPath:a.join("/"),segments:a}:{root:null,folderPath:"",segments:n}}function Z(r,n,s){let a=[r,ue(n)];return s&&a.push(String(s).trim()),"/"+a.filter(Boolean).join("/")}var We="/api/v1/user/me";function i(r,n,s){let a=document.createElement(r);return n&&(a.className=n),s!=null&&(a.textContent=s),a}function Je(r){if(!r||r<=0)return"";let n=["B","KB","MB","GB"],s=r,a=0;for(;s>=1024&&a<n.length-1;)s/=1024,a++;return(s>=10||a===0?Math.round(s):s.toFixed(1))+" "+n[a]}function Ve(r){if(typeof r!="number"||!(r>0))return"";r=Math.round(r);let n=Math.floor(r/60),s=r%60;return n+":"+(s<10?"0"+s:s)}function Se(r){let n=i("span","rk-aichat-fic "+(r.kind==="folder"?"rk-aichat-fic-folder":"rk-aichat-fic-file"));if(r.kind==="folder")return n.textContent="/",n;if(r.thumbUrl){let a=i("img");return a.src=r.thumbUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}let s=r.contentType||"";if(r.viewUrl&&s.indexOf("image/")===0){let a=i("img");return a.src=r.viewUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}if(r.viewUrl&&s.indexOf("video/")===0){let a=i("video");return a.src=r.viewUrl,a.muted=!0,a.playsInline=!0,n.appendChild(a),n}return n.textContent=(r.name.split(".").pop()||r.name.slice(0,1)||"?").slice(0,3).toUpperCase(),n}var fe;function he(r){let n=document.getElementById("rk-dir-toast");n||(n=i("div"),n.id="rk-dir-toast",n.className="rk-dir-toast",document.body.appendChild(n)),n.textContent=r,n.classList.add("is-on"),fe&&window.clearTimeout(fe),fe=window.setTimeout(()=>n&&n.classList.remove("is-on"),1800)}function $e(r){return navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r):new Promise((n,s)=>{try{let a=i("textarea");a.value=r,a.style.position="fixed",a.style.opacity="0",document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a),n()}catch(a){s(a)}})}var q=null;function Re(r,n){q&&q();let s=i("div","rk-dir-menu");n.forEach(f=>{let L=i("button","rk-dir-menuitem"+(f.danger?" is-danger":""),f.label);L.type="button",L.addEventListener("click",N=>{N.stopPropagation(),x(),f.run()}),s.appendChild(L)}),document.body.appendChild(s);let a=r instanceof HTMLElement?r.getBoundingClientRect():r,h=s.offsetWidth,v=s.offsetHeight,S=a.bottom+4,w=a.right-h;w<8&&(w=a.left),S+v>window.innerHeight-8&&(S=Math.max(8,a.top-v-4)),s.style.top=S+"px",s.style.left=Math.max(8,w)+"px";function x(){s.remove(),document.removeEventListener("click",m,!0),document.removeEventListener("keydown",D,!0),window.removeEventListener("scroll",x,!0),q===x&&(q=null)}function m(f){s.contains(f.target)||x()}function D(f){f.key==="Escape"&&x()}setTimeout(()=>{document.addEventListener("click",m,!0),document.addEventListener("keydown",D,!0),window.addEventListener("scroll",x,!0)},0),q=x}function me(r,n={}){let s=n.apiBase||We,a=n.roots&&n.roots.length?n.roots:Me.slice(),h=a.length===1?a[0]:null,v=n.mode||"attach",S=n.showSearch!==!1,w=n.showMultiSelect!==!1,x=n.showUpload!=null?n.showUpload:v==="attach",m=n.primaryClick||"copyPath",D=n.cloudAvailable!=null?n.cloudAvailable:typeof window<"u"&&window.__vidfarmCloudSpace===!0,f=window.__rkDirectoryHost||{},L=e=>(n.onAttach||f.onAttach||(()=>he("Attached "+e.length+" item(s)")))(e),N=(e,t)=>{let o=n.onPreview||f.onPreview;o?o(e,t):e[t]&&e[t].viewUrl&&window.open(e[t].viewUrl,"_blank","noopener")},T=e=>(n.onToast||f.onToast||he)(e),R=e=>$e(e).then(()=>T("Copied "+e)).catch(()=>T("Couldn't copy path")),p=He(n.initialPath,h),u="idle",g=[],P=[],V=null,W=!1,k=new Map,$=!1,I=[],X="idle",H=!1,le="local";function ge(){return le==="cloud"?"/cloud":""}function He(e,t){let o=J(e||"");return o.root?Z(o.root,o.folderPath):t?"/"+t:"/"}r.classList.add("rk-dir"),r.innerHTML="";let be=i("div","rk-dir-search"),z=i("input","rk-dir-search-input");z.type="search",z.placeholder="Search files \u2014 meaning, name, or path\u2026",be.appendChild(z);let O=i("div","rk-aichat-crumbs rk-dir-crumbs"),_=i("div","rk-dir-selbar");_.hidden=!0;let b=i("div","rk-aichat-files-body rk-dir-body"),y=i("label","rk-aichat-drop rk-dir-drop");y.hidden=!0;let ee=i("span","rk-aichat-drop-text","Drop files here"),B=i("input");B.type="file",B.multiple=!0,B.hidden=!0,y.appendChild(ee),y.appendChild(B);let de=i("div","rk-dir-space"),te=i("button","rk-dir-space-btn is-on","Local"),ne=i("button","rk-dir-space-btn","Cloud");te.type="button",ne.type="button",de.appendChild(te),de.appendChild(ne);function ke(e){le!==e&&(le=e,te.classList.toggle("is-on",e==="local"),ne.classList.toggle("is-on",e==="cloud"),$=!1,I=[],z.value="",k.clear(),p=h?"/"+h:"/",u="idle",F(!0))}te.addEventListener("click",()=>ke("local")),ne.addEventListener("click",()=>ke("cloud")),D&&r.appendChild(de),S&&r.appendChild(be),r.appendChild(O),w&&r.appendChild(_),r.appendChild(b),x&&r.appendChild(y);function ye(e,t){let o=new URL(s+ge()+"/directory",window.location.href);return o.searchParams.set("path",e),t&&o.searchParams.set("offset",String(t)),o.toString()}function F(e){if(!H){if(!e&&u==="ready"){C();return}u="loading",C(),fetch(ye(p),{credentials:"same-origin",headers:{accept:"application/json"}}).then(t=>{if(t.status===401||t.status===403)return u="auth",null;if(!t.ok)throw new Error("http "+t.status);return t.json()}).then(t=>{if(!H){if(!t){C();return}g=Oe(t.folders||[]),P=t.files||[],V=typeof t.next_offset=="number"?t.next_offset:null,u="ready",C()}}).catch(()=>{H||(u="error",C())})}}function Oe(e){return p!=="/"?e:e.filter(t=>a.indexOf(t.root)!==-1)}function _e(){V==null||W||(W=!0,C(),fetch(ye(p,V),{credentials:"same-origin",headers:{accept:"application/json"}}).then(e=>e.ok?e.json():null).then(e=>{if(W=!1,H||!e){C();return}P=P.concat(e.files||[]),V=typeof e.next_offset=="number"?e.next_offset:null,C()}).catch(()=>{W=!1,C()}))}let ce;function Be(){let e=z.value.trim();if(ce&&window.clearTimeout(ce),!e){$=!1,I=[],C();return}ce=window.setTimeout(()=>Ue(e),260)}function Ue(e){$=!0,X="loading",C();let t=h?"/"+h:p!=="/"?p:"";fetch(s+ge()+"/directory/search",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:e,path:t,mode:"auto",limit:40})}).then(o=>o.ok?o.json():null).then(o=>{H||(I=o&&o.results||[],X="ready",C())}).catch(()=>{H||(X="error",C())})}function U(e){let t=J(e);p=t.root?Z(t.root,t.folderPath):"/",u="idle",$=!1,z.value="",(n.onNavigate||(()=>{}))(p),F(!0)}function j(){return J(p).root}function re(){return J(p).folderPath}function Y(e){return!!e&&e!=="projects"}function oe(e){let t=j();if(!t){T("Open a root (/files, /temp, /raws) first");return}if(!Y(t)){T("/projects is read-only");return}let o=(window.prompt("New folder name")||"").trim();if(!o)return;let d=ue(e??re()),c=Z(t,d?d+"/"+o:o);fetch(s+"/directory/folders",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:c})}).then(l=>l.ok?l.json():l.json().then(E=>Promise.reject(new Error(E.error||"http "+l.status)))).then(l=>{U(l.path||(t===j()?p:"/"+t)),T("Created "+(l.path||o))}).catch(l=>T(l.message||"Couldn't create folder"))}function ie(e){let t=e.kind==="folder",o=(window.prompt(t?"Rename folder":"Rename file",e.name)||"").trim();!o||o===e.name||fetch(s+"/directory/rename",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:e.path,new_name:o,...t?{}:{file_id:e.id}})}).then(d=>d.ok?d.json():d.json().then(c=>Promise.reject(new Error(c.error||"http "+d.status)))).then(()=>{k.has(e.path)&&(k.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(k.values()))),F(!0),T("Renamed to "+o)}).catch(d=>T(d.message||"Couldn't rename"))}function je(e,t){t?k.set(e.path,e):k.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(k.values())),Ce();let o=b.querySelector('[data-path="'+Xe(e.path)+'"]');o&&o.classList.toggle("is-selected",t)}function ve(){k.clear(),(n.onSelectionChange||(()=>{}))([]),C()}function se(e,t,o){let d=i("button","rk-aichat-crumb"+(t?" is-current":""),e);return d.type="button",d.addEventListener("click",o),d}function Ne(){O.innerHTML="";let e=j(),t=re();if(h||O.appendChild(se("Files",p==="/",()=>U("/"))),!e)return;let o=(pe.find(c=>c.key===e)||{label:e}).label;h||O.appendChild(we()),O.appendChild(se(o,!t,()=>U("/"+e)));let d="";if(t.split("/").filter(Boolean).forEach((c,l,E)=>{O.appendChild(we()),d=d?d+"/"+c:c;let M="/"+e+"/"+d;O.appendChild(se(c,l===E.length-1,()=>U(M)))}),Y(e)){let c=i("button","rk-dir-newfolder","+ Folder");c.type="button",c.title="New folder here (or right-click)",c.addEventListener("click",()=>oe()),O.appendChild(c)}}function we(){return i("span","rk-aichat-crumb-sep","/")}function Ce(){if(!w)return;let e=k.size;if(_.hidden=e===0,e===0)return;if(_.innerHTML="",_.appendChild(i("span","rk-dir-selcount",e+" selected")),v==="attach"){let d=i("button","rk-dir-selbtn","Attach");d.type="button",d.addEventListener("click",()=>{L(Array.from(k.values())),ve()}),_.appendChild(d)}let t=i("button","rk-dir-selbtn","Copy paths");t.type="button",t.addEventListener("click",()=>R(Array.from(k.values()).map(d=>d.path).join(`
|
|
2
|
+
`)));let o=i("button","rk-dir-selbtn is-ghost","Clear");o.type="button",o.addEventListener("click",ve),_.appendChild(t),_.appendChild(o)}function xe(e){let t=i("input","rk-dir-check");return t.type="checkbox",t.checked=k.has(e.path),t.setAttribute("aria-label","Select "+e.name),t.addEventListener("click",o=>o.stopPropagation()),t.addEventListener("change",()=>je(e,t.checked)),t}function Ee(e){let t=i("div","rk-aichat-frow rk-dir-row"+(k.has(e.path)?" is-selected":""));t.setAttribute("data-path",e.path),w&&t.appendChild(xe(e));let o=i("button","rk-aichat-fmainbtn");o.type="button",o.title="Copy path "+e.path,o.appendChild(Se(e));let d=i("span","rk-aichat-fmain");d.appendChild(i("span","rk-aichat-fname",e.name));let c=e.meta&&typeof e.meta.description=="string"?e.meta.description:"";d.appendChild(i("span","rk-aichat-fmeta",c||"folder")),o.appendChild(d),o.addEventListener("click",()=>R(e.path)),t.appendChild(o);let l=i("button","rk-aichat-fadd rk-dir-open","Open \u203A");l.type="button",l.title="Open folder",l.addEventListener("click",M=>{M.stopPropagation(),U(e.path)}),t.appendChild(l);let E=[{label:"Open folder",run:()=>U(e.path)}];return Y(e.root)&&(E.push({label:"New subfolder",run:()=>oe(e.folderPath)}),E.push({label:"Rename",run:()=>ie(e)})),E.push({label:"Copy path",run:()=>R(e.path)}),t.appendChild(Le(e,E)),t}function De(e,t,o,d){let c=i("div","rk-aichat-frow rk-dir-row"+(k.has(e.path)?" is-selected":""));c.setAttribute("data-path",e.path),w&&c.appendChild(xe(e));let l=i("button","rk-aichat-fmainbtn");l.type="button";let E=m==="copyPath"?"Copy path ":m==="attach"?"Attach ":"Preview ";l.title=E+e.name,l.appendChild(Se(e));let M=i("span","rk-aichat-fmain");M.appendChild(i("span","rk-aichat-fname",e.name));let G=d?e.path:Ve(e.durationSec)||Je(e.sizeBytes)||e.contentType||"file";if(M.appendChild(i("span","rk-aichat-fmeta",G)),l.appendChild(M),l.addEventListener("click",()=>{m==="attach"?L([e]):m==="preview"?N(t,o):R(e.path)}),c.appendChild(l),v==="attach"&&m==="preview"){let Q=i("button","rk-aichat-fadd rk-dir-attach","+");Q.type="button",Q.title="Attach "+e.name,Q.setAttribute("aria-label","Attach "+e.name),Q.addEventListener("click",Ke=>{Ke.stopPropagation(),L([e])}),c.appendChild(Q)}let A=[];return v==="attach"&&A.push({label:"Attach",run:()=>L([e])}),e.viewUrl&&A.push({label:"View",run:()=>window.open(e.viewUrl,"_blank","noopener")}),e.viewUrl&&A.push({label:"Preview",run:()=>N(t,o)}),(e.root==="files"||e.root==="temp")&&e.id&&A.push({label:"Rename",run:()=>ie(e)}),A.push({label:"Copy path",run:()=>R(e.path)}),c.appendChild(Le(e,A)),c}function Le(e,t){let o=i("button","rk-dir-kebab","\u22EF");return o.type="button",o.setAttribute("aria-label","More actions"),o.addEventListener("click",d=>{d.stopPropagation(),Re(o,t)}),o}function K(e,t,o){let d=i("div","rk-aichat-fstate");if(d.appendChild(i("div",void 0,e)),t){let c=i("a");c.href=t.href,c.textContent=t.label,d.appendChild(c)}if(o){let c=i("button",void 0,"Try again");c.type="button",c.addEventListener("click",()=>F(!0)),d.appendChild(c)}return d}function C(){if(!H){if(Ne(),Ce(),Fe(),b.innerHTML="",$){ze();return}if(u==="loading"&&!P.length&&!g.length){b.appendChild(K("Loading your files\u2026"));return}if(u==="auth"){b.appendChild(K("Sign in to browse your files.",{href:"/login",label:"Sign in"}));return}if(u==="error"){b.appendChild(K("Couldn't reach your files.",void 0,!0));return}if(!g.length&&!P.length){b.appendChild(K(p==="/"?"No files yet.":"This folder is empty."));return}if(g.forEach(e=>b.appendChild(Ee(e))),P.forEach((e,t)=>b.appendChild(De(e,P,t))),V!=null){let e=i("button","rk-aichat-loadmore",W?"Loading\u2026":"Load more");e.type="button",e.disabled=W,e.addEventListener("click",_e),b.appendChild(e)}}}function ze(){if(X==="loading"&&!I.length){b.appendChild(K("Searching\u2026"));return}if(X==="error"){b.appendChild(K("Search failed."));return}if(!I.length){b.appendChild(K("No matches."));return}let e=I.filter(t=>t.kind!=="folder");I.forEach((t,o)=>{t.kind==="folder"?b.appendChild(Ee(t)):b.appendChild(De(t,e,e.indexOf(t),!0))})}let ae=!1;function Te(){let e=j();return e==="files"?s+"/attachments/upload":e==="temp"?s+"/temporary-files/upload":null}function Fe(){if(!x)return;let e=Te();if(y.hidden=!e||u==="auth",!y.hidden&&!ae){let t=re(),o=j()?(pe.find(d=>d.key===j())||{label:""}).label:"";ee.textContent="Drop files into "+o+(t?" / "+t:"")}}function Pe(e){let t=Te();if(!t||ae||!e||!e.length)return;ae=!0;let o=re(),d=Array.from(e),c=0,l=0;ee.textContent="Uploading "+d.length+" file(s)\u2026";let E=M=>{if(M>=d.length){ae=!1,l&&T(l+" of "+d.length+" failed"),F(!0);return}let G=new FormData;G.append("file",d[M]),G.append("folder_path",o),fetch(t,{method:"POST",credentials:"same-origin",body:G}).then(A=>{if(!A.ok)throw new Error("http "+A.status);c++}).catch(()=>{l++}).then(()=>E(M+1))};E(0)}function Ye(e){return g.concat(P,I).find(t=>t.path===e)}return b.addEventListener("contextmenu",e=>{let t=!!j(),o=e.target.closest(".rk-dir-row"),d={top:e.clientY,bottom:e.clientY,left:e.clientX,right:e.clientX},c=[],l=o?Ye(o.getAttribute("data-path")||""):void 0;l&&l.kind==="folder"?(c.push({label:"Open folder",run:()=>U(l.path)}),Y(l.root)&&c.push({label:"New subfolder",run:()=>oe(l.folderPath)}),Y(l.root)&&c.push({label:"Rename",run:()=>ie(l)}),c.push({label:"Copy path",run:()=>R(l.path)})):l&&(v==="attach"&&c.push({label:"Attach",run:()=>L([l])}),l.viewUrl&&c.push({label:"View",run:()=>window.open(l.viewUrl,"_blank","noopener")}),l.viewUrl&&c.push({label:"Preview",run:()=>N(P,P.indexOf(l))}),l.root!=="raws"&&Y(l.root)&&l.id&&c.push({label:"Rename",run:()=>ie(l)}),c.push({label:"Copy path",run:()=>R(l.path)})),t&&Y(j())&&c.push({label:"New folder here",run:()=>oe()}),c.length&&(e.preventDefault(),Re(d,c))}),z.addEventListener("input",Be),y.addEventListener("click",e=>{(e.target===y||e.target===ee)&&B.click()}),B.addEventListener("change",()=>{Pe(B.files),B.value=""}),y.addEventListener("dragover",e=>{e.preventDefault(),y.classList.add("is-drag")}),y.addEventListener("dragleave",e=>{e.target===y&&y.classList.remove("is-drag")}),y.addEventListener("drop",e=>{e.preventDefault(),y.classList.remove("is-drag"),e.dataTransfer&&e.dataTransfer.files&&Pe(e.dataTransfer.files)}),(n.onNavigate||(()=>{}))(p),F(!0),{refresh:()=>F(!0),navigate:U,getSelection:()=>Array.from(k.values()),getCurrentPath:()=>p,destroy:()=>{H=!0,q&&q(),r.innerHTML=""}}}function Xe(r){return window.CSS&&window.CSS.escape?window.CSS.escape(r):r.replace(/["\\]/g,"\\$&")}var Ae="rk-dirpick-style";function Ge(){if(document.getElementById(Ae))return;let r=document.createElement("style");r.id=Ae,r.textContent=[".rk-dirpick{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:20px;","background:rgba(28,25,23,.44);backdrop-filter:blur(2px);animation:rk-dirpick-fade .16s ease}","@keyframes rk-dirpick-fade{from{opacity:0}to{opacity:1}}",".rk-dirpick-panel{width:min(560px,100%);max-height:min(82vh,700px);display:flex;flex-direction:column;","background:var(--rk-surface,#fff);border:1px solid var(--rk-border,#e6e0d6);border-radius:var(--rk-r-3xl,20px);","box-shadow:var(--rk-shadow-lg,0 24px 60px rgba(28,25,23,.28));overflow:hidden}",".rk-dirpick-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 18px;","border-bottom:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-title{font-family:var(--rk-font-display,inherit);font-weight:800;font-size:15px;color:var(--rk-ink,#1c1917)}",".rk-dirpick-close{border:0;background:transparent;font-size:22px;line-height:1;color:var(--rk-text-muted,#78716c);cursor:pointer;padding:0 4px}",".rk-dirpick-close:hover{color:var(--rk-ink,#1c1917)}",".rk-dirpick-hint{padding:10px 18px 0;font-size:12.5px;line-height:1.4;color:var(--rk-text-muted,#78716c)}",".rk-dirpick-mount{padding:12px 14px;overflow:auto;flex:1;min-height:0}",".rk-dirpick-foot{display:flex;align-items:center;gap:10px;padding:12px 18px;border-top:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-dest{flex:1;min-width:0;font-size:12.5px;color:var(--rk-text-muted,#78716c);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",".rk-dirpick-dest b{color:var(--rk-ink,#1c1917);font-weight:700}",".rk-dirpick-btn{flex:none;min-height:36px;padding:0 16px;border-radius:999px;border:0;cursor:pointer;","font:inherit;font-size:13px;font-weight:800;background:var(--rk-gold-500,var(--rk-gold-600,#fcb900));color:var(--rk-ink,#1c1917)}",".rk-dirpick-btn:hover:not(:disabled){background:var(--rk-gold-600,#e0a500)}",".rk-dirpick-btn:disabled{opacity:.5;cursor:default}",".rk-dirpick-btn.is-ghost{background:transparent;border:1px solid var(--rk-border,#e6e0d6);color:var(--rk-ink,#1c1917)}"].join(""),document.head.appendChild(r)}function Qe(r={}){Ge();let n=r.select==="folder"?"folder":"file",s=!1,a=null,h=i("div","rk-dirpick"),v=i("div","rk-dirpick-panel"),S=i("div","rk-dirpick-head");S.appendChild(i("span","rk-dirpick-title",r.title||(n==="folder"?"Choose a folder":"Choose a file")));let w=i("button","rk-dirpick-close");w.type="button",w.setAttribute("aria-label","Close"),w.innerHTML="×",S.appendChild(w),v.appendChild(S),r.hint&&v.appendChild(i("div","rk-dirpick-hint",r.hint));let x=i("div","rk-dirpick-mount");v.appendChild(x);let m=null,D=null;function f(p){s||(s=!0,R(),p?(r.onPick||(()=>{}))(p):(r.onCancel||(()=>{}))())}function L(p){let u=J(p);if(!u.root)return null;let g=u.folderPath||"",P=g?g.split("/").filter(Boolean).pop()||g:u.root;return{path:Z(u.root,g),root:u.root,folderPath:g,name:P,kind:"folder"}}function N(p){if(!m||!D)return;let u=L(p);if(u){m.innerHTML="",m.appendChild(document.createTextNode("Save to "));let g=i("b",void 0,u.path);m.appendChild(g),D.disabled=!1}else m.textContent="Open a folder (Files, Temp, \u2026) to choose a destination.",D.disabled=!0}if(n==="folder"){let p=i("div","rk-dirpick-foot");m=i("div","rk-dirpick-dest");let u=i("button","rk-dirpick-btn is-ghost","Cancel");u.type="button",u.addEventListener("click",()=>f(null)),D=i("button","rk-dirpick-btn",r.confirmLabel||"Use this folder"),D.type="button",D.addEventListener("click",()=>{let g=a?L(a.getCurrentPath()):null;g&&f(g)}),p.appendChild(m),p.appendChild(u),p.appendChild(D),v.appendChild(p)}h.appendChild(v),document.body.appendChild(h);function T(p){p.key==="Escape"&&f(null)}function R(){document.removeEventListener("keydown",T,!0);try{a&&a.destroy()}catch{}h.remove()}return w.addEventListener("click",()=>f(null)),h.addEventListener("click",p=>{p.target===h&&f(null)}),document.addEventListener("keydown",T,!0),a=me(x,{roots:r.roots,initialPath:r.initialPath,apiBase:r.apiBase,mode:"standalone",showSearch:!0,showMultiSelect:!1,showUpload:!1,primaryClick:n==="file"?"attach":"copyPath",onNavigate:p=>N(p),onAttach:p=>{if(n!=="file")return;let u=p&&p[0];if(u){if(r.accept&&!r.accept(u)){he(r.rejectMessage||"That file can't be used here.");return}f(u)}}}),{close:()=>f(null)}}function Ze(r){let n=r.dataset,s=(n.roots||"").split(",").map(a=>a.trim()).filter(Boolean);return{roots:s.length?s:void 0,initialPath:n.initialPath||void 0,mode:n.mode==="standalone"?"standalone":"attach",showSearch:n.showSearch!=="false",showMultiSelect:n.showMultiselect!=="false",showUpload:n.showUpload!=null?n.showUpload==="true":void 0,primaryClick:n.primaryClick||"copyPath",cloudAvailable:n.cloudAvailable!=null?n.cloudAvailable==="true":void 0}}function Ie(){Array.prototype.slice.call(document.querySelectorAll("[data-rk-directory]")).forEach(n=>{n.getAttribute("data-rk-dir-mounted")!=="1"&&(n.setAttribute("data-rk-dir-mounted","1"),window.__rkDirectoryInstance=me(n,Ze(n)))})}window.__vidfarmDirectory={mount:me,pick:Qe};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ie):Ie();window.dispatchEvent(new CustomEvent("vidfarm:directory-ready"));export{me as createDirectoryExplorer,Qe as openDirectoryPicker};
|