/
githubmirror
/
anime
Обзор
Документация
Войти
/
githubmirror
/
anime
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
examples/auto-layout/planets/index.js
200 строк
7 KB
Julian Garnier
4.5.0
22 июн 2026, 17:32
22 июн 2026, 17:32
34f4179
Код
Авторство
О чём код?
import { createLayout, utils, stagger } from '../../../dist/modules/index.js'; const planetTypes = [ "Rocky planet", "Gas giant", "Ice giant" ]; const planets = [ 60, "Mercury", "Smallest planet and closest to the Sun.", 0, 3, 3, 1, [], 90, "Venus", "Slow-spinning world with runaway greenhouse heat.", 0, 4, 3, 2, [], 100, "Earth", "It's apparently pretty nice over there.", 0, 5, 3, 6, [], 80, "Mars", "Cold desert planet with canyons and polar ice.", 0, 6, 3, 0, [], 250, "Jupiter", "Gigantic gas giant with a powerful magnetic field.", 1, 8, 3, 3, [], 150, "Saturn", "Ringed gas giant with dozens of icy moons.", 1, 9, 3, 4, [180, 200, 220, 240], 120, "Uranus", "An ice giant tipped almost completely on its side.", 2, 10, 3, 8, [150], 110, "Neptune", "Distant ice giant with supersonic winds.", 2, 11, 3, 10, [], ]; const latin = [ "lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua", "enim", "minim", "veniam", "quis", "nostrud", "exercitation", "ullamco", "laboris", "nisi", "aliquip", "ex", "ea", "commodo", "consequat", "duis", "aute", "irure", "dolor", "in", "reprehenderit", "voluptate" ] function loremIpsum(words = 100) { let text = []; for (let i = 0; i < words; i++) { text.push(latin[Math.floor(Math.random() * latin.length)]); } let sentence = text.join(" "); return sentence.charAt(0).toUpperCase() + sentence.slice(1) + "."; } let nextPlanetIndex = 0; const initialPlanets = 4; const toggles = utils.$('.controls button.toggle'); const [ $root ] = utils.$('#root'); const [ $overlay ] = /** @type {[HTMLDialogElement]} */(utils.$('#overlay')); const actions = { add: () => { const $visibleCards = utils.$('#root .card:not(.is-removed)'); const visibleCardsLength = $visibleCards.length; if (visibleCardsLength) utils.set($visibleCards, { '--total': visibleCardsLength + 1 }); nextPlanetIndex = visibleCardsLength * 8; if (nextPlanetIndex >= planets.length) return; const template = /** @type {HTMLTemplateElement} */(utils.$('#card')[0]); const $removed = utils.$('#root .card.is-removed')[0]; let $cardTarget = $removed; if (!$cardTarget) { const clone = /** @type {DocumentFragment} */(template.content.cloneNode(true)); const $card = /** @type {HTMLElement} */(clone.querySelector('.card')); if (!$card) return; const $image = $card.querySelector('.card-image'); const $title = $card.querySelector('.card-title'); const $type = $card.querySelector('.card-type'); const $intro = $card.querySelector('.card-intro-description'); const $description = $card.querySelector('.card-more-info'); $image.innerHTML += ` <svg class="planet" viewBox="0 0 600 600"><circle cx="300" cy="300" r="${planets[nextPlanetIndex]}"/></svg> `; $image.innerHTML += ` <svg class="rings" viewBox="0 0 600 600"> ${/** @type {Number[]} */(planets[nextPlanetIndex + 7]).map(r => `<circle cx="300" cy="300" r="${r}"/>`).join('')} </svg> `; utils.set($card, { '--index': visibleCardsLength + 1 }); $card.dataset.title = $title.textContent = `${planets[nextPlanetIndex + 1]}`; $type.textContent = planetTypes[/** @type {Number} */(planets[nextPlanetIndex + 3])]; $intro.textContent = `${planets[nextPlanetIndex + 2]}`; $card.dataset.color = `${planets[nextPlanetIndex + 6]}`; $description.textContent = loremIpsum(utils.random(100, 150)); $cardTarget = $card; $root.appendChild(clone); } $cardTarget.classList.remove('is-removed'); }, remove: () => { const $lastCard = utils.$('#root .card:not(.is-removed)').pop(); if ($lastCard) $lastCard.classList.add('is-removed'); }, shuffle: () => { utils.shuffle(utils.$('.card:not(.is-removed)')).forEach($el => $el.parentElement.appendChild($el)); } } for (let i = 0; i < initialPlanets; i++) { actions.add(); } const cardsLayout = createLayout($root, { properties: ['font-size'], enterFrom: { opacity: $el => $el.classList.contains('card') ? `1` : '0', transform: $el => $el.classList.contains('card') ? `translateY(150%) scale(.5)` : 'none', }, leaveTo: { opacity: 0, transform: ($el) => { const i = [...$el.parentElement.children].indexOf($el); const d = i % 2 ? -1 : 1; return $el.classList.contains('card') ? `translate(${50 * d}%, 50%) rotate(${20 * d}deg) scale(.5)` : 'none'; }, }, }); const modalLayout = createLayout($overlay, { children: ['.card', '.card-image', '.card-image-grid', '.card-title', '.card-type', '.close-overlay'], properties: ['--overlay-alpha'], duration: 500, }); const closeModal = () => { let $card; modalLayout.update(() => { $overlay.close(); $card = utils.$('#root .card.is-open')[0]; $card.classList.remove('is-open'); $card.focus({ preventScroll: true }); }).then(() => { $card.focus({ preventScroll: true }); }) }; const handleClick = e => { const $target = e.target; const $card = $target.closest('#root .card'); if ($card) { e.preventDefault(); const $clone = document.createElement('div'); $clone.innerHTML = $card.cloneNode(true).innerHTML; $clone.classList = $card.classList; $clone.dataset.layoutId = $card.dataset.layoutId; $clone.dataset.color = $card.dataset.color; $overlay.innerHTML = ''; const cloneChildren = $clone.querySelectorAll('*'); cloneChildren.forEach($el => $el.removeAttribute('style')); $overlay.appendChild($clone); modalLayout.update(() => { $overlay.showModal(); $clone.querySelector('button').disabled = false; $card.classList.add('is-open'); }); } if ($target.closest('#overlay .close-overlay') || $target.id === 'overlay') { closeModal(); } const $button = $target.closest('.controls button'); if ($button) { const isToggle = $button.classList.contains('toggle'); const isAction = $button.classList.contains('action'); const buttonId = $button.id; cardsLayout.update(() => { if (isToggle) { toggles.forEach(toggle => toggle.classList.remove('is-active')); $button.classList.add('is-active'); } else if (isAction) { actions[buttonId](); } const cards = utils.$('#root .card:not(.is-removed)'); const layoutType = utils.$('button.is-active')[0].id; $root.dataset.layout = layoutType; if (cards.length) { if (layoutType === 'stack') { utils.set(cards, { x: 0, y: stagger(10, { reversed: true}), z: stagger(-20, { reversed: true}), rotateX: 0, rotateY: 0, rotateZ: 0, scale: 1, }); } else if (layoutType === 'chaos') { utils.set(cards, { x: () => utils.random(-10, 10) + 'vw', y: () => utils.random(-10, 10) + 'vh', z: () => utils.random(600, 750), rotateX: () => utils.random(-45, 45), rotateY: () => utils.random(-45, 45), rotateZ: () => utils.random(-45, 45), scale: () => utils.random(.2, .3, 2), }); } else { utils.set(cards, { transform: 'none' }); } } }, { duration: isAction ? 350 : 450, ease: isAction ? 'out(3)' : 'inOut(3)', delay: isAction ? 0 : stagger([0, 350]) }); } } document.addEventListener('click', handleClick); $overlay.addEventListener('cancel', closeModal);