IMPERIVM

антуражное фэнтези ◆ 18+
готовность к открытию

BDH tester

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » BDH tester » МАТЧАСТЬ » Хронология


Хронология

Сообщений 1 страница 9 из 9

1

[html]
<article class="lore-article chronicle-page" id="chronicle-app">

  <header class="chronicle-plate" id="chronicle-plate">
    <span class="chronicle-art-note">Место для иллюстрации</span>
    <span class="lore-badge">Общая хронология</span>
    <h1>Хроники Материка</h1>
    <p class="lore-tagline">От исхода пришлых до нынешнего безмолвного противостояния</p>
  </header>

  <!-- инлайновый скрипт ниже вставляет сразу после плашки N радио
       .chronicle-era-input и nav.lore-tabs.chronicle-eras, а в конец
       #chronicle-app — div.lore-panels.chronicle-panels, всё из JSON, чтобы
       контент и разметка не расходились -->

  <div class="chronicle-filter">
    <span class="chronicle-filter-label">Показать:</span>
    <div class="chronicle-filter-chips" id="chronicle-filter-chips" role="group" aria-label="Фильтр по стране, Империи в целом или общим событиям"></div>
  </div>

  <p class="chronicle-intro">Единого летоисчисления материк не знал до основания престола — годы до него провинции считали каждая по-своему, и здесь они даны условно, «от основания» (И.Э. — Имперская эра). Эта хроника сводит две вещи, которые обычно рассказывают порознь: то, что происходило со всем материком разом, и то, что происходило в землях, которые сегодня зовутся Латериумом, Альсаром и Тянься. Фильтр общий для всех эпох и сохраняется при переключении.</p>
</article>

<script>
  // Данные хроники — отдельный JSON-файл (articles/timeline-data.json,
  // залитый на forumstatic.ru тем же способом, что и другие внешние ассеты
  // форума), а не разметка в этом файле — так фильтр, полоса эпох и сам
  // таймлайн строятся из одного источника и правятся в одном месте.
  const CHRONICLE_DATA_URL = 'https://forumstatic.ru/files/001c/c7/56/26482.json';

  // цвет области берётся из --tl-<id> в colors.css по id из JSON — новая
  // область в JSON требует только новой переменной, не новых правил CSS
  const scopeAccent = (scopeId) => `--item-accent: var(--tl-${scopeId})`;

  const renderChip = ({ id, label }) => `
    <input class="chronicle-filter-input" type="checkbox" id="filter-${id}" data-scope="${id}">
    <label class="chronicle-chip" data-scope="${id}" for="filter-${id}" style="${scopeAccent(id)}">${label}</label>
  `;

  // год — отдельная колонка слева от оси (на телефоне — строкой над
  // заголовком), страна/Империя — безрамочная подпись под заголовком
  const renderEvent = (scopeLabels) => ({ year, scope, title, text }) => `
    <li class="chronicle-item" data-scope="${scope}" style="${scopeAccent(scope)}">
      <span class="chronicle-year">${year}</span>
      <h4>${title}</h4>
      <span class="chronicle-scope-tag">${scopeLabels.get(scope) ?? scope}</span>
      <p>${text}</p>
    </li>
  `;

  const renderEraInput = ({ id }, index) => `
    <input class="lore-tab-input chronicle-era-input" type="radio" name="chronicle-era" id="era-${id}" ${index === 0 ? 'checked' : ''}>
  `;

  const renderEraCard = ({ id, name, range }) => `
    <label class="lore-tab chronicle-era-card" for="era-${id}">
      <span class="chronicle-era-name">${name}</span>
      <span class="chronicle-era-range">${range}</span>
    </label>
  `;

  // oneLiner эпохи — не в полосе эпох (пять колонок его не вмещают), а
  // вводной строкой открытой панели
  const renderEraPanel = (scopeLabels) => ({ id, oneLiner, intro, events }) => `
    <section class="lore-panel chronicle-detail" data-panel="${id}">
      <p class="chronicle-detail-lead">${oneLiner}</p>
      <p>${intro}</p>
      <ol class="chronicle-timeline">${events.map(renderEvent(scopeLabels)).join('')}</ol>
      <p class="chronicle-empty" hidden>Ни одно событие этой эпохи не подходит под выбранный фильтр.</p>
    </section>
  `;

  // радио должны стоять раньше и полосы эпох, и панелей (общий сосед для ~)
  const renderEras = ({ periods, scopes }) => {
    const scopeLabels = new Map(scopes.map(({ id, label }) => [id, label]));
    document.getElementById('chronicle-plate').insertAdjacentHTML('afterend', `
      ${periods.map(renderEraInput).join('')}
      <nav class="lore-tabs chronicle-eras" aria-label="Эпохи материка">${periods.map(renderEraCard).join('')}</nav>
    `);
    document.getElementById('chronicle-app').insertAdjacentHTML('beforeend', `
      <div class="lore-panels chronicle-panels">${periods.map(renderEraPanel(scopeLabels)).join('')}</div>
    `);
  };

  const renderFilterChips = ({ scopes }) => {
    document.getElementById('chronicle-filter-chips').insertAdjacentHTML('beforeend', `
      <input class="chronicle-filter-input" type="checkbox" id="filter-all" checked>
      <label class="chronicle-chip" for="filter-all">Всё</label>
      ${scopes.map(renderChip).join('')}
    `);
  };

  const scopeCheckboxes = () => Array.from(document.querySelectorAll('.chronicle-filter-input[data-scope]'));

  // пустой список = фильтр не сужает ничего, показываем все события
  const applyFilter = () => {
    const active = scopeCheckboxes().filter((input) => input.checked).map((input) => input.dataset.scope);
    document.querySelectorAll('.chronicle-detail').forEach((panel) => {
      const items = Array.from(panel.querySelectorAll('.chronicle-item'));
      const shown = items.filter((item) => !active.length || active.includes(item.dataset.scope));
      items.forEach((item) => { item.hidden = !shown.includes(item); });
      panel.querySelector('.chronicle-empty').hidden = shown.length > 0;
    });
  };

  const onFilterChange = (target) => {
    const allCheckbox = document.getElementById('filter-all');
    if (target === allCheckbox) {
      if (target.checked) scopeCheckboxes().forEach((input) => { input.checked = false; });
    } else {
      if (target.checked) allCheckbox.checked = false;
      if (!scopeCheckboxes().some((input) => input.checked)) allCheckbox.checked = true;
    }
    applyFilter();
  };

  // на телефоне полоса эпох прокручивается вбок — выбранная эпоха не должна
  // оставаться за краем экрана
  const onEraChange = (target) => {
    target.labels[0].scrollIntoView({ block: 'nearest', inline: 'nearest' });
  };

  // один делегированный обработчик на всю статью: и радио эпох, и чекбоксы
  // фильтра вставляются скриптом, а не стоят в разметке заранее
  const onChange = ({ target }) => {
    if (target.matches('.chronicle-filter-input')) onFilterChange(target);
    else if (target.matches('.chronicle-era-input')) onEraChange(target);
  };

  const initChronicle = (data) => {
    renderEras(data);
    renderFilterChips(data);
    document.getElementById('chronicle-app').addEventListener('change', onChange);
  };

  fetch(CHRONICLE_DATA_URL)
    .then((response) => response.json())
    .then(initChronicle);
