@office-kit/pptx-dev 0.11.0 → 0.13.0
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/README.md +6 -6
- package/dist/animation-player.js +1 -1
- package/dist/cli.mjs +43 -18
- package/dist/cli.mjs.map +1 -1
- package/dist/editor-chunks/agent-tools-emRGeP2H-WN4XUNCN.js +425 -0
- package/dist/editor-chunks/chunk-Q3KT5ZGJ.js +738 -0
- package/dist/editor.js +24 -162
- package/dist/index.mjs +1 -1
- package/dist/src-DASlwPDd.mjs +457 -0
- package/dist/src-DASlwPDd.mjs.map +1 -0
- package/package.json +6 -6
- package/dist/editor.css +0 -1
- package/dist/src-CI73YbYS.mjs +0 -1741
- package/dist/src-CI73YbYS.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @office-kit/pptx-dev
|
|
2
2
|
|
|
3
3
|
Local TSX authoring tools for `@office-kit/pptx-dsl`. Build and preview an editable
|
|
4
|
-
|
|
4
|
+
presentation while changing its source in VSCode or Claude Code.
|
|
5
5
|
Requires Node.js 22.18 or later.
|
|
6
6
|
|
|
7
7
|
For Claude Code, [install the office-kit skill](https://office-kit.github.io/pptx/docs/authoring)
|
|
@@ -106,15 +106,15 @@ the saved edited presentation, including after restarting the server.
|
|
|
106
106
|
|
|
107
107
|
Saving a slide file, `theme.ts` or `deck.tsx` rebuilds the source. Changes from
|
|
108
108
|
TSX merge with canvas edits, saved or not yet saved: shapes, slide settings,
|
|
109
|
-
media and links changed on only one side are combined, and the editor
|
|
110
|
-
the merged presentation
|
|
109
|
+
media and links changed on only one side are combined, and the editor applies
|
|
110
|
+
the merged presentation as one Undo step, "Source changed". The editor asks you
|
|
111
111
|
to choose **Keep my edits** or **Use source** only when the same item was
|
|
112
112
|
changed in both places, such as one shape edited on the canvas and in TSX, a
|
|
113
113
|
shape deleted on one side and changed on the other, or slides added, removed or
|
|
114
114
|
reordered on both sides. The message names each collision, for example
|
|
115
115
|
"Slide 2: Title 1 was changed both here and in the source." Keeping edits keeps
|
|
116
116
|
the entire edited deck without the TSX changes; using source discards the saved
|
|
117
|
-
canvas version. You can download the source version before choosing. CLI export
|
|
117
|
+
canvas version (Undo in the editor brings it back as unsaved edits). You can download the source version before choosing. CLI export
|
|
118
118
|
refuses an unresolved conflict so that it cannot silently export the wrong
|
|
119
119
|
version. Editor files from versions before merging was available cannot merge
|
|
120
120
|
until the conflict is resolved once.
|
|
@@ -134,7 +134,7 @@ npm run build
|
|
|
134
134
|
`check` runs TypeScript; `build` writes `deck.pptx`. Compilation alone does not
|
|
135
135
|
perform TypeScript checking, so run both before delivery. Exported charts, text,
|
|
136
136
|
images and tables remain editable. The renderer previews the serialized PPTX,
|
|
137
|
-
but is not a guarantee of identical rendering in
|
|
137
|
+
but is not a guarantee of identical rendering in desktop presentation apps.
|
|
138
138
|
|
|
139
139
|
The generated `CLAUDE.md` explains authoring conventions. VSCode picks up the
|
|
140
140
|
included `tsconfig.json` for completion and diagnostics. Start the **Preview
|
|
@@ -151,7 +151,7 @@ slides. Update time depends on the deck size and any code it runs.
|
|
|
151
151
|
|
|
152
152
|
**Agents** at the right end of the editor's tab row, beside Comments and Share,
|
|
153
153
|
opens the Agents task pane docked on the right (closed by default, like
|
|
154
|
-
|
|
154
|
+
the reference desktop app's panes; × closes it). The pane follows the editor's light or dark
|
|
155
155
|
appearance, including the terminal colors. Each agent defaults to **Claude Code**. Click **Start** to open the locally
|
|
156
156
|
installed `claude` CLI in an interactive terminal. Install and sign in to Claude
|
|
157
157
|
Code first. Use a current version with HTTP `UserPromptSubmit` hook support.
|
package/dist/animation-player.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var fe=["appear","disappear"],me=["fadeIn","appear","flyIn","zoomIn"],pe=["fadeOut","disappear","flyOut","zoomOut"],ye=["spin"],se={appear:"none",disappear:"none",fadeIn:"fade",fadeOut:"fade",flyIn:"fly",flyOut:"fly",zoomIn:"zoom",zoomOut:"zoom",spin:"spin"},ge=360,te=t=>t instanceof HTMLElement||t instanceof SVGElement?t:null,he=t=>t.effect===null?null:me.includes(t.effect)?"entrance":pe.includes(t.effect)?"exit":ye.includes(t.effect)?"emphasis":null,be=t=>t.durationMs!==null&&Number.isFinite(t.durationMs)&&t.durationMs>=0?t.durationMs:t.effect!==null&&fe.includes(t.effect)?0:null,Se=t=>{let m=[],S=[],r=(l,E)=>{S.push({step:l,reason:E})},p=null,c=0,i=0,a=!1;for(let l of t??[]){if(l.sequence!=="mainSeq"){r(l,"notInMainSeq");continue}let E=!a;if(a=!0,l.start==="unknown"){c=null,i=null,r(l,"notModelled");continue}l.start==="click"||E?(p={items:[],auto:E&&l.start!=="click"},m.push(p),c=0,i=0):l.start==="afterPrevious"&&(c=i,i=c);let h=l.playable?he(l):null,I=h===null?null:be(l),M=l.delayMs;if(h===null||M===null||c===null){r(l,h===null||M===null?"notModelled":"unknownTiming"),i=null;continue}let T=c+M;p?.items.push({step:l,kind:h,begin:T,duration:I}),i=I===null||i===null?null:Math.max(i,T+I)}return{stops:m,unsupported:S}},le=t=>`[data-pptx-shape-id="${t}"]`,oe=(t,m,S)=>{let r=m.target;if(r.kind!=="shape"&&r.kind!=="paragraphs")return[];if(!Number.isInteger(r.shapeId))return[];let p=String(r.shapeId);if(S.has(p))return[];let c=t.querySelectorAll(le(p)),i=c.length===1?te(c[0]):null;if(i===null)return[];if(r.kind!=="paragraphs")return[i];let a=[];for(let l of i.querySelectorAll("[data-pptx-paragraph]")){if(l.closest("[data-pptx-shape-id]")!==i)continue;let E=Number(l.getAttribute("data-pptx-paragraph"));if(E<r.firstParagraph||E>r.lastParagraph)continue;let h=te(l);h!==null&&a.push(h)}return a},re=()=>typeof performance=="object"?performance.now():Date.now(),Ee=(t,m)=>{let S=t.closest("svg");return S!==null?S.getBoundingClientRect():m instanceof Element?m.getBoundingClientRect():null},ve=t=>{if(t instanceof SVGGraphicsElement)return t.getScreenCTM();let m=t.closest("foreignObject");return m instanceof SVGGraphicsElement?m.getScreenCTM():null},Ae=(t,m,S)=>{let r=Ee(t,S);if(r===null||r.width<=0||r.height<=0)return null;let p=t.getBoundingClientRect(),c=m==="right"?r.right-p.left:m==="left"?r.left-p.right:0,i=m==="bottom"?r.bottom-p.top:m==="top"?r.top-p.bottom:0,a=ve(t);if(a===null)return{dx:c,dy:i};let l=a.a*a.d-a.b*a.c;return l===0?null:{dx:(a.d*c-a.c*i)/l,dy:(a.a*i-a.b*c)/l}},Ie=t=>t.step.effect!==null&&se[t.step.effect]==="fly",xe=(t,m,S)=>{let r=t.step.effect,p=t.kind==="entrance";switch(r===null?"none":se[r]??"none"){case"none":return null;case"fade":return{frames:p?[{opacity:0},{opacity:1}]:[{opacity:1},{opacity:0}],aboutOwnCentre:!1};case"zoom":{let c={scale:"0"},i={scale:"1"};return{frames:p?[c,i]:[i,c],aboutOwnCentre:!0}}case"spin":return{frames:[{rotate:"0deg"},{rotate:`${ge}deg`}],aboutOwnCentre:!0};case"fly":{let c=t.step.direction;if(c===null)return null;let i=Ae(m,c,S);if(i===null)return null;let a={translate:`${i.dx}px ${i.dy}px`},l={translate:"0px 0px"};return{frames:p?[a,l]:[l,a],aboutOwnCentre:!1}}}},Me=t=>{let m=()=>typeof t.root=="function"?t.root():t.root,S=Se(t.steps),r=S.stops,p=[...S.unsupported],c=()=>t.reducedMotion?.()===!0,i=t.onChange??(()=>{}),a=[],l=[],E=new Set,h=new Map,I=new Map,M=new Map,T=new Set,g=0,P=!1,O=null,k=0,R=new Set;for(let e of p)for(let n of e.step.targetShapeIds)R.add(String(n));let z=new Map;for(let e of r)for(let n of e.items){let s=String(n.step.target.shapeId);z.has(s)||z.set(s,m().querySelectorAll(le(s)).length)}for(let e of r)for(let n of e.items)(z.get(String(n.step.target.shapeId))??0)>1&&p.push({step:n.step,reason:"ambiguousTarget"});for(let[e,n]of z)n>1&&R.add(e);let ie=e=>{let n=new Set;for(let s of r){let f=new Map;for(let o of s.items){let u=o.duration===null?Number.POSITIVE_INFINITY:o.begin+o.duration;for(let y of oe(e,o.step,R)){let d={item:o,begin:o.begin,end:u},b=f.get(y);b===void 0?f.set(y,[d]):b.push(d)}}for(let o of f.values()){if(o.length<2)continue;o.sort((d,b)=>d.begin-b.begin);let u=Number.NEGATIVE_INFINITY;for(let d of o)d.begin<u&&n.add(d.item),u=Math.max(u,d.end);let y=Number.POSITIVE_INFINITY;for(let d=o.length-1;d>=0;d-=1){let b=o[d];b!==void 0&&(b.end>y&&n.add(b.item),y=Math.min(y,b.begin))}}}for(let s of r){let f=0;for(let o of s.items){if(o.step.valueAfterEnd==="unstated"&&n.has(o)){p.push({step:o.step,reason:"notModelled"});for(let u of o.step.targetShapeIds)R.add(String(u));continue}s.items[f]=o,f+=1}s.items.length=f}},C=()=>{for(let e of l)clearTimeout(e);l.length=0;for(let e of a)e.cancel();a.length=0;for(let e of I.values())for(let n of e)n.cancel();I.clear(),h.clear(),M.clear(),T.clear()},$=(e,n)=>{let s=e.indexOf(n);s>=0&&e.splice(s,1)},Y=()=>{P||(l.length===0&&a.length===0&&(O=null),i(x))},ae=e=>{E.add(e),e.style.transformBox="fill-box",e.style.transformOrigin="50% 50%"},U=e=>{e.style.transformBox="",e.style.transformOrigin=""},ue=e=>{E.add(e),e.style.visibility="",e.style.opacity="",U(e)},de=e=>{E.add(e),e.style.visibility="hidden",e.style.opacity="",U(e)},H=null,V=!0,w=new Map,B=new Map,K=0,L=e=>e.stopIndex<K||T.has(e.item),X=()=>{for(let e of w.values()){e.top=null;for(let s of e.gates)L(s)&&(e.top=s);let n=e.gates[0];e.firstPlayed=n!==void 0&&L(n)}},G=()=>{let e=m(),n=w.keys().next();if(!(e===H&&n.done!==!0&&n.value.isConnected&&V)){H=e,V=!0,ie(e),w=new Map,B=new Map,r.forEach((s,f)=>{for(let o of s.items){let u=[];for(let y of oe(e,o.step,R)){let d=w.get(y)??{list:[],gates:[],top:null,firstPlayed:!1};w.set(y,d);let b={item:o,stopIndex:f,order:0};d.list.push(b),o.kind!=="emphasis"&&d.gates.push(b);let A=xe(o,y,e);A===null&&Ie(o)&&(V=!1),u.push({el:y,plan:d,entry:b,movement:A})}B.set(o,u)}});for(let s of w.values()){let f=(o,u)=>o.stopIndex-u.stopIndex||o.item.begin-u.item.begin;s.list.sort(f),s.gates.sort(f),s.list.forEach((o,u)=>{o.order=u})}X()}},ce=e=>{let n=e.gates[0];return n===void 0?!0:n.item.kind==="entrance"&&!e.firstPlayed?!1:e.top===null||e.top.item.kind!=="exit"},J=(e,n)=>{h.has(e)||(ce(n)?ue(e):de(e))},F=e=>{T.clear(),K=e,G(),X();for(let[n,s]of w)J(n,s)},j=e=>{let{plan:n,entry:s}=e;s.item.kind!=="emphasis"&&(s===n.gates[0]&&(n.firstPlayed=!0),(n.top===null||s.order>n.top.order)&&(n.top=s)),J(e.el,n)},D=e=>{T.add(e),G();for(let n of B.get(e)??[])j(n)},Q=(e,n)=>{G();let s=B.get(e)??[];if(s.length===0){D(e);return}let f=s.filter(A=>A.movement!==null),o=e.duration,u=Math.max(0,n),y=o===null||o===0||u>=o,d=e.step.valueAfterEnd!=="removed";if(c()||f.length===0||y&&(!d||!f.some(A=>h.has(A.el)))){D(e);return}for(let A of s)A.movement===null&&j(A);let b=y?0:o;M.set(e,f.length);for(let A of f){let v=A.el,ee=A.movement;E.add(v),e.kind!=="emphasis"&&(v.style.visibility=""),ee.aboutOwnCentre&&ae(v),h.set(v,(h.get(v)??0)+1);let N=v.animate(ee.frames,{duration:b,fill:"both"});N.currentTime=y?b:u,a.push(N),N.finished.then(()=>{if(P)return;$(a,N);let _=(h.get(v)??1)-1;if(_<=0||!d){if(_<=0){h.delete(v);for(let q of I.get(v)??[])q.cancel();I.delete(v)}else h.set(v,_);N.cancel()}else{h.set(v,_);let q=I.get(v);q===void 0?I.set(v,[N]):q.push(N)}j(A);let ne=(M.get(e)??1)-1;M.set(e,ne),ne<=0&&D(e),Y()},()=>{})}},W=(e,n)=>{let s=r[e];if(s===void 0)return;let f=Math.max(0,n);O=re()-f;let o=[...s.items].sort((u,y)=>u.begin-y.begin);for(let u of o){let y=u.begin-f;if(c()||y<=0){Q(u,f-u.begin);continue}let d=setTimeout(()=>{$(l,d),Q(u,0),Y()},y);l.push(d)}},Z=e=>Math.max(0,Math.min(Number.isFinite(e)?Math.round(e):0,r.length)),x={get cursor(){return g},get stopCount(){return r.length},get pending(){return g<r.length},get running(){return l.length>0||a.length>0},get progress(){return{cursor:g,stops:r.length,elapsed:O===null?null:Math.round(re()-O),generation:k}},get unsupported(){return[...p]},reset(){k+=1,C(),O=null,g=0,F(0),i(x),r[0]?.auto===!0&&x.advance()},advance(){if(P||g>=r.length)return!1;k+=1,C(),F(g);let e=g;return g+=1,W(e,0),i(x),!0},back(){return P||g<=0?!1:(k+=1,C(),O=null,g-=1,F(g),i(x),!0)},jumpTo(e){P||(k+=1,C(),O=null,g=Z(e),F(g),i(x))},resume(e,n){P||(k+=1,C(),O=null,g=Z(e),g>0&&n!==null&&Number.isFinite(n)?(F(g-1),W(g-1,n)):F(g),i(x))},finish(){x.jumpTo(r.length)},dispose(){if(!P){P=!0,C();for(let e of E)e.style.visibility="",e.style.opacity="",U(e);E.clear()}}};return G(),x};export{Se as buildAnimationStops,Me as createAnimationPlayer};
|
|
1
|
+
var St=["appear","disappear"],Ft=["blinds","checkerboard","peek","randomBars","shape","split","strips","wedge","wheel","wipe"],Dt={entr:"entrance",exit:"exit",emph:"emphasis"},It=t=>{if(St.includes(t))return"none";let o=t.replace(/(In|Out)$/,"");return o==="fly"||o==="credits"?"fly":o==="peek"?"peek":Ft.includes(o)?"filter":"pose"},Bt={fade:{opacity:0},dissolve:{opacity:0},expand:{opacity:0,scale:"0.7 1"},contract:{opacity:0,scale:"0.7 1"},swivel:{opacity:0,scale:"0 1"},zoom:{opacity:0,scale:"0"},basicZoom:{scale:"0"},float:{opacity:0,translate:"0% 50%"},growTurn:{opacity:0,scale:"0",rotate:"90deg"},shrinkTurn:{opacity:0,scale:"0",rotate:"90deg"},spinner:{opacity:0,scale:"0",rotate:"-90deg"},stretch:{scale:"0 1"},stretchy:{scale:"0 1"},collapse:{scale:"0 1"},pinwheel:{opacity:0,scale:"0",rotate:"720deg"},spiral:{scale:"0",translate:"-100% 100%"},basicSwivel:{scale:"0 1"}},Lt={opacity:1,scale:"1",rotate:"0deg",translate:"0% 0%"},Gt=t=>Object.fromEntries(Object.keys(t).map(o=>[o,Lt[o]])),Y=(t,o)=>[{filter:t},{filter:o}],Ot=(t,o)=>[{filter:t},{filter:o},{filter:t}],N=Y("hue-rotate(0deg)","hue-rotate(180deg)"),ut=Ot("contrast(1)","contrast(1.8)"),Ut={pulse:[{offset:0,scale:"1",opacity:1},{offset:.2,opacity:.5},{offset:.5,scale:"1.05"},{offset:.8,opacity:.5},{offset:1,scale:"1",opacity:1}],teeter:[{offset:0,rotate:"0deg"},{offset:.1,rotate:"2deg"},{offset:.2,rotate:"2deg"},{offset:.4,rotate:"-2deg"},{offset:.6,rotate:"2deg"},{offset:.8,rotate:"-2deg"},{offset:1,rotate:"0deg"}],wave:[{offset:0,translate:"0% 0%",rotate:"0deg",easing:"ease-in-out"},{offset:.25,rotate:"25deg"},{offset:.5,translate:"0% -20%",rotate:"0deg",easing:"ease-in-out"},{offset:.75,rotate:"-25deg"},{offset:1,translate:"0% 0%",rotate:"0deg"}],shimmer:[{scale:"1",translate:"0% 0%",rotate:"0deg"},{scale:"0.8 1",translate:"10% -10%",rotate:"-8deg"},{scale:"1",translate:"0% 0%",rotate:"0deg"}],blink:[{offset:0,opacity:0,easing:"step-end"},{offset:.5,opacity:1},{offset:1,opacity:1}],fillColor:N,lineColor:N,fontColor:N,objectColor:N,brushColor:N,complementaryColor:N,complementaryColor2:N,contrastingColor:N,darken:Y("brightness(1)","brightness(0.6)"),lighten:Y("brightness(1)","brightness(1.4)"),desaturate:Y("saturate(1)","saturate(0)"),colorPulse:Ot("brightness(1)","brightness(1.4)"),growWithColor:[{scale:"1",filter:"hue-rotate(0deg)"},{scale:"1.1",filter:"hue-rotate(180deg)"}],boldFlash:[{offset:0,filter:"contrast(1)",easing:"step-end"},{offset:.5,filter:"contrast(1.8)",easing:"step-end"},{offset:.6,filter:"contrast(1)"},{offset:1,filter:"contrast(1)"}],boldReveal:ut,underline:ut},Vt=t=>{switch(t.effect){case"spin":return[{rotate:"0deg"},{rotate:`${(t.spinDirection==="counterclockwise"?-1:1)*(t.spinDegrees??360)}deg`}];case"growShrink":{let o=(t.scalePercent??150)/100;return[{scale:"1"},{scale:t.scaleDirection==="horizontal"?`${o} 1`:t.scaleDirection==="vertical"?`1 ${o}`:`${o}`}]}case"transparency":return[{opacity:1},{opacity:1-(t.transparencyPercent??50)/100}];default:return null}},jt=(t,o)=>{for(let s=1;s<t.length;s+=1){let[e,r]=t[s],[a,i]=t[s-1];if(o<=e)return i+(r-i)*(o-a)/(e-a)}return 1},Ht=[[0,0],[.14,.36],[.43,.73],[.71,.91],[1,1]],dt=1822,pt=[664,1324,1656,1822],qt=[1/9,1/27,1/81],zt=[[0,0,.31],[.25,.1096,.2646],[.5,.155,.155],[.75,.1096,.0454],[1,0,0]],z=[[-.46736,.92887],[.0908,.66613],[.23177,.40825],[.18264,.09152],[0,0]],p=(t,o,s={})=>o===null?null:{offset:t,translate:o,...s},k=t=>t.every(o=>o!==null)?t:null,ht={bounce:t=>{let o=(e,r,a)=>p(e/dt,t.shift(-.25*(1-jt(Ht,e/dt)),-r),{easing:a}),s=[o(0,.3333333333333333,"ease-in")];return pt.forEach((e,r)=>{s.push(o(e,0,"ease-out"));let a=pt[r+1];a!==void 0&&s.push(o((e+a)/2,qt[r],"ease-in"))}),k(s)},boomerang:t=>k([p(0,t.shift(.4,-.2),{rotate:"-90deg",scale:"1 1",opacity:0,easing:"ease-out"}),p(.5,t.shift(0,.1),{rotate:"0deg",scale:"0.05 1",opacity:.5,easing:"ease-in"}),p(1,t.shift(0,0),{rotate:"0deg",scale:"1 1",opacity:1})]),centerRevolve:t=>k([p(0,t.shift(0,.31),{opacity:0}),p(.1,t.shift(0,.31),{opacity:1}),...zt.map(([o,s,e])=>p(.4+.6*o,t.shift(s,e),{opacity:1}))]),riseUp:t=>k([p(0,t.shift(0,1),{opacity:0,easing:"ease-out"}),p(.9,t.shift(0,-.03),{opacity:.9,easing:"ease-in"}),p(1,t.shift(0,0),{opacity:1})]),floating:t=>k([p(0,t.shift(.4,-.4),{rotate:"-90deg",opacity:0,easing:"ease-out"}),p(.8,t.shift(-.05,.1),{rotate:"0deg",opacity:1,easing:"ease-in"}),p(1,t.shift(0,0),{rotate:"0deg",opacity:1})]),whip:t=>k([p(0,t.shift(0,0),{scale:"0.1",opacity:0}),p(.5,t.shift(.1,0),{scale:"1.02",opacity:1}),p(1,t.shift(0,0),{scale:"1",opacity:1})]),curveUp:t=>k(z.map(([o,s],e)=>p(e/(z.length-1),t.shift(o,s),{scale:`${2.5-1.5*e/(z.length-1)}`,opacity:e/(z.length-1)}))),drop:t=>k([p(0,t.shift(0,-1),{rotate:"-45deg",easing:"ease-in"}),p(.455,t.shift(0,0,0,-10),{rotate:"-45deg",easing:"ease-out"}),p(.611,t.shift(0,0,0,-50),{rotate:"0deg",easing:"ease-in"}),p(.767,t.shift(0,0,0,-10),{rotate:"42deg"}),p(.864,t.shift(0,0,0,-10),{rotate:"15deg"}),p(.91,t.shift(0,0,0,-5),{rotate:"0deg"}),p(1,t.shift(0,0),{rotate:"0deg"})]),flip:t=>Et(t,"top")},Et=(t,o)=>{let s=t.past(o);if(s===null)return null;let e=(d,c)=>`calc(${s.dx*d}px + ${c}%) calc(${s.dy*d}px + 0%)`,r=o==="top",a=r?1:0,i=r?0:1;return[{offset:0,translate:e(a,0),scale:"1 1",rotate:"0deg"},{offset:.5,translate:e(.5,50),scale:"-1 1",rotate:"180deg"},{offset:1,translate:e(i,0),scale:"1 1",rotate:"360deg"}]},Kt={drop:t=>k([p(0,t.shift(0,0),{rotate:"0deg",easing:"ease-in"}),p(1,t.shift(0,1),{rotate:"45deg"})]),flip:t=>Et(t,"bottom")},Yt={sinkDown:"riseUp",curveDown:"curveUp"},Wt={"ease-in":"ease-out","ease-out":"ease-in"},Xt=t=>{let o=t.length;return t.map((s,e)=>{let r={...t[o-1-e]};delete r.easing,typeof r.offset=="number"&&(r.offset=1-r.offset);let a=t[o-2-e]?.easing;return typeof a=="string"&&(r.easing=Wt[a]??a),r})},xt=t=>{let o=t.step.effect?.replace(/(In|Out)$/,"");if(o===void 0)return;if(t.kind==="entrance")return ht[o];let s=Kt[o];if(s!==void 0)return s;let e=ht[Yt[o]??o];return e===void 0?void 0:r=>{let a=e(r);return a===null?null:Xt(a)}},gt=t=>t instanceof HTMLElement||t instanceof SVGElement?t:null,Qt=t=>t.effect===null||t.presetClass===null?null:Dt[t.presetClass]??null,Zt=t=>t.durationMs!==null&&Number.isFinite(t.durationMs)&&t.durationMs>=0?t.durationMs:t.effect!==null&&St.includes(t.effect)?0:null,Ct=t=>{let o=[],s=[],e=(c,w)=>{s.push({step:c,reason:w})},r=null,a=0,i=0,d=!1;for(let c of t??[]){if(c.sequence!=="mainSeq"){e(c,"notInMainSeq");continue}let w=!d;if(d=!0,c.start==="unknown"){a=null,i=null,e(c,"notModelled");continue}c.start==="click"||w?(r={items:[],auto:w&&c.start!=="click"},o.push(r),a=0,i=0):c.start==="afterPrevious"&&(a=i,i=a);let y=c.playable?Qt(c):null,E=y===null?null:Zt(c),M=c.delayMs;if(y===null||M===null||a===null){e(c,y===null||M===null?"notModelled":"unknownTiming"),i=null;continue}let _=a+M;r?.items.push({step:c,kind:y,begin:_,duration:E}),i=E===null||i===null?null:Math.max(i,_+E)}return{stops:o,unsupported:s}},kt=t=>`[data-pptx-shape-id="${t}"]`,mt=(t,o,s)=>{let e=o.target;if(e.kind!=="shape"&&e.kind!=="paragraphs")return[];if(!Number.isInteger(e.shapeId))return[];let r=String(e.shapeId);if(s.has(r))return[];let a=t.querySelectorAll(kt(r)),i=a.length===1?gt(a[0]):null;if(i===null)return[];if(e.kind!=="paragraphs")return[i];let d=[];for(let c of i.querySelectorAll("[data-pptx-paragraph]")){if(c.closest("[data-pptx-shape-id]")!==i)continue;let w=Number(c.getAttribute("data-pptx-paragraph"));if(w<e.firstParagraph||w>e.lastParagraph)continue;let y=gt(c);y!==null&&d.push(y)}return d},yt=()=>typeof performance=="object"?performance.now():Date.now(),Mt=(t,o)=>{let s=t.closest("svg");return s!==null?s.getBoundingClientRect():o instanceof Element?o.getBoundingClientRect():null},Jt=t=>{if(t instanceof SVGGraphicsElement)return t.getScreenCTM();let o=t.closest("foreignObject");return o instanceof SVGGraphicsElement?o.getScreenCTM():null},Tt=(t,o,s)=>{let e=Mt(t,s);if(e===null||e.width<=0||e.height<=0)return null;let r=t.getBoundingClientRect(),a=o.toLowerCase();return At(t,a.includes("right")?e.right-r.left:a.includes("left")?e.left-r.right:0,a.includes("bottom")?e.bottom-r.top:a.includes("top")?e.top-r.bottom:0)},At=(t,o,s)=>{let e=Jt(t);if(e===null)return{dx:o,dy:s};let r=e.a*e.d-e.b*e.c;return r===0?null:{dx:(e.d*o-e.c*s)/r,dy:(e.a*s-e.b*o)/r}},te=(t,o)=>({shift(s,e,r=0,a=0){let i=Mt(t,o);if(i===null||i.width<=0||i.height<=0)return null;let d=At(t,s*i.width,e*i.height);return d===null?null:`calc(${d.dx}px + ${r}%) calc(${d.dy}px + ${a}%)`},past(s){return Tt(t,s,o)}}),ee=t=>t.step.effect!==null&&(It(t.step.effect)==="fly"||xt(t)!==void 0),ne=(t,o,s)=>{let e=t.step.effect,r=t.kind==="entrance";if(e===null)return null;switch(It(e)){case"none":return null;case"pose":{if(t.kind==="emphasis"){let c=Vt(t.step)??Ut[e];return c===void 0?null:{frames:c,aboutOwnCentre:!0}}let a=xt(t);if(a!==void 0){let c=a(te(o,s));return c===null?null:{frames:c,aboutOwnCentre:!0}}let i=Bt[e.replace(/(In|Out)$/,"")];if(i===void 0)return null;let d=Gt(i);return{frames:r?[i,d]:[d,i],aboutOwnCentre:!0}}case"fly":{let a=e==="creditsIn"?"bottom":e==="creditsOut"?"top":t.step.direction;if(a===null)return null;let i=Tt(o,a,s);if(i===null)return null;let d={translate:`${i.dx}px ${i.dy}px`},c={translate:"0px 0px"};return{frames:r?[d,c]:[c,d],aboutOwnCentre:!1}}case"filter":case"peek":{let a=ce(t.step);if(a===null)return null;let i={clipPath:a.covered},d={clipPath:a.uncovered},c=t.step.direction===null?void 0:oe[t.step.direction];if(e==="peekIn"||e==="peekOut"){if(c===void 0)return null;i.translate=`${c[0]*112.5}% ${c[1]*112.5}%`,d.translate="0% 0%"}return{frames:r?[i,d]:[d,i],aboutOwnCentre:!0}}}},oe={top:[0,-1],bottom:[0,1],left:[-1,0],right:[1,0]},se={top:"bottom",bottom:"top",left:"right",right:"left"},re={top:"inset(0% 0% 100% 0%)",bottom:"inset(100% 0% 0% 0%)",left:"inset(0% 100% 0% 0%)",right:"inset(0% 0% 0% 100%)"},ae={topLeft:[0,0],topRight:[100,0],bottomLeft:[0,100],bottomRight:[100,100]},x=(t,o=!1)=>`polygon(${o?"evenodd, ":""}${t.map(([s,e])=>`${s}% ${e}%`).join(", ")}) fill-box`,vt=[[0,0],[100,0],[100,100],[0,100]],B=(t,o,s)=>{let e=[];for(let r=0;r<t;r++){let a=100*r/t,i=a+100*s/t;o?e.push([0,a],[100,a],[100,i],[0,i]):e.push([a,0],[a,100],[i,100],[i,0])}return x(e)},bt=50*Math.SQRT2,wt=32,ie=12,K=(t,o)=>{let s=(e,r)=>[50+e*o,50+r*o];switch(t){case"box":return[s(-50,-50),s(50,-50),s(50,50),s(-50,50)];case"diamond":return[s(0,-100),s(100,0),s(0,100),s(-100,0)];case"plus":return[s(-50,-100),s(50,-100),s(50,-50),s(100,-50),s(100,50),s(50,50),s(50,100),s(-50,100),s(-50,50),s(-100,50),s(-100,-50),s(-50,-50)];default:return Array.from({length:wt},(e,r)=>{let a=2*Math.PI*r/wt;return s(bt*Math.cos(a),bt*Math.sin(a))})}},G=(t,o)=>[[50,50],...Array.from({length:13},(s,e)=>{let r=2*Math.PI*(t+o*e/ie);return[50+100*Math.sin(r),50-100*Math.cos(r)]})],ce=t=>{let o=t.effect;if(o===null)return null;let s=o.replace(/(In|Out)$/,""),e=t.orientation!=="vertical";switch(s){case"wipe":case"peek":{let r=t.direction===null?void 0:s==="peek"?se[t.direction]:t.direction,a=r===void 0?void 0:re[r];return a===void 0?null:{covered:`${a} fill-box`,uncovered:"inset(0% 0% 0% 0%) fill-box"}}case"blinds":return{covered:B(6,e,0),uncovered:B(6,e,1)};case"randomBars":return{covered:B(16,e,0),uncovered:B(16,e,1)};case"checkerboard":return{covered:B(8,!e,0),uncovered:B(8,!e,1)};case"split":{let r=t.orientation==="vertical";if(t.inOut==="out"){let i=d=>{let c=`${50-d/2}%`;return r?`inset(0% ${c} 0% ${c}) fill-box`:`inset(${c} 0% ${c} 0%) fill-box`};return{covered:i(0),uncovered:i(100)}}let a=i=>x(r?[[0,0],[i,0],[i,100],[100-i,100],[100-i,0],[100,0],[100,100],[0,100]]:[[0,0],[100,0],[100,i],[0,i],[0,100-i],[100,100-i],[100,100],[0,100]]);return{covered:a(0),uncovered:a(50)}}case"shape":{let r=t.shape??"circle";return t.inOut==="out"?{covered:x(K(r,0)),uncovered:x(K(r,1))}:{covered:x([...vt,...K(r,1)],!0),uncovered:x([...vt,...K(r,0)],!0)}}case"strips":{let r=t.direction===null?void 0:ae[t.direction];if(r===void 0)return null;let[a,i]=r,d=a===0?1:-1,c=i===0?1:-1,w=y=>x([[a,i],[a+d*y,i],[a,i+c*y]]);return{covered:w(0),uncovered:w(200)}}case"wedge":return{covered:x([...G(0,0),...G(0,0)]),uncovered:x([...G(0,.5),...G(0,-.5)])};case"wheel":{let r=t.spokes??1,a=i=>x(Array.from({length:r},(d,c)=>G(c/r,i/r)).flat());return{covered:a(0),uncovered:a(1)}}default:return null}},le=t=>{let o=()=>typeof t.root=="function"?t.root():t.root,s=Ct(t.steps),e=s.stops,r=[...s.unsupported],a=()=>t.reducedMotion?.()===!0,i=t.onChange??(()=>{}),d=[],c=[],w=new Set,y=new Map,E=new Map,M=new Map,_=new Set,b=0,T=!1,A=null,R=0,L=new Set;for(let n of r)for(let l of n.step.targetShapeIds)L.add(String(l));let U=new Map;for(let n of e)for(let l of n.items){let u=String(l.step.target.shapeId);U.has(u)||U.set(u,o().querySelectorAll(kt(u)).length)}for(let n of e)for(let l of n.items)(U.get(String(l.step.target.shapeId))??0)>1&&r.push({step:l.step,reason:"ambiguousTarget"});for(let[n,l]of U)l>1&&L.add(n);let Nt=n=>{let l=new Set;for(let u of e){let m=new Map;for(let f of u.items){let h=f.duration===null?Number.POSITIVE_INFINITY:f.begin+f.duration;for(let v of mt(n,f.step,L)){let g={item:f,begin:f.begin,end:h},S=m.get(v);S===void 0?m.set(v,[g]):S.push(g)}}for(let f of m.values()){if(f.length<2)continue;f.sort((g,S)=>g.begin-S.begin);let h=Number.NEGATIVE_INFINITY;for(let g of f)g.begin<h&&l.add(g.item),h=Math.max(h,g.end);let v=Number.POSITIVE_INFINITY;for(let g=f.length-1;g>=0;g-=1){let S=f[g];S!==void 0&&(S.end>v&&l.add(S.item),v=Math.min(v,S.begin))}}}for(let u of e){let m=0;for(let f of u.items){if(f.step.valueAfterEnd==="unstated"&&l.has(f)){r.push({step:f.step,reason:"notModelled"});for(let h of f.step.targetShapeIds)L.add(String(h));continue}u.items[m]=f,m+=1}u.items.length=m}},F=()=>{for(let n of c)clearTimeout(n);c.length=0;for(let n of d)n.cancel();d.length=0;for(let n of E.values())for(let l of n)l.cancel();E.clear(),y.clear(),M.clear(),_.clear()},J=(n,l)=>{let u=n.indexOf(l);u>=0&&n.splice(u,1)},tt=()=>{T||(c.length===0&&d.length===0&&(A=null),i(C))},_t=n=>{w.add(n),n.style.transformBox="fill-box",n.style.transformOrigin="50% 50%"},W=n=>{n.style.transformBox="",n.style.transformOrigin=""},$t=n=>{w.add(n),n.style.visibility="",n.style.opacity="",W(n)},Pt=n=>{w.add(n),n.style.visibility="hidden",n.style.opacity="",W(n)},et=null,X=!0,$=new Map,V=new Map,nt=0,ot=n=>n.stopIndex<nt||_.has(n.item),st=()=>{for(let n of $.values()){n.top=null;for(let u of n.gates)ot(u)&&(n.top=u);let l=n.gates[0];n.firstPlayed=l!==void 0&&ot(l)}},j=()=>{let n=o(),l=$.keys().next();if(!(n===et&&l.done!==!0&&l.value.isConnected&&X)){et=n,X=!0,Nt(n),$=new Map,V=new Map,e.forEach((u,m)=>{for(let f of u.items){let h=[];for(let v of mt(n,f.step,L)){let g=$.get(v)??{list:[],gates:[],top:null,firstPlayed:!1};$.set(v,g);let S={item:f,stopIndex:m,order:0};g.list.push(S),f.kind!=="emphasis"&&g.gates.push(S);let O=ne(f,v,n);O===null&&ee(f)&&(X=!1),h.push({el:v,plan:g,entry:S,movement:O})}V.set(f,h)}});for(let u of $.values()){let m=(f,h)=>f.stopIndex-h.stopIndex||f.item.begin-h.item.begin;u.list.sort(m),u.gates.sort(m),u.list.forEach((f,h)=>{f.order=h})}st()}},Rt=n=>{let l=n.gates[0];return l===void 0?!0:l.item.kind==="entrance"&&!n.firstPlayed?!1:n.top===null||n.top.item.kind!=="exit"},rt=(n,l)=>{y.has(n)||(Rt(l)?$t(n):Pt(n))},D=n=>{_.clear(),nt=n,j(),st();for(let[l,u]of $)rt(l,u)},Q=n=>{let{plan:l,entry:u}=n;u.item.kind!=="emphasis"&&(u===l.gates[0]&&(l.firstPlayed=!0),(l.top===null||u.order>l.top.order)&&(l.top=u)),rt(n.el,l)},Z=n=>{_.add(n),j();for(let l of V.get(n)??[])Q(l)},at=(n,l)=>{j();let u=V.get(n)??[];if(u.length===0){Z(n);return}let m=u.filter(O=>O.movement!==null),f=n.duration,h=Math.max(0,l),v=f===null||f===0||h>=f,g=n.step.valueAfterEnd!=="removed";if(a()||m.length===0||v&&(!g||!m.some(O=>y.has(O.el)))){Z(n);return}for(let O of u)O.movement===null&&Q(O);let S=v?0:f;M.set(n,m.length);for(let O of m){let I=O.el,lt=O.movement;w.add(I),n.kind!=="emphasis"&&(I.style.visibility=""),lt.aboutOwnCentre&&_t(I),y.set(I,(y.get(I)??0)+1);let P=I.animate(lt.frames,{duration:S,fill:"both"});P.currentTime=v?S:h,d.push(P),P.finished.then(()=>{if(T)return;J(d,P);let H=(y.get(I)??1)-1;if(H<=0||!g){if(H<=0){y.delete(I);for(let q of E.get(I)??[])q.cancel();E.delete(I)}else y.set(I,H);P.cancel()}else{y.set(I,H);let q=E.get(I);q===void 0?E.set(I,[P]):q.push(P)}Q(O);let ft=(M.get(n)??1)-1;M.set(n,ft),ft<=0&&Z(n),tt()},()=>{})}},it=(n,l)=>{let u=e[n];if(u===void 0)return;let m=Math.max(0,l);A=yt()-m;let f=[...u.items].sort((h,v)=>h.begin-v.begin);for(let h of f){let v=h.begin-m;if(a()||v<=0){at(h,m-h.begin);continue}let g=setTimeout(()=>{J(c,g),at(h,0),tt()},v);c.push(g)}},ct=n=>Math.max(0,Math.min(Number.isFinite(n)?Math.round(n):0,e.length)),C={get cursor(){return b},get stopCount(){return e.length},get pending(){return b<e.length},get running(){return c.length>0||d.length>0},get progress(){return{cursor:b,stops:e.length,elapsed:A===null?null:Math.round(yt()-A),generation:R}},get unsupported(){return[...r]},reset(){R+=1,F(),A=null,b=0,D(0),i(C),e[0]?.auto===!0&&C.advance()},advance(){if(T||b>=e.length)return!1;R+=1,F(),D(b);let n=b;return b+=1,it(n,0),i(C),!0},back(){return T||b<=0?!1:(R+=1,F(),A=null,b-=1,D(b),i(C),!0)},jumpTo(n){T||(R+=1,F(),A=null,b=ct(n),D(b),i(C))},resume(n,l){T||(R+=1,F(),A=null,b=ct(n),b>0&&l!==null&&Number.isFinite(l)?(D(b-1),it(b-1,l)):D(b),i(C))},finish(){C.jumpTo(e.length)},dispose(){if(!T){T=!0,F();for(let n of w)n.style.visibility="",n.style.opacity="",W(n);w.clear()}}};return j(),C};export{Ct as buildAnimationStops,le as createAnimationPlayer};
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as editorStore,
|
|
2
|
+
import { a as editorStore, i as initProject, n as exportDeck, o as sourceFingerprint, r as inspectTemplate, s as createDeckBuilder } from "./src-DASlwPDd.mjs";
|
|
3
3
|
import { n as renderDeck } from "./build-cpmt-r9Q.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { chmod, lstat, mkdir, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
@@ -7,6 +7,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "nod
|
|
|
7
7
|
import { watch } from "node:fs";
|
|
8
8
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
9
9
|
import { getGroupChildren, getShapeBounds, getShapeId, getShapeKind, getShapeRotation, getShapeXmlString, getSlideShapes, getSlideXmlString, getSlides, loadPresentation } from "@office-kit/pptx";
|
|
10
|
+
import { mergeDecks } from "@office-kit/pptx-editor/merge";
|
|
10
11
|
import { planPropEdit, planTextEdit, verifyTextEdit } from "@office-kit/pptx-dsl/source-edit";
|
|
11
12
|
import { chromium } from "playwright";
|
|
12
13
|
import { createServer } from "node:http";
|
|
@@ -638,7 +639,7 @@ const previewJapanese={
|
|
|
638
639
|
'Changes appear automatically · Text can be selected and copied':'変更は自動的に反映されます・文字を選択してコピーできます',
|
|
639
640
|
'Skipped during presentation':'プレゼンテーションでスキップされます',
|
|
640
641
|
'Allow popups to open presenter view.':'発表者ビューを開くにはポップアップを許可してください。',
|
|
641
|
-
'
|
|
642
|
+
'Presentation preview':'プレゼンテーションのプレビュー'
|
|
642
643
|
};
|
|
643
644
|
const pt=key=>previewLocale==='ja'?(previewJapanese[key]??key):key;
|
|
644
645
|
const slideLabel=i=>previewLocale==='ja'?'スライド '+(i+1):'Slide '+(i+1);
|
|
@@ -647,7 +648,7 @@ function updatePreviewStatus(){
|
|
|
647
648
|
byId('status').textContent=connectionLost?pt('Reconnecting…'):state.error?pt('Build failed · showing last successful output'):state.building?pt('Updating…'):previewLocale==='ja'?state.slides.length+' スライド・ライブ':state.slides.length+' slides · Live';
|
|
648
649
|
}
|
|
649
650
|
function updatePreviewLabels(){
|
|
650
|
-
document.documentElement.lang=previewLocale;document.title=pt('
|
|
651
|
+
document.documentElement.lang=previewLocale;document.title=pt('Presentation preview');
|
|
651
652
|
const labels={'#present':'Present','#presenter':'Presenter view','.download':'Download PPTX','#toggle-chat span':'Agents','#agents-title':'Agents','.filmstrip h2':'Slides','#empty':'Waiting for slides…','footer .hint':'Changes appear automatically · Text can be selected and copied','label[for="zoom"]':'Zoom','#zoom option[value="fit"]':'Fit'};
|
|
652
653
|
for(const [selector,key] of Object.entries(labels))document.querySelector(selector).textContent=pt(key);
|
|
653
654
|
for(const [selector,key] of Object.entries({'.filmstrip':'Slides','main':'Slide viewer','#chat-resizer':'Chat width','#close-chat':'Close Agents','#toggle-editor':'Normal','.status-views':'Presentation views','#prev':'Previous slide','#present-prev':'Previous slide','#next':'Next slide','#present-next':'Next slide'}))document.querySelector(selector).setAttribute('aria-label',pt(key));
|
|
@@ -686,6 +687,13 @@ function renderSlide(svg,options){
|
|
|
686
687
|
const style='<style>svg{display:block;width:100%;height:100%}.transition-layer{position:absolute;inset:0;background:white;overflow:hidden}.transition-old{pointer-events:none}</style>';
|
|
687
688
|
canvas.innerHTML=svg?style+svg:'';
|
|
688
689
|
const playableEffects=['fade','push','wipe','cover','pull','zoom','split','circle','diamond','plus','blinds','comb','checker','strips','randomBar','dissolve','wedge','newsflash','wheel'];
|
|
690
|
+
// The reference desktop app (2010+) effects (p14 / p15 / p159) play as the nearest flat
|
|
691
|
+
// effect above: their 3-D turns, particles and page curls are not drawn.
|
|
692
|
+
const approximations={morph:'fade',flash:'fade',reveal:'fade',prstTrans:'fade',honeycomb:'dissolve',glitter:'dissolve',vortex:'dissolve',shred:'dissolve',ripple:'circle',switch:'push',flip:'push',gallery:'push',conveyor:'push',ferris:'push',pan:'push',prism:'push',doors:'split',window:'split',warp:'zoom',flythrough:'zoom',wheelReverse:'wheel'};
|
|
693
|
+
const alias=Object.hasOwn(approximations,options?.effect??'')?approximations[options.effect]:undefined;
|
|
694
|
+
if(alias)options=alias==='split'
|
|
695
|
+
?{...options,effect:alias,orientation:options.direction==='horz'?'horz':'vert',direction:'out'}
|
|
696
|
+
:{...options,effect:alias};
|
|
689
697
|
// Choose per visit without replacing the persisted random transition or its timing.
|
|
690
698
|
const effect=options?.effect==='random'?playableEffects[Math.floor(Math.random()*playableEffects.length)]:options?.effect;
|
|
691
699
|
if(!previous||!svg||reducedMotion.matches||(effect==='cut'&&!options.thruBlack)||!(effect==='cut'||playableEffects.includes(effect)))return;
|
|
@@ -694,8 +702,9 @@ function renderSlide(svg,options){
|
|
|
694
702
|
outgoing.className='transition-layer transition-old';outgoing.innerHTML=previousMarkup;
|
|
695
703
|
outgoing.setAttribute('aria-hidden','true');outgoing.inert=true;
|
|
696
704
|
canvas.innerHTML=style;canvas.append(outgoing,incoming);
|
|
697
|
-
//
|
|
698
|
-
|
|
705
|
+
// The reference desktop app plays fast/med/slow as 0.5/0.75/1 s; p14:dur overrides them.
|
|
706
|
+
// No spd is the schema default, fast.
|
|
707
|
+
const duration=options.durationMs??(options.speed==='slow'?1000:options.speed==='med'?750:500);
|
|
699
708
|
const timing={duration,easing:'ease-in-out',fill:'both'};
|
|
700
709
|
const animate=(node,frames,easing=timing.easing)=>transitionAnimations.push(node.animate(frames,{...timing,easing}));
|
|
701
710
|
const vectors={l:[-100,0],r:[100,0],u:[0,-100],d:[0,100],lu:[-100,-100],ru:[100,-100],ld:[-100,100],rd:[100,100]};
|
|
@@ -986,7 +995,7 @@ body{display:flex;flex-direction:column;background:var(--ok-panel);height:100dvh
|
|
|
986
995
|
const page = `<!doctype html>
|
|
987
996
|
<html lang="en">
|
|
988
997
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width">
|
|
989
|
-
<title>
|
|
998
|
+
<title>Presentation preview</title>
|
|
990
999
|
<link rel="stylesheet" href="/terminal.css">
|
|
991
1000
|
<style>
|
|
992
1001
|
${previewStyles}
|
|
@@ -1116,7 +1125,7 @@ function moveSlide(step,skipHidden=presenting,focusThumbnail=false){
|
|
|
1116
1125
|
const nextPosition=skipHidden&&presenting?nextShowPosition(step):-1;
|
|
1117
1126
|
const next=skipHidden&&presenting?(nextPosition<0?-1:showOrder[nextPosition]):findSlide(index+step,step,skipHidden);
|
|
1118
1127
|
// Arriving backwards lands on a slide that has already played out, the way
|
|
1119
|
-
//
|
|
1128
|
+
// the reference desktop app shows it; arriving forwards starts its build from the top.
|
|
1120
1129
|
if(next>=0){
|
|
1121
1130
|
selectSlide(next,focusThumbnail,true,step<0?'end':'start',nextPosition);
|
|
1122
1131
|
if(presenting&&step>0&&nextPosition>=0&&nextPosition<=previousShowCursor&&loopShow())scheduleKioskRestart();
|
|
@@ -1684,7 +1693,7 @@ stage.onclick=event=>{
|
|
|
1684
1693
|
};
|
|
1685
1694
|
document.addEventListener('keydown',event=>{
|
|
1686
1695
|
if(event.key==='Escape'&&presenting){event.preventDefault();void exitPresentation();return;}
|
|
1687
|
-
// As in
|
|
1696
|
+
// As in the reference desktop app's Reading View, Esc goes back to Normal view, unless it
|
|
1688
1697
|
// is closing the viewer's own text field or area selection first.
|
|
1689
1698
|
if(event.key==='Escape'&&!document.body.classList.contains('editing')&&!event.target.closest('select,input,textarea,[contenteditable]')&&document.querySelector('.slide-edit-panel')?.hidden!==false){event.preventDefault();chooseView(true);return;}
|
|
1690
1699
|
if(presenting&&state.showProperties?.mode?.kind==='kiosk')return;
|
|
@@ -1718,7 +1727,9 @@ async function refresh(){
|
|
|
1718
1727
|
}
|
|
1719
1728
|
const editorFrame=byId('editor-frame');
|
|
1720
1729
|
let editorFocus;
|
|
1721
|
-
// The
|
|
1730
|
+
// The preview revision the editor last saw; it reports this apart from its focus.
|
|
1731
|
+
let editorRevision=0;
|
|
1732
|
+
// The Agents task pane opens on demand, like the reference desktop app's panes; the editor's
|
|
1722
1733
|
// Agents button (in its tab row) mirrors that state, so every change is reported back.
|
|
1723
1734
|
const agentsKey='office-kit-agents-open';
|
|
1724
1735
|
function agentsOpen(){return !document.body.classList.contains('chat-hidden');}
|
|
@@ -1753,7 +1764,7 @@ function applyEditorFocus(){
|
|
|
1753
1764
|
if(!editorFocus)return;
|
|
1754
1765
|
index=Math.max(0,editorFocus.slide);
|
|
1755
1766
|
byId('chat-context').textContent=(editorFocus.locale==='ja'?'スライド ':'Slide ')+(index+1)+' / '+editorFocus.count+(editorFocus.dirty?' · '+(editorFocus.locale==='ja'?'未保存':'Unsaved'):'');
|
|
1756
|
-
byId('chat-context').dataset.focus=JSON.stringify({slide:editorFocus.count?index:null,revision:editorFocus.dirty?-1:
|
|
1767
|
+
byId('chat-context').dataset.focus=JSON.stringify({slide:editorFocus.count?index:null,revision:editorFocus.dirty?-1:editorRevision});
|
|
1757
1768
|
window.dispatchEvent(new Event('agent-focus'));
|
|
1758
1769
|
}
|
|
1759
1770
|
window.addEventListener('message',event=>{
|
|
@@ -1773,6 +1784,11 @@ window.addEventListener('message',event=>{
|
|
|
1773
1784
|
else if(event.data.action==='presenter')byId('presenter').click();
|
|
1774
1785
|
else if(event.data.action==='rehearse'){void startPresentation();if(presenting)startRehearsal();}
|
|
1775
1786
|
});
|
|
1787
|
+
window.addEventListener('message',event=>{
|
|
1788
|
+
if(event.origin!==location.origin||event.source!==editorFrame.contentWindow||event.data?.type!=='editor-revision'||!Number.isInteger(event.data.revision))return;
|
|
1789
|
+
editorRevision=event.data.revision;
|
|
1790
|
+
if(document.body.classList.contains('editing'))applyEditorFocus();
|
|
1791
|
+
});
|
|
1776
1792
|
window.addEventListener('message',event=>{
|
|
1777
1793
|
if(event.origin!==location.origin||event.source!==editorFrame.contentWindow||event.data?.type!=='editor-focus')return;
|
|
1778
1794
|
editorFocus=event.data;
|
|
@@ -1789,7 +1805,7 @@ const events=new EventSource('/events');events.onmessage=event=>{if(event.data==
|
|
|
1789
1805
|
/** Separate window so speaker notes never appear on the audience surface. */
|
|
1790
1806
|
const presenterPage = `<!doctype html>
|
|
1791
1807
|
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width">
|
|
1792
|
-
<title>Presenter view
|
|
1808
|
+
<title>Presenter view</title>
|
|
1793
1809
|
<style>
|
|
1794
1810
|
*{box-sizing:border-box}body{margin:0;background:#141929;color:#e4e8f0;font:15px system-ui,sans-serif;height:100vh;display:flex;flex-direction:column}header,footer{display:flex;align-items:center;gap:14px;padding:16px;flex-wrap:wrap}h1{font-size:18px;margin:0;flex:1}h2{font-size:13px;color:#b9c2d8;margin:0 0 10px}button{font:inherit;color:inherit;background:#29243e;border:1px solid #675487;border-radius:6px;padding:8px 12px;cursor:pointer}button:disabled{opacity:.4;cursor:default}button:focus-visible{outline:2px solid #bca3ff;outline-offset:3px}main{display:grid;grid-template-columns:minmax(0,3fr) minmax(240px,2fr);gap:20px;padding:0 20px;flex:1;min-height:0;overflow:auto}section{min-width:0}#current{position:relative}#current [hidden]{display:none!important}#current,#next{background:#090c14;aspect-ratio:16/9}#current svg,#next svg{width:100%;height:100%}#notes{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.6;max-height:40vh;overflow:auto;padding:14px;background:#1e2538;border-radius:8px}#notes-title{margin-top:20px}#count{flex:1}#message{padding:0 20px;color:#ffc9bd}#elapsed{font-variant-numeric:tabular-nums}footer{justify-content:flex-end}@media(max-width:640px){main{grid-template-columns:1fr}#notes{max-height:none}}
|
|
1795
1811
|
</style>
|
|
@@ -1883,7 +1899,7 @@ for(const canvas of Object.values(canvases))canvas.addEventListener('click',even
|
|
|
1883
1899
|
function update(data){
|
|
1884
1900
|
connected=true;locale=data.locale;document.documentElement.lang=locale;
|
|
1885
1901
|
for(const [id,en,ja] of [['title','Presenter view','発表者ビュー'],['timer-label','Elapsed','経過時間'],['reset','Reset timer','タイマーをリセット'],['current-title','Current slide','現在のスライド'],['notes-title','Speaker notes','発表者ノート'],['next-title','Next slide','次のスライド'],['prev','Previous','前へ'],['next-button','Next','次へ'],['exit','Exit presentation','プレゼンテーションを終了']])byId(id).textContent=text(en,ja);
|
|
1886
|
-
document.title=text('Presenter view
|
|
1902
|
+
document.title=text('Presenter view','発表者ビュー');
|
|
1887
1903
|
byId('message').textContent=data.presenting?'':text('Presentation is stopped.','プレゼンテーションは停止中です。');
|
|
1888
1904
|
const animation=data.animation&&data.animation.stops>0
|
|
1889
1905
|
? ' · '+text('Click '+data.animation.cursor+' of '+data.animation.stops,'クリック '+data.animation.cursor+' / '+data.animation.stops)
|
|
@@ -2117,7 +2133,7 @@ function createTerminal(entry, busy = () => false, base = "", verify = async ()
|
|
|
2117
2133
|
review?.begin();
|
|
2118
2134
|
json(200, { hookSpecificOutput: {
|
|
2119
2135
|
hookEventName: "UserPromptSubmit",
|
|
2120
|
-
additionalContext: `You are editing the local
|
|
2136
|
+
additionalContext: `You are editing the local presentation TSX project at ${resolve(entry)}.
|
|
2121
2137
|
Read the project's authoring instructions. Make focused source patches and preserve unrelated work.
|
|
2122
2138
|
The preview rebuilds on save; do not start another dev server. A Stop hook checks the actual build and returns errors for repair.
|
|
2123
2139
|
${authoringGuidance}
|
|
@@ -2345,7 +2361,7 @@ function createChat(entry, notify, busy = () => false, verify = async () => null
|
|
|
2345
2361
|
...message,
|
|
2346
2362
|
text: message.text.slice(-12e3)
|
|
2347
2363
|
}));
|
|
2348
|
-
const prompt = `You are editing a local
|
|
2364
|
+
const prompt = `You are editing a local presentation TSX project in ${dirname(resolve(entry))}.
|
|
2349
2365
|
Read the project's authoring instructions. Make focused patches to the TSX source, preserving unrelated work.
|
|
2350
2366
|
The preview rebuilds automatically on save; do not start another dev server.
|
|
2351
2367
|
${authoringGuidance}
|
|
@@ -2612,11 +2628,11 @@ function mediaRange(value, length) {
|
|
|
2612
2628
|
};
|
|
2613
2629
|
}
|
|
2614
2630
|
const REMEMBERED_DOCUMENTS = 32;
|
|
2631
|
+
const EDITOR_CHUNK = /^\/editor-chunks\/[\w-]+\.js$/;
|
|
2615
2632
|
const BUNDLED_ASSETS = {
|
|
2616
2633
|
"/terminal.js": "terminal-client.js",
|
|
2617
2634
|
"/terminal.css": "terminal-client.css",
|
|
2618
2635
|
"/editor.js": "editor.js",
|
|
2619
|
-
"/editor.css": "editor.css",
|
|
2620
2636
|
"/animation-player.js": "animation-player.js",
|
|
2621
2637
|
"/media-player.js": "media-player.js"
|
|
2622
2638
|
};
|
|
@@ -3084,9 +3100,18 @@ async function serveDeck(entry, port = 4173) {
|
|
|
3084
3100
|
response.writeHead(200, { "Content-Type": asset.endsWith(".css") ? "text/css" : "text/javascript" });
|
|
3085
3101
|
response.end(bytes);
|
|
3086
3102
|
}, () => response.writeHead(500).end("Preview assets unavailable. Rebuild pptx-dev."));
|
|
3087
|
-
} else if (request.
|
|
3103
|
+
} else if (request.method === "GET" && EDITOR_CHUNK.test(request.url ?? "")) readFile(new URL(`.${request.url}`, import.meta.url)).then((bytes) => response.writeHead(200, { "Content-Type": "text/javascript" }).end(bytes), () => response.writeHead(404).end());
|
|
3104
|
+
else if (request.url?.startsWith("/editor/") && request.method !== "GET") edit(request, response);
|
|
3088
3105
|
else if (request.method === "GET" && request.url === "/editor/state") response.writeHead(200, { "Content-Type": "application/json" }).end(JSON.stringify(editorState()));
|
|
3089
|
-
else if (request.method === "GET" &&
|
|
3106
|
+
else if (request.method === "GET" && (request.url === "/editor/base" || request.url?.startsWith("/editor/document?revision="))) {
|
|
3107
|
+
const bytes = request.url === "/editor/base" ? saved?.base : documents.get(new URL(request.url, "http://localhost").searchParams.get("revision") ?? "");
|
|
3108
|
+
if (!bytes) {
|
|
3109
|
+
response.writeHead(404).end();
|
|
3110
|
+
return;
|
|
3111
|
+
}
|
|
3112
|
+
response.writeHead(200, { "Content-Type": "application/octet-stream" });
|
|
3113
|
+
response.end(bytes);
|
|
3114
|
+
} else if (request.method === "GET" && ["/editor/document", "/editor/source"].includes(request.url ?? "")) {
|
|
3090
3115
|
const result = request.url === "/editor/source" ? source : latest;
|
|
3091
3116
|
if (!result) {
|
|
3092
3117
|
response.writeHead(503).end();
|
|
@@ -3133,7 +3158,7 @@ async function serveDeck(entry, port = 4173) {
|
|
|
3133
3158
|
response.end(latest.bytes);
|
|
3134
3159
|
} else if (request.url === "/editor") {
|
|
3135
3160
|
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
3136
|
-
response.end("<!doctype html><html><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width\"><title>
|
|
3161
|
+
response.end("<!doctype html><html><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width\"><title>Presentation editor</title><body><script type=\"module\" src=\"/editor.js\"><\/script></body></html>");
|
|
3137
3162
|
} else if (request.url === "/presenter") {
|
|
3138
3163
|
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
3139
3164
|
response.end(presenterPage);
|