Compare commits

...
1 Commits
Author SHA1 Message Date
Kristian WindandClaude Opus 5 8d5dd1f1c3 fix(notes): grupperne stod tomme — hver liste rullede for sig
Release / Build and publish image (push) Failing after 9m59s
Meldt ind som "noter vises ikke i den nye listeform": hver eneste overskrift stod
der med sit tal, og der var ikke en eneste note under nogen af dem.

Før var der ét `<ul>`, og *det* rullede. Da listen blev delt i grupper, blev hver
gruppe sit eget `<ul>` — og dermed sit eget flex-element med `overflow-y: auto`.
Flex-elementer skrumper som udgangspunkt, og et element, der skrumper og klipper,
viser ingenting. Med tyve måneder i søjlen fik hver liste nul at være høj i.

Rulningen hører til kassen om dem alle, ikke til hver af dem.

**Prøven fangede det ikke, og det er værd at forstå hvorfor.** Den lavede to noter,
altså tre grupper, i et vindue på 720 pixels — og med så få grupper er der plads
nok til, at skrumpningen ikke bider. Fejlen kræver pres. Prøven gør vinduet lavt
nu og kigger efter, at rækkerne kan *ses* og ikke bare findes, og den siger
desuden hvor rulningen ligger: på kassen, ikke på listerne. Den er set fejle med
den gamle stil.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:00:15 +02:00
2 changed files with 136 additions and 92 deletions
+29
View File
@@ -3366,6 +3366,35 @@ test('notelisten grupperer favoritter og datoer, også i arkivet', async ({ page
await expect(page.locator('h3.group')).toHaveCount(0); await expect(page.locator('h3.group')).toHaveCount(0);
await page.getByPlaceholder('Søg i noter').fill(''); await page.getByPlaceholder('Søg i noter').fill('');
// Rækkerne skal kunne *ses*, ikke bare findes.
//
// Da listen blev delt i grupper, blev hver gruppe sit eget `<ul>` — og dermed
// sit eget flex-element med `overflow-y: auto`. Flex-elementer skrumper som
// udgangspunkt, og et element, der skrumper og klipper, viser ingenting: alle
// overskrifter stod med deres tal, og der var ikke en eneste note under nogen af
// dem. Med tre grupper og en høj skærm var der plads nok til at det ikke skete,
// hvilket er hvorfor prøven herover ikke fangede det.
//
// Et lavt vindue fremtvinger presset. Tolv hundrede noter i tyve måneder gør det
// samme i virkeligheden.
await page.setViewportSize({ width: 1100, height: 380 });
await page.waitForTimeout(300);
await expect(
page.locator('li').filter({ hasText: 'Gruppe to' }).first(),
'rækkerne blev klippet væk, da der ikke var plads'
).toBeVisible();
// Og rulningen ligger på kassen om grupperne, ikke på hver liste for sig.
const scroller = await page
.locator('.list')
.evaluate((el) => getComputedStyle(el).overflowY);
expect(scroller, 'kassen om grupperne ruller ikke').toBe('auto');
const inner = await page
.locator('.list ul')
.first()
.evaluate((el) => getComputedStyle(el).overflowY);
expect(inner, 'den enkelte liste ruller stadig for sig').toBe('visible');
await page.setViewportSize({ width: 1280, height: 720 });
// Arkivet grupperes på samme måde. Det er dér, det betyder mest. // Arkivet grupperes på samme måde. Det er dér, det betyder mest.
await row.hover(); await row.hover();
await row.getByRole('button', { name: /Arkivér/i }).click(); await row.getByRole('button', { name: /Arkivér/i }).click();
+107 -92
View File
@@ -629,99 +629,108 @@
{query ? t('notes.noneFound') : showArchive ? t('notes.emptyArchive') : t('notes.noneYet')} {query ? t('notes.noneFound') : showArchive ? t('notes.emptyArchive') : t('notes.noneYet')}
</p> </p>
{:else} {:else}
{#each groups as group (group.key)} <!-- Én rulleboks om alle grupperne.
<!-- Overskriften klæber, mens man ruller. Med tolv hundrede noter er det Før var der ét `<ul>`, og *det* rullede. Da listen blev delt i grupper,
forskellen på at rulle og på at lede: man kan altid se, hvilken måned blev hver gruppe sit eget `<ul>` — og dermed sit eget flex-element med
man er nede i. --> `overflow-y: auto`. Flex-elementer skrumper som udgangspunkt, og et
{#if !group.plain} element, der skrumper og klipper, viser ingenting: alle overskrifter
<h3 class="group"> stod med deres tal, og der var ikke en eneste note under nogen af dem.
<!-- Ingen `aria-label`. Den ville erstatte knappens indhold som dens Rulningen hører til kassen om dem alle, ikke til hver af dem. -->
navn, og knappen *er* overskriften — så overskriften ville hedde <div class="list">
"Fold I dag sammen" i stedet for "I dag". `aria-expanded` siger {#each groups as group (group.key)}
tilstanden, som den gør på gruppehovederne i sidebjælken. --> <!-- Overskriften klæber, mens man ruller. Med tolv hundrede noter er det
<button onclick={() => toggleGroup(group.key)} aria-expanded={!folded.has(group.key)}> forskellen på at rulle og på at lede: man kan altid se, hvilken måned
{#if group.star} man er nede i. -->
<span class="mark favmark" aria-hidden="true">★</span> {#if !group.plain}
{:else} <h3 class="group">
<span class="mark" class:closed={folded.has(group.key)} aria-hidden="true">▾</span> <!-- Ingen `aria-label`. Den ville erstatte knappens indhold som dens
{/if} navn, og knappen *er* overskriften — så overskriften ville hedde
{group.label} "Fold I dag sammen" i stedet for "I dag". `aria-expanded` siger
<span class="count">{group.notes.length}</span> tilstanden, som den gør på gruppehovederne i sidebjælken. -->
</button> <button onclick={() => toggleGroup(group.key)} aria-expanded={!folded.has(group.key)}>
</h3> {#if group.star}
{/if} <span class="mark favmark" aria-hidden="true">★</span>
{#if !folded.has(group.key)} {:else}
<ul> <span class="mark" class:closed={folded.has(group.key)} aria-hidden="true">▾</span>
{#each group.notes as note (note.id)} {/if}
<li> {group.label}
<div class="rowline"> <span class="count">{group.notes.length}</span>
<button </button>
class="row" </h3>
class:on={selectedId === note.id} {/if}
class:picked={picked.has(note.id)} {#if !folded.has(group.key)}
onclick={(e) => rowClick(e, note)} <ul>
draggable="true" {#each group.notes as note (note.id)}
ondragstart={(e) => onDragStart(e, note)} <li>
ondragend={() => (dragging = null)} <div class="rowline">
> <button
<!-- Titel og projekt på linje ét, uddrag på linje to. Datoen står class="row"
i gruppens overskrift og ikke her — undtagen når der er sorteret class:on={selectedId === note.id}
på navn, for så er der ingen overskrift, der siger den, og så er class:picked={picked.has(note.id)}
den det eneste tilbage, der gør. --> onclick={(e) => rowClick(e, note)}
<span class="head"> draggable="true"
<strong>{note.title || t('notes.untitled')}</strong> ondragstart={(e) => onDragStart(e, note)}
{#if order === 'title'} ondragend={() => (dragging = null)}
<span class="when" title={stamp(note)}>{when(shownDate(note))}</span> >
{/if} <!-- Titel og projekt på linje ét, uddrag på linje to. Datoen står
{#if note.project_id} i gruppens overskrift og ikke her — undtagen når der er sorteret
<!-- Projektets egen farve, den samme som prikken i sidebjælken. på navn, for så er der ingen overskrift, der siger den, og så er
Mærkaten sagde det samme som alle de andre i en grå, der var den det eneste tilbage, der gør. -->
lysere end uddraget — og projektet er dét, man skanner efter, <span class="head">
når man leder i tolv hundrede noter. Nu kan Hjem kendes fra <strong>{note.title || t('notes.untitled')}</strong>
Claude uden at læse ordet. --> {#if order === 'title'}
<span class="filed" style="--project: {projectColour(note.project_id)}"> <span class="when" title={stamp(note)}>{when(shownDate(note))}</span>
<span class="dot" aria-hidden="true"></span> {/if}
{projectName(note.project_id)} {#if note.project_id}
</span> <!-- Projektets egen farve, den samme som prikken i sidebjælken.
{/if} Mærkaten sagde det samme som alle de andre i en grå, der var
</span> lysere end uddraget — og projektet er dét, man skanner efter,
<span class="preview">{preview(note)}</span> når man leder i tolv hundrede noter. Nu kan Hjem kendes fra
</button> Claude uden at læse ordet. -->
<!-- De to knapper står oven på hinanden i en smal søjle. <span class="filed" style="--project: {projectColour(note.project_id)}">
Ved siden af hinanden tog de toogfyrre pixels af en liste, <span class="dot" aria-hidden="true"></span>
der er tre hundrede bred — og de bruges sjældent, mens {projectName(note.project_id)}
titlen og uddraget læses hele tiden. --> </span>
<div class="rowactions"> {/if}
<!-- Én note lagt væk, uden at markere den først. Markeringen er </span>
til flere; det her er til den ene, man står med — og i <span class="preview">{preview(note)}</span>
arkivet er det vejen tilbage. --> </button>
<button <!-- De to knapper står oven på hinanden i en smal søjle.
class="archive-one" Ved siden af hinanden tog de toogfyrre pixels af en liste,
onclick={() => archiveOne(note)} der er tre hundrede bred — og de bruges sjældent, mens
aria-label={note.archived_at ? t('notes.unarchive') : t('notes.archiveOne')} titlen og uddraget læses hele tiden. -->
title={note.archived_at ? t('notes.unarchive') : t('notes.archiveOne')} <div class="rowactions">
> <!-- Én note lagt væk, uden at markere den først. Markeringen er
<svg viewBox="0 0 24 24" aria-hidden="true"> til flere; det her er til den ene, man står med — og i
<path d="M3 7h18v3H3zM5 10v9h14v-9M10 14h4" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" /> arkivet er det vejen tilbage. -->
</svg> <button
</button> class="archive-one"
<button onclick={() => archiveOne(note)}
class="star" aria-label={note.archived_at ? t('notes.unarchive') : t('notes.archiveOne')}
class:on={note.pinned} title={note.archived_at ? t('notes.unarchive') : t('notes.archiveOne')}
onclick={() => favourite(note)} >
aria-pressed={note.pinned} <svg viewBox="0 0 24 24" aria-hidden="true">
aria-label={note.pinned ? t('notes.unfavourite') : t('notes.favourite')} <path d="M3 7h18v3H3zM5 10v9h14v-9M10 14h4" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" />
title={note.pinned ? t('notes.unfavourite') : t('notes.favourite')} </svg>
> </button>
{note.pinned ? '★' : '☆'} <button
</button> class="star"
class:on={note.pinned}
onclick={() => favourite(note)}
aria-pressed={note.pinned}
aria-label={note.pinned ? t('notes.unfavourite') : t('notes.favourite')}
title={note.pinned ? t('notes.unfavourite') : t('notes.favourite')}
>
{note.pinned ? '★' : '☆'}
</button>
</div>
</div> </div>
</div> </li>
</li> {/each}
{/each}
</ul> </ul>
{/if} {/if}
{/each} {/each}
</div>
{/if} {/if}
</aside> </aside>
@@ -1007,12 +1016,18 @@
-webkit-appearance: none; -webkit-appearance: none;
} }
/* Kassen ruller. Listerne indeni gør ikke: de er mange nu, og et flex-element,
der både skrumper og klipper, viser ingenting. */
.list {
flex: 1;
min-height: 0;
overflow-y: auto;
}
ul { ul {
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow-y: auto;
min-height: 0;
} }
/* Rækker uden for skærmen koster ingenting. /* Rækker uden for skærmen koster ingenting.