→ לכל המאגר

B59 · רשימה חיה שפריטים נכנסים אליה

התנהגויות vanilla JS · FLIP טעינה ופידבקכרטיסים ממתין

פריט חדש נכנס לראש הרשימה בקפיצה קטנה, והקודמים נדחפים למטה בחלקות במקום לקפוץ. הרשימה מרגישה כמו פיד חי.

מתי משתמשים: פיד התראות, הדגמת מערכת שעובדת, לוג פעילות, "מה קרה היום". מקסימום חמישה פריטים גלויים.

הדמו כאן עיצובי-ניטרלי בכוונה. כשהמהלך נכנס לפרויקט, מיובאת רק ההתנהגות: הצבעים, הרדיוסים, הפונטים והצללים יורשים את העיצוב של אותו פרויקט.

הדמו

מקור: MagicUI AnimatedList. נכתב מחדש עם FLIP ידני: מודדים מיקום לפני ואחרי ההוספה ומזיזים ב-transform. הישנים נגזרים מלמטה, לא נמחקים בבת אחת.

קוד להדבקה

הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --accent או --line משלו יורש אותם אוטומטית. הרכיב הזה מסתמך על dir="rtl".

פתח קובץ עצמאי ↗
הצג את הקוד כאן

CSS

/* מחלקות עזר של המאגר שהרכיב הזה משתמש בהן */
.stage{padding:var(--sec, clamp(120px, 12vw, 260px)) var(--gutter, clamp(24px, 5vw, 96px));position:relative}
.stage.tight{padding-block:clamp(48px,5vw,90px)}
.stage.full{padding-inline:0}

/* B59 · רשימה חיה שפריטים נכנסים אליה */
.al{max-width:440px;margin-inline:auto;display:flex;flex-direction:column;gap:12px;height:380px;overflow:hidden;
  mask-image:linear-gradient(180deg,#000 70%,transparent);-webkit-mask-image:linear-gradient(180deg,#000 70%,transparent)}
.al-item{display:flex;align-items:center;gap:14px;background:var(--card, #fff);border:1px solid var(--line, #e4e4ee);border-radius:16px;padding:14px 16px;box-shadow:0 6px 20px rgba(0,0,0,.06);will-change:transform}
.al-item.enter{animation:al-in .55s cubic-bezier(.2,.6,.2,1) both}
@keyframes al-in{from{opacity:0;transform:scale(.92) translateY(-10px)}}
.al-ic{width:42px;height:42px;border-radius:12px;display:grid;place-items:center;color:#fff;font-weight:800;flex:none}
.al-t{display:flex;flex-direction:column;gap:2px;min-width:0}
.al-t b{font-size:15px}.al-t span{font-size:13px;color:var(--muted, #6a6d85);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.al-time{margin-inline-start:auto;font-size:12px;color:var(--muted, #6a6d85);flex:none}
@media (prefers-reduced-motion: reduce){.al-item.enter{animation:none}}

HTML

<div class="stage tight"><div class="al" aria-live="polite"></div></div>

JS

(function(){
  const list=document.querySelector(".al"),reduce=matchMedia("(prefers-reduced-motion: reduce)").matches;
  const feed=[["ליד חדש","דנה מחיפה השאירה פרטים בטופס","ph-a"],["תשלום התקבל","חשבונית 2041 שולמה","ph-d"],["פגישה נקבעה","יום שלישי 10:00 עם רועי","ph-b"],["הודעת וואטסאפ","\"אפשר הצעת מחיר?\"","ph-c"],["ביקור חוזר","לקוח מ-2024 חזר לעמוד המחירים","ph-e"]];
  let i=0;
  function add(){
    const [t,s,c]=feed[i++%feed.length];
    const before=new Map([...list.children].map(el=>[el,el.getBoundingClientRect().top]));
    const el=document.createElement("div");el.className="al-item enter";
    el.innerHTML='<span class="al-ic '+c+'">'+t[0]+'</span><div class="al-t"><b>'+t+'</b><span>'+s+'</span></div><span class="al-time">עכשיו</span>';
    list.prepend(el);
    if(!reduce){before.forEach((top,node)=>{const d=top-node.getBoundingClientRect().top;if(!d)return;
      node.animate([{transform:"translateY("+d+"px)"},{transform:"none"}],{duration:500,easing:"cubic-bezier(.2,.6,.2,1)"});});}
    [...list.children].slice(6).forEach(n=>n.remove());
    el.addEventListener("animationend",()=>el.classList.remove("enter"),{once:true});
  }
  add();add();add();
  setInterval(add,2200);
})();