experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(build): separate derivedDataPath for simulator and device builds

Simulator builds use /tmp/peek-xcodebuild-sim, device builds use
/tmp/peek-xcodebuild-device. This allows both to run in parallel
without xcodebuild conflicts.

+19 -19
+1 -1
DEVELOPMENT.md
··· 503 503 504 504 **Gotchas:** 505 505 - Xcode scheme is `peek-save_iOS` — all xcodebuild commands use this 506 - - All xcodebuild outputs go to `/tmp/peek-xcodebuild` (derivedDataPath) 506 + - Simulator builds go to `/tmp/peek-xcodebuild-sim`, device builds to `/tmp/peek-xcodebuild-device` (separate derivedDataPaths so they can run in parallel) 507 507 - `tauri.conf.json` should NOT have `devUrl` or `beforeDevCommand` checked in — `dev-ios-sim.sh` patches these temporarily and restores on exit 508 508 - If Rust code changes during HMR, stop vite (Ctrl+C), restart `yarn mobile:ios:dev` 509 509 - `cargo tauri ios dev` is broken on Apple Silicon (passes `ARCHS=x86_64`) — use `yarn mobile:ios:dev` instead which bypasses it
+3 -3
backend/tauri-mobile/dev-ios-sim.sh
··· 61 61 62 62 # Build with xcodebuild 63 63 echo "[dev] Running xcodebuild..." 64 - rm -rf /tmp/peek-xcodebuild 64 + rm -rf /tmp/peek-xcodebuild-sim 65 65 cd "$SCRIPT_DIR/src-tauri/gen/apple" && xcodebuild \ 66 66 -scheme peek-save_iOS \ 67 67 -configuration Debug \ 68 68 -sdk iphonesimulator \ 69 - -derivedDataPath /tmp/peek-xcodebuild \ 69 + -derivedDataPath /tmp/peek-xcodebuild-sim \ 70 70 -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ 71 71 clean build 2>&1 | tail -5 72 72 ··· 91 91 92 92 # Install and launch 93 93 echo "[dev] Installing to simulator..." 94 - xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/debug-iphonesimulator/Peek Save.app' 94 + xcrun simctl install booted '/tmp/peek-xcodebuild-sim/Build/Products/debug-iphonesimulator/Peek Save.app' 95 95 xcrun simctl terminate booted com.dietrich.peek-mobile 2>/dev/null || true 96 96 xcrun simctl launch booted com.dietrich.peek-mobile 97 97 echo "[dev] App launched. HMR active — Ctrl+C to stop."
+3 -3
backend/tauri-mobile/package.json
··· 31 31 "sim:launch": "xcrun simctl terminate booted com.dietrich.peek-mobile 2>/dev/null; xcrun simctl launch booted com.dietrich.peek-mobile", 32 32 "sim:log": "xcrun simctl spawn booted log stream --predicate 'process == \"Peek Save\"' --level debug", 33 33 "sim:log:webview": "xcrun simctl spawn booted log stream --predicate 'process == \"Peek Save\" AND eventMessage CONTAINS \"webview\"' --style compact", 34 - "sim:install": "xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/debug-iphonesimulator/Peek Save.app'", 35 - "xcode:clean": "cd src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean", 36 - "xcode:build": "rm -rf /tmp/peek-xcodebuild && cd src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean build" 34 + "sim:install": "xcrun simctl install booted '/tmp/peek-xcodebuild-sim/Build/Products/debug-iphonesimulator/Peek Save.app'", 35 + "xcode:clean": "cd src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild-sim -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean", 36 + "xcode:build": "rm -rf /tmp/peek-xcodebuild-sim && cd src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild-sim -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean build" 37 37 }, 38 38 "dependencies": { 39 39 "@tauri-apps/api": "2.9.1",
+1 -1
backend/tauri-mobile/src-tauri/gen/apple/assets/assets/index-cOJDMxFD.js backend/tauri-mobile/src-tauri/gen/apple/assets/assets/index-CcqWsS36.js
··· 12 12 ${F}${mt} `,fl=r+ve+j;Y(fl),requestAnimationFrame(()=>{if(ct.current){const bl=W+ve.length;ct.current.selectionStart=bl,ct.current.selectionEnd=bl}})}};return z.useEffect(()=>{const U=r=>ie(r.clientY),J=r=>{r.touches.length===1&&ie(r.touches[0].clientY)},W=()=>b();return document.addEventListener("mousemove",U),document.addEventListener("mouseup",W),document.addEventListener("touchmove",J,{passive:!0}),document.addEventListener("touchend",W),()=>{document.removeEventListener("mousemove",U),document.removeEventListener("mouseup",W),document.removeEventListener("touchmove",J),document.removeEventListener("touchend",W)}},[Ut]),z.useEffect(()=>{if(!k)return;const U=setTimeout(()=>{if(ct.current){ct.current.focus();const J=ct.current.value.length;ct.current.selectionStart=J,ct.current.selectionEnd=J}},50);return()=>clearTimeout(U)},[]),s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"undo-redo-buttons",children:[s.jsx("button",{type:"button",onClick:le,disabled:Qt.current<=0,title:"Undo",children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("polyline",{points:"1 4 1 10 7 10"}),s.jsx("path",{d:"M3.51 15a9 9 0 1 0 2.13-9.36L1 10"})]})}),s.jsx("button",{type:"button",onClick:yt,disabled:Qt.current>=pt.current.length-1,title:"Redo",children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("polyline",{points:"23 4 23 10 17 10"}),s.jsx("path",{d:"M20.49 15a9 9 0 1 1-2.13-9.36L23 10"})]})})]}),s.jsxs("div",{className:"resizable-input-wrapper",ref:V,style:$!=null?{height:`${je}px`,minHeight:`${Ut}px`}:{minHeight:`${Ut}px`},children:[s.jsx("textarea",{ref:ct,className:"resizable-input-textarea",value:E,onChange:U=>{const J=U.target.value.replace(/^(\s*(?:[-*+]|\d+\.))\s{2,}/gm,"$1 ");Y(J),gt&&gt(J)},onFocus:()=>{requestAnimationFrame(()=>window.scrollTo(0,0))},onKeyDown:O,placeholder:B,autoCapitalize:H,autoCorrect:T,autoComplete:"off",spellCheck:T==="on"}),rt&&s.jsx(Kc,{show:E.length>0,onClear:()=>Y(""),className:"textarea-clear"}),s.jsx("div",{className:"drag-handle",onMouseDown:U=>{U.preventDefault(),Kt(U.clientY)},onTouchStart:U=>{Kt(U.touches[0].clientY)},children:s.jsx("div",{className:"drag-handle-bar"})})]})]})},pm=()=>{const[E,Y]=z.useState(0),B=z.useRef(0);return z.useEffect(()=>{const v=window.visualViewport;if(!v)return;const q=()=>{const k=Math.max(0,window.innerHeight-v.height);k===0?(B.current=0,Y(0)):(B.current=Math.max(B.current,k),Y(B.current))};return v.addEventListener("resize",q),v.addEventListener("scroll",q),()=>{v.removeEventListener("resize",q),v.removeEventListener("scroll",q)}},[]),E};function Sm(){z.useEffect(()=>{const c=Math.floor(Math.random()*360);document.documentElement.style.setProperty("--dev-bg-light",`hsl(${c}, 80%, 85%)`),document.documentElement.style.setProperty("--dev-bg-dark",`hsl(${c}, 15%, 12%)`)},[]);const[E,Y]=z.useState("all"),[B,v]=z.useState([]),[q,k]=z.useState([]),[rt,gt]=z.useState([]),[H,T]=z.useState([]),[$,X]=z.useState([]),[V,ct]=z.useState(null),[wt,Ht]=z.useState(""),[ee,pt]=z.useState(new Set),[Qt,At]=z.useState([]),[Xt,le]=z.useState(""),[yt,lt]=z.useState(null),[It,be]=z.useState(""),[me,ue]=z.useState(new Set),[Ut,je]=z.useState(""),[Kt,ie]=z.useState(null),[b,O]=z.useState(new Set),[U,J]=z.useState(""),[W,r]=z.useState(null),[j,M]=z.useState(new Set),[R,Z]=z.useState(""),[F,nt]=z.useState(""),[zt,mt]=z.useState(new Set),[ae,ve]=z.useState(!1),[fl,bl]=z.useState(""),ol=200,[xl,fn]=z.useState(null),[fu,on]=z.useState(!1),[ou,Oa]=z.useState(!1),[rn,ru]=z.useState(!1),[Ma,ge]=z.useState(null),[Tl,Ua]=z.useState(new Set),[qe,El]=z.useState(""),gi=z.useRef(null),Pl=z.useRef(null),dn=z.useRef(null),[hn,jl]=z.useState(null),[Lt,Ye]=z.useState(()=>localStorage.getItem("searchText")||""),[Bt,du]=z.useState(()=>{const c=localStorage.getItem("selectedFilterTags");return c?new Set(JSON.parse(c)):new Set}),[Ra,Jc]=z.useState(()=>localStorage.getItem("sortOrder")||"newest"),[_l,mn]=z.useState(()=>{const c=localStorage.getItem("filterTagsHeight");return c?parseInt(c,10):116}),wa=z.useRef(null),Ge=z.useRef(!1),Al=z.useRef(!1),ta=z.useRef(0),yi=z.useRef(0),[vn,gn]=z.useState(null),zl=z.useRef(null),qt=(c,h="success")=>{zl.current&&clearTimeout(zl.current),gn({message:c,type:h}),zl.current=setTimeout(()=>gn(null),3e3)},[yn,Nl]=z.useState(null),[Pt,Oe]=z.useState(null),[pn,hu]=z.useState(!1),[pi,el]=z.useState(!1),[Nt,ce]=z.useState(""),[ll,Sn]=z.useState(""),[kc,Si]=z.useState(""),[Ha,ea]=z.useState(""),[mu,Cl]=z.useState(!1),[rl,La]=z.useState(!1),[_e,Ct]=z.useState(!1),[Ba,tt]=z.useState(null),[dl,Dl]=z.useState(null),[bn,bi]=z.useState(null),[Dt,xn]=z.useState(null),[Ol,Ml]=z.useState(""),[Qe,ye]=z.useState(!1),[la,xi]=z.useState("archive"),[aa,vu]=z.useState("archive"),Xe=pm(),Ul=z.useRef(null),Jt=z.useRef(null),[na,Rl]=z.useState("idle"),Tn=80,ua=300,gu=c=>{Ge.current=!0,Al.current=!0,ta.current=c,yi.current=wa.current?.offsetHeight??_l,document.body.style.userSelect="none",document.body.style.cursor="ns-resize"};z.useEffect(()=>{const c=D=>{if(!Ge.current)return;const St=D-ta.current,at=Math.max(71,yi.current+St);mn(at)},h=D=>c(D.clientY),N=D=>{D.touches.length===1&&c(D.touches[0].clientY)},C=()=>{Ge.current&&(Ge.current=!1,Al.current=!1,document.body.style.userSelect="",document.body.style.cursor="",localStorage.setItem("filterTagsHeight",String(Math.round(_l))))};return document.addEventListener("mousemove",h),document.addEventListener("mouseup",C),document.addEventListener("touchmove",N,{passive:!0}),document.addEventListener("touchend",C),()=>{document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",C),document.removeEventListener("touchmove",N),document.removeEventListener("touchend",C)}},[_l]),z.useEffect(()=>{localStorage.setItem("searchText",Lt)},[Lt]),z.useEffect(()=>{localStorage.setItem("selectedFilterTags",JSON.stringify(Array.from(Bt)))},[Bt]),z.useEffect(()=>{localStorage.setItem("sortOrder",Ra)},[Ra]),z.useEffect(()=>{},[]),z.useEffect(()=>{const c=async()=>{try{const D=await Q("is_dark_mode");hu(D)}catch{const St=window.matchMedia("(prefers-color-scheme: dark)");hu(St.matches)}};c();const h=window.matchMedia("(prefers-color-scheme: dark)"),N=()=>c();h.addEventListener("change",N);const C=()=>{document.visibilityState==="visible"&&c()};return document.addEventListener("visibilitychange",C),()=>{h.removeEventListener("change",N),document.removeEventListener("visibilitychange",C)}},[]),z.useEffect(()=>{document.body.classList.toggle("dark",pn)},[pn]),z.useEffect(()=>{const c=()=>{Ze(),Ve(),Me(),se(),fe()},h=async()=>{try{await Q("auto_sync_if_needed")}catch(C){console.log("Auto-sync check:",C)}};c(),Ti(),ia(),Wc(),_i(),En(),jn(),ji(),h();const N=()=>{document.visibilityState==="visible"&&(c(),h())};return document.addEventListener("visibilitychange",N),()=>{document.removeEventListener("visibilitychange",N)}},[]),z.useEffect(()=>{let c;return(async()=>{c=await ym("webview:navigated",async N=>{const{itemId:C}=N.payload;try{await Q("record_visit",{itemId:C,source:"webview",windowType:"embedded"})}catch(D){console.error("Failed to record webview visit:",D)}})})(),()=>{c&&c()}},[]),z.useEffect(()=>{const c=()=>{document.visibilityState==="visible"&&ae&&!F.trim()&&zt.size===0&&ve(!1)};return document.addEventListener("visibilitychange",c),()=>{document.removeEventListener("visibilitychange",c)}},[ae,F,zt]);const Ti=async()=>{try{const c=await Q("get_webhook_url");c&&(ce(c),Sn(c))}catch(c){console.error("Failed to load webhook URL:",c)}},ia=async()=>{try{const c=await Q("get_webhook_api_key");c&&(Si(c),ea(c))}catch(c){console.error("Failed to load webhook API key:",c)}},Wc=async()=>{try{const c=await Q("get_auto_sync");Cl(c)}catch(c){console.error("Failed to load auto-sync setting:",c)}},Ei=async c=>{try{await Q("set_auto_sync",{enabled:c}),Cl(c)}catch(h){console.error("Failed to set auto-sync:",h)}},ji=async()=>{try{const c=await Q("get_archive_tag");xi(c),vu(c)}catch(c){console.error("Failed to load archive tag:",c)}},yu=async()=>{try{await Q("set_archive_tag",{tag:aa}),xi(aa)}catch(c){console.error("Failed to save archive tag:",c)}},_i=async()=>{try{const c=await Q("get_last_sync");Dl(c)}catch(c){console.error("Failed to load last sync:",c)}},En=async()=>{try{const c=await Q("get_sync_status");bi(c),c.last_sync_time&&Dl(c.last_sync_time)}catch(c){console.error("Failed to load sync status:",c)}},jn=async()=>{try{const c=await Q("get_profile_info");xn(c),Ml("")}catch(c){console.error("Failed to load profile info:",c)}},al=async c=>{console.log(`[Profile] setProfile called with: ${c}`);try{console.log("[Profile] Invoking set_profile command...");const h=await Q("set_profile",{profileId:c});console.log("[Profile] set_profile returned:",h),xn(h),Ml(""),ye(!0)}catch(h){console.error("[Profile] Failed to set profile:",h),tt(`Failed: ${h}`),setTimeout(()=>tt(null),3e3)}},_n=async()=>{try{await Q("quit_app")}catch(c){console.error("Failed to quit:",c)}},pu=async()=>{try{await Q("set_webhook_url",{url:ll}),await Q("set_webhook_api_key",{key:Ha}),ce(ll),Si(Ha),tt("Settings saved"),setTimeout(()=>tt(null),2e3)}catch(c){console.error("Failed to save webhook settings:",c),tt("Failed to save settings"),setTimeout(()=>tt(null),3e3)}},wl=async()=>{if(!Nt){qt("Please configure server URL first","error");return}Ct(!0),qt("Syncing...");try{const c=await Q("sync_all"),h=`Synced: ${c.pulled} pulled, ${c.pushed} pushed${c.conflicts>0?`, ${c.conflicts} conflicts`:""}`;qt(h),tt(h),await _i(),await En(),Ze(),Ve(),Me(),se(),fe(),setTimeout(()=>tt(null),4e3)}catch(c){console.error("Failed to sync:",c);const h=`Sync failed: ${c}`;qt(h,"error"),tt(h),setTimeout(()=>tt(null),5e3)}finally{Ct(!1)}},ca=async()=>{if(!Nt){tt("Please save a server URL first"),setTimeout(()=>tt(null),3e3);return}Ct(!0),tt(null);try{const c=await Q("pull_from_server"),h=`Pulled ${c.pulled} items${c.conflicts>0?`, ${c.conflicts} conflicts`:""}`;tt(h),await En(),Ze(),Ve(),Me(),se(),fe(),setTimeout(()=>tt(null),4e3)}catch(c){console.error("Failed to pull:",c),tt(`Pull failed: ${c}`),setTimeout(()=>tt(null),5e3)}finally{Ct(!1)}},Ai=async()=>{if(!Nt){tt("Please save a server URL first"),setTimeout(()=>tt(null),3e3);return}Ct(!0),tt(null);try{const c=await Q("push_to_server");tt(`Pushed ${c.pushed} items`),await En(),setTimeout(()=>tt(null),4e3)}catch(c){console.error("Failed to push:",c),tt(`Push failed: ${c}`),setTimeout(()=>tt(null),5e3)}finally{Ct(!1)}},Ze=async()=>{try{const c=await Q("get_saved_urls");v(c)}catch(c){console.error("Failed to load saved URLs:",c)}},Ve=async()=>{try{const c=await Q("get_saved_texts");k(c)}catch(c){console.error("Failed to load saved texts:",c)}},Me=async()=>{try{const c=await Q("get_saved_tagsets");gt(c)}catch(c){console.error("Failed to load saved tagsets:",c)}},se=async()=>{try{const c=await Q("get_saved_images");T(c)}catch(c){console.error("Failed to load saved images:",c)}},fe=async()=>{try{const c=await Q("get_tags_by_frecency");X(c)}catch(c){console.error("Failed to load tags:",c)}},qa=()=>Pt?wt!==Pt.url||JSON.stringify(Array.from(ee).sort())!==JSON.stringify(Pt.tags):!1,hl=()=>Pt?It!==Pt.content||JSON.stringify(Array.from(me).sort())!==JSON.stringify(Pt.tags):!1,Su=()=>Pt?JSON.stringify(Array.from(b).sort())!==JSON.stringify(Pt.tags):!1,An=()=>Pt?JSON.stringify(Array.from(j).sort())!==JSON.stringify(Pt.tags):!1,zi=async c=>{Pl.current?.focus(),ct(c.id),Ht(c.url),pt(new Set(c.tags)),le(""),Oe({url:c.url,tags:[...c.tags].sort()});try{const h=await Q("get_tags_by_frecency_for_url",{url:c.url});At(h)}catch(h){console.error("Failed to load domain-boosted tags:",h),At($)}},Hl=()=>{ct(null),Ht(""),pt(new Set),At([]),le(""),Oe(null)},Ya=()=>{qa()?Nl({type:"page"}):Hl()},Ni=async c=>{console.log("[Frontend] deleteUrl called for id:",c);try{await Q("delete_url",{id:c}),console.log("[Frontend] delete_url invoke succeeded"),await Ze(),Hl()}catch(h){console.error("[Frontend] Failed to delete URL:",h)}},pe=c=>{const h=new Set(ee);h.has(c)?h.delete(c):h.add(c),pt(h)},Ll=()=>{const c=new Set(ee),h=Xt.split(",");let N=!1;for(const C of h){const D=C.trim().toLowerCase();D&&!c.has(D)&&(c.add(D),N=!0)}N&&pt(c),le("")},zn=async()=>{if(!V)return;const c=new Set(ee);if(Xt.trim()){for(const h of Xt.split(",").map(N=>N.trim().toLowerCase()).filter(N=>N.length>0))c.add(h);le("")}try{await Q("update_url",{id:V,url:wt,tags:Array.from(c)}),await Ze(),await fe(),Hl(),qt("Page saved")}catch(h){console.error("[Frontend] Failed to update URL:",h),qt("Failed to save page","error")}},Ga=c=>{console.log("[toggleAddInputTag] toggling tag:",c);const h=new Set(zt);h.has(c)?h.delete(c):h.add(c),console.log("[toggleAddInputTag] new tags:",Array.from(h)),mt(h)},bu=()=>{nt(""),mt(new Set),ve(!1),bl("")},xu=()=>{const c=new Set(zt),h=fl.split(",");for(const N of h){const C=N.trim().toLowerCase();C&&c.add(C)}mt(c),bl("")},Tu=()=>{gi.current?.click()},Qa=c=>{const h=c.target.files?.[0];if(!h)return;const N=new FileReader;N.onload=C=>{const D=C.target?.result;ge(D),Ua(new Set),El("")},N.readAsDataURL(h),c.target.value=""},Xa=c=>{const h=new Set(Tl);h.has(c)?h.delete(c):h.add(c),Ua(h)},Eu=()=>{const c=new Set(Tl),h=qe.split(",");for(const N of h){const C=N.trim().toLowerCase();C&&c.add(C)}Ua(c),El("")},ju=()=>{ge(null),Ua(new Set),El("")},Fc=async()=>{if(!Ma)return;const c=new Set(Tl);if(qe.trim()){const h=qe.split(",");for(const N of h){const C=N.trim().toLowerCase();C&&c.add(C)}}try{const h=Ma.split(",")[1],N=Ma.split(";")[0].split(":")[1];await Q("save_captured_image",{imageData:h,mimeType:N,tags:Array.from(c)}),ju(),await se(),await fe()}catch(h){console.error("Failed to save captured image:",h)}},$c=async()=>{const c=F.trim(),h=new Set(zt);if(console.log("[saveAddInput] addInputTags:",Array.from(zt)),fl.trim()){const D=fl.split(",");for(const St of D){const at=St.trim().toLowerCase();at&&h.add(at)}}const N=Array.from(h);if(console.log("[saveAddInput] final tags to save:",N),c.startsWith("http://")||c.startsWith("https://"))try{await Q("save_url",{url:c,tags:N}),bu(),await Ze(),await fe(),qt("Page saved")}catch(D){console.error("Failed to save URL:",D),qt("Failed to save page","error")}else if(c)try{console.log("[saveAddInput] Saving text with tags:",{content:c,tags:N}),await Q("save_text",{content:c,tags:N}),bu(),await Ve(),await fe(),qt("Note saved")}catch(D){console.error("Failed to save text:",D),qt("Failed to save note","error")}else if(N.length>0)try{await Q("save_tagset",{tags:N}),bu(),await Me(),await fe(),qt("Tags saved")}catch(D){console.error("Failed to save tagset:",D),qt("Failed to save tags","error")}},_u=()=>{const c=F.trim();return c.startsWith("http://")||c.startsWith("https://")?"url":c?"text":zt.size>0?"tagset":null},Ic=c=>{Pl.current?.focus(),lt(c.id),be(c.content);const h=c.tags.length>0?c.tags:Ui(c.content);ue(new Set(h)),je(""),Oe({content:c.content,tags:[...h].sort()})},Nn=()=>{lt(null),be(""),ue(new Set),je(""),Oe(null)},Ci=()=>{hl()?Nl({type:"text"}):Nn()},Pc=c=>{const h=new Set(me);h.has(c)?h.delete(c):h.add(c),ue(h)},ts=()=>{const c=Ut.trim().toLowerCase();c&&(ue(new Set(me).add(c)),je(""))},ml=z.useRef(null),es=z.useCallback(c=>{!yt||!Pt||(ml.current&&clearTimeout(ml.current),c.trim()!==Pt.content&&(ml.current=setTimeout(async()=>{try{await Q("update_text",{id:yt,content:c.trim(),tags:Array.from(me)}),Oe(h=>h?{...h,content:c.trim()}:null),await Ve()}catch(h){console.error("Auto-save failed:",h)}},500)))},[yt,Pt,me]);z.useEffect(()=>()=>{ml.current&&clearTimeout(ml.current)},[yt]);const ls=async()=>{if(!yt)return;ml.current&&clearTimeout(ml.current);const c=new Set(me);if(Ut.trim())for(const h of Ut.split(",").map(N=>N.trim().toLowerCase()).filter(N=>N.length>0))c.add(h);try{await Q("update_text",{id:yt,content:It.trim(),tags:Array.from(c)}),await Ve(),await fe(),Nn(),qt("Note saved")}catch(h){console.error("Failed to update text:",h),qt("Failed to save note","error")}},as=async c=>{try{await Q("delete_url",{id:c}),await Ve(),Nn()}catch(h){console.error("Failed to delete text:",h)}},ns=c=>{Pl.current?.focus(),ie(c.id),O(new Set(c.tags)),J(""),Oe({tags:[...c.tags].sort()})},sa=()=>{ie(null),O(new Set),J(""),Oe(null)},Di=()=>{Su()?Nl({type:"tagset"}):sa()},us=c=>{const h=new Set(b);h.has(c)?h.delete(c):h.add(c),O(h)},is=()=>{const c=new Set(b),h=U.split(",");for(const N of h){const C=N.trim().toLowerCase();C&&c.add(C)}O(c),J("")},Oi=async()=>{if(!Kt)return;const c=new Set(b);if(U.trim())for(const h of U.split(",").map(N=>N.trim().toLowerCase()).filter(N=>N.length>0))c.add(h);if(c.size===0){qt("At least one tag is required","error");return}try{await Q("update_tagset",{id:Kt,tags:Array.from(c)}),await Me(),await fe(),sa(),qt("Tags saved")}catch(h){console.error("Failed to update tagset:",h),qt("Failed to save tags","error")}},cs=async c=>{try{await Q("delete_url",{id:c}),await Me(),sa()}catch(h){console.error("Failed to delete tagset:",h)}},ss=c=>{Pl.current?.focus(),r(c.id),M(new Set(c.tags)),Z(""),Oe({tags:[...c.tags].sort()})},Cn=()=>{r(null),M(new Set),Z(""),Oe(null)},Mi=()=>{An()?Nl({type:"image"}):Cn()},fs=c=>{const h=new Set(j);h.has(c)?h.delete(c):h.add(c),M(h)},os=()=>{const c=new Set(j),h=R.split(",");for(const N of h){const C=N.trim().toLowerCase();C&&c.add(C)}M(c),Z("")},rs=async()=>{if(!W)return;const c=new Set(j);if(R.trim()){const h=R.split(",");for(const N of h){const C=N.trim().toLowerCase();C&&c.add(C)}}try{await Q("update_image_tags",{id:W,tags:Array.from(c)}),await se(),await fe(),Cn(),qt("Image saved")}catch(h){console.error("Failed to update image:",h),qt("Failed to save image","error")}},Ui=c=>{const h=c.match(/#(\w+)/g);return h?h.map(N=>N.slice(1).toLowerCase()):[]},Dn=c=>{Y(E===c?"all":c)},On=()=>{dn.current?.scrollTo({top:0,behavior:"smooth"})},Za=c=>{if(V||yt||Kt||W||ae||_e||Al.current||document.body.dataset.resizing)return;const N=dn.current;N&&N.scrollTop<=0&&(Ul.current=c.touches[0].clientY,Jt.current=null,Rl("idle"))},Ri=c=>{if(Ul.current===null)return;if(Al.current||document.body.dataset.resizing){Ul.current=null,Jt.current=null,Rl("idle");return}c.touches[0].clientY-Ul.current>Tn?(c.preventDefault(),Jt.current===null?(Jt.current=Date.now(),Rl("pulling")):Date.now()-Jt.current>=ua&&Rl("ready")):(Jt.current=null,Rl("idle"))},wi=c=>{if(Ul.current===null)return;const h=c.changedTouches[0].clientY-Ul.current,N=na==="ready";Ul.current=null,Jt.current=null,Rl("idle"),h>Tn&&N&&wl()};z.useEffect(()=>{const c=dn.current;if(c)return c.addEventListener("touchmove",Ri,{passive:!1}),()=>{c.removeEventListener("touchmove",Ri)}},[V,yt,Kt,W,ae,_e]);const Hi=()=>{Y("all"),Ye(""),du(new Set),On()},Li=c=>{const h=new Set(Bt);h.has(c)?h.delete(c):h.add(c),du(h)},Au=()=>{if(!Lt.trim())return $;const c=Lt.toLowerCase();return $.filter(h=>h.name.toLowerCase().includes(c))},Bi=()=>{const c=[],h=D=>E==="all"||E===D;h("page")&&B.forEach(D=>{c.push({id:D.id,type:"page",url:D.url,tags:D.tags,saved_at:D.saved_at,metadata:D.metadata})}),h("text")&&q.forEach(D=>{c.push({id:D.id,type:"text",content:D.content,tags:D.tags,saved_at:D.saved_at,metadata:D.metadata})}),h("tagset")&&rt.forEach(D=>{c.push({id:D.id,type:"tagset",tags:D.tags,saved_at:D.saved_at,metadata:D.metadata})}),h("image")&&H.forEach(D=>{c.push({id:D.id,type:"image",tags:D.tags,saved_at:D.saved_at,metadata:D.metadata,thumbnail:D.thumbnail,mime_type:D.mime_type,width:D.width,height:D.height})});const N=Lt.toLowerCase();return c.filter(D=>{const St=!Lt.trim()||D.tags.some(Ke=>Ke.toLowerCase().includes(N))||D.url?.toLowerCase().includes(N)||D.content?.toLowerCase().includes(N)||D.metadata?.title?.toLowerCase().includes(N),at=Bt.size===0||Array.from(Bt).every(Ke=>D.tags.includes(Ke)),Te=la&&D.tags.includes(la),ul=la&&Bt.has(la);return Te&&!ul?!1:St&&at}).sort((D,St)=>{const at=new Date(St.saved_at).getTime()-new Date(D.saved_at).getTime();return Ra==="oldest"?-at:at})},vl=V||yt||Kt||W;z.useEffect(()=>(vl||ae?document.body.classList.add("editor-open"):document.body.classList.remove("editor-open"),()=>{document.body.classList.remove("editor-open")}),[vl,ae]);const ds=()=>{if(!vl)return null;if(V)return B.find(h=>h.id===V)?s.jsxs(hi,{onDismiss:Ya,keyboardHeight:Xe,className:"text-editor-overlay",children:[s.jsxs("div",{className:"input-with-clear editor-url-wrapper",children:[s.jsx("input",{type:"url",className:"editor-url-input",value:wt,onChange:h=>Ht(h.target.value),onFocus:()=>{requestAnimationFrame(()=>window.scrollTo(0,0))},placeholder:"URL",autoCapitalize:"none",autoCorrect:"off"}),s.jsx(Kc,{show:wt.length>0,onClear:()=>Ht("")})]}),s.jsx(mi,{selectedTags:ee,availableTags:Qt,tagInput:Xt,onTagInputChange:le,onToggleTag:pe,onAddTag:Ll}),s.jsx(vi,{onSave:zn,onCancel:Ya,onDelete:()=>nl(V,"page")})]}):null;if(yt)return s.jsxs(hi,{onDismiss:Ci,keyboardHeight:Xe,className:"text-editor-overlay",children:[s.jsx(wh,{value:It,onChange:be,placeholder:"Note text...",keyboardHeight:Xe,autoFocus:!0,showClearButton:!1,onAutoSave:es}),s.jsx(mi,{selectedTags:me,availableTags:$,tagInput:Ut,onTagInputChange:je,onToggleTag:Pc,onAddTag:ts}),s.jsx(vi,{onSave:ls,onCancel:Ci,onDelete:()=>nl(yt,"text"),saveLabel:"Done"})]});if(Kt)return s.jsxs(hi,{onDismiss:Di,keyboardHeight:Xe,className:"text-editor-overlay",children:[s.jsx(mi,{selectedTags:b,availableTags:$,tagInput:U,onTagInputChange:J,onToggleTag:us,onAddTag:is}),s.jsx(vi,{onSave:Oi,onCancel:Di,onDelete:()=>nl(Kt,"tagset")})]});if(W){const c=H.find(C=>C.id===W);if(!c)return null;const N=c.metadata?.title;return s.jsxs(hi,{onDismiss:Mi,keyboardHeight:Xe,className:"text-editor-overlay",children:[s.jsxs("div",{className:"editor-image-preview",children:[c.thumbnail?s.jsx("img",{src:`data:image/jpeg;base64,${c.thumbnail}`,alt:N||"Preview",className:"edit-modal-image"}):s.jsx("div",{className:"image-placeholder",children:s.jsxs("svg",{width:"48",height:"48",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),s.jsx("polyline",{points:"21 15 16 10 5 21"})]})}),N&&s.jsx("div",{className:"edit-image-title",children:N})]}),s.jsx(mi,{selectedTags:j,availableTags:$,tagInput:R,onTagInputChange:Z,onToggleTag:fs,onAddTag:os}),s.jsx(vi,{onSave:rs,onCancel:Mi,onDelete:()=>nl(W,"image")})]})}return null},hs=c=>{switch(c.type){case"page":return Va({id:c.id,url:c.url,tags:c.tags,saved_at:c.saved_at,metadata:c.metadata});case"text":return Ka({id:c.id,content:c.content,tags:c.tags,saved_at:c.saved_at,metadata:c.metadata});case"tagset":return vs({id:c.id,tags:c.tags,saved_at:c.saved_at,metadata:c.metadata});case"image":return xe({id:c.id,tags:c.tags,saved_at:c.saved_at,metadata:c.metadata,thumbnail:c.thumbnail,mime_type:c.mime_type||"image/jpeg",width:c.width,height:c.height});default:return null}},ms=async(c,h)=>{try{let N=0;const D=document.getElementById(`card-${h}`)?.querySelector(".webview-inline");D&&(N=D.getBoundingClientRect().top),console.log("[App] Creating inline webview at topOffset:",N,"for:",c),await Q("open_inline_webview",{url:c,topOffset:N}),Oa(!0)}catch(N){console.error("[App] Failed to create inline webview:",N),ru(!0)}},qi=async()=>{try{await Q("close_inline_webview")}catch(c){console.error("[App] Failed to close inline webview:",c)}},zu=c=>s.jsxs("div",{className:`webview-inline ${fu?"webview-expanded":""}`,children:[rn?s.jsxs("div",{className:"webview-error",children:[s.jsx("p",{children:"This site can't be displayed inline."}),s.jsx("button",{onClick:h=>{h.stopPropagation(),Vc(c)},children:"Open in Safari"})]}):null,!ou&&!rn&&s.jsx("div",{className:"webview-loading",children:"Loading..."})]}),Va=c=>{const h=c.metadata?.title,N=xl?.itemId===c.id;return s.jsxs("div",{id:`card-${c.id}`,className:`saved-item-card ${N?"card-webview-expanded":""}`,onClick:()=>!N&&zi(c),children:[s.jsxs("div",{className:"card-header",children:[N&&s.jsx("button",{className:`card-action-btn webview-back-btn ${fu?"visible":""}`,onClick:C=>{C.stopPropagation(),Hn()},title:"Back",children:s.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",children:s.jsx("path",{d:"M15 18l-6-6 6-6"})})}),s.jsx("div",{className:"card-type-icon",children:s.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("circle",{cx:"12",cy:"12",r:"10"}),s.jsx("line",{x1:"2",y1:"12",x2:"22",y2:"12"}),s.jsx("path",{d:"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"})]})}),s.jsx("span",{className:"card-title",children:h||c.url}),s.jsxs("div",{className:"card-actions",children:[s.jsx("button",{className:"card-action-btn",onClick:C=>N?(C.stopPropagation(),Vc(c.url)):Du(c.url,c.id,C),title:"Open in Safari",children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"}),s.jsx("polyline",{points:"15 3 21 3 21 9"}),s.jsx("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})}),s.jsx("button",{className:"card-action-btn",onClick:C=>N?(C.stopPropagation(),Hn()):Gi(c.url,c.id,C),title:N?"Close webview":"Open in app",children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("line",{x1:"3",y1:"9",x2:"21",y2:"9"})]})}),s.jsx("button",{className:"card-delete-btn",onClick:C=>{C.stopPropagation(),nl(c.id,"page")},children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("polyline",{points:"3 6 5 6 21 6"}),s.jsx("path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"})]})})]})]}),N&&zu(xl.url),s.jsxs("div",{className:"card-footer",children:[(c.tags.includes("todo")||c.tags.includes("done"))&&s.jsx("button",{className:`todo-checkbox ${c.tags.includes("done")?"checked":""}`,onClick:C=>Rn(C,c.id,"page",c.tags),children:c.tags.includes("done")?s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("polyline",{points:"9 11 12 14 22 4"})]}):s.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"})})}),s.jsxs("div",{className:"card-tags",children:[c.tags.map(C=>s.jsx("span",{className:"card-tag",children:C},C)),s.jsx("span",{className:"card-date",children:new Date(c.saved_at).toLocaleDateString()})]})]})]},c.id)},Ka=c=>{const h=c.tags.length>0?c.tags:Ui(c.content),C=c.content.replace(/#\w+/g,"").trim().split(` 13 13 `)[0].slice(0,100)||c.content.slice(0,100),D=c.content.match(/https?:\/\/[^\s<>"{}|\\^`[\]]+/),St=xl?.itemId===c.id;return s.jsxs("div",{id:`card-${c.id}`,className:`saved-item-card ${St?"card-webview-expanded":""}`,onClick:()=>!St&&Ic(c),children:[s.jsxs("div",{className:"card-header",children:[St&&s.jsx("button",{className:`card-action-btn webview-back-btn ${fu?"visible":""}`,onClick:at=>{at.stopPropagation(),Hn()},title:"Back",children:s.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",children:s.jsx("path",{d:"M15 18l-6-6 6-6"})})}),s.jsx("div",{className:"card-type-icon",children:s.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"}),s.jsx("polyline",{points:"14 2 14 8 20 8"}),s.jsx("line",{x1:"16",y1:"13",x2:"8",y2:"13"}),s.jsx("line",{x1:"16",y1:"17",x2:"8",y2:"17"})]})}),s.jsx("div",{className:"card-title",children:C}),s.jsxs("div",{className:"card-actions",children:[D&&s.jsx("button",{className:"card-action-btn",onClick:at=>St?(at.stopPropagation(),Vc(D[0])):Du(D[0],c.id,at),title:"Open in Safari",children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"}),s.jsx("polyline",{points:"15 3 21 3 21 9"}),s.jsx("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})}),D&&s.jsx("button",{className:"card-action-btn",onClick:at=>St?(at.stopPropagation(),Hn()):Gi(D[0],c.id,at),title:St?"Close webview":"Open in app",children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("line",{x1:"3",y1:"9",x2:"21",y2:"9"})]})}),s.jsx("button",{className:"card-delete-btn",onClick:at=>{at.stopPropagation(),nl(c.id,"text")},children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("polyline",{points:"3 6 5 6 21 6"}),s.jsx("path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"})]})})]})]}),St&&zu(xl.url),s.jsxs("div",{className:"card-footer",children:[(h.includes("todo")||h.includes("done"))&&s.jsx("button",{className:`todo-checkbox ${h.includes("done")?"checked":""}`,onClick:at=>Rn(at,c.id,"text",h),children:h.includes("done")?s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("polyline",{points:"9 11 12 14 22 4"})]}):s.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"})})}),s.jsxs("div",{className:"card-tags",children:[h.map(at=>s.jsx("span",{className:"card-tag",children:at},at)),s.jsx("span",{className:"card-date",children:new Date(c.saved_at).toLocaleDateString()})]})]})]},c.id)},vs=c=>s.jsxs("div",{className:"saved-item-card",onClick:()=>ns(c),children:[s.jsxs("div",{className:"card-header",children:[s.jsx("div",{className:"card-type-icon",children:s.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"}),s.jsx("line",{x1:"7",y1:"7",x2:"7.01",y2:"7"})]})}),s.jsx("div",{className:"card-tags card-title-tags",children:c.tags.map(h=>s.jsx("span",{className:"card-tag",children:h},h))}),s.jsx("button",{className:"card-delete-btn",onClick:h=>{h.stopPropagation(),nl(c.id,"tagset")},children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("polyline",{points:"3 6 5 6 21 6"}),s.jsx("path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"})]})})]}),s.jsx("div",{className:"card-footer",children:s.jsx("div",{className:"card-tags",children:s.jsx("span",{className:"card-date",children:new Date(c.saved_at).toLocaleDateString()})})})]},c.id),Mn=async c=>{try{await Q("delete_url",{id:c}),await se(),Cn()}catch(h){console.error("Failed to delete image:",h)}},nl=(c,h)=>{jl({id:c,type:h})},Nu=()=>{jl(null)},Cu=async()=>{if(!hn)return;const{id:c,type:h}=hn;jl(null);const N={page:"Page",text:"Note",tagset:"Tags",image:"Image"};try{switch(h){case"page":await Ni(c);break;case"text":await as(c);break;case"tagset":await cs(c);break;case"image":await Mn(c);break}qt(`${N[h]} deleted`)}catch(C){console.error("Failed to delete:",C),qt("Failed to delete","error")}},Un=()=>{Nl(null)},Yi=async()=>{if(!yn)return;const{type:c}=yn;switch(Nl(null),c){case"page":Hl();break;case"text":if(yt&&Pt?.content!==void 0)try{await Q("update_text",{id:yt,content:Pt.content,tags:Pt.tags||[]}),await Ve()}catch(h){console.error("Failed to restore original content:",h)}Nn();break;case"tagset":sa();break;case"image":Cn();break}},Rn=async(c,h,N,C)=>{c.stopPropagation();const D=C.includes("todo"),St=C.includes("done");let at;if(D)at=C.filter(Te=>Te!=="todo").concat("done");else if(St)at=C.filter(Te=>Te!=="done").concat("todo");else return;try{switch(await Q("update_url_tags",{id:h,tags:at}),N){case"page":await Ze();break;case"text":await Ve();break;case"tagset":await Me();break;case"image":await se();break}await fe()}catch(Te){console.error("Failed to toggle todo/done:",Te)}},Du=async(c,h,N)=>{N.stopPropagation();try{await Q("record_visit",{itemId:h,source:"browser",windowType:"external"}),await Vc(c)}catch(C){console.error("Failed to open in browser:",C)}},wn=z.useRef(null),Gi=async(c,h,N)=>{N.stopPropagation(),Oa(!1),ru(!1),on(!1),fn({url:c,itemId:h}),requestAnimationFrame(()=>{requestAnimationFrame(()=>{const C=document.getElementById(`card-${h}`),D=wn.current;if(C&&D){const St=C.getBoundingClientRect(),at=D.getBoundingClientRect(),Te=document.createElement("div");Te.style.cssText="position:fixed;top:0;height:env(safe-area-inset-top,0px);visibility:hidden;",document.body.appendChild(Te);const ul=Te.offsetHeight;document.body.removeChild(Te);const Ke=St.top-at.top-ul;D.style.setProperty("--slide-offset",`${Math.max(0,Ke)}px`)}document.documentElement.style.setProperty("--webview-ease","var(--webview-ease-in)"),on(!0),setTimeout(()=>ms(c,h),ol)})});try{await Q("record_visit",{itemId:h,source:"webview",windowType:"embedded"})}catch(C){console.error("[App] Failed to record webview visit:",C)}},Hn=()=>{qi(),document.documentElement.style.setProperty("--webview-ease","var(--webview-ease-out)"),on(!1),wn.current&&wn.current.style.setProperty("--slide-offset","0px"),setTimeout(()=>{fn(null),Oa(!1),ru(!1)},ol)},gs=()=>yn?s.jsx("div",{className:"confirm-modal-overlay",onClick:Un,children:s.jsxs("div",{className:"confirm-modal",onClick:c=>c.stopPropagation(),children:[s.jsx("p",{children:"Discard unsaved changes?"}),s.jsxs("div",{className:"confirm-modal-buttons",children:[s.jsx("button",{className:"cancel-btn",onClick:Un,children:"Cancel"}),s.jsx("button",{className:"delete-btn",onClick:Yi,children:"Discard"})]})]})}):null,ys=()=>{if(!hn)return null;const c={page:"page",text:"note",tagset:"tag set",image:"image"};return s.jsx("div",{className:"confirm-modal-overlay",onClick:Nu,children:s.jsxs("div",{className:"confirm-modal",onClick:h=>h.stopPropagation(),children:[s.jsxs("p",{children:["Delete this ",c[hn.type],"?"]}),s.jsxs("div",{className:"confirm-modal-buttons",children:[s.jsx("button",{className:"cancel-btn",onClick:Nu,children:"Cancel"}),s.jsx("button",{className:"delete-btn",onClick:Cu,children:"Delete"})]})]})})},xe=c=>{const h=c.metadata,N=h?.title,C=h?.sourceUrl;return s.jsxs("div",{className:"saved-item-card image-card",onClick:()=>ss(c),children:[s.jsxs("div",{className:"card-header",children:[s.jsx("div",{className:"card-thumbnail",children:c.thumbnail?s.jsx("img",{src:`data:image/jpeg;base64,${c.thumbnail}`,alt:N||"Preview"}):s.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),s.jsx("polyline",{points:"21 15 16 10 5 21"})]})}),s.jsx("div",{className:"card-title",children:N||C||"Image"}),s.jsx("button",{className:"card-delete-btn",onClick:D=>{D.stopPropagation(),nl(c.id,"image")},children:s.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("polyline",{points:"3 6 5 6 21 6"}),s.jsx("path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"})]})})]}),s.jsxs("div",{className:"card-footer",children:[(c.tags.includes("todo")||c.tags.includes("done"))&&s.jsx("button",{className:`todo-checkbox ${c.tags.includes("done")?"checked":""}`,onClick:D=>Rn(D,c.id,"image",c.tags),children:c.tags.includes("done")?s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("polyline",{points:"9 11 12 14 22 4"})]}):s.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"})})}),s.jsxs("div",{className:"card-tags",children:[c.tags.map(D=>s.jsx("span",{className:"card-tag",children:D},D)),s.jsx("span",{className:"card-date",children:new Date(c.saved_at).toLocaleDateString()})]})]})]},c.id)},Ja=()=>{el(!1),Ze(),fe()};if(pi)return s.jsxs("div",{className:"app",children:[s.jsxs("header",{children:[s.jsx("button",{className:"header-btn back-btn",onClick:Ja,children:"Back"}),s.jsx("h1",{children:"Settings"}),s.jsx("div",{className:"header-spacer"})]}),s.jsxs("main",{className:"settings-view",children:[s.jsxs("div",{className:"settings-section",children:[s.jsx("h2",{children:"Server Sync"}),s.jsx("p",{className:"settings-description",children:"Sync your saved items with the server. Pull to get items from other devices, push to send local items, or sync all to do both."}),s.jsx("p",{className:"settings-description",style:{fontSize:"0.85rem",opacity:.8},children:"Items sync to your account's current profile on the server."}),s.jsx("div",{className:"webhook-input",children:s.jsx("input",{type:"url",value:ll,onChange:c=>Sn(c.target.value),placeholder:"https://your-server.example.com",autoCapitalize:"none",autoCorrect:"off"})}),s.jsxs("div",{className:"webhook-input api-key-field",children:[s.jsx("input",{type:rl?"text":"password",value:Ha,onChange:c=>ea(c.target.value),placeholder:"API key",autoCapitalize:"none",autoCorrect:"off"}),s.jsx("button",{type:"button",className:"toggle-visibility-btn",onClick:()=>La(!rl),children:rl?s.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"}),s.jsx("line",{x1:"1",y1:"1",x2:"23",y2:"23"})]}):s.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"}),s.jsx("circle",{cx:"12",cy:"12",r:"3"})]})})]}),s.jsx("button",{onClick:pu,disabled:ll===Nt&&Ha===kc,className:"save-settings-btn",children:"Save Settings"}),s.jsxs("label",{className:"auto-sync-toggle",children:[s.jsx("input",{type:"checkbox",checked:mu,onChange:c=>Ei(c.target.checked)}),s.jsx("span",{children:"Auto-sync when items are added or modified"})]}),dl&&s.jsxs("p",{className:"last-sync-info",children:["Last synced: ",new Date(dl).toLocaleString()]}),bn&&bn.pending_count>0&&s.jsxs("p",{className:"sync-pending-info",children:[bn.pending_count," item",bn.pending_count===1?"":"s"," pending sync"]}),s.jsx("button",{className:"sync-btn primary",onClick:wl,disabled:!Nt||_e,children:_e?"Syncing...":"Sync All"}),s.jsxs("div",{className:"sync-btn-row",children:[s.jsx("button",{className:"sync-btn secondary",onClick:ca,disabled:!Nt||_e,children:"Pull"}),s.jsx("button",{className:"sync-btn secondary",onClick:Ai,disabled:!Nt||_e,children:"Push"})]}),Ba&&s.jsx("div",{className:`sync-message ${Ba.includes("failed")||Ba.includes("Failed")?"error":"success"}`,children:Ba})]}),s.jsxs("div",{className:"settings-section",children:[s.jsx("h2",{children:"Profiles"}),Dt&&s.jsxs(s.Fragment,{children:[s.jsxs("p",{className:"settings-description",children:[Dt.isProductionBuild?"App Store/TestFlight build":"Development build",". Each profile has separate local data and sync destination."]}),(()=>{const c=Dt.profiles.find(C=>C.id===Dt.currentProfileId),h=Dt.profiles[0],N=c?.id===h?.id;return s.jsxs(s.Fragment,{children:[!N&&c&&s.jsxs("div",{className:"profile-warning-banner",children:['Using "',c.name,'" profile - data is isolated from default']}),s.jsx("div",{className:"profile-list",children:Dt.profiles.map(C=>{const D=C.id===Dt.currentProfileId,St=!D&&Dt.profiles.length>1;return s.jsxs("div",{className:`profile-item ${D?"active":""}`,children:[s.jsxs("label",{className:"profile-radio-label",children:[s.jsx("input",{type:"radio",name:"profile",checked:D,onChange:()=>{console.log(`[Profile] Radio clicked: ${C.id}, isCurrent: ${D}`),D||(console.log(`[Profile] Switching to: ${C.id}`),al(C.id))}}),s.jsx("span",{className:"profile-name",children:C.name}),D&&s.jsx("span",{className:"profile-badge current",children:"active"})]}),St&&s.jsx("button",{className:"profile-delete-btn",onClick:async()=>{if(confirm(`Delete profile "${C.name}"? 14 14 15 - The database file will be preserved.`))try{const at=await Q("delete_profile",{profileId:C.id});xn(at)}catch(at){alert(`Failed to delete: ${at}`)}},children:"Delete"})]},C.id)})}),s.jsx("div",{className:"profile-add-section",children:s.jsxs("div",{className:"profile-input-row",children:[s.jsx("input",{type:"text",value:Ol,onChange:C=>Ml(C.target.value),placeholder:"New profile name"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{if(Ol.trim())try{const C=await Q("create_profile",{name:Ol.trim()});xn(C),Ml("")}catch(C){alert(`Failed to create: ${C}`)}},disabled:!Ol.trim(),children:"Add"})]})})]})})()]})]}),s.jsxs("div",{className:"settings-section",children:[s.jsx("h2",{children:"Display"}),s.jsx("p",{className:"settings-description",children:"Items with this tag are hidden from the main view unless the tag is selected as a filter."}),s.jsx("div",{className:"webhook-input",children:s.jsx("input",{type:"text",value:aa,onChange:c=>vu(c.target.value),placeholder:"archive",autoCapitalize:"none",autoCorrect:"off"})}),s.jsx("button",{onClick:yu,disabled:aa===la,className:"save-settings-btn",children:"Save Archive Tag"})]}),s.jsxs("div",{className:"settings-section",children:[s.jsx("h2",{children:"Debug"}),s.jsxs("div",{className:"sync-btn-row",style:{flexDirection:"column",gap:"0.5rem"},children:[s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_list_container_files");tt("FILES: "+c.join(" | "))}catch(c){tt("ERROR: "+String(c))}},children:"List Container Files"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_profiles_json");tt(c)}catch(c){tt("PROFILES ERROR: "+String(c))}},children:"Show profiles.json"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_settings_table");tt(c)}catch(c){tt("SETTINGS ERROR: "+String(c))}},children:"Show Settings Table"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_query_database");tt(c)}catch(c){tt("DB ERROR: "+String(c))}},children:"Query Database"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{tt("Exporting...");const c=await Q("debug_export_database");tt("DB_START>>>"+c.substring(0,500)+"...("+c.length+" total chars). Use AirDrop or copy manually."),console.log("FULL_DB_BASE64:",c)}catch(c){tt("EXPORT ERROR: "+String(c))}},children:"Export Database"}),Dt&&Dt.profiles.length>=2&&s.jsx("button",{className:"sync-btn secondary",style:{backgroundColor:"#c44"},onClick:async()=>{const c=Dt.profiles[0],h=Dt.profiles[1];try{tt("Swapping...");const N=await Q("swap_profile_databases",{profileIdA:c.id,profileIdB:h.id});tt(N)}catch(N){tt("SWAP ERROR: "+String(N))}},children:"Swap Default ↔ Dev Databases"})]})]})]}),Qe&&s.jsx("div",{className:"modal-overlay",children:s.jsxs("div",{className:"modal-content",children:[s.jsx("h3",{children:"Profile Changed"}),s.jsxs("p",{children:["Switched to ",s.jsx("strong",{children:Dt?.profiles.find(c=>c.id===Dt?.currentProfileId)?.name??"unknown"})," profile."]}),s.jsx("p",{children:"Please restart the app to ensure complete data isolation."}),s.jsxs("div",{className:"modal-buttons",children:[s.jsx("button",{className:"modal-btn secondary",onClick:()=>ye(!1),children:"Later"}),s.jsx("button",{className:"modal-btn primary",onClick:_n,children:"Quit Now"})]})]})})]});const Ou=Bi(),Qi=B.length+q.length+rt.length+H.length,Mu=s.jsx("input",{ref:gi,type:"file",accept:"image/*",capture:"environment",onChange:Qa,style:{display:"none"}});return Ma?s.jsxs("div",{className:"app",children:[Mu,s.jsxs("header",{children:[s.jsx("button",{className:"header-btn back-btn",onClick:ju,children:"Cancel"}),s.jsx("h1",{children:"Save Photo"}),s.jsx("div",{className:"header-spacer"})]}),s.jsx("main",{className:"saved-view",children:s.jsxs("div",{className:"captured-image-view",children:[s.jsx("div",{className:"captured-image-preview",children:s.jsx("img",{src:Ma,alt:"Captured"})}),Tl.size>0&&s.jsx("div",{className:"edit-section",children:s.jsx("div",{className:"editing-tags",children:Array.from(Tl).sort().map(c=>s.jsxs("span",{className:"editing-tag",children:[c,s.jsx("button",{onClick:()=>Xa(c),children:"×"})]},c))})}),s.jsx("div",{className:"edit-section",children:s.jsxs("div",{className:"new-tag-input",children:[s.jsx("input",{type:"text",value:qe,onChange:c=>El(c.target.value),onKeyDown:c=>{c.key==="Enter"&&(c.preventDefault(),Eu())},placeholder:"Add tag...",autoCapitalize:"none",autoCorrect:"off",autoComplete:"off",spellCheck:!1}),s.jsx("button",{onClick:Eu,disabled:!qe.trim(),children:"Add"})]})}),$.filter(c=>!Tl.has(c.name)&&(!qe.trim()||c.name.toLowerCase().includes(qe.toLowerCase().trim()))).length>0&&s.jsx("div",{className:"edit-section",children:s.jsx("div",{className:"all-tags-list",children:$.filter(c=>!Tl.has(c.name)&&(!qe.trim()||c.name.toLowerCase().includes(qe.toLowerCase().trim()))).map(c=>s.jsx("span",{className:"tag-chip",onClick:()=>Xa(c.name),children:c.name},c.name))})}),s.jsxs("div",{className:"edit-buttons",children:[s.jsx("button",{className:"cancel-btn",onClick:ju,children:"Cancel"}),s.jsx("button",{className:"save-btn",onClick:Fc,children:"Save"})]})]})})]}):s.jsxs("div",{className:`app ${xl?"webview-active":""}`,ref:wn,children:[s.jsx("input",{ref:Pl,style:{position:"fixed",opacity:0,top:"-100px"},readOnly:!0}),Mu,s.jsxs("header",{children:[s.jsxs("h1",{onClick:()=>{E!=="all"||Lt||Bt.size>0?Hi():On()},style:{cursor:"pointer"},children:["Peek ",s.jsx("span",{style:{fontSize:"0.5em",opacity:.5},children:"v1066"})]}),s.jsx("div",{style:{flex:1}}),s.jsxs("div",{className:"filter-icons",children:[s.jsxs("button",{className:`filter-btn ${E==="page"?"active":""}`,onClick:()=>Dn("page"),title:"Pages",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("circle",{cx:"12",cy:"12",r:"10"}),s.jsx("line",{x1:"2",y1:"12",x2:"22",y2:"12"}),s.jsx("path",{d:"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"})]}),s.jsx("span",{className:"filter-count",children:B.length})]}),s.jsxs("button",{className:`filter-btn ${E==="text"?"active":""}`,onClick:()=>Dn("text"),title:"Notes",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"}),s.jsx("polyline",{points:"14 2 14 8 20 8"}),s.jsx("line",{x1:"16",y1:"13",x2:"8",y2:"13"}),s.jsx("line",{x1:"16",y1:"17",x2:"8",y2:"17"})]}),s.jsx("span",{className:"filter-count",children:q.length})]}),s.jsxs("button",{className:`filter-btn ${E==="tagset"?"active":""}`,onClick:()=>Dn("tagset"),title:"Tag Sets",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"}),s.jsx("line",{x1:"7",y1:"7",x2:"7.01",y2:"7"})]}),s.jsx("span",{className:"filter-count",children:rt.length})]}),s.jsxs("button",{className:`filter-btn ${E==="image"?"active":""}`,onClick:()=>Dn("image"),title:"Images",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),s.jsx("polyline",{points:"21 15 16 10 5 21"})]}),s.jsx("span",{className:"filter-count",children:H.length})]})]}),s.jsx("button",{className:"sort-btn",onClick:()=>Jc(c=>c==="newest"?"oldest":"newest"),title:Ra==="newest"?"Newest first":"Oldest first",children:Ra==="newest"?s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),s.jsx("polyline",{points:"19 12 12 19 5 12"})]}):s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("line",{x1:"12",y1:"19",x2:"12",y2:"5"}),s.jsx("polyline",{points:"5 12 12 5 19 12"})]})}),s.jsx("div",{style:{flex:1}}),s.jsx("button",{className:`header-btn settings-btn ${_e?"syncing":""}`,onClick:()=>el(!0),children:s.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("circle",{cx:"12",cy:"12",r:"3"}),s.jsx("path",{d:"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"})]})})]}),Dt&&Dt.profiles.length>0&&Dt.currentProfileId!==Dt.profiles[0].id&&s.jsxs("div",{className:"profile-banner",children:["Profile: ",Dt.profiles.find(c=>c.id===Dt.currentProfileId)?.name??"Unknown"]}),s.jsxs("main",{className:"saved-view",ref:dn,onTouchStart:Za,onTouchEnd:wi,children:[na!=="idle"&&s.jsx("div",{className:`pull-indicator ${na}`,children:na==="pulling"?"Hold to refresh...":"Release to refresh!"}),s.jsxs("div",{className:"input-row",children:[s.jsx("div",{className:"input-row-card",children:s.jsxs("div",{className:"input-with-clear",style:{flex:1},children:[s.jsx("input",{type:"text",className:"input-row-input",placeholder:"Search...",value:Lt,onChange:c=>Ye(c.target.value),autoCapitalize:"none",autoCorrect:"off",autoComplete:"off",spellCheck:!1}),s.jsx(Kc,{show:Lt.length>0||Bt.size>0,onClear:()=>{Ye(""),du(new Set)}})]})}),s.jsxs("div",{className:"input-row-card",children:[s.jsx("div",{className:"input-with-clear",style:{flex:1},children:s.jsx("input",{type:"text",className:"input-row-input",placeholder:"Add...",value:F,onChange:c=>nt(c.target.value),onFocus:()=>ve(!0),autoCapitalize:"none",autoCorrect:"off",autoComplete:"off",spellCheck:!1})}),s.jsx("button",{className:"camera-btn",onClick:Tu,title:"Take photo",children:s.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"}),s.jsx("circle",{cx:"12",cy:"13",r:"4"})]})})]})]}),s.jsxs("div",{className:"drag-handle-wrapper",children:[s.jsx("div",{className:"filter-tags-container",ref:wa,style:{height:`${_l}px`},children:Au().length===0?s.jsx("div",{className:"filter-tags-empty",children:"No matching tags"}):s.jsx("div",{className:"filter-tags",children:Au().map(c=>s.jsx("span",{className:`tag-chip ${Bt.has(c.name)?"selected":""}`,onClick:()=>Li(c.name),children:c.name},c.name))})}),s.jsx("div",{className:"drag-handle",onMouseDown:c=>{c.preventDefault(),gu(c.clientY)},onTouchStart:c=>{gu(c.touches[0].clientY)},children:s.jsx("div",{className:"drag-handle-bar"})})]}),s.jsx("div",{className:"unified-list",children:Qi===0?s.jsxs("div",{className:"empty-state",children:[s.jsx("p",{children:"No saved items yet."}),s.jsx("p",{children:"Share a URL from any app to get started!"})]}):Ou.length===0?s.jsxs("div",{className:"empty-state",children:[s.jsx("p",{children:"No matching items."}),s.jsx("p",{children:"Tap Peek to clear filters."})]}):Ou.map(c=>hs(c))})]}),ds(),ae&&s.jsxs(hi,{onDismiss:()=>ve(!1),keyboardHeight:Xe,children:[s.jsx(wh,{value:F,onChange:nt,placeholder:"Enter text, URL, or just select tags...",keyboardHeight:Xe,autoFocus:!0,autoCapitalize:"none",autoCorrect:"off"}),s.jsx(mi,{selectedTags:zt,availableTags:$,tagInput:fl,onTagInputChange:bl,onToggleTag:Ga,onAddTag:xu,placeholder:"Add new tag..."}),s.jsx(vi,{onSave:$c,onCancel:()=>ve(!1),cancelLabel:"Close",saveDisabled:!_u()})]}),ys(),gs(),vn&&s.jsx("div",{className:`toast toast-${vn.type}`,children:vn.message}),Qe&&s.jsx("div",{className:"modal-overlay",children:s.jsxs("div",{className:"modal-content",children:[s.jsx("h3",{children:"Profile Changed"}),s.jsxs("p",{children:["Switched to ",s.jsx("strong",{children:Dt?.profiles.find(c=>c.id===Dt?.currentProfileId)?.name??"unknown"})," profile."]}),s.jsx("p",{children:"Please restart the app to ensure complete data isolation."}),s.jsxs("div",{className:"modal-buttons",children:[s.jsx("button",{className:"modal-btn secondary",onClick:()=>ye(!1),children:"Later"}),s.jsx("button",{className:"modal-btn primary",onClick:_n,children:"Quit Now"})]})]})})]})}mm.createRoot(document.getElementById("root")).render(s.jsx(im.StrictMode,{children:s.jsx(Sm,{})})); 15 + The database file will be preserved.`))try{const at=await Q("delete_profile",{profileId:C.id});xn(at)}catch(at){alert(`Failed to delete: ${at}`)}},children:"Delete"})]},C.id)})}),s.jsx("div",{className:"profile-add-section",children:s.jsxs("div",{className:"profile-input-row",children:[s.jsx("input",{type:"text",value:Ol,onChange:C=>Ml(C.target.value),placeholder:"New profile name"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{if(Ol.trim())try{const C=await Q("create_profile",{name:Ol.trim()});xn(C),Ml("")}catch(C){alert(`Failed to create: ${C}`)}},disabled:!Ol.trim(),children:"Add"})]})})]})})()]})]}),s.jsxs("div",{className:"settings-section",children:[s.jsx("h2",{children:"Display"}),s.jsx("p",{className:"settings-description",children:"Items with this tag are hidden from the main view unless the tag is selected as a filter."}),s.jsx("div",{className:"webhook-input",children:s.jsx("input",{type:"text",value:aa,onChange:c=>vu(c.target.value),placeholder:"archive",autoCapitalize:"none",autoCorrect:"off"})}),s.jsx("button",{onClick:yu,disabled:aa===la,className:"save-settings-btn",children:"Save Archive Tag"})]}),s.jsxs("div",{className:"settings-section",children:[s.jsx("h2",{children:"Debug"}),s.jsxs("div",{className:"sync-btn-row",style:{flexDirection:"column",gap:"0.5rem"},children:[s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_list_container_files");tt("FILES: "+c.join(" | "))}catch(c){tt("ERROR: "+String(c))}},children:"List Container Files"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_profiles_json");tt(c)}catch(c){tt("PROFILES ERROR: "+String(c))}},children:"Show profiles.json"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_settings_table");tt(c)}catch(c){tt("SETTINGS ERROR: "+String(c))}},children:"Show Settings Table"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{const c=await Q("debug_query_database");tt(c)}catch(c){tt("DB ERROR: "+String(c))}},children:"Query Database"}),s.jsx("button",{className:"sync-btn secondary",onClick:async()=>{try{tt("Exporting...");const c=await Q("debug_export_database");tt("DB_START>>>"+c.substring(0,500)+"...("+c.length+" total chars). Use AirDrop or copy manually."),console.log("FULL_DB_BASE64:",c)}catch(c){tt("EXPORT ERROR: "+String(c))}},children:"Export Database"}),Dt&&Dt.profiles.length>=2&&s.jsx("button",{className:"sync-btn secondary",style:{backgroundColor:"#c44"},onClick:async()=>{const c=Dt.profiles[0],h=Dt.profiles[1];try{tt("Swapping...");const N=await Q("swap_profile_databases",{profileIdA:c.id,profileIdB:h.id});tt(N)}catch(N){tt("SWAP ERROR: "+String(N))}},children:"Swap Default ↔ Dev Databases"})]})]})]}),Qe&&s.jsx("div",{className:"modal-overlay",children:s.jsxs("div",{className:"modal-content",children:[s.jsx("h3",{children:"Profile Changed"}),s.jsxs("p",{children:["Switched to ",s.jsx("strong",{children:Dt?.profiles.find(c=>c.id===Dt?.currentProfileId)?.name??"unknown"})," profile."]}),s.jsx("p",{children:"Please restart the app to ensure complete data isolation."}),s.jsxs("div",{className:"modal-buttons",children:[s.jsx("button",{className:"modal-btn secondary",onClick:()=>ye(!1),children:"Later"}),s.jsx("button",{className:"modal-btn primary",onClick:_n,children:"Quit Now"})]})]})})]});const Ou=Bi(),Qi=B.length+q.length+rt.length+H.length,Mu=s.jsx("input",{ref:gi,type:"file",accept:"image/*",capture:"environment",onChange:Qa,style:{display:"none"}});return Ma?s.jsxs("div",{className:"app",children:[Mu,s.jsxs("header",{children:[s.jsx("button",{className:"header-btn back-btn",onClick:ju,children:"Cancel"}),s.jsx("h1",{children:"Save Photo"}),s.jsx("div",{className:"header-spacer"})]}),s.jsx("main",{className:"saved-view",children:s.jsxs("div",{className:"captured-image-view",children:[s.jsx("div",{className:"captured-image-preview",children:s.jsx("img",{src:Ma,alt:"Captured"})}),Tl.size>0&&s.jsx("div",{className:"edit-section",children:s.jsx("div",{className:"editing-tags",children:Array.from(Tl).sort().map(c=>s.jsxs("span",{className:"editing-tag",children:[c,s.jsx("button",{onClick:()=>Xa(c),children:"×"})]},c))})}),s.jsx("div",{className:"edit-section",children:s.jsxs("div",{className:"new-tag-input",children:[s.jsx("input",{type:"text",value:qe,onChange:c=>El(c.target.value),onKeyDown:c=>{c.key==="Enter"&&(c.preventDefault(),Eu())},placeholder:"Add tag...",autoCapitalize:"none",autoCorrect:"off",autoComplete:"off",spellCheck:!1}),s.jsx("button",{onClick:Eu,disabled:!qe.trim(),children:"Add"})]})}),$.filter(c=>!Tl.has(c.name)&&(!qe.trim()||c.name.toLowerCase().includes(qe.toLowerCase().trim()))).length>0&&s.jsx("div",{className:"edit-section",children:s.jsx("div",{className:"all-tags-list",children:$.filter(c=>!Tl.has(c.name)&&(!qe.trim()||c.name.toLowerCase().includes(qe.toLowerCase().trim()))).map(c=>s.jsx("span",{className:"tag-chip",onClick:()=>Xa(c.name),children:c.name},c.name))})}),s.jsxs("div",{className:"edit-buttons",children:[s.jsx("button",{className:"cancel-btn",onClick:ju,children:"Cancel"}),s.jsx("button",{className:"save-btn",onClick:Fc,children:"Save"})]})]})})]}):s.jsxs("div",{className:`app ${xl?"webview-active":""}`,ref:wn,children:[s.jsx("input",{ref:Pl,style:{position:"fixed",opacity:0,top:"-100px"},readOnly:!0}),Mu,s.jsxs("header",{children:[s.jsxs("h1",{onClick:()=>{E!=="all"||Lt||Bt.size>0?Hi():On()},style:{cursor:"pointer"},children:["Peek ",s.jsx("span",{style:{fontSize:"0.5em",opacity:.5},children:"v1072"})]}),s.jsx("div",{style:{flex:1}}),s.jsxs("div",{className:"filter-icons",children:[s.jsxs("button",{className:`filter-btn ${E==="page"?"active":""}`,onClick:()=>Dn("page"),title:"Pages",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("circle",{cx:"12",cy:"12",r:"10"}),s.jsx("line",{x1:"2",y1:"12",x2:"22",y2:"12"}),s.jsx("path",{d:"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"})]}),s.jsx("span",{className:"filter-count",children:B.length})]}),s.jsxs("button",{className:`filter-btn ${E==="text"?"active":""}`,onClick:()=>Dn("text"),title:"Notes",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"}),s.jsx("polyline",{points:"14 2 14 8 20 8"}),s.jsx("line",{x1:"16",y1:"13",x2:"8",y2:"13"}),s.jsx("line",{x1:"16",y1:"17",x2:"8",y2:"17"})]}),s.jsx("span",{className:"filter-count",children:q.length})]}),s.jsxs("button",{className:`filter-btn ${E==="tagset"?"active":""}`,onClick:()=>Dn("tagset"),title:"Tag Sets",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"}),s.jsx("line",{x1:"7",y1:"7",x2:"7.01",y2:"7"})]}),s.jsx("span",{className:"filter-count",children:rt.length})]}),s.jsxs("button",{className:`filter-btn ${E==="image"?"active":""}`,onClick:()=>Dn("image"),title:"Images",children:[s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),s.jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),s.jsx("polyline",{points:"21 15 16 10 5 21"})]}),s.jsx("span",{className:"filter-count",children:H.length})]})]}),s.jsx("button",{className:"sort-btn",onClick:()=>Jc(c=>c==="newest"?"oldest":"newest"),title:Ra==="newest"?"Newest first":"Oldest first",children:Ra==="newest"?s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),s.jsx("polyline",{points:"19 12 12 19 5 12"})]}):s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("line",{x1:"12",y1:"19",x2:"12",y2:"5"}),s.jsx("polyline",{points:"5 12 12 5 19 12"})]})}),s.jsx("div",{style:{flex:1}}),s.jsx("button",{className:`header-btn settings-btn ${_e?"syncing":""}`,onClick:()=>el(!0),children:s.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("circle",{cx:"12",cy:"12",r:"3"}),s.jsx("path",{d:"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"})]})})]}),Dt&&Dt.profiles.length>0&&Dt.currentProfileId!==Dt.profiles[0].id&&s.jsxs("div",{className:"profile-banner",children:["Profile: ",Dt.profiles.find(c=>c.id===Dt.currentProfileId)?.name??"Unknown"]}),s.jsxs("main",{className:"saved-view",ref:dn,onTouchStart:Za,onTouchEnd:wi,children:[na!=="idle"&&s.jsx("div",{className:`pull-indicator ${na}`,children:na==="pulling"?"Hold to refresh...":"Release to refresh!"}),s.jsxs("div",{className:"input-row",children:[s.jsx("div",{className:"input-row-card",children:s.jsxs("div",{className:"input-with-clear",style:{flex:1},children:[s.jsx("input",{type:"text",className:"input-row-input",placeholder:"Search...",value:Lt,onChange:c=>Ye(c.target.value),autoCapitalize:"none",autoCorrect:"off",autoComplete:"off",spellCheck:!1}),s.jsx(Kc,{show:Lt.length>0||Bt.size>0,onClear:()=>{Ye(""),du(new Set)}})]})}),s.jsxs("div",{className:"input-row-card",children:[s.jsx("div",{className:"input-with-clear",style:{flex:1},children:s.jsx("input",{type:"text",className:"input-row-input",placeholder:"Add...",value:F,onChange:c=>nt(c.target.value),onFocus:()=>ve(!0),autoCapitalize:"none",autoCorrect:"off",autoComplete:"off",spellCheck:!1})}),s.jsx("button",{className:"camera-btn",onClick:Tu,title:"Take photo",children:s.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[s.jsx("path",{d:"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"}),s.jsx("circle",{cx:"12",cy:"13",r:"4"})]})})]})]}),s.jsxs("div",{className:"drag-handle-wrapper",children:[s.jsx("div",{className:"filter-tags-container",ref:wa,style:{height:`${_l}px`},children:Au().length===0?s.jsx("div",{className:"filter-tags-empty",children:"No matching tags"}):s.jsx("div",{className:"filter-tags",children:Au().map(c=>s.jsx("span",{className:`tag-chip ${Bt.has(c.name)?"selected":""}`,onClick:()=>Li(c.name),children:c.name},c.name))})}),s.jsx("div",{className:"drag-handle",onMouseDown:c=>{c.preventDefault(),gu(c.clientY)},onTouchStart:c=>{gu(c.touches[0].clientY)},children:s.jsx("div",{className:"drag-handle-bar"})})]}),s.jsx("div",{className:"unified-list",children:Qi===0?s.jsxs("div",{className:"empty-state",children:[s.jsx("p",{children:"No saved items yet."}),s.jsx("p",{children:"Share a URL from any app to get started!"})]}):Ou.length===0?s.jsxs("div",{className:"empty-state",children:[s.jsx("p",{children:"No matching items."}),s.jsx("p",{children:"Tap Peek to clear filters."})]}):Ou.map(c=>hs(c))})]}),ds(),ae&&s.jsxs(hi,{onDismiss:()=>ve(!1),keyboardHeight:Xe,children:[s.jsx(wh,{value:F,onChange:nt,placeholder:"Enter text, URL, or just select tags...",keyboardHeight:Xe,autoFocus:!0,autoCapitalize:"none",autoCorrect:"off"}),s.jsx(mi,{selectedTags:zt,availableTags:$,tagInput:fl,onTagInputChange:bl,onToggleTag:Ga,onAddTag:xu,placeholder:"Add new tag..."}),s.jsx(vi,{onSave:$c,onCancel:()=>ve(!1),cancelLabel:"Close",saveDisabled:!_u()})]}),ys(),gs(),vn&&s.jsx("div",{className:`toast toast-${vn.type}`,children:vn.message}),Qe&&s.jsx("div",{className:"modal-overlay",children:s.jsxs("div",{className:"modal-content",children:[s.jsx("h3",{children:"Profile Changed"}),s.jsxs("p",{children:["Switched to ",s.jsx("strong",{children:Dt?.profiles.find(c=>c.id===Dt?.currentProfileId)?.name??"unknown"})," profile."]}),s.jsx("p",{children:"Please restart the app to ensure complete data isolation."}),s.jsxs("div",{className:"modal-buttons",children:[s.jsx("button",{className:"modal-btn secondary",onClick:()=>ye(!1),children:"Later"}),s.jsx("button",{className:"modal-btn primary",onClick:_n,children:"Quit Now"})]})]})})]})}mm.createRoot(document.getElementById("root")).render(s.jsx(im.StrictMode,{children:s.jsx(Sm,{})}));
+1 -1
backend/tauri-mobile/src-tauri/tauri.conf.json
··· 6 6 "build": { 7 7 "beforeBuildCommand": "npm run build", 8 8 "frontendDist": "../dist", 9 - "devUrl": "http://192.168.50.143:51684" 9 + "devUrl": "http://192.168.50.143:61905" 10 10 }, 11 11 "app": { 12 12 "windows": [
+1 -1
docs/mobile.md
··· 681 681 682 682 **Fix:** The yarn scripts use `clean build`. If using Xcode GUI: 683 683 1. Product → Clean Build Folder (Cmd+Shift+K) 684 - 2. Delete DerivedData: `rm -rf /tmp/peek-xcodebuild` 684 + 2. Delete DerivedData: `rm -rf /tmp/peek-xcodebuild-sim /tmp/peek-xcodebuild-device` 685 685 3. Rebuild 686 686 687 687 ### Wrong Library Architecture
+6 -6
package.json
··· 47 47 "mobile:ios:build:release": "cd backend/tauri-mobile && ./build-release.sh", 48 48 "mobile:ios:xcode": "open backend/tauri-mobile/src-tauri/gen/apple/peek-save.xcodeproj", 49 49 "mobile:ios:xcodebuild:list": "xcodebuild -project backend/tauri-mobile/src-tauri/gen/apple/peek-save.xcodeproj -list", 50 - "mobile:ios:xcodebuild": "rm -rf /tmp/peek-xcodebuild && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean build", 51 - "mobile:ios:xcodebuild:release": "rm -rf /tmp/peek-xcodebuild && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration release -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean build", 52 - "mobile:ios:xcodebuild:install": "xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/debug-iphonesimulator/Peek Save.app'", 53 - "mobile:ios:xcodebuild:install:release": "xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/release-iphonesimulator/Peek Save.app'", 50 + "mobile:ios:xcodebuild": "rm -rf /tmp/peek-xcodebuild-sim && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild-sim -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean build", 51 + "mobile:ios:xcodebuild:release": "rm -rf /tmp/peek-xcodebuild-sim && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration release -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild-sim -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean build", 52 + "mobile:ios:xcodebuild:install": "xcrun simctl install booted '/tmp/peek-xcodebuild-sim/Build/Products/debug-iphonesimulator/Peek Save.app'", 53 + "mobile:ios:xcodebuild:install:release": "xcrun simctl install booted '/tmp/peek-xcodebuild-sim/Build/Products/release-iphonesimulator/Peek Save.app'", 54 54 "mobile:ios:xcodebuild:full": "yarn mobile:ios:build && yarn mobile:ios:xcodebuild && yarn mobile:ios:xcodebuild:install", 55 55 "mobile:ios:xcodebuild:release:full": "yarn mobile:ios:build && yarn mobile:ios:xcodebuild:release && yarn mobile:ios:xcodebuild:install:release", 56 - "mobile:ios:xcodebuild:device": "rm -rf /tmp/peek-xcodebuild && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration release -sdk iphoneos -derivedDataPath /tmp/peek-xcodebuild -destination 'generic/platform=iOS' ONLY_ACTIVE_ARCH=NO clean build", 56 + "mobile:ios:xcodebuild:device": "rm -rf /tmp/peek-xcodebuild-device && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration release -sdk iphoneos -derivedDataPath /tmp/peek-xcodebuild-device -destination 'generic/platform=iOS' ONLY_ACTIVE_ARCH=NO clean build", 57 57 "mobile:ios:device:list": "xcrun devicectl list devices", 58 - "mobile:ios:xcodebuild:device:install": "DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep 'iPhone' | awk '{for(i=1;i<=NF;i++)if($i~/^[0-9A-F-]{36}$/)print $i}' | head -1) && [ -n \"$DEVICE_ID\" ] || { echo 'Error: No iOS device connected'; exit 1; } && echo \"Installing to device: $DEVICE_ID\" && xcrun devicectl device install app --device \"$DEVICE_ID\" '/tmp/peek-xcodebuild/Build/Products/release-iphoneos/Peek Save.app'", 58 + "mobile:ios:xcodebuild:device:install": "DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep 'iPhone' | awk '{for(i=1;i<=NF;i++)if($i~/^[0-9A-F-]{36}$/)print $i}' | head -1) && [ -n \"$DEVICE_ID\" ] || { echo 'Error: No iOS device connected'; exit 1; } && echo \"Installing to device: $DEVICE_ID\" && xcrun devicectl device install app --device \"$DEVICE_ID\" '/tmp/peek-xcodebuild-device/Build/Products/release-iphoneos/Peek Save.app'", 59 59 "mobile:ios:xcodebuild:device:full": "yarn mobile:ios:build:release && yarn mobile:ios:xcodebuild:device && yarn mobile:ios:xcodebuild:device:install", 60 60 "mobile:ios:device:launch": "DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep 'iPhone' | awk '{for(i=1;i<=NF;i++)if($i~/^[0-9A-F-]{36}$/)print $i}' | head -1) && [ -n \"$DEVICE_ID\" ] || { echo 'Error: No iOS device connected'; exit 1; } && xcrun devicectl device process launch --device \"$DEVICE_ID\" com.dietrich.peek-mobile", 61 61 "mobile:ios:device:terminate": "DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep 'iPhone' | awk '{for(i=1;i<=NF;i++)if($i~/^[0-9A-F-]{36}$/)print $i}' | head -1) && [ -n \"$DEVICE_ID\" ] || { echo 'Error: No iOS device connected'; exit 1; } && xcrun devicectl device process terminate --device \"$DEVICE_ID\" --bundle-id com.dietrich.peek-mobile 2>/dev/null || echo 'App not running'",
+3 -3
scripts/e2e-full-sync-test.sh
··· 15 15 # │ yarn interactive-test:e2e:full-sync -- --headless --build │ 16 16 # │ │ 17 17 # │ The --build flag uses xcodebuild CLI with isolated DerivedData │ 18 - # │ path (/tmp/peek-xcodebuild) to avoid conflicts with Xcode GUI. │ 18 + # │ path (/tmp/peek-xcodebuild-sim) to avoid conflicts with Xcode GUI. │ 19 19 # └─────────────────────────────────────────────────────────────────┘ 20 20 # 21 21 # Clean-room test covering all sync permutations: ··· 548 548 # Build with xcodebuild using isolated DerivedData path 549 549 cd backend/tauri-mobile/src-tauri/gen/apple 550 550 xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator \ 551 - -derivedDataPath /tmp/peek-xcodebuild \ 551 + -derivedDataPath /tmp/peek-xcodebuild-sim \ 552 552 -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ 553 553 build 2>&1 | grep -E "(BUILD|error:|warning:.*error)" || true 554 554 ··· 561 561 562 562 # Install to simulator 563 563 echo " Installing to simulator..." 564 - xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/debug-iphonesimulator/Peek Save.app' 564 + xcrun simctl install booted '/tmp/peek-xcodebuild-sim/Build/Products/debug-iphonesimulator/Peek Save.app' 565 565 echo " iOS app installed" 566 566 cd "$PROJECT_DIR" 567 567 fi