@mevdragon/vidfarm-devcli 0.20.0 → 0.20.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/dist/src/editor-chat.js
CHANGED
|
@@ -79,7 +79,7 @@ export function buildTemplateEditorChatSystemPrompt(input) {
|
|
|
79
79
|
"FINE TIMELINE CONTROL — you have trackpad-level verbs; use them instead of rewriting the whole document for small changes: (1) set_layer_keyframes authors a custom, script-free CSS @keyframes animation on ONE layer that previews AND renders — pass layer_key + keyframes:[{offset(0..1), opacity?, translate_x?, translate_y?, scale?, rotate?}, …] (>=2 stops), optional keyframe_easing (linear/ease/ease-in/ease-out/ease-in-out/cubic-bezier(...)) and keyframe_duration (seconds, default = clip duration). translate_x/translate_y are percentages of the layer's OWN box. Example fly-up-and-fade-in: keyframes=[{offset:0,opacity:0,translate_y:40},{offset:1,opacity:1,translate_y:0}]. This is the durable way to hand-author motion beyond the Ken Burns / transition / caption presets — the JS runtime adapters (anime.js/GSAP/Lottie) are devcli-only. (2) nudge_layers shifts one or more layers by a RELATIVE delta_start (seconds) and/or delta_track (lanes) — pass layer_key or layer_keys; grouped clips move together. (3) ripple_edit inserts (delta_start>0) or closes (delta_start<0) time at at_time and shifts every downstream clip so the rest of the timeline stays in sync — use it to make room before an insert or to close a gap you can see in timeline_gaps. (4) trim_layer moves ONE edge to a time: edge='start' (left; advances the in-point, and for video/audio pushes the media start so the visible frame is unchanged) or edge='end' (right; changes duration), with to_time in composition seconds. (5) set_layer_zindex restacks: z_order='front'|'back'|'forward'|'backward' (stacking == track index; higher draws on top) or an explicit track. All of these auto-resolve track collisions and note it in the summary; read the NEXT editor_context to confirm the new start/duration/track/animation landed.",
|
|
80
80
|
"If the user asks to export, render, publish, or produce the final MP4 for this composition (phrases like 'export it', 'render this', 'kick off the export', 'make the mp4'), call editor_action with action_type=export_composition and a brief explanation. This is the same action as the editor's Export button — it queues the composition on production AWS Lambda. Do NOT try to hit any /api/v1/compositions/:id/export route via http_request for this; use the editor_action tool. After calling export_composition, tell the user the export has started and that the finished MP4 URL will appear once the render succeeds; do not fabricate a URL or claim success until a later turn shows last_export_url populated in editor_context.",
|
|
81
81
|
"CONFIRM BEFORE RENDERING — DO NOT auto-render. Rendering the final MP4 is a slow, costly, screen-taking action, so by DEFAULT you must NOT call export_composition on your own initiative. After you finish an edit (a swap, a re-theme, a scene rebuild), STOP and let the user review the live preview, then ASK a short question like 'Happy with the preview? Want me to render the final MP4?' and wait for a yes. Only fire export_composition when EITHER (a) the user explicitly asks to render/export/'make the mp4' in that turn, or (b) the user has told you up front to just render without asking (e.g. 'edit and render it', 'no need to check, just export'). If in doubt, ask — never surprise the user with a render. Never render merely because you judged the edit 'done'.",
|
|
82
|
-
"MEDIA SWAP — TARGET A REAL LAYER KEY, NOT A SCENE NAME. To swap a clip's media with set_layer_media, the layer_key MUST be an EXACT key (or its slug) from editor_context.layers — that array lists every targetable layer with its key, slug, kind (video/image/audio), and current src. Read it and copy the real key of the video/image layer you mean; do NOT invent a semantic name (like 'growth_examples' or 'mistakes_reflection') unless that exact string appears as a layer key/slug in editor_context, and never target a scene label/group when you mean the video inside it. If set_layer_media returns 'No change applied' or 'Layer not found', the error now lists the actual media layers — re-read it and retry with one of those exact keys. NEVER report a swap as done
|
|
82
|
+
"MEDIA SWAP — TARGET A REAL LAYER KEY, NOT A SCENE NAME. To swap a clip's media with set_layer_media, the layer_key MUST be an EXACT key (or its slug) from editor_context.layers — that array lists every targetable layer with its key, slug, kind (video/image/audio), and current src. Read it and copy the real key of the video/image layer you mean; do NOT invent a semantic name (like 'growth_examples' or 'mistakes_reflection') unless that exact string appears as a layer key/slug in editor_context, and never target a scene label/group when you mean the video inside it. If set_layer_media returns 'No change applied' or 'Layer not found', the error now lists the actual media layers — re-read it and retry with one of those exact keys. This applies to EVERY set_layer_media field (src, object_fit, object_position, volume, muted, ken_burns, transitions), not just src: the layer_key you used to add a layer (e.g. add_layer layer_key='vf-fishing-snippet-1') becomes an 'element_'-prefixed key on the timeline, so target the real key/slug shown in editor_context, not the bare name you passed earlier. NEVER report a swap or fit/position change as done while any editor_action in this turn came back with a ⚠ / 'Layer not found' error — those calls did NOT apply; re-read the listed keys, retry against a real one, and only confirm success once the action returns ✓ (and, for src, the NEXT editor_context shows the layer changed). Do not claim you changed layers you never successfully targeted.",
|
|
83
83
|
"GETTING THE MEDIA URL IS EASY — USE browse_files. When the user says 'use my raws' / 'it's in my file directory' / 'the fishing clips', you do NOT need them to paste a URL. Call browse_files action=search (or list path='/raws') to find the clip, then action=read with its file_id — the read result's view_url IS the public, ready-to-use media URL. Drop that view_url straight into set_layer_media src (or add_layer src). Do not stall asking the user for a URL you can look up yourself, and never pass a placeholder like 'please-ignore' as src.",
|
|
84
84
|
"The editor_context block includes last_export_url, last_export_title, last_export_status, and last_export_render_id when a render has succeeded in this session. Treat last_export_url as the current 'finished Export MP4' for this composition. If the user asks to approve, package, share, or schedule the exported video without providing an explicit URL, use last_export_url as the primary MP4 media (kind=video, role=primary) for POST /api/v1/approved/posts. If last_export_url is null, tell the user to Export first (or offer to call editor_action with action_type=export_composition on their behalf) instead of guessing a URL.",
|
|
85
85
|
"Each layer in editor_context includes element_id (data-hf-id), optional slug (data-hf-slug), and optional note (data-hf-note). layer_key on any editor_action may be EITHER the element_id or the slug — prefer the slug when the user (or a viral DNA blurb) refers to a layer by its human name like 'the hero_image'. Use set_layer_identity to add/change a layer's slug or note. Slugs are the stable AI-friendly handle: when planning viral DNA notes, reference the element by its slug (e.g., 'raise the {{hero_image}} to full canvas at 4s') so future turns can resolve it deterministically.",
|
|
@@ -501,20 +501,23 @@ export function createDirectoryExplorer(mount, opts = {}) {
|
|
|
501
501
|
return;
|
|
502
502
|
selbar.innerHTML = "";
|
|
503
503
|
selbar.appendChild(el("span", "rk-dir-selcount", n + " selected"));
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
selbar.appendChild(att);
|
|
509
|
-
}
|
|
510
|
-
const cp = el("button", "rk-dir-selbtn", "Copy paths");
|
|
504
|
+
const picked = () => Array.from(selection.values());
|
|
505
|
+
// Primary action stays on the bar; everything else tucks into a "⋯" menu so
|
|
506
|
+
// the toolbar never overflows in the narrow editor dock.
|
|
507
|
+
const cp = el("button", "rk-dir-selbtn is-primary", "Copy paths");
|
|
511
508
|
cp.type = "button";
|
|
512
|
-
cp.addEventListener("click", () => copyPath(
|
|
513
|
-
const clr = el("button", "rk-dir-selbtn is-ghost", "Clear");
|
|
514
|
-
clr.type = "button";
|
|
515
|
-
clr.addEventListener("click", clearSelection);
|
|
509
|
+
cp.addEventListener("click", () => copyPath(picked().map((s) => s.path).join("\n")));
|
|
516
510
|
selbar.appendChild(cp);
|
|
517
|
-
|
|
511
|
+
const more = [];
|
|
512
|
+
if (mode === "attach")
|
|
513
|
+
more.push({ label: "Attach", run: () => { emitAttach(picked()); clearSelection(); } });
|
|
514
|
+
more.push({ label: "Copy paths", run: () => copyPath(picked().map((s) => s.path).join("\n")) });
|
|
515
|
+
more.push({ label: "Clear selection", run: clearSelection });
|
|
516
|
+
const menuBtn = el("button", "rk-dir-selbtn is-ghost rk-dir-selmore", "⋯");
|
|
517
|
+
menuBtn.type = "button";
|
|
518
|
+
menuBtn.setAttribute("aria-label", "More actions");
|
|
519
|
+
menuBtn.addEventListener("click", (e) => { e.stopPropagation(); openMenuAt(menuBtn, more); });
|
|
520
|
+
selbar.appendChild(menuBtn);
|
|
518
521
|
}
|
|
519
522
|
function checkbox(it) {
|
|
520
523
|
const box = el("input", "rk-dir-check");
|
|
@@ -719,15 +722,27 @@ export function createDirectoryExplorer(mount, opts = {}) {
|
|
|
719
722
|
return;
|
|
720
723
|
uploading = true;
|
|
721
724
|
const folder = currentFolder();
|
|
725
|
+
const root = currentRoot();
|
|
722
726
|
const arr = Array.from(list);
|
|
723
727
|
let done = 0, failed = 0;
|
|
728
|
+
// The server may re-home an upload (e.g. /temp files land in a dated
|
|
729
|
+
// subfolder). Track where the bytes actually landed so we can reveal them —
|
|
730
|
+
// otherwise the refresh shows the folder we uploaded FROM, which looks empty.
|
|
731
|
+
let landedFolder = null;
|
|
724
732
|
dropText.textContent = "Uploading " + arr.length + " file(s)…";
|
|
733
|
+
const finish = () => {
|
|
734
|
+
uploading = false;
|
|
735
|
+
if (failed)
|
|
736
|
+
toast(failed + " of " + arr.length + " failed");
|
|
737
|
+
const target = root && landedFolder != null ? buildDirectoryPath(root, landedFolder) : null;
|
|
738
|
+
if (target && target !== currentPath)
|
|
739
|
+
navigate(target); // reveal the uploads
|
|
740
|
+
else
|
|
741
|
+
load(true);
|
|
742
|
+
};
|
|
725
743
|
const next = (i) => {
|
|
726
744
|
if (i >= arr.length) {
|
|
727
|
-
|
|
728
|
-
if (failed)
|
|
729
|
-
toast(failed + " of " + arr.length + " failed");
|
|
730
|
-
load(true);
|
|
745
|
+
finish();
|
|
731
746
|
return;
|
|
732
747
|
}
|
|
733
748
|
const fd = new FormData();
|
|
@@ -735,7 +750,13 @@ export function createDirectoryExplorer(mount, opts = {}) {
|
|
|
735
750
|
fd.append("folder_path", folder);
|
|
736
751
|
fetch(endpoint, { method: "POST", credentials: "same-origin", body: fd })
|
|
737
752
|
.then((r) => { if (!r.ok)
|
|
738
|
-
throw new Error("http " + r.status);
|
|
753
|
+
throw new Error("http " + r.status); return r.json().catch(() => null); })
|
|
754
|
+
.then((j) => {
|
|
755
|
+
done++;
|
|
756
|
+
const fp = j && ((j.file && j.file.folderPath) ?? (j.attachment && j.attachment.folderPath));
|
|
757
|
+
if (typeof fp === "string" && landedFolder == null)
|
|
758
|
+
landedFolder = fp;
|
|
759
|
+
})
|
|
739
760
|
.catch(() => { failed++; })
|
|
740
761
|
.then(() => next(i + 1));
|
|
741
762
|
};
|
|
@@ -943,7 +964,9 @@ export function openDirectoryPicker(opts = {}) {
|
|
|
943
964
|
mode: "standalone",
|
|
944
965
|
showSearch: true,
|
|
945
966
|
showMultiSelect: false,
|
|
946
|
-
|
|
967
|
+
// Opt-in upload: when allowed, the explorer shows its drop zone so users can
|
|
968
|
+
// add a file to the currently-open folder (Files/Temp), then click it to pick.
|
|
969
|
+
showUpload: opts.allowUpload === true,
|
|
947
970
|
// In file mode a name-click resolves the pick; folders still navigate.
|
|
948
971
|
primaryClick: select === "file" ? "attach" : "copyPath",
|
|
949
972
|
onNavigate: (p) => syncFooter(p),
|
package/dist/src/reskin/theme.js
CHANGED
|
@@ -261,11 +261,14 @@ export const RESKIN_CSS = `
|
|
|
261
261
|
background:var(--rk-gold-tint);border:1px solid var(--rk-gold-600);border-radius:var(--rk-r-xl)}
|
|
262
262
|
.rk-dir-selbar[hidden]{display:none}
|
|
263
263
|
.rk-dir-selcount{flex:1;font-size:12px;font-weight:700;color:var(--rk-gold-700)}
|
|
264
|
-
.rk-dir-selbtn{font-family:inherit;font-size:12px;font-weight:
|
|
265
|
-
background
|
|
266
|
-
|
|
264
|
+
.rk-dir-selbtn{flex:none;font-family:inherit;font-size:12px;font-weight:800;color:var(--rk-ink);cursor:pointer;
|
|
265
|
+
background:transparent;border:1px solid var(--rk-gold-600);border-radius:var(--rk-r-full);padding:5px 14px;
|
|
266
|
+
transition:background var(--rk-dur) var(--rk-ease),border-color var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease)}
|
|
267
|
+
.rk-dir-selbtn.is-primary{background:var(--rk-gold-500);border-color:var(--rk-gold-600);color:var(--rk-ink)}
|
|
268
|
+
.rk-dir-selbtn.is-primary:hover{background:var(--rk-gold-600)}
|
|
267
269
|
.rk-dir-selbtn.is-ghost{border-color:var(--rk-border);color:var(--rk-text-muted);background:transparent}
|
|
268
|
-
.rk-dir-selbtn.is-ghost:hover{background:var(--rk-
|
|
270
|
+
.rk-dir-selbtn.is-ghost:hover{background:var(--rk-gold-tint);border-color:var(--rk-gold-600);color:var(--rk-ink)}
|
|
271
|
+
.rk-dir-selmore{padding:5px 10px;font-size:15px;line-height:1;font-weight:700}
|
|
269
272
|
/* per-row select checkbox — discoverable on hover, sticky when selected */
|
|
270
273
|
.rk-dir-check{flex:none;width:15px;height:15px;margin:0;accent-color:var(--rk-gold-600);cursor:pointer;opacity:0;
|
|
271
274
|
transition:opacity var(--rk-dur) var(--rk-ease)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mevdragon/vidfarm-devcli",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.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,3 @@
|
|
|
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};
|
|
1
|
+
var Ie=["files","temp","raws","projects","approved"],fe=[{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 Je(r){return r==="files"||r==="temp"||r==="raws"||r==="projects"||r==="approved"}function he(r){return String(r??"").split("/").map(n=>n.trim()).filter(Boolean).join("/")}function $(r){let n=String(r??"").split("/").map(h=>h.trim()).filter(Boolean);if(n.length===0)return{root:null,folderPath:"",segments:[]};let[c,...a]=n;return Je(c)?{root:c,folderPath:a.join("/"),segments:a}:{root:null,folderPath:"",segments:n}}function X(r,n,c){let a=[r,he(n)];return c&&a.push(String(c).trim()),"/"+a.filter(Boolean).join("/")}var Ve="/api/v1/user/me";function i(r,n,c){let a=document.createElement(r);return n&&(a.className=n),c!=null&&(a.textContent=c),a}function $e(r){if(!r||r<=0)return"";let n=["B","KB","MB","GB"],c=r,a=0;for(;c>=1024&&a<n.length-1;)c/=1024,a++;return(c>=10||a===0?Math.round(c):c.toFixed(1))+" "+n[a]}function Xe(r){if(typeof r!="number"||!(r>0))return"";r=Math.round(r);let n=Math.floor(r/60),c=r%60;return n+":"+(c<10?"0"+c:c)}function He(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 c=r.contentType||"";if(r.viewUrl&&c.indexOf("image/")===0){let a=i("img");return a.src=r.viewUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}if(r.viewUrl&&c.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 me;function be(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"),me&&window.clearTimeout(me),me=window.setTimeout(()=>n&&n.classList.remove("is-on"),1800)}function Ge(r){return navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r):new Promise((n,c)=>{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){c(a)}})}var J=null;function ge(r,n){J&&J();let c=i("div","rk-dir-menu");n.forEach(f=>{let P=i("button","rk-dir-menuitem"+(f.danger?" is-danger":""),f.label);P.type="button",P.addEventListener("click",N=>{N.stopPropagation(),E(),f.run()}),c.appendChild(P)}),document.body.appendChild(c);let a=r instanceof HTMLElement?r.getBoundingClientRect():r,h=c.offsetWidth,y=c.offsetHeight,A=a.bottom+4,v=a.right-h;v<8&&(v=a.left),A+y>window.innerHeight-8&&(A=Math.max(8,a.top-y-4)),c.style.top=A+"px",c.style.left=Math.max(8,v)+"px";function E(){c.remove(),document.removeEventListener("click",m,!0),document.removeEventListener("keydown",L,!0),window.removeEventListener("scroll",E,!0),J===E&&(J=null)}function m(f){c.contains(f.target)||E()}function L(f){f.key==="Escape"&&E()}setTimeout(()=>{document.addEventListener("click",m,!0),document.addEventListener("keydown",L,!0),window.addEventListener("scroll",E,!0)},0),J=E}function ke(r,n={}){let c=n.apiBase||Ve,a=n.roots&&n.roots.length?n.roots:Ie.slice(),h=a.length===1?a[0]:null,y=n.mode||"attach",A=n.showSearch!==!1,v=n.showMultiSelect!==!1,E=n.showUpload!=null?n.showUpload:y==="attach",m=n.primaryClick||"copyPath",L=n.cloudAvailable!=null?n.cloudAvailable:typeof window<"u"&&window.__vidfarmCloudSpace===!0,f=window.__rkDirectoryHost||{},P=e=>(n.onAttach||f.onAttach||(()=>be("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||be)(e),R=e=>Ge(e).then(()=>T("Copied "+e)).catch(()=>T("Couldn't copy path")),p=Be(n.initialPath,h),u="idle",g=[],M=[],G=null,V=!1,w=new Map,Q=!1,B=[],Z="idle",U=!1,de="local";function ye(){return de==="cloud"?"/cloud":""}function Be(e,t){let o=$(e||"");return o.root?X(o.root,o.folderPath):t?"/"+t:"/"}r.classList.add("rk-dir"),r.innerHTML="";let ve=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",ve.appendChild(z);let j=i("div","rk-aichat-crumbs rk-dir-crumbs"),Y=i("div","rk-dir-selbar");Y.hidden=!0;let b=i("div","rk-aichat-files-body rk-dir-body"),k=i("label","rk-aichat-drop rk-dir-drop");k.hidden=!0;let te=i("span","rk-aichat-drop-text","Drop files here"),F=i("input");F.type="file",F.multiple=!0,F.hidden=!0,k.appendChild(te),k.appendChild(F);let ce=i("div","rk-dir-space"),ne=i("button","rk-dir-space-btn is-on","Local"),re=i("button","rk-dir-space-btn","Cloud");ne.type="button",re.type="button",ce.appendChild(ne),ce.appendChild(re);function we(e){de!==e&&(de=e,ne.classList.toggle("is-on",e==="local"),re.classList.toggle("is-on",e==="cloud"),Q=!1,B=[],z.value="",w.clear(),p=h?"/"+h:"/",u="idle",K(!0))}ne.addEventListener("click",()=>we("local")),re.addEventListener("click",()=>we("cloud")),L&&r.appendChild(ce),A&&r.appendChild(ve),r.appendChild(j),v&&r.appendChild(Y),r.appendChild(b),E&&r.appendChild(k);function Ce(e,t){let o=new URL(c+ye()+"/directory",window.location.href);return o.searchParams.set("path",e),t&&o.searchParams.set("offset",String(t)),o.toString()}function K(e){if(!U){if(!e&&u==="ready"){C();return}u="loading",C(),fetch(Ce(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(!U){if(!t){C();return}g=Ue(t.folders||[]),M=t.files||[],G=typeof t.next_offset=="number"?t.next_offset:null,u="ready",C()}}).catch(()=>{U||(u="error",C())})}}function Ue(e){return p!=="/"?e:e.filter(t=>a.indexOf(t.root)!==-1)}function je(){G==null||V||(V=!0,C(),fetch(Ce(p,G),{credentials:"same-origin",headers:{accept:"application/json"}}).then(e=>e.ok?e.json():null).then(e=>{if(V=!1,U||!e){C();return}M=M.concat(e.files||[]),G=typeof e.next_offset=="number"?e.next_offset:null,C()}).catch(()=>{V=!1,C()}))}let se;function Fe(){let e=z.value.trim();if(se&&window.clearTimeout(se),!e){Q=!1,B=[],C();return}se=window.setTimeout(()=>Ne(e),260)}function Ne(e){Q=!0,Z="loading",C();let t=h?"/"+h:p!=="/"?p:"";fetch(c+ye()+"/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=>{U||(B=o&&o.results||[],Z="ready",C())}).catch(()=>{U||(Z="error",C())})}function I(e){let t=$(e);p=t.root?X(t.root,t.folderPath):"/",u="idle",Q=!1,z.value="",(n.onNavigate||(()=>{}))(p),K(!0)}function H(){return $(p).root}function oe(){return $(p).folderPath}function q(e){return!!e&&e!=="projects"}function ie(e){let t=H();if(!t){T("Open a root (/files, /temp, /raws) first");return}if(!q(t)){T("/projects is read-only");return}let o=(window.prompt("New folder name")||"").trim();if(!o)return;let s=he(e??oe()),l=X(t,s?s+"/"+o:o);fetch(c+"/directory/folders",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:l})}).then(d=>d.ok?d.json():d.json().then(x=>Promise.reject(new Error(x.error||"http "+d.status)))).then(d=>{I(d.path||(t===H()?p:"/"+t)),T("Created "+(d.path||o))}).catch(d=>T(d.message||"Couldn't create folder"))}function ae(e){let t=e.kind==="folder",o=(window.prompt(t?"Rename folder":"Rename file",e.name)||"").trim();!o||o===e.name||fetch(c+"/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(s=>s.ok?s.json():s.json().then(l=>Promise.reject(new Error(l.error||"http "+s.status)))).then(()=>{w.has(e.path)&&(w.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(w.values()))),K(!0),T("Renamed to "+o)}).catch(s=>T(s.message||"Couldn't rename"))}function ze(e,t){t?w.set(e.path,e):w.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(w.values())),De();let o=b.querySelector('[data-path="'+Qe(e.path)+'"]');o&&o.classList.toggle("is-selected",t)}function xe(){w.clear(),(n.onSelectionChange||(()=>{}))([]),C()}function pe(e,t,o){let s=i("button","rk-aichat-crumb"+(t?" is-current":""),e);return s.type="button",s.addEventListener("click",o),s}function Ye(){j.innerHTML="";let e=H(),t=oe();if(h||j.appendChild(pe("Files",p==="/",()=>I("/"))),!e)return;let o=(fe.find(l=>l.key===e)||{label:e}).label;h||j.appendChild(Ee()),j.appendChild(pe(o,!t,()=>I("/"+e)));let s="";if(t.split("/").filter(Boolean).forEach((l,d,x)=>{j.appendChild(Ee()),s=s?s+"/"+l:l;let S="/"+e+"/"+s;j.appendChild(pe(l,d===x.length-1,()=>I(S)))}),q(e)){let l=i("button","rk-dir-newfolder","+ Folder");l.type="button",l.title="New folder here (or right-click)",l.addEventListener("click",()=>ie()),j.appendChild(l)}}function Ee(){return i("span","rk-aichat-crumb-sep","/")}function De(){if(!v)return;let e=w.size;if(Y.hidden=e===0,e===0)return;Y.innerHTML="",Y.appendChild(i("span","rk-dir-selcount",e+" selected"));let t=()=>Array.from(w.values()),o=i("button","rk-dir-selbtn is-primary","Copy paths");o.type="button",o.addEventListener("click",()=>R(t().map(d=>d.path).join(`
|
|
2
|
+
`))),Y.appendChild(o);let s=[];y==="attach"&&s.push({label:"Attach",run:()=>{P(t()),xe()}}),s.push({label:"Copy paths",run:()=>R(t().map(d=>d.path).join(`
|
|
3
|
+
`))}),s.push({label:"Clear selection",run:xe});let l=i("button","rk-dir-selbtn is-ghost rk-dir-selmore","\u22EF");l.type="button",l.setAttribute("aria-label","More actions"),l.addEventListener("click",d=>{d.stopPropagation(),ge(l,s)}),Y.appendChild(l)}function Le(e){let t=i("input","rk-dir-check");return t.type="checkbox",t.checked=w.has(e.path),t.setAttribute("aria-label","Select "+e.name),t.addEventListener("click",o=>o.stopPropagation()),t.addEventListener("change",()=>ze(e,t.checked)),t}function Pe(e){let t=i("div","rk-aichat-frow rk-dir-row"+(w.has(e.path)?" is-selected":""));t.setAttribute("data-path",e.path),v&&t.appendChild(Le(e));let o=i("button","rk-aichat-fmainbtn");o.type="button",o.title="Copy path "+e.path,o.appendChild(He(e));let s=i("span","rk-aichat-fmain");s.appendChild(i("span","rk-aichat-fname",e.name));let l=e.meta&&typeof e.meta.description=="string"?e.meta.description:"";s.appendChild(i("span","rk-aichat-fmeta",l||"folder")),o.appendChild(s),o.addEventListener("click",()=>R(e.path)),t.appendChild(o);let d=i("button","rk-aichat-fadd rk-dir-open","Open \u203A");d.type="button",d.title="Open folder",d.addEventListener("click",S=>{S.stopPropagation(),I(e.path)}),t.appendChild(d);let x=[{label:"Open folder",run:()=>I(e.path)}];return q(e.root)&&(x.push({label:"New subfolder",run:()=>ie(e.folderPath)}),x.push({label:"Rename",run:()=>ae(e)})),x.push({label:"Copy path",run:()=>R(e.path)}),t.appendChild(Me(e,x)),t}function Te(e,t,o,s){let l=i("div","rk-aichat-frow rk-dir-row"+(w.has(e.path)?" is-selected":""));l.setAttribute("data-path",e.path),v&&l.appendChild(Le(e));let d=i("button","rk-aichat-fmainbtn");d.type="button";let x=m==="copyPath"?"Copy path ":m==="attach"?"Attach ":"Preview ";d.title=x+e.name,d.appendChild(He(e));let S=i("span","rk-aichat-fmain");S.appendChild(i("span","rk-aichat-fname",e.name));let ue=s?e.path:Xe(e.durationSec)||$e(e.sizeBytes)||e.contentType||"file";if(S.appendChild(i("span","rk-aichat-fmeta",ue)),d.appendChild(S),d.addEventListener("click",()=>{m==="attach"?P([e]):m==="preview"?N(t,o):R(e.path)}),l.appendChild(d),y==="attach"&&m==="preview"){let D=i("button","rk-aichat-fadd rk-dir-attach","+");D.type="button",D.title="Attach "+e.name,D.setAttribute("aria-label","Attach "+e.name),D.addEventListener("click",ee=>{ee.stopPropagation(),P([e])}),l.appendChild(D)}let O=[];return y==="attach"&&O.push({label:"Attach",run:()=>P([e])}),e.viewUrl&&O.push({label:"View",run:()=>window.open(e.viewUrl,"_blank","noopener")}),e.viewUrl&&O.push({label:"Preview",run:()=>N(t,o)}),(e.root==="files"||e.root==="temp")&&e.id&&O.push({label:"Rename",run:()=>ae(e)}),O.push({label:"Copy path",run:()=>R(e.path)}),l.appendChild(Me(e,O)),l}function Me(e,t){let o=i("button","rk-dir-kebab","\u22EF");return o.type="button",o.setAttribute("aria-label","More actions"),o.addEventListener("click",s=>{s.stopPropagation(),ge(o,t)}),o}function W(e,t,o){let s=i("div","rk-aichat-fstate");if(s.appendChild(i("div",void 0,e)),t){let l=i("a");l.href=t.href,l.textContent=t.label,s.appendChild(l)}if(o){let l=i("button",void 0,"Try again");l.type="button",l.addEventListener("click",()=>K(!0)),s.appendChild(l)}return s}function C(){if(!U){if(Ye(),De(),qe(),b.innerHTML="",Q){Ke();return}if(u==="loading"&&!M.length&&!g.length){b.appendChild(W("Loading your files\u2026"));return}if(u==="auth"){b.appendChild(W("Sign in to browse your files.",{href:"/login",label:"Sign in"}));return}if(u==="error"){b.appendChild(W("Couldn't reach your files.",void 0,!0));return}if(!g.length&&!M.length){b.appendChild(W(p==="/"?"No files yet.":"This folder is empty."));return}if(g.forEach(e=>b.appendChild(Pe(e))),M.forEach((e,t)=>b.appendChild(Te(e,M,t))),G!=null){let e=i("button","rk-aichat-loadmore",V?"Loading\u2026":"Load more");e.type="button",e.disabled=V,e.addEventListener("click",je),b.appendChild(e)}}}function Ke(){if(Z==="loading"&&!B.length){b.appendChild(W("Searching\u2026"));return}if(Z==="error"){b.appendChild(W("Search failed."));return}if(!B.length){b.appendChild(W("No matches."));return}let e=B.filter(t=>t.kind!=="folder");B.forEach((t,o)=>{t.kind==="folder"?b.appendChild(Pe(t)):b.appendChild(Te(t,e,e.indexOf(t),!0))})}let le=!1;function Se(){let e=H();return e==="files"?c+"/attachments/upload":e==="temp"?c+"/temporary-files/upload":null}function qe(){if(!E)return;let e=Se();if(k.hidden=!e||u==="auth",!k.hidden&&!le){let t=oe(),o=H()?(fe.find(s=>s.key===H())||{label:""}).label:"";te.textContent="Drop files into "+o+(t?" / "+t:"")}}function Re(e){let t=Se();if(!t||le||!e||!e.length)return;le=!0;let o=oe(),s=H(),l=Array.from(e),d=0,x=0,S=null;te.textContent="Uploading "+l.length+" file(s)\u2026";let ue=()=>{le=!1,x&&T(x+" of "+l.length+" failed");let D=s&&S!=null?X(s,S):null;D&&D!==p?I(D):K(!0)},O=D=>{if(D>=l.length){ue();return}let ee=new FormData;ee.append("file",l[D]),ee.append("folder_path",o),fetch(t,{method:"POST",credentials:"same-origin",body:ee}).then(_=>{if(!_.ok)throw new Error("http "+_.status);return _.json().catch(()=>null)}).then(_=>{d++;let Ae=_&&((_.file&&_.file.folderPath)??(_.attachment&&_.attachment.folderPath));typeof Ae=="string"&&S==null&&(S=Ae)}).catch(()=>{x++}).then(()=>O(D+1))};O(0)}function We(e){return g.concat(M,B).find(t=>t.path===e)}return b.addEventListener("contextmenu",e=>{let t=!!H(),o=e.target.closest(".rk-dir-row"),s={top:e.clientY,bottom:e.clientY,left:e.clientX,right:e.clientX},l=[],d=o?We(o.getAttribute("data-path")||""):void 0;d&&d.kind==="folder"?(l.push({label:"Open folder",run:()=>I(d.path)}),q(d.root)&&l.push({label:"New subfolder",run:()=>ie(d.folderPath)}),q(d.root)&&l.push({label:"Rename",run:()=>ae(d)}),l.push({label:"Copy path",run:()=>R(d.path)})):d&&(y==="attach"&&l.push({label:"Attach",run:()=>P([d])}),d.viewUrl&&l.push({label:"View",run:()=>window.open(d.viewUrl,"_blank","noopener")}),d.viewUrl&&l.push({label:"Preview",run:()=>N(M,M.indexOf(d))}),d.root!=="raws"&&q(d.root)&&d.id&&l.push({label:"Rename",run:()=>ae(d)}),l.push({label:"Copy path",run:()=>R(d.path)})),t&&q(H())&&l.push({label:"New folder here",run:()=>ie()}),l.length&&(e.preventDefault(),ge(s,l))}),z.addEventListener("input",Fe),k.addEventListener("click",e=>{(e.target===k||e.target===te)&&F.click()}),F.addEventListener("change",()=>{Re(F.files),F.value=""}),k.addEventListener("dragover",e=>{e.preventDefault(),k.classList.add("is-drag")}),k.addEventListener("dragleave",e=>{e.target===k&&k.classList.remove("is-drag")}),k.addEventListener("drop",e=>{e.preventDefault(),k.classList.remove("is-drag"),e.dataTransfer&&e.dataTransfer.files&&Re(e.dataTransfer.files)}),(n.onNavigate||(()=>{}))(p),K(!0),{refresh:()=>K(!0),navigate:I,getSelection:()=>Array.from(w.values()),getCurrentPath:()=>p,destroy:()=>{U=!0,J&&J(),r.innerHTML=""}}}function Qe(r){return window.CSS&&window.CSS.escape?window.CSS.escape(r):r.replace(/["\\]/g,"\\$&")}var Oe="rk-dirpick-style";function Ze(){if(document.getElementById(Oe))return;let r=document.createElement("style");r.id=Oe,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 et(r={}){Ze();let n=r.select==="folder"?"folder":"file",c=!1,a=null,h=i("div","rk-dirpick"),y=i("div","rk-dirpick-panel"),A=i("div","rk-dirpick-head");A.appendChild(i("span","rk-dirpick-title",r.title||(n==="folder"?"Choose a folder":"Choose a file")));let v=i("button","rk-dirpick-close");v.type="button",v.setAttribute("aria-label","Close"),v.innerHTML="×",A.appendChild(v),y.appendChild(A),r.hint&&y.appendChild(i("div","rk-dirpick-hint",r.hint));let E=i("div","rk-dirpick-mount");y.appendChild(E);let m=null,L=null;function f(p){c||(c=!0,R(),p?(r.onPick||(()=>{}))(p):(r.onCancel||(()=>{}))())}function P(p){let u=$(p);if(!u.root)return null;let g=u.folderPath||"",M=g?g.split("/").filter(Boolean).pop()||g:u.root;return{path:X(u.root,g),root:u.root,folderPath:g,name:M,kind:"folder"}}function N(p){if(!m||!L)return;let u=P(p);if(u){m.innerHTML="",m.appendChild(document.createTextNode("Save to "));let g=i("b",void 0,u.path);m.appendChild(g),L.disabled=!1}else m.textContent="Open a folder (Files, Temp, \u2026) to choose a destination.",L.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)),L=i("button","rk-dirpick-btn",r.confirmLabel||"Use this folder"),L.type="button",L.addEventListener("click",()=>{let g=a?P(a.getCurrentPath()):null;g&&f(g)}),p.appendChild(m),p.appendChild(u),p.appendChild(L),y.appendChild(p)}h.appendChild(y),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 v.addEventListener("click",()=>f(null)),h.addEventListener("click",p=>{p.target===h&&f(null)}),document.addEventListener("keydown",T,!0),a=ke(E,{roots:r.roots,initialPath:r.initialPath,apiBase:r.apiBase,mode:"standalone",showSearch:!0,showMultiSelect:!1,showUpload:r.allowUpload===!0,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)){be(r.rejectMessage||"That file can't be used here.");return}f(u)}}}),{close:()=>f(null)}}function tt(r){let n=r.dataset,c=(n.roots||"").split(",").map(a=>a.trim()).filter(Boolean);return{roots:c.length?c: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 _e(){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=ke(n,tt(n)))})}window.__vidfarmDirectory={mount:ke,pick:et};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",_e):_e();window.dispatchEvent(new CustomEvent("vidfarm:directory-ready"));export{ke as createDirectoryExplorer,et as openDirectoryPicker};
|