Иркана

Локальная вики вымышленного мира: markdown-файлы, wiki-ссылки <span class="wiki-link missing" title="Страница не найдена">страница</span>, инфобоксы, поиск, карта мира и тёмная/светлая тема. Весь контент берётся из папки content/ — добавил .md-файл, и он сразу появляется в навигации, разделах и поиске.

Запуск

npm install
npm run dev

Откроется локальный сайт (http://localhost:5173).

Одним щелчком

В корне лежит «Запустить сайт.bat» — двойной щелчок поднимает сервер и сам открывает браузер. На рабочем столе есть ярлык «Иркана» на этот же файл. Чёрное окно, которое остаётся, и есть сервер: пока оно открыто, сайт работает и подхватывает правки в content/; закрыл окно — остановил сайт.

Если сайт уже запущен, второй сервер не поднимается — просто открывается браузер на работающем. При первом запуске на новой машине скрипт сам сделает npm install. Логика лежит в scripts/start-site.ps1; другой порт — "Запустить сайт.bat" -Port 5199.

Как добавить страницу

Создай .md-файл в папке content/. Папка = раздел. Например файл content/страны/Орловия.md попадёт в раздел «Страны».

content/
  страны/    → раздел «Страны»
  люди/      → раздел «Люди»
  династии/  → раздел «Династии»
  события/   → раздел «События»
  места/     → раздел «Места»
    Города/  → подраздел «Города»
  прочее/    → раздел «Прочее»
  маршруты/  → служебная папка, в «Разделы» не попадает

Вложенные папки становятся подразделами. Файл content/места/Города/Авьер.md попадёт в раздел «Места», подраздел «Города» — и в боковом меню, и на странице раздела. Глубже одного уровня вложенности не поддерживается.

Самый быстрый способ завести новую страницу — скопировать файл-шаблон content/страны/Амбрания.md и поменять в нём поля.

Карточка страницы (frontmatter)

Блок между --- в начале файла. Все поля необязательны, кроме текста.

---
title: Орловия                     # заголовок (если нет — берётся из имени файла)
category: Страны                   # раздел (если нет — берётся из папки)
description: Морская держава юга.   # короткое описание для карточек и поиска
tags: [море, монархия]             # теги; по клику — список страниц с тегом
map:                               # метка на карте мира, в процентах
  x: 62
  y: 48
cover: /covers/orlovia.webp        # обложка для карточки в списках
photo: /covers/orlovia.webp        # фото в рамке инфобокса (как в Википедии)
caption: Герб Орловии              # подпись под фото
info:                              # строки инфобокса справа — любые поля
  Столица: Порт-Орлов
  Население: ~1 200 000
  Форма правления: Монархия
  Язык: Орловский
---

Здесь основной текст в **markdown**. Заголовки разделов — через `##`.

Пустые поля info (со значением или вовсе без значения) в инфобоксе не показываются, так что можно держать заготовку и заполнять постепенно.

Персонажи: фото, годы жизни и титулы

У людей и событий есть дополнительные поля. Образцы — в файлах content/люди/Эдурд Чарр.md (персонаж), content/события/Падение Катренского метеорита.md (событие).

---
title: Эдуард IX Чарр
category: Люди
photo: /people/eduard.webp     # портрет в рамке инфобокса
born: 1402                     # годы жизни (отрицательное число = днэ)
died: 1478                     # → строка «Годы жизни» + метка на хронологии
info:
  Династия: Чарры
  Отец: Карл II Чарр
titles:                        # титулы в стиле Википедии
  - title: Король Катрении
    from: 1435
    to: 1478
    before: люди/Карл Чарр      # путь к странице → станет ссылкой
    after: люди/Миллард Чарр
---

У событий вместо born/diedyear: 1456 (точечное) или start/end (период).

Фото

photo: показывается в рамке инфобокса (как в Википедии), cover: — на карточке в списках. Можно указать один и тот же файл. Пока файла нет, в инфобоксе видна рамка-заглушка «фото».

Wiki-ссылки

<a href="/страны/Орловия/" class="wiki-link" data-slug="страны/Орловия">Орловия</a>                # ссылка по пути
<span class="wiki-link missing" title="Страница не найдена">Арден</span>   # ссылка с другим текстом
<a href="/прочее/Ребенсне/" class="wiki-link" data-slug="прочее/Ребенсне" data-section="Новое Ребенсне">Ребенсне › Новое Ребенсне</a>       # ссылка на раздел внутри статьи
<a href="/прочее/Ребенсне/" class="wiki-link" data-slug="прочее/Ребенсне" data-section="Новое Ребенсне">туда</a>  # то же, но со своей подписью

Ссылка на раздел открывает статью и подводит её к нужному заголовку. Заголовок ищется по тексту, поэтому при переименовании раздела ссылку надо поправить. Без своей подписи такая ссылка показывается как «Ребенсне › Новое Ребенсне».

На целевой странице автоматически появляется блок «Ссылки сюда» (обратные ссылки). Ссылки на раздел считаются ссылками на саму статью.

Карта мира

Карта рисуется контурами стран: страна выделяется наведением на саму территорию, клик открывает её статью, колесо приближает, перетаскивание двигает карту. Как её собрать — ниже, в разделе «Контуры стран».

Метка map: { x, y } (проценты от ширины и высоты карты) у страны всё ещё нужна, но на сайте она не показывается: по ней npm run borders понимает, какой контур чей.

Как получить координаты метки: на карте нажми кнопку «Метка» и кликни в нужную точку страны. Под картой появятся координаты и цвет пикселя нарисованной карты в этой точке; клик по цвету копирует строку color:, клик по координатам — блок map:. В этом режиме клик по стране статью не открывает; выключи кнопку — карта снова обычная. Нарисованная карта public/map.webp весит около 11 МБ и подгружается только при первом включении режима.

Флаги и гербы

Оригиналы лежат в public/symbols/. Показывать их напрямую нельзя: у флагов разрешение под 8000×4500, и чтобы нарисовать флажок в 18 px, браузер разворачивает в память 36 мегапикселей — одна такая картинка раскодируется треть секунды, а в таблице войны их полтора десятка.

Поэтому после добавления нового флага или герба:

npm run flags

Скрипт кладёт уменьшенные копии в public/symbols/mini (96 px — флажки в строках) и public/symbols/thumb (480 px — рамка инфобокса). Именно они и уходят на страницы, оригиналы остаются нетронутыми. Уже собранные копии пересобираются только если оригинал новее.

Контуры стран

Из них и состоит «Карта мира». Нарисованная карта public/map.webp на сайте больше не показывается — она осталась источником: по ней обводятся контуры, с неё снимается цвет в режиме «Метка» и тон страны при сборке.

Контуры обводятся в Inkscape поверх public/map.webp инструментом Paint Bucket и складываются в Карта.svg в корне проекта. Требование одно: размер документа должен совпадать с картой (7016×4960), иначе координаты не лягут. Подписывать контуры не нужно.

Дальше:

npm run borders

Скрипт scripts/borders.mjs читает Карта.svg, распрямляет кривые, упрощает контуры и кладёт результат в public/borders.json (он подтягивается только на странице карты, в общий бандл не попадает). Какой контур какой стране принадлежит, он определяет сам: смотрит, внутрь какого контура попала метка map: { x, y } из frontmatter. Если меток внутри контура несколько, берётся наименьший по площади — так анклав не съедает страну вокруг себя.

Вырезать одну страну

Если нужен контур отдельной страны — своим файлом, например чтобы рисовать по нему области или герб:

node scripts/country-svg.mjs Хебек

Рядом появится Хебек.svg. Исходная Карта.svg при этом только читается — в неё не пишется ни байта. Данные пути копируются как есть, вместе с кривыми Безье: это выборка нужных объектов, а не пересчёт контура. Координаты остаются мировыми (7016×4960), поэтому кусок можно вставить обратно в карту, и он встанет на своё место.

Ключи: --out путь/файл.svg — куда положить, --world — оставить рамку всей карты вместо рамки по стране, --plain — без заливки, только контур. Заливка по умолчанию берётся из color страны.

Если один объект карты держит сразу несколько стран (так бывает после заливки Paint Bucket), скрипт об этом предупредит: в файл попадут и соседи.

Площадь страны

Тот же скрипт считает по контурам площади и кладёт их в src/map-areas.ts (файл сгенерирован — руками не править, он перезаписывается каждым npm run borders). Правило масштаба задано там же, в начале scripts/borders.mjs:

  • Иркана в 1,75 раза больше Земли, доля суши у неё земная — значит и суши ровно в 1,75 раза больше земной: 148 940 000 × 1,75 = 260 645 000 км².
  • Вся нарисованная суша — это те самые 100 %. Площадь страны — её доля контуров от общей суммы, умноженная на 260 645 000.

Размер карты в пикселях и доля океана на рисунке в расчёт не входят: важны только пропорции стран между собой. Карта считается плоской и равновеликой — искажений проекции у неё нет, поэтому север и юг не растянуты.

Площадь считается как рисуется: озеро внутри страны вычитается, остров посреди озера прибавляется. Дырка определяется правилом nonzero (кольцо, закрученное против объемлющего), тем же, каким Inkscape заливает фигуру.

Цвет страны

По кнопке «Цвета» карта раскрашивается по странам. Цвет можно задать самой стране, в её frontmatter:

color: "#3f6ea5"

Заданный так цвет используется ровно как написан, в обеих темах. Принимается #abc и #aabbcc.

Без color цвет подбирается сам: тон снимается с нарисованной карты public/map.webp (скрипт тычет сеткой точек внутрь контура и берёт самый частый цвет — самый частый, а не средний: усреднение смешало бы заливку с чёрными линиями границ), а насыщенность и светлота приходят из темы сайта. Такая страна сама перекрашивается вместе с темой и держится общей гаммы. Тон достался 148 странам из 157; у остальных на карте серая заливка, тона у неё нет, и они остаются общего цвета суши.

То есть по умолчанию карта сама собой в гамме сайта, а color — это способ сказать «вот этой стране нужен именно такой цвет». Учти только, что заданный цвет не подстраивается под тему: тёмный будет тёмным и на светлом фоне.

Общую гамму автоматических цветов задают две строки в src/styles.css--map-s (насыщенность) и --map-l (светлота), отдельно для светлой и тёмной темы.

Страна из нескольких кусков

Paint Bucket делает отдельный контур на каждый клик, поэтому страна с островами или анклавом состоит из нескольких контуров, а одна метка map забирает только один из них — остальные куски остаются ничьими.

Лишние куски раздаются точками в блоке areas — это те же координаты в процентах, что и map, только списком:

map:
  x: 61.2
  y: 46.8
areas:
  - x: 58.1
    y: 44.3
  - x: 63.9
    y: 45.0

Страна забирает все контуры, внутрь которых попала хоть одна её точка.

Руками эти координаты подбирать не надо: включи на карте режим «Метка» и кликни в нужный кусок — координаты скопируются кликом по ним. Второй способ, когда кусок вообще ничей: посмотреть в Inkscape его id (например path186) и вписать пару «id → страна» в scripts/borders-bind.json — так привязаны 15 кусков, до которых метки не дотянулись.

В конце скрипт печатает отчёт: сколько сопоставлено, у каких стран ни одна точка не попала в контур и сколько кусков осталось ничьими.

Хронология

Два режима, переключаются кнопками сверху.

Срез года — ползунок лет от 8200 днэ до 2050 нэ. Под ним показываются статьи, актуальные для выбранного года: сначала люди (от «Величайших» вниз), потом события, потом остальное. Дорожка покрывает больше десяти тысяч лет, то есть один пиксель — это полтора десятка лет, поэтому точный год выставляется кнопками и + справа от года, по одному году за нажатие. Открывается хронология на самом «населённом» статьями годе.

Лента — все датированные статьи подряд, от древности к современности. Клик по заголовку века переключает на срез этого времени.

Статья попадает в хронологию по полям born/died (люди), year или start/end (события). Если их нет, даты подхватываются из строк инфобокса («Годы жизни», «Дата», «Период»).

Маршруты по лору

Файлы в content/маршруты/ — кураторские цепочки статей для знакомства с миром. Карточки маршрутов показываются на главной, а внизу каждой статьи-шага появляется плашка «шаг N из M» со ссылками вперёд/назад. Формат:

---
title: Путь Ветолло
kicker: Династии            # надзаголовок карточки
description: Короткое описание маршрута.
steps:                      # порядок строк = порядок чтения
  - династии/Ветолло
  - люди/Дарий Ветолло
---
Свободный текст-введение (необязательно).

Инфобокс: разделы, флаг и герб

  • Разделы. Строка info без значения становится заголовком раздела — удобно отделять блоки полей: История: и дальше поля этого раздела.
  • Флаг и герб. Поля flag и coat во frontmatter — картинки в шапке инфобокса: флаг во всю ширину, герб под ним. Если файла нет, картинка просто не показывается.
  • Перечень в строке. Точка с запятой начинает новую строку — длинный список режимов или титулов читается столбиком, а не сплошняком.
  • Годы до нашей эры. Значение вида -1320 показывается как «1320 днэ». Правило срабатывает, только когда всё значение целиком — отрицательное число.
  • Территория с прочерком заполняется сама — площадью по контурам карты, тем же числом, что в рейтинге площади. Своё значение, если оно вписано, остаётся.
  • Предшественники и преемники вынесены из таблицы в отдельную плашку на всю ширину: слева те, кто был до, справа те, кто после, у каждого свой флажок. Работает и в единственном числе (Предшественник), и во множественном; несколько государств разделяются той же точкой с запятой. Пока обе строки пустые, это обычные строки «уточняется».
flag: /symbols/катрения-флаг.webp
coat: /symbols/катрения-герб.webp
info:
  Столица: Велгард
  Основано: -1320           # покажется как «1320 днэ»
  Режим: диктатура (1924—1938); хунта (1963—1979)   # каждая позиция с новой строки
  Территория: -             # подставится площадь по карте
  История:                  # строка без значения = заголовок раздела
  Предшественники: <span class="wiki-link missing" title="Страница не найдена">Южный блок</span>; <a href="/страны/Гесбанс/" class="wiki-link" data-slug="страны/Гесбанс">Гесбанский директорат</a>
  Преемники: <a href="/страны/МСЗ/" class="wiki-link" data-slug="страны/МСЗ">Международная Союзническая Зона</a>

Состояние государства (экономика)

Странам можно добавить блок economy со срезами по годам — на странице страны сразу после введения появится блок «Состояние государства»: выбор года, таблица показателей, график по годам (ВВП/население) с подсказками по точкам, круговая диаграмма сословий, народов или профессий и радар показателей. Считаются сами: реальное ВВП (ВВП × контроль), ВВП на д/н, доля армии, госдолг к ВВП и торговый баланс — он считается от внешнеторгового оборота ((экспорт − импорт) / (экспорт + импорт)), поэтому работает при любом масштабе чисел. Срез, где все показатели нулевые, считается незаполненным и не показывается.

Экспорт, импорт и госдолг записываются в процентах от ВВП — сумма считается сама и показывается в таблице, а под ней стоит сама доля. Доля и есть то, что задумывается («торговая страна» или «закрытая»), а сумма из неё следует; при пересчёте ВВП абсолютные числа молча превращались бы в другую долю, и заметить это было бы нельзя. Для ориентира, сколько это на Земле: США ≈ 11 % ВВП, Китай ≈ 20 %, Япония ≈ 22 %, Германия ≈ 43 %. Знак процента в значении можно писать, можно нет — 1.8 и 1.8% понимаются одинаково.

Рейтинг стран — отдельная страница со всеми показателями таблицы: страны ранжируются за выбранный год, лучшие 20 % зелёные, худшие 20 % красные. Клик по значку места («№3») в таблице страны открывает рейтинг на этом показателе. Этими же цветами раскрашены значения в самой таблице.

Особняком стоит рейтинг «Площадь»: он берётся не из economy, а из контуров карты (src/map-areas.ts), поэтому в нём сразу все 157 стран с контуром и нет выбора года — границы на карте одни на все времена. Показывается площадь в км² с тремя значащими цифрами и доля от всей суши мира. Такому показателю в RANK_METRICS ставится timeless: true — он и убирает выбор года.

Индекс мощи (под радаром) — взвешенная оценка государства. База считается по семи показателям с весами, дающими в сумме 100: экономика 25, армия 20, наука 17, дипломатия 12, население 12, территория 8, культура 6. Затем база умножается на множитель стабильности 0.4 + 0.6 × (Стабильность − 1) / 8, то есть от 0,4 при одном балле до 1,0 при девяти. «Развитие» в расчёте не участвует. Если какого-то показателя нет, веса пересчитываются по имеющимся; у полностью незаполненной страны индекс не показывается. «Территория» одна страну заполненной не делает: она проставлена всем по площади с карты (ниже), и иначе у каждой заготовки индекс считался бы от неё одной.

Территория в радаре считается по площади с карты, а не выставляется на глаз: node scripts/territory.mjs --write прописывает её всем странам с контуром. Шкала логарифмическая с полом: до 200 тыс. км² — единица, самая большая страна — девятка, остальные между ними по логарифму площади. Площади размазаны на четыре порядка, и без пола страна в 60 тыс. км² выходила бы на четыре балла. После перерисовки карты — сначала npm run borders, потом этот скрипт. Ручное значение он перезапишет, так что не спорь с ним, а меняй пол или шкалу в самом скрипте.

Цвета в таблице «Состояние государства» — по месту среди стран за тот же год: лучшие 20 % зелёные, худшие 20 % красные, середина без цвета. Так у всех денежных показателей, включая ВВП на душу; пороговые только продовольствие, торговый баланс, безработица и ИЧР.

Ранг государства выводится из индекса мощи и показывается цветным щитом справа от заголовка «Состояние государства», а также в сравнении стран и в рейтинге. Границы и названия рангов правятся в одном месте — константа POWER_TIERS в src/special.ts:

Индекс Ранг
от 8.6 Гегемон
от 7.5 Сверхдержава
от 6.5 Великая держава
от 5.5 Сильная региональная держава
от 3.5 Региональная держава
от 2.0 Слабое государство
от 1.1 Несостоявшееся государство
ниже Не государство

ИЧР считается из радара как среднее геометрическое трёх показателей, приведённых к 0–1: Стабильность, Экономика и скрытого Развитие (1–9). «Развитие» не рисуется на радаре и не участвует ни в каком другом расчёте — он нужен только для индекса. Диапазон итога — как у настоящего ИЧР: 0,001–0,999. Госдолг задаётся процентом от ВВП, а сумма считается сама: Госдолг: 86.5 при ВВП 3 700 000 000 000 даст 3 200 500 000 000. В таблице показывается сумма, а под ней исходный процент. Поля Госдолг и Безработица необязательны — если их нет, ячейки не показываются.

Показатели по годам. Блок radar можно задать двумя способами: одним общим набором (значения не меняются) либо списком срезов с полем Год — тогда радар, индекс мощи и ИЧР меняются вместе с выбранным годом. Годы срезов удобно держать теми же, что в economy; если точного совпадения нет, берётся ближайший более ранний срез. Для сайдбара и сравнения стран используется последний срез.

radar:                        # вариант со срезами по годам
  - Год: 1838
    Армия: 6
    Экономика: 5.2
    Стабильность: 4.5
    Развитие: 4
  - Год: 2000
    Армия: 9
    Экономика: 8.4
    Стабильность: 6.3
    Развитие: 7

Валюта у мира единая — кэт; её значок задаётся константой CURRENCY_ICON в src/special.ts.

Курс: 1 кэт = 30 долларов. Запись на память, для сверки цифр между собой — в коде это число нигде не используется и на сайте не показывается. Отсюда и брались суммы: ВВП страны = ВВП её земного прообраза, поделённый на курс. По этому курсу Топес считался с США (970 млрд кэтов ≈ 29 трлн $), а Празия и Чатрия набирались раньше, от Германии и Китая, и на 30 не сходятся — получается, что Празия вдвое богаче Германии, а Чатрия в полтора раза богаче Китая. Так и оставлено намеренно.

Пример блока экономики:

economy:
  - Год: 1838
    Население: 34000000
    Контроль: 80            # % выпуска, доступный центру
    ВВП: 90000000
    Армия: 700000
    Продовольствие: 88      # процент обеспеченности
    Экспорт: 19.3           # процент от ВВП, сумма считается сама
    Импорт: 16.7            # то же
    Госдолг: 44.4           # процент от ВВП, сумма считается сама
    Безработица: 9          # необязательно, в процентах
  - Год: 2000
    Население: 42000000
    Контроль: 85
    ВВП: 120000000
    Армия: 850000
    Продовольствие: 92
    Экспорт: 22.5
    Импорт: 19.8
classes:                    # сословия, в процентах
  Высшее сословие: 5
  Среднее сословие: 27
  Низшее сословие: 68
peoples:                    # народы, в процентах
  Катренцы: 91
  Прочие народы: 9
professions:                # профессии, в процентах
  Крестьяне: 58
  Ремесленники: 18
  Торговцы: 11
religions:                  # религии, в процентах
  Катренская церковь: 62
  Старая вера: 24
  Неверующие: 14

Все четыре среза — сословия, народы, профессии, религии — рисуются одной и той же кольцевой диаграммой; переключатель над ней показывает только заполненные.

Доли идут по убыванию — и на кольце, и в списке рядом; порядок в frontmatter на это не влияет и нужен только тебе. Равные доли остаются в том порядке, в каком записаны.

Наведение на долю в круговой диаграмме подсвечивает её и её строку в легенде (и наоборот), а название доли уходит в центр кольца. На телефоне наведения нет — там подсветка закрепляется нажатием на строку легенды.

Длинный список не растягивает бокс: под легенду отведён потолок примерно в восемь строк, дальше она прокручивается. Цветов долей шестнадцать (BAR_COLORS в src/special.ts) — хватает и на дробные срезы вроде профессий с четырнадцатью строками.

Парламент

Блок идёт сразу за «Состоянием государства» в той же рамке. Задаётся во frontmatter страны, палат может быть одна или две:

parliament:
  name: Национальное собрание   # необязательно; по умолчанию просто «Парламент»
  chambers:
    - name: Палата представителей
      years:
        - year: 2025            # созыв
          seats: 450            # столько точек будет на дуге
          parties:
            - name: Либертарианская партия
              share: 34.5       # процент мест
              color: "#a8802f"  # необязательно
            - name: Союз федералистов
              share: 27
            - name: Независимые
              share: 6
        - year: 2021
          name: Народное собрание   # палату переучредили — новое имя с этого созыва
          seats: 450
          parties:
            - name: Союз федералистов
              share: 41
    - name: Сенат
      years:
        - year: 2023
          seats: 120
          parties:
            - name: Союз федералистов
              share: 30

Годы можно и не заводить — тогда состав описывается прямо в палате, seats и parties рядом с name, и переключателя не будет.

Как это считается:

  • Годы созывов собираются со всех палат и попадают в переключатель в шапке блока, как у «Состояния государства». Год из until в списке не появляется: роспуск сам по себе года в переключатель не добавляет. Для выбранного года каждая палата показывает последний состоявшийся к нему созыв: палата заседает между выборами, а избираются палаты вразнобой. Год созыва стоит плашкой рядом с названием, и по нему видно, что состав старше выбранного года.
  • Палата видна не всегда. Её нет, пока не прошёл первый созыв, и нет начиная с года в поле until. Этим однопалатный парламент превращается в двухпалатный и обратно:
  chambers:
    - name: Старый собор
      until: 1874          # с 1874 этой палаты больше нет
      years:
        - year: 1839
          seats: 150
          parties: [...]
    - name: Нижняя палата  # первый созыв 1874 — раньше её не существовало
      years:
        - year: 1874
          seats: 300
          parties: [...]
    - name: Верхняя палата
      until: 1890          # с 1890 парламент снова однопалатный
      years:
        - year: 1874
          seats: 100
          parties: [...]
  • Если на выбранный год не осталось ни одной палаты — так бывает, когда созыв задан позже года роспуска своей палаты, — блок остаётся на месте с пометкой «В этом году парламент не заседал». Он не исчезает целиком нарочно: иначе вместе с ним пропал бы переключатель года и вернуться было бы нечем.
  • Порядок палат на экране обратный порядку в файле: дописанная в конец chambers палата показывается первой.
  • Если палату переучредили под новым именем, не заводи вторую палату — иначе старая продолжит показываться рядом с новой, как две существующие одновременно. Добавь созыв с полем name: с этого года палата называется по-новому, а до него — по-старому. Отдельные записи в chambers нужны только для палат, которые заседают одновременно (нижняя и верхняя).
  • Точек ровно столько, сколько мест (seats), до 3000. Ряды и размер точек подбираются сами: чем больше мест, тем мельче точки.
  • Проценты → места методом наибольших остатков: место достаётся целиком одной партии, дробных мест не бывает.
  • Недобор до 100 % остаётся вакантными местами — белые точки и строка «Вакантные» в списке.
  • Перебор больше 100 % ужимает доли пропорционально: мест в палате всё равно ровно seats.
  • Цвет. Свой — в color (только #rrggbb). Без него цвет берётся по очереди из общей палитры, так что у всех парламентов одна гамма и внутри палаты цвета не повторяются. Партия, чьё название начинается со слова «Независим…», всегда серая; серого в палитре нет.
  • Название палатыname; без него будет «Нижняя палата» / «Верхняя палата» по порядку.
  • Палата без parties рисуется целиком вакантной — годится как заготовка.

Наведение на партию (на дуге или в списке) подсвечивает её места и строку, гасит остальные и выносит название в середину дуги; нажатие на строку закрепляет подсветку.

Стороны войны

Блок появляется на страницах раздела события с тегом война, если во frontmatter заполнен sides. Идёт после инфобокса и вводной части, в той же рамке, что «Состояние государства».

tags: [война]
start: 1914
end: 1918
sides:
  - name: Первая коалиция
    outcome: Победа              # «Победа» зелёная, «Поражение» красное
    commanders:
      - name: Дарий Ветолло      # статья человека
        country: Отой            # только ради микрофлага рядом с именем
        note: главнокомандующий
      - name: Анна Тогштов
        country: Празия
        from: 1890               # возглавил не с начала войны
    members:
      - country: Топес           # название или slug статьи страны
        troops: 12000000         # всего мобилизовано
        survived: 10200000       # сколько вернулось
        population: 45200000     # население на начало войны
        civilians: 300000        # погибло мирных
      - country: Амбрания
        from: 1915               # вступила позже — годы подсветятся
        troops: 5615000
        dead: 651000             # можно вместо survived
        population: 35600000
    support:                     # помогали, но не воевали
      - country: Асфалия
        from: 1916
        note: поставки оружия
  - name: Вторая коалиция
    outcome: Поражение
    members:
      - country: Празия
        to: 1917                 # вышла из войны раньше
        troops: 13250000
        dead: 2050000

Как это работает:

  • Порядок участников считается сам: сначала по году вступления в войну, потом по числу войск. Руками сортировать не нужно.
  • Микрофлаг и ссылка берутся из статьи страны — её flag и title. Отдельно указывать флаг не нужно; для участника без своей статьи есть поле flag. Если в ту войну страна звалась иначе, чем зовётся её статья, пиши через палку как в wiki-ссылках: country: Гесбанс|Гесбанская империя.
  • Командующие — строкой под названием стороны: имя ведёт на статью человека, флаг берётся из страны в поле country.
  • Пометка note у воевавшей страны показывается после годов («1889—1897 · помощь») — для тех, кто участвовал ограниченно, но с войсками. Кто вовсе не воевал, идёт в support, там числа не показываются.
  • Годы участия. Без from/to берутся годы всей войны (start/end). Если они отличаются — годы подсвечиваются, видно, кто вступил позже или вышел раньше.
  • Погибшие и вернувшиеся — задай любое одно из двух, второе считается само (survived = troopsdead).
  • Общие потери = погибшие военные + погибшие мирные; «осталось» — население за вычетом этих потерь.
  • Проценты считаются сами: погибшие от мобилизованных, общие потери от населения. Полоска под общими потерями — в одном масштабе для всех участников обеих сторон, красная часть военные, охряная мирные.
  • Незаполненное поле показывается как «—» и в итоги не идёт.
  • Строка «Итого» под каждой стороной и общая сводка сверху считаются сами.

«Сведения уточняются»

  • В инфобоксе значение показывается как пометка «уточняется».
  • В тексте статьи строки, начинающиеся с ?>, собираются в блок «Сведения уточняются» — удобно помечать непридуманный лор.

Спойлеры

Текст между двойными палками скрыт до клика:

Кристан I правил сорок лет. ||На самом деле его отравил брат.||
  • Внутри работают обычные <span class="wiki-link missing" title="Страница не найдена">wiki-ссылки</span>.
  • Скрытый текст не попадает в поиск — иначе спойлер не имел бы смысла.
  • Строки таблиц (| Топес || 1 |) и блоки кода не затрагиваются.

Вставка чужой статьи

<div class="transclusion is-missing">Вставка не удалась: страница «Оунизм» не найдена</div>                  вставить страницу целиком
<div class="transclusion is-missing">Вставка не удалась: страница «Оунизм» не найдена</div>           вставить один раздел

Текст подтягивается из статьи-источника, под вставкой стоит ссылка на неё. Вложенность ограничена тремя уровнями, циклы (A → B → A) отсекаются. Вставка считается ссылкой: источник получит обратную ссылку «Ссылки сюда».

Сноски на полях

Обычный markdown-синтаксис сносок:

Фраза с примечанием.<span class="sidenote-wrap"><button type="button" class="sidenote-ref" aria-expanded="false">1</button><span class="sidenote"><span class="sidenote-num">1</span>Текст примечания. Ссылки внутри тоже работают — <a href="/страны/Топес/" class="wiki-link" data-slug="страны/Топес">Топес</a>.</span></span>

На широких экранах сноска встаёт на поля рядом со строкой, на узких — раскрывается по клику на номер.

Комментарии <span class="note-wrap"><button type="button" class="note-mark" aria-expanded="false" aria-label="Комментарий"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 2.5h10a1.5 1.5 0 0 1 1.5 1.5v6a1.5 1.5 0 0 1-1.5 1.5H7.2L4 14.2V11.5H3A1.5 1.5 0 0 1 1.5 10V4A1.5 1.5 0 0 1 3 2.5z"/></svg></button><span class="note-pop" role="note">…</span></span>

Пометка к конкретному месту: значок, по наведению на который всплывает карточка с комментарием. В отличие от сноски не нумеруется и не уходит на поля, зато ставится где угодно — в тексте, в значениях инфобокса, в годах правления:

…последний монарх страны<span class="note-wrap"><button type="button" class="note-mark" aria-expanded="false" aria-label="Комментарий"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 2.5h10a1.5 1.5 0 0 1 1.5 1.5v6a1.5 1.5 0 0 1-1.5 1.5H7.2L4 14.2V11.5H3A1.5 1.5 0 0 1 1.5 10V4A1.5 1.5 0 0 1 3 2.5z"/></svg></button><span class="note-pop" role="note">Отречения не подписывала — см. ниже.</span></span> и последняя…
info:
  Смерть: 24 апреля 1901, Ирз <span class="note-wrap"><button type="button" class="note-mark" aria-expanded="false" aria-label="Комментарий"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 2.5h10a1.5 1.5 0 0 1 1.5 1.5v6a1.5 1.5 0 0 1-1.5 1.5H7.2L4 14.2V11.5H3A1.5 1.5 0 0 1 1.5 10V4A1.5 1.5 0 0 1 3 2.5z"/></svg></button><span class="note-pop" role="note">По другим данным — 25 апреля.</span></span>
titles:
  - title: Императрица Празии
    from: 1856
    to: 1894
    note: Фактически отошла от дел в 1894 году. Отречения не подписывала и де-юре оставалась императрицей до смерти в 1901 году.

У титула комментарий к годам правления удобнее задавать отдельным полем note — годы остаются числами, а пояснение может быть длинным; но <span class="note-wrap"><button type="button" class="note-mark" aria-expanded="false" aria-label="Комментарий"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 2.5h10a1.5 1.5 0 0 1 1.5 1.5v6a1.5 1.5 0 0 1-1.5 1.5H7.2L4 14.2V11.5H3A1.5 1.5 0 0 1 1.5 10V4A1.5 1.5 0 0 1 3 2.5z"/></svg></button><span class="note-pop" role="note">…</span></span> прямо в from/to тоже работает. Внутри комментария работают <span class="wiki-link missing" title="Страница не найдена">ссылки</span> и курсив, переносов строк нет.

На тач-экране наведения нет: там карточка раскрывается нажатием на значок и закрывается нажатием мимо или Escape. Карточка одна на страницу и висит поверх всего, поэтому не обрезается краем инфобокса или таблицы.

Примечание над статьёй (хатноут)

hatnote: Не путать с <a href="/люди/Дарий%20Гако/" class="wiki-link" data-slug="люди/Дарий Гако">Дарий Гако</a>.

Если поле не заполнено, но в вики есть страница с таким же названием, подсказка «Не путать с…» соберётся сама.

Готовность статьи

Рядом с заголовком стоит значок стадии: заготовка → росток → развивается → зрелая. Оценка складывается из четырёх признаков: собственный текст, описание, ссылки на другие статьи и профильное поле раздела (метка на карте у стран, даты у людей и событий). У зрелых статей значок не показывается.

Тело статьи считается заготовкой, если дословно тот же текст стоит ещё минимум на двух страницах — такие статьи выглядят написанными, но содержания в них нет. Их список есть на странице «Состояние вики».

Там же первым разделом стоит список «Пустые, но нужные»: статьи без своего текста и без описания, на которые при этом ссылаются другие (или которые сами ссылаются из инфобокса). Читатель приходит по ссылке в пустоту — это то, что стоит написать первым. Список отсортирован по числу входящих ссылок; чистые заготовки, на которые никто не ведёт, в него не попадают.

Известность людей

Уровень известности задаётся одним тегом из пяти. Тег ставится в общий список tags рядом с остальными:

tags: [Празия, монарх, Величайшие]
тег тест ожидаемая доля
Легенда Историчность не подтверждена, заслуги проверить нельзя сколько наберётся
Величайшие Знают на всех континентах и через поколения; его именем меряют других 1–3 человека
Великие Знают далеко за пределами родной страны, вошёл в общую историю Перии ~8
Значимые Определял историю своей страны; за её пределами — удел специалистов ~20
Известные Известен в своей провинции, династии или ремесле ~30
Малоизвестные Существует в записях, но собственной славы нет — живёт в чужих статьях остальные

Пирамида: каждый уровень примерно вдвое-втрое шире предыдущего. Если «Величайших» набралось больше пяти — уровень обесценился, пора пересматривать.

Легенда стоит особняком и в пирамиду не входит: это не ступень славы, а оговорка о самом человеке — слава есть, а был ли он, неизвестно. Поэтому доля для него не задаётся, а в списке он идёт первым: в разделе «Люди» предания показываются перед историей. Пишется в единственном числе, но Легенды и Легендарные понимаются так же — форма слова не решает, появится щит или нет.

Код знает эту шкалу, поэтому уровень ведёт себя не как рядовой тег:

  • в шапке статьи он показывается щитом в цвет уровня — так же, как ранг у государства, — и из ленты #тегов при этом убирается, чтобы не дублироваться;
  • в карточках списков щит стоит перед названием;
  • раздел «Люди» сортируется по убыванию известности, неразмеченные идут следом по алфавиту. Если в разделе нет ни одного размеченного, сортировка не включается и порядок остаётся прежним;
  • сами уровни, их цвета и подсказки правятся в одном месте — константа FAME_TIERS в src/special.ts, рядом с рангами государств.

Два правила, чтобы шкала не расползлась:

  • Только множественное число. Величайшие годится всем.
  • Ровно один тег известности на человека. Уровни не складываются.

Известность — это отдельная ось от принадлежности (Ветолло, Ребенсне) и от рода занятий (монарх, военные, политики); они живут в том же списке tags и друг другу не мешают.

Поиск и тема

  • Поиск — кнопка в сайдбаре, строка на главной или Ctrl/⌘ + K. Ищет по заголовкам, описаниям, тегам и тексту; понимает несколько слов и ё/е.
  • Тема — переключатель внизу сайдбара (светлая/тёмная), выбор запоминается.

Сборка

npm run build
npm run preview

Статический сайт появится в папке dist/ — её можно открыть локально или выложить на любой статический хостинг.