Changeset ea138c0 in Klonkt


Ignore:
Timestamp:
08/07/2026 11:37:53 AM (5 weeks ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
1e172f3
Parents:
f889429
git-author:
Robin <roboburr@…> (08/07/2026 11:37:51 AM)
git-committer:
roboburr <roboburr@…> (08/07/2026 11:37:53 AM)
Message:

Gesprekken in- en uitklappen door op de tegenpartij te tikken

Barts aanwijzing: de uitsparing met de naam is ook de knop. Dat is waar je van
nature naar wijst als je "dit gesprek" bedoelt, en het scheelt een extra
bedieningselement in een lijst die juist rustiger moest worden.

Een BUTTON en geen span met een klikhandler: dan werkt hij met het toetsenbord en
leest een schermlezer de stand voor (aria-expanded). Zonder JavaScript doet hij
niets, en dan staat het gesprek open -- wat ook de beginstand is. Standaard
uitgeklapt, zoals gevraagd.

Ingeklapt blijven de naam en het AANTAL staan. Dat aantal is juist ingeklapt het
meest waard: het is dan het enige wat zegt hoe groot het gesprek is.

Twee dingen die eromheen moesten:

RAAKVLAK de uitsparing is 18px hoog en dat is op een telefoon niet te raken.

De knop krijgt een minimumhoogte; de uitsparing blijft klein, het
doel wordt groter.

ZOEKEN een treffer in een dichtgeklapt gesprek liet alleen de naam zien: je

zoekt iets, het staat er, en je ziet het niet. Zolang er gezocht
wordt gaat zo'n gesprek open en daarna keert hij terug naar de stand
die de lezer zelf koos.

De stand leeft alleen in de pagina en niet in opslag. Een gesprek dat je gisteren
dichtklapte stilhouden is iets anders dan het opruimen van je scherm van nu.

De nieuwe CSS staat NA .msg-item, om dezelfde reden als de rest van dat blok: bij
gelijke specificiteit wint de laatste regel.

Templates compileren, suite 551/551. De pagina zelf staat achter een login, dus
het gedrag in beeld is aan Bart.

Location:
src/views
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/messages.ejs

    rf889429 rea138c0  
    101101        (!term || li._search.indexOf(term) !== -1);
    102102      li.style.display = ok ? '' : 'none';
     103      // Een treffer die in een dichtgeklapt gesprek zit, laat anders alleen de
     104      // naam zien: je zoekt iets, het staat er, en je ziet het niet. Zolang er
     105      // gezocht wordt gaat zo'n gesprek open; daarna keert hij terug naar de
     106      // stand die de lezer zelf koos.
     107      if (li.classList.contains('msg-thread')) {
     108        li.classList.toggle('is-search-open', !!term && ok);
     109      }
    103110      if (ok) shown++;
    104111    });
    105112    if (noMatch) noMatch.hidden = shown !== 0;
    106113  }
     114  // In- en uitklappen door op de tegenpartij te tikken (Barts aanwijzing).
     115  // Gedelegeerd, zodat draden die via "meer laden" binnenkomen het vanzelf ook
     116  // doen. De stand leeft alleen in deze pagina: standaard uitgeklapt, en na een
     117  // herlading weer. Dat is bewust -- een gesprek dat je gisteren dichtklapte
     118  // stilhouden is niet hetzelfde als het opruimen van je scherm van nu.
     119  document.addEventListener('click', function (e) {
     120    var who = e.target.closest('.msg-thread-who'); if (!who) return;
     121    var li = who.closest('.msg-thread'); if (!li) return;
     122    var dicht = li.classList.toggle('is-collapsed');
     123    who.setAttribute('aria-expanded', dicht ? 'false' : 'true');
     124  });
    107125  document.addEventListener('click', function (e) {
    108126    var chip = e.target.closest('.msg-chip'); if (!chip) return;
     
    166184     kleine verzonken uitsparing, zodat de bubbels eronder de ruimte krijgen.
    167185     Het aantal zit in dezelfde uitsparing in plaats van ernaast. */
     186  /* Ook de knop die het gesprek in- en uitklapt. Een button erft geen font en
     187     geen kleur, dus die staan hier expliciet; zonder dat wordt het ineens
     188     systeemblauw in 13px. */
    168189  .msg-thread-who { display: inline-flex; align-items: center; gap: .3rem; min-width: 0;
    169     font-size: .78em; line-height: 1.5; font-weight: 500;
    170     padding: .05rem .5rem; border-radius: 999px;
     190    font: inherit; font-size: .78em; line-height: 1.5; font-weight: 500;
     191    padding: .05rem .5rem; border-radius: 999px; border: 0; cursor: pointer;
    171192    color: color-mix(in srgb, var(--ink, #000) 62%, transparent);
    172193    background: color-mix(in srgb, var(--ink, #000) 5%, transparent);
    173194    box-shadow: inset 0 1px 2px color-mix(in srgb, var(--ink, #000) 9%, transparent);
    174     max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
     195    max-width: 100%; overflow: hidden; white-space: nowrap;
     196    /* Ruimer aanraakvlak dan de tekst: een chip van 18px hoog is op een telefoon
     197       niet te raken. De uitsparing blijft klein, het doel wordt groter. */
     198    min-height: 32px; }
     199  .msg-thread-who:hover { background: color-mix(in srgb, var(--ink, #000) 9%, transparent); }
     200  .msg-thread-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
     201  .msg-thread-chevron { width: 12px; height: 12px; flex: none; opacity: .55;
     202    transition: transform .18s ease; }
     203  /* Ingeklapt: de bubbels en het antwoordveld verdwijnen, de uitsparing met de
     204     naam en het AANTAL blijft staan -- dat aantal is juist ingeklapt het meest
     205     waard. */
     206  .msg-thread.is-collapsed .msg-thread-msgs,
     207  .msg-thread.is-collapsed .msg-thread-foot { display: none; }
     208  /* Tijdens het zoeken wint de treffer van de dichtgeklapte stand. */
     209  .msg-thread.is-collapsed.is-search-open .msg-thread-msgs { display: flex; }
     210  .msg-thread.is-collapsed.is-search-open .msg-thread-foot { display: flex; }
     211  .msg-thread.is-collapsed .msg-thread-chevron { transform: rotate(-90deg); }
     212  .msg-thread.is-collapsed .msg-thread-head { margin-bottom: 0; }
     213  @media (prefers-reduced-motion: reduce) { .msg-thread-chevron { transition: none; } }
    175214  .msg-thread-count { font-variant-numeric: tabular-nums; opacity: .75; flex: 0 0 auto;
    176215    padding-inline-start: .3rem; border-inline-start: 1px solid color-mix(in srgb, var(--ink, #000) 14%, transparent); }
  • src/views/partials/msg-item.ejs

    rf889429 rea138c0  
    1515          <div class="msg-thread-head">
    1616            <%# Tegenpartij en aantal in EEN uitsparing: het is een label bij het
    17                 gesprek, geen kop erboven. Zo houdt de inhoud de ruimte. %>
    18             <span class="msg-thread-who"><%= _tlabel %><% if (n.count > 1) { %><span class="msg-thread-count"><%= n.count %></span><% } %></span>
     17                gesprek, geen kop erboven. Zo houdt de inhoud de ruimte.
     18
     19                Deze uitsparing is ook de knop die het gesprek in- en uitklapt
     20                (Barts aanwijzing): tikken op de tegenpartij is waar je van
     21                nature naar wijst als je "dit gesprek" bedoelt. Een BUTTON en
     22                geen span met een klikhandler, want dan werkt hij ook met het
     23                toetsenbord en leest een schermlezer de stand voor.
     24
     25                Zonder JavaScript doet hij niets, en dan staat het gesprek
     26                gewoon open -- dat is ook de stand waar we mee beginnen. %>
     27            <button type="button" class="msg-thread-who" aria-expanded="true">
     28              <span class="msg-thread-name"><%= _tlabel %></span>
     29              <% if (n.count > 1) { %><span class="msg-thread-count"><%= n.count %></span><% } %>
     30              <svg class="msg-thread-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
     31            </button>
    1932            <% if (_tnew) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
    2033            <%# De context bij de draad: waar gaat dit gesprek over? Zonder deze
Note: See TracChangeset for help on using the changeset viewer.