Fix quote

This commit is contained in:
Felix Klement committed 2026-10-17 18:07:08 +02:00
1 parent d1a9214ffd
commit 327f53922d
1 file changed
+15 -1
+15 -1
View File
@@ -16,7 +16,7 @@ const quoted = (text: string) => (lang === 'de' ? `„${text}“` : `“${text}
--- ---
<section class="section--tight quote" aria-roledescription="carousel" aria-label={ui.quote.label} data-quotes> <section class="section--tight quote" aria-roledescription="carousel" aria-label={ui.quote.label} data-quotes>
<div class="container"> <div class="container">
<div class="quote__frame"> <div class="quote__frame" data-frame>
<div class="quote__panel"> <div class="quote__panel">
<div class="quote__stack" aria-live="off" data-live> <div class="quote__stack" aria-live="off" data-live>
{items.map((item, i) => ( {items.map((item, i) => (
@@ -85,6 +85,8 @@ const quoted = (text: string) => (lang === 'de' ? `„${text}“` : `“${text}
display: grid; display: grid;
background: var(--paper-deep); background: var(--paper-deep);
} }
/* The whole card advances on click once the script has set it up. */
.quote[data-ready] .quote__frame { cursor: pointer; }
.quote__panel { .quote__panel {
display: grid; display: grid;
gap: var(--space-7); gap: var(--space-7);
@@ -232,6 +234,7 @@ const quoted = (text: string) => (lang === 'de' ? `„${text}“` : `“${text}
const picks = Array.from(root.querySelectorAll<HTMLButtonElement>('[data-pick]')); const picks = Array.from(root.querySelectorAll<HTMLButtonElement>('[data-pick]'));
const live = root.querySelector<HTMLElement>('[data-live]')!; const live = root.querySelector<HTMLElement>('[data-live]')!;
const controls = root.querySelector<HTMLElement>('[data-controls]')!; const controls = root.querySelector<HTMLElement>('[data-controls]')!;
const frame = root.querySelector<HTMLElement>('[data-frame]')!;
const fills = picks.map((p) => p.querySelector<HTMLElement>('.quote__fill')!); const fills = picks.map((p) => p.querySelector<HTMLElement>('.quote__fill')!);
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
let index = 0; let index = 0;
@@ -258,6 +261,16 @@ const quoted = (text: string) => (lang === 'de' ? `„${text}“` : `“${text}
fills.forEach((fill) => fill.addEventListener('animationend', () => { if (playing) show(index + 1); })); fills.forEach((fill) => fill.addEventListener('animationend', () => { if (playing) show(index + 1); }));
picks.forEach((pick, i) => pick.addEventListener('click', () => { setPlaying(false); show(i); })); picks.forEach((pick, i) => pick.addEventListener('click', () => { setPlaying(false); show(i); }));
// A click anywhere else on the card moves on to the next statement and (re)starts the rotation,
// so the new statement gets its full hold. Links and the picks keep their own behaviour, and
// selecting the quote to copy it does not count.
frame.addEventListener('click', (e) => {
if ((e.target as Element).closest('a, button')) return;
if (window.getSelection()?.toString()) return;
show(index + 1);
setPlaying(!reduced);
});
const hold = (on: boolean) => root.toggleAttribute('data-held', on); const hold = (on: boolean) => root.toggleAttribute('data-held', on);
root.addEventListener('focusin', () => hold(true)); root.addEventListener('focusin', () => hold(true));
root.addEventListener('focusout', (e) => { if (!root.contains(e.relatedTarget as Node)) hold(false); }); root.addEventListener('focusout', (e) => { if (!root.contains(e.relatedTarget as Node)) hold(false); });
@@ -266,6 +279,7 @@ const quoted = (text: string) => (lang === 'de' ? `„${text}“` : `“${text}
new IntersectionObserver(([entry]) => root.toggleAttribute('data-away', !entry.isIntersecting), { threshold: 0.4 }).observe(root); new IntersectionObserver(([entry]) => root.toggleAttribute('data-away', !entry.isIntersecting), { threshold: 0.4 }).observe(root);
controls.hidden = false; controls.hidden = false;
root.setAttribute('data-ready', '');
setPlaying(!reduced); setPlaying(!reduced);
} }
</script> </script>