diff --git a/frontend/dashboard.css b/frontend/dashboard.css index b245c22..302bbd5 100644 --- a/frontend/dashboard.css +++ b/frontend/dashboard.css @@ -94,6 +94,10 @@ textarea { resize: vertical; min-height: 120px; } .plan-today-item { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:8px; align-items:center; padding:10px; border:1px solid #1f3a5f; border-radius:12px; background:#0f1d33; } .plan-today-item-copy { min-width:0; overflow-wrap:anywhere; } .plan-today-item-actions { display:flex; gap:6px; flex-wrap:wrap; justify-content:flex-end; } +.plan-today-candidate-actions { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:6px; } +.plan-preview-actions { position:fixed; z-index:76; right:16px; bottom:calc(16px + env(safe-area-inset-bottom)); display:grid; grid-template-columns:1fr 1fr; gap:8px; width:min(420px,calc(100vw - 32px)); padding:10px; border:1px solid #31577f; border-radius:12px; background:rgba(11,21,38,.98); box-shadow:0 12px 36px rgba(0,0,0,.45); } +.plan-preview-actions[hidden] { display:none; } +.plan-preview-actions button { min-height:44px; } .plan-today-actions { position:sticky; bottom:0; display:grid; grid-template-columns:1fr 1fr; gap:8px; margin:16px -6px -6px; padding:12px 6px; padding-bottom:calc(12px + env(safe-area-inset-bottom)); background:rgba(11,21,38,.98); border-top:1px solid #2a496e; } .plan-today-actions button { min-height:44px; width:100%; } .my-work-header { display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; } @@ -365,6 +369,7 @@ textarea { resize: vertical; min-height: 120px; } .plan-today-panel { width:100%; border-left:0; padding:14px; } .plan-today-item { grid-template-columns:1fr; } .plan-today-item-actions { display:grid; grid-template-columns:repeat(3,1fr); width:100%; } + .plan-today-candidate-actions { grid-template-columns:repeat(2,1fr); width:100%; } .plan-today-item-actions button { min-width:0; padding-inline:4px; } .work-filters { width:100%; } .work-filter { flex:1 1 calc(50% - 8px); } diff --git a/frontend/dashboard.js b/frontend/dashboard.js index 4bf8e31..2d4996d 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -728,7 +728,7 @@ const title = escapeHtml(item.title || 'Untitled work'); const controls = selected ? '
' : - ''; + '
'; return '
' + key + '' + title + '
' + controls + '
'; } @@ -747,6 +747,15 @@ qs('#plan-today-error').textContent = result === 'full' ? 'Today is full. Remove an item before adding another.' : ''; renderPlanToday(); })); + document.querySelectorAll('[data-plan-preview]').forEach(button => button.addEventListener('click', () => { + const item = planToday.item(button.dataset.planPreview); + if (!canPreviewPlanItem(item)) { + qs('#plan-today-error').textContent = 'Preview unavailable offline. Reconnect or add the item without previewing it.'; + return; + } + qs('#plan-today-error').textContent = ''; + if (planTodayPreview.open(item, button)) taskOverlayHistory.open('plan-today-preview'); + })); document.querySelectorAll('[data-plan-remove]').forEach(button => button.addEventListener('click', () => { planToday.toggle(planToday.item(button.dataset.planRemove)); qs('#plan-today-error').textContent = ''; @@ -792,6 +801,58 @@ }, }); + function canPreviewPlanItem(item) { + if (!item || !offlineWorkMode) return Boolean(item); + const login = planningOwnerLogin || confirmedOwnerLogin || + String(offlineWorkStore.load()?.user?.login || '').trim(); + return Boolean(offlineWorkStore.loadDetail(login, item)); + } + + function openPlanPreviewDetail(item, trigger) { + qs('#plan-today-sheet').hidden = true; + qs('#plan-preview-actions').hidden = false; + if (offlineWorkMode) { + openRoutedWork(item, trigger); + } else if (item.kind === 'update' && item.has_update) { + updateTrigger = trigger; + notificationReader.open(item, lastMyWork); + } else if (item.is_review || item.kind === 'review') { + reviewTrigger = trigger; + openReviewSheet(item, trigger); + } else if (item.kind === 'issue') { + issueTrigger = trigger; + openIssueSheet(item, trigger); + } else if (item.kind === 'pull') { + pullTrigger = trigger; + openPullSheet(item, trigger); + } + } + + const planTodayPreview = createPlanTodayPreview({ + planner: planToday, + identity: item => todayWork.identity(item), + getScroll: () => qs('.plan-today-panel').scrollTop, + setScroll: value => requestAnimationFrame(() => { qs('.plan-today-panel').scrollTop = value; }), + onOpen: openPlanPreviewDetail, + onClose: (_item, trigger) => { + closeOpenWorkSheets(); + qs('#plan-preview-actions').hidden = true; + qs('#plan-today-sheet').hidden = false; + renderPlanToday(); + requestAnimationFrame(() => trigger?.focus()); + }, + }); + let addPlanPreviewOnReturn = false; + + qs('#back-to-plan').addEventListener('click', () => { + addPlanPreviewOnReturn = false; + taskOverlayHistory.close(); + }); + qs('#add-plan-preview').addEventListener('click', () => { + addPlanPreviewOnReturn = true; + taskOverlayHistory.close(); + }); + function openPlanToday(trigger, navigate = true) { if (!planningOwnerLogin) { qs('#my-work-action-status').textContent = 'Planning is unavailable until your operator identity is restored.'; @@ -2652,11 +2713,16 @@ mobileSearchViewport.close(); qs('#open-palette').focus(); } - if (previous === 'plan-today' && kind !== 'plan-today') closePlanToday(false); + if (previous === 'plan-today-preview' && kind !== 'plan-today-preview') { + if (addPlanPreviewOnReturn) planTodayPreview.close({ add:true }); + else planTodayPreview.close(); + addPlanPreviewOnReturn = false; + } + if (previous === 'plan-today' && kind !== 'plan-today' && kind !== 'plan-today-preview') closePlanToday(false); if (kind === 'new' && previous !== 'new') openCreateIssueSheet(false); if (kind === 'find' && previous !== 'find') openFindWorkSheet(false); if (kind === 'search' && previous !== 'search-preview') openCommandPalette(false); - if (kind === 'plan-today' && previous !== 'plan-today') openPlanToday(planTodayTrigger, false); + if (kind === 'plan-today' && previous !== 'plan-today' && previous !== 'plan-today-preview') openPlanToday(planTodayTrigger, false); }, }); taskOverlayHistory.start(); diff --git a/frontend/index.html b/frontend/index.html index d6018c3..0d1dee9 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -196,6 +196,11 @@ + +