webui: keep a long north-star heading in the overview preview
The word-boundary cut removed everything after '# ' when the first 500 characters were one long heading, leaving '#…'. Keep the hard cut when the soft cut would leave only a markdown marker. Review P3 on F1 (#1873).
This commit was merged in pull request #1877.
This commit is contained in:
1 parent
e12713f68e
commit
c9c409ac4e
2 files changed
+9
-1
No files matched your search
@@ -276,7 +276,7 @@
|
||||
if(data.failed && ['files','tasks'].includes(section)) container.insertAdjacentHTML('afterbegin','<p role="status">Some request data could not be read; this list may be incomplete.</p>');
|
||||
const selectedRequest=data.requests.find(r=>r.id===(selected||data.requests.find(x=>x.draft)?.id));
|
||||
const md=container.querySelector('[data-prd]'); if(md && selectedRequest?.draft) { md.replaceChildren(window.MosaicMarkdown?.render(selectedRequest.draft.prd) || document.createTextNode(selectedRequest.draft.prd)); const toggle=container.querySelector('.project-prd-toggle'); toggle.hidden=!md.classList.contains('expanded') && md.scrollHeight<=md.clientHeight; toggle.addEventListener('click',()=>{const key=project.id+':'+selectedRequest.id; if(expandedPrds.has(key)) expandedPrds.delete(key); else expandedPrds.add(key); const open=expandedPrds.has(key); md.classList.toggle('expanded',open); toggle.setAttribute('aria-expanded',String(open));toggle.textContent=open?'Show less':'Show full PRD';}); }
|
||||
const north=container.querySelector('[data-north-star]'); if(north && typeof data.north?.content==='string') { const text=section==='overview' && data.north.content.length>500 ? data.north.content.slice(0,500).replace(/\s+\S*$/, '')+'…' : data.north.content; north.replaceChildren(window.MosaicMarkdown?.render(text) || document.createTextNode(text)); }
|
||||
const north=container.querySelector('[data-north-star]'); if(north && typeof data.north?.content==='string') { const text=section==='overview' && data.north.content.length>500 ? previewCut(data.north.content,500) : data.north.content; north.replaceChildren(window.MosaicMarkdown?.render(text) || document.createTextNode(text)); }
|
||||
container.querySelector('#project-request-select')?.addEventListener('change',e=>{selectedRequests.set(project.id,e.target.value);draw(e.target.value);container.querySelector('#project-request-select')?.focus({preventScroll:true});});
|
||||
};
|
||||
draw(selection);
|
||||
@@ -287,6 +287,11 @@
|
||||
const sectionTarget=new URLSearchParams(location.hash.split('?')[1] || '').get('section');
|
||||
if(section==='requirements' && ['prd','north-star'].includes(sectionTarget)) container.querySelector('#project-'+sectionTarget)?.scrollIntoView({block:'start'});
|
||||
}
|
||||
// Cut at a word boundary, unless that would leave only a markdown marker (a long heading).
|
||||
function previewCut(content,max) {
|
||||
const hard=content.slice(0,max), soft=hard.replace(/\s+\S*$/, '');
|
||||
return (/[^\s#>*+\-\d.`]/.test(soft.split('\n').pop()) ? soft : hard)+'…';
|
||||
}
|
||||
async function enhanceList(container,projects,threads) {
|
||||
for(const project of projects.filter(p=>!p.archived)) {
|
||||
const slot=container.querySelector(`[data-project-status="${project.id}"]`); if(!slot) continue;
|
||||
|
||||
@@ -18,4 +18,7 @@ test('overview renders a safe, bounded north star markdown preview and links to
|
||||
assert.ok(result.length < 700, 'preview is bounded'); assert.equal(result.link, 'Open north star in Docs');
|
||||
await b.evaluate(`{const old=window.fetch;window.fetch=(u,o)=>String(u).startsWith('/api/project-file?')?Promise.resolve(new Response(JSON.stringify({content:'# Updated direction'}),{headers:{'content-type':'application/json'}})):old(u,o);document.querySelector('#refresh').click();}`);
|
||||
await b.evaluate(`(async()=>{for(let i=0;i<200;i++){if(document.querySelector('[data-north-star] h1')?.textContent==='Updated direction')return;await new Promise(r=>setTimeout(r,30));}throw Error('north star did not refresh')})()`);
|
||||
// A heading longer than the preview keeps its text instead of collapsing to the marker.
|
||||
await b.evaluate(`{const old=window.fetch;window.fetch=(u,o)=>String(u).startsWith('/api/project-file?')?Promise.resolve(new Response(JSON.stringify({content:'# '+'A'.repeat(600)}),{headers:{'content-type':'application/json'}})):old(u,o);document.querySelector('#refresh').click();}`);
|
||||
await b.evaluate(`(async()=>{for(let i=0;i<200;i++){if((document.querySelector('[data-north-star] h1')?.textContent||'').startsWith('AAAA'))return;await new Promise(r=>setTimeout(r,30));}throw Error('long heading collapsed: '+document.querySelector('[data-north-star]')?.textContent)})()`);
|
||||
});
|
||||
Reference in new issue
Block a user