</script>
[/html][hideprofile]

0

2

Общая хронология.

0

3

АЛЬСАР
Начался 453 год (и.э. - имперская эпоха).
До и.э. — Великая пустыня, будущий Альсар, остаётся необитаемой. Ни пришлые, ни коренные не находят в ней ничего, кроме одичавших виверн.
22 и.э. — Первый Император жалует Основательнице Великую пустыню. За ней следуют освобождённые легионеры, ветераны и ремесленники. Начинается строительство первых поселений, колодцев и цистерн.
60 и.э. — рождение Имперских трактов. Альсар превращается в главный сухопутный коридор Империи.
129–136 и.э. — завоевание Рунхейма. Альсарские всадники помогают покорить Север.
140–200 и.э. — расцвет караванного Альсара. После расширения Империи через пустыню начинает проходить ещё больше товаров и людей. Возникают новые караванные города, а великие дома укрепляют власть над оазисами и трактами.
299 и.э. — катастрофа виверн. Виверны внезапно обращаются против своих всадников. В тот же день подобное происходит в Латериуме. За несколько дней погибают сотни людей. Уцелевшие звери покидают земли людей и уходят в Железные горы. В новый век Империя входит уже без всадников.
~300–400-е гг. — век без виверн. Альсар перестраивается: караванные пути и укрепления становятся важнее воздушной силы, а приручение виверн превращается из живой традиции в утраченное искусство. Попытки восстановить его почти неизменно заканчиваются смертью.
438 и.э. - обострение отношений Альсара и Эринора. Попытка положить конец многолетним спорам оканчивается таинственной смертью эринорской невесты.
451 и.э. — пробуждение вулкана в Каменных землях. Извержение разрушает богатейшие рудники и гнёзда последних диких виверн.
453 и.э. — исчезновение Советника Капитула Альрика Лашанса в Великой пустыне. Вместе с ним исчезает караван и груз уцелевших яиц виверн.

0

4

Хронология Вельгории.

0

5

Хронология Восточного Триархата.

0

6

Хронология Латериума.

0

7

Хронология Рунхейма

0

8

Хронология Эринора

0

9

Хронология магии.

0


Вы здесь » BDH tester » МАТЧАСТЬ » Хронология


Рейтинг форумов | Создать форум бесплатно