mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-19 01:26:29 +03:00
Improve: review components within expanded comparisons
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -31,6 +31,8 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
const shortcutLabel = /Mac|iPhone|iPad/.test(navigator.platform) ? '⌘Enter' : 'Ctrl+Enter';
|
||||
let overlay = false;
|
||||
let expandedComparison = false;
|
||||
let closingComparison = false;
|
||||
let collapseComparison: ((done: () => void) => void) | null = null;
|
||||
let showAll = false;
|
||||
let trayOpen = true;
|
||||
let restoreTrayAfterFeedback = false;
|
||||
@@ -57,8 +59,12 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
if (next) selected = next;
|
||||
mobilePane='component'; previousRound=false; overlay=false; zoom='fit'; outputMode='isolated';
|
||||
inventoryFilter = finished ? 'reviewed' : 'pending';
|
||||
render();
|
||||
focusReview(finished ? 'review-summary' : edits[selected!] ? 'feedback' : 'approve');
|
||||
const showNext = () => {
|
||||
render();
|
||||
focusReview(finished ? 'review-summary' : edits[selected!] ? 'feedback' : 'approve');
|
||||
};
|
||||
if (finished && expandedComparison && collapseComparison) collapseComparison(showNext);
|
||||
else showNext();
|
||||
}
|
||||
async function sendReview() {
|
||||
if (sending || submitted || previousRound || Object.keys(edits).length) return;
|
||||
@@ -70,7 +76,7 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
finally { sending=false; render(); }
|
||||
}
|
||||
function updateDecision(action: 'approve' | 'revise') {
|
||||
if (sending || submitted || previousRound) return;
|
||||
if (sending || submitted || previousRound || closingComparison) return;
|
||||
const c = packet.components.find(c => c.id === selected);
|
||||
if (!c) return;
|
||||
const saved = draft.decisions[c.id];
|
||||
@@ -88,7 +94,7 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
} else advance(c.id);
|
||||
}
|
||||
function beginFeedback() {
|
||||
if (sending || submitted || previousRound) return;
|
||||
if (sending || submitted || previousRound || closingComparison) return;
|
||||
const c = packet.components.find(c=>c.id===selected);
|
||||
if (!c) return;
|
||||
const saved = draft.decisions[c.id];
|
||||
@@ -109,6 +115,7 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
}
|
||||
function render() {
|
||||
resize?.disconnect();
|
||||
if (submitted || (finished && !assembled)) expandedComparison = false;
|
||||
const active = root.activeElement as HTMLElement | null;
|
||||
const focusId = active?.id;
|
||||
const focusSelection = active?.dataset.select;
|
||||
@@ -213,9 +220,15 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
const comparisonDialog=root.querySelector<HTMLDialogElement>('#comparison-dialog')!;
|
||||
const comparisonPanel=root.querySelector<HTMLElement>('.comparison-panel');
|
||||
const comparisonSlot=root.querySelector<HTMLElement>('.comparison-slot');
|
||||
const reviewForm=root.querySelector<HTMLElement>('.inspector > .review-form');
|
||||
const inspector=root.querySelector<HTMLElement>('.inspector')!;
|
||||
const expandContents=()=>{
|
||||
comparisonDialog.append(comparisonPanel!);
|
||||
if(reviewForm)comparisonDialog.append(reviewForm);
|
||||
};
|
||||
if(expandedComparison && comparisonPanel && comparisonSlot){
|
||||
comparisonSlot.style.height=`${oldComparisonHeight}px`;
|
||||
comparisonDialog.append(comparisonPanel);comparisonDialog.showModal();
|
||||
expandContents();comparisonDialog.showModal();
|
||||
}
|
||||
if(viewingPrevious)root.querySelectorAll<HTMLButtonElement|HTMLInputElement|HTMLTextAreaElement>('.decisions button,#feedback,#split,#save-feedback,#cancel-feedback,#undo-decision,#approve-rest,#submit,#inventory-confirm').forEach(el=>el.disabled=true);
|
||||
root.querySelector('.inspection-content')!.scrollTop=inspectorTop;
|
||||
@@ -322,7 +335,7 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
const panes=Array.from(root.querySelectorAll<HTMLElement>('.pan-viewport'));
|
||||
if(content?.clientHeight){
|
||||
const height=expandedComparison
|
||||
? Math.max(100,comparisonDialog.clientHeight-(comparisonPanel?.querySelector('.compare-toolbar')?.clientHeight??0)-(comparisonPanel?.querySelector('.expanded-title')?.clientHeight??0)-(comparisonPanel?.querySelector('.view-controls')?.clientHeight??0)-112)
|
||||
? Math.max(100,comparisonDialog.clientHeight-(comparisonPanel?.querySelector('.compare-toolbar')?.clientHeight??0)-(comparisonPanel?.querySelector('.expanded-title')?.clientHeight??0)-(comparisonPanel?.querySelector('.view-controls')?.clientHeight??0)-(reviewForm?.getBoundingClientRect().height??0)-124)
|
||||
: Math.min(assembled?Number.POSITIVE_INFINITY:248,Math.max(100,content.clientHeight
|
||||
- ((panes[0]?.getBoundingClientRect().top ?? content.getBoundingClientRect().top)-content.getBoundingClientRect().top+content.scrollTop)
|
||||
- (comparisonPanel?.querySelector('.view-controls')?.clientHeight ?? 0)-12));
|
||||
@@ -335,7 +348,7 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
const path=root.querySelector<SVGPathElement>('.connector path');
|
||||
if(region&&end&&path){const a=region.getBoundingClientRect(),b=end.getBoundingClientRect();const x1=a.right-bounds.left,y1=a.top+a.height/2-bounds.top,x2=b.left-bounds.left-8,y2=b.top+b.height/2-bounds.top;path.setAttribute('d',`M ${x1} ${y1} H ${x2-14} V ${y2} H ${x2}`);}
|
||||
}
|
||||
function setComparisonExpanded(open: boolean) {
|
||||
function setComparisonExpanded(open: boolean, afterClose?: () => void) {
|
||||
if(!comparisonPanel||!comparisonSlot||open===expandedComparison)return;
|
||||
const button=root.querySelector<HTMLButtonElement>('#expand-comparison')!;
|
||||
const before=(expandedComparison?comparisonDialog:comparisonPanel).getBoundingClientRect();
|
||||
@@ -345,12 +358,15 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
const py=currentPane ? currentPane.scrollTop/Math.max(1,currentPane.scrollHeight-currentPane.clientHeight) : 0;
|
||||
const restorePan=()=>comparisonPanel.querySelectorAll<HTMLElement>('.pan-viewport').forEach(p=>{p.scrollLeft=px*Math.max(0,p.scrollWidth-p.clientWidth);p.scrollTop=py*Math.max(0,p.scrollHeight-p.clientHeight);});
|
||||
const restore=()=>{
|
||||
comparisonSlot.append(comparisonPanel);comparisonDialog.close();comparisonSlot.style.height='';
|
||||
comparisonSlot.append(comparisonPanel);
|
||||
if(reviewForm){inspector.append(reviewForm);reviewForm.inert=false;}
|
||||
comparisonDialog.close();comparisonSlot.style.height='';closingComparison=false;
|
||||
expandedComparison=false;button.innerHTML=icon('expand');button.setAttribute('aria-label','Enlarge comparison');button.title='Enlarge comparison';button.setAttribute('aria-expanded','false');
|
||||
resizePreview();restorePan();button.focus({preventScroll:true});
|
||||
afterClose?.();
|
||||
};
|
||||
if(open){
|
||||
comparisonSlot.style.height=`${before.height}px`;comparisonDialog.append(comparisonPanel);comparisonDialog.showModal();expandedComparison=true;
|
||||
comparisonSlot.style.height=`${before.height}px`;expandContents();comparisonDialog.showModal();expandedComparison=true;
|
||||
button.innerHTML=icon('compact');button.setAttribute('aria-label','Restore comparison');button.title='Restore comparison (Esc)';button.setAttribute('aria-expanded','true');
|
||||
resizePreview();restorePan();button.focus({preventScroll:true});
|
||||
const after=comparisonDialog.getBoundingClientRect();
|
||||
@@ -359,15 +375,16 @@ export function mountComponentReview(host: HTMLElement, packet: ReviewPacket, op
|
||||
if(button.disabled)return;
|
||||
const target=comparisonSlot.getBoundingClientRect();
|
||||
if(reduced){restore();return;}
|
||||
button.disabled=true;
|
||||
button.disabled=true;closingComparison=true;if(reviewForm)reviewForm.inert=true;
|
||||
const animation=comparisonDialog.animate([{transform:'none',opacity:1},{transform:`translate(${target.x-before.x}px,${target.y-before.y}px) scale(${target.width/before.width},${target.height/before.height})`,opacity:.6}],{duration:200,easing:'cubic-bezier(.4,0,.2,1)',fill:'forwards'});
|
||||
animation.finished.then(()=>{if(comparisonDialog.isConnected){animation.cancel();button.disabled=false;restore();}}).catch(()=>{});
|
||||
}
|
||||
}
|
||||
collapseComparison=done=>setComparisonExpanded(false,done);
|
||||
on('expand-comparison',()=>setComparisonExpanded(!expandedComparison));
|
||||
comparisonDialog.addEventListener('cancel',e=>{e.preventDefault();e.stopPropagation();setComparisonExpanded(false);});
|
||||
comparisonDialog.addEventListener('keydown',e=>{if(e.key==='Escape'){e.preventDefault();e.stopPropagation();setComparisonExpanded(false);}});
|
||||
resize=new ResizeObserver(()=>{resizePreview();updateScrollEdges();});resize.observe(workbench);resize.observe(comparisonDialog);const content=root.querySelector('.inspection-content');if(content)resize.observe(content);const feedback=root.querySelector('.repair-context');if(feedback)resize.observe(feedback);const toolbar=comparisonPanel?.querySelector('.compare-toolbar');if(toolbar)resize.observe(toolbar);resizePreview();
|
||||
resize=new ResizeObserver(()=>{resizePreview();updateScrollEdges();});resize.observe(workbench);resize.observe(comparisonDialog);if(reviewForm)resize.observe(reviewForm);const content=root.querySelector('.inspection-content');if(content)resize.observe(content);const feedback=root.querySelector('.repair-context');if(feedback)resize.observe(feedback);const toolbar=comparisonPanel?.querySelector('.compare-toolbar');if(toolbar)resize.observe(toolbar);resizePreview();
|
||||
const panes=Array.from(root.querySelectorAll<HTMLElement>('.pan-viewport'));
|
||||
panes.forEach(pane=>{pane.scrollLeft=panLeft;pane.scrollTop=panTop;});
|
||||
panes.forEach(pane=>{
|
||||
|
||||
@@ -48,8 +48,11 @@ export const styles = `
|
||||
|
||||
.comparison-panel{min-width:0;container-type:inline-size}.comparison-panel .expanded-title{display:none}.comparison-panel .compare-toolbar{justify-content:flex-start}.comparison-panel .overlay-control{margin-left:0}.comparison-panel #expand-comparison{flex-shrink:0}.pan-viewport.pannable{cursor:move}.pan-viewport img{user-select:none;-webkit-user-drag:none}
|
||||
#comparison-dialog{position:fixed;inset:16px;width:calc(100vw - 32px);height:calc(100dvh - 32px);max-width:none;max-height:none;margin:0;padding:24px;background:var(--paper);color:inherit;border:1px solid var(--line);border-radius:8px;box-shadow:0 20px 60px #14292340;overflow:hidden;transform-origin:top left}
|
||||
#comparison-dialog[open]{display:flex;flex-direction:column;gap:12px}
|
||||
#comparison-dialog>.review-form{width:100%;max-width:900px;align-self:center;max-height:55%;padding:12px 4px 0}
|
||||
#comparison-dialog>.review-form .decision-title{display:none}
|
||||
#comparison-dialog::backdrop{background:#172821a6}
|
||||
#comparison-dialog .comparison-panel{height:100%;display:flex;flex-direction:column;gap:12px}
|
||||
#comparison-dialog .comparison-panel{flex:1;min-height:0;display:flex;flex-direction:column;gap:12px}
|
||||
#comparison-dialog .expanded-title{display:block;font-size:20px;line-height:1.3;margin:0;font-weight:500}
|
||||
#comparison-dialog .compare-toolbar{flex-shrink:0;margin:0}
|
||||
#comparison-dialog .compare{flex:1;min-height:0;max-width:none;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
|
||||
|
||||
Reference in New Issue
Block a user