Работа с MDX

Автор: Петър Петров

Обяснение на заглавната част, която предхожда всеки модул и решение, и списък на специалните компоненти, които могат да се използват в модулите или решенията.

Използваме MDX, специален вид Markdown, заедно с компилатора XDM. HTML и React компоненти се поддържат, така че е възможно да се добави всякакви персонализирани компоненти към всеки модул.

Заглавна част (Frontmatter)

Frontmatter (на български: заглавна част) е оградената с три тирета част в началото на всеки модул. Frontmatter се пише в стил на YAML. В него се съхраняват „метаданните“ (идентификация, заглавие, автор, и други) за всеки модул.

  • ID: Задължително. Идентификаторът на модула. Например: getting-started или contributing. Използва се за идентифициране на модула, затова се уверете, че е уникален и съдържа само малки букви с тирета на латиница. Ще бъде генериран URL адрес въз основа на това.
  • Заглавие (Title): Задължително. Заглавието на модула. Например: Въведение
  • Автор (Author): Задължително. Авторът на модула. Например: Иван Иванов
  • Съавтори (Contributors): По избор. Хората, които са редактирали разни грешки или са допълнили някои обяснения към модула.
  • Описание (Description): Задължително. Кратко описание на модула, едно-две изречения макс. Markdown/LaTeX не работи в полето за описание.
  • Предварителни модули (Prerequisites): По избор. Предварителен прочит преди да се започне с модула. За да посочите предварителен модул, добавете неговия идентификатор (ID). Връзката ще се генерира автоматично.
  • Честота (Frequency): По избор. Приема число от 0 до 4 включително, където 0 = никога не се срещала темата преди, а 4 = появява се ~един път на състезание. Оставете това поле празно, ако не искате да искате да показвате честотата.
  • Пренасочвания (Redirects): По избор. Приема списък с URL адреси, които ще пренасочват към текущия модул. Добавете пренасочване, само когато промените идентификатора на модула или го преместите в друг раздел.

Примерен Frontmatter

---
id: getting-started
title: Да започваме
description: 'Добре дошли в Olympiads XYZ! В този модул примерно ще научите как да използвате нашия сайт.'
author: Иван Иванов
frequency: 3
prerequisites:
 - prerequesite-module
 - another-module
redirects:
  - /general/new-getting-started
---

# Как да ползваме сайта?
...

Подредбата на модули

Файлът, разположен в content/ordering.ts, съхранява подредбата на модулите. По принцип не би трябвало да Ви се налага да го променяте, ние ще се погрижим за правилната подредба според Вашите предпочитания. Начинът на подреждане и групиране на модули във файла би трябвало да се подразбира (подрежда се въз основа на ID).

Препратки към други части от сайта

Препращането към друг модул трябва да изглежда по следния начин:

[сложете текст тук](/general/about-us).

сложете текст тук

Не използвайте относителни връзки като само /about-us, тъй като това ще наруши работата на нашата програма за проверка на връзки. Трябва връзката да започва от кореновия път (root path) /, например /general/about-us.

Съдържание

Съдържанието ще бъде генерирано автоматично въз основа на заглавията в Markdown и се показва в левия панел на страницата (най-отгоре, на мобилната версия). Имайте това предвид, когато оформяте модула си.

MDX и специални компоненти

XDM и MDX

Използваме компилатора XDM, който има няколко разлики от MDX v1:

  • Markdown, преплетен с JSX, се поддържа напълно; т.е. това тук работи, както бихте очаквали: <Info>някакъв текст в стил **markdown**</Info>
  • Като допълнение на горното, отстъпите също се поддържат напълно. Можете да изреждате markdown с отстъпи, вложен в JSX тагове. Това също така означава, че текст с отстъп от четири интервала не се превръща в блок с код; изрично обвийвайте блока с код с три апострофа (```)
  • < и > трябва да се избягват с обратни наклонени черти; т.е. \<

Имайте предвид, че JSX коментарите ({/* ... */}) не работят добре с Prettier (въпреки че все пак работят), затова използвайте HTML коментари вместо тях. Вътрешно преобразуваме HTML коментарите в JSX коментари, преди да предадем markdown-а на XDM. Не се притеснявайте, ако все още не разбирате всичко това.

Някои компоненти са глобално достъпни във всеки модул (тоест не е необходимо да бъдат изрично импортирани):

  • <Spoiler>
  • <Info>
  • <Warning>
  • <Optional>
  • <Problems>
  • <FocusProblem>
  • <Resources>
  • <Resource>
  • <TextTooltip>
  • <IncompleteSection>
  • <Asterisk>
  • <DifficultyBox>
  • <Quiz>

Всичките са документирани по-долу.

Спойлери/Подсказки (Spoilers)

Спойлерите са сгъваеми елементи, които се показват само когато потребителят кликне върху тях. Това е полезно, когато пишете подсказки или решения към задачи.

<Spoiler title="Покажи нещо скрито">
- Поставете подсказка или решение тук
</Spoiler>

Покажи нещо скрито

Информационен блок

<Info title="Сложете заглавието тук">
**Markdown** и $\LaTeX$ се поддържат!
</Info>

Сложете заглавието тук

Markdown и LaTeX\LaTeX се поддържат във всички компоненти!

Предупредителен блок

<Warning title="Сложете заглавието тук">
Интересен факт: атрибутът title не е задължителен.
</Warning>

Внимание: Сложете заглавието тук

Интересен факт: атрибутът title не е задължителен.

Допълнително съдържание или идея

<Optional title="Сложете заглавието тук">
Интересен факт: атрибутът title не е задължителен. Този компонент се използва, когато вмъквате **Идея** към модула.
</Optional>

Сложете заглавието тук

Интересен факт: атрибутът title не е задължителен. Този компонент се използва, когато вмъквате Идея към модула.

Списъци със задачи

Всеки модул съответстват два файла - файл .mdx и файл .problems.json. Файлът .problems.json съхранява задачите за съсредоточаване и списъците със задачи за самоподготовка, използвани в дадения модул; той също така се индексира от Algolia за търсачката на задачи.

Добре е да сте запознати с JSON

Информацията за задачите и техните решения са съхранени във файл в формата JSON. Винаги можете да използвате някой от шаблоните, които ще намерите по-долу тук, но е препоръчително да се запознаете какво е JSON и допълнителните атрибути, които могат да бъдат добавени към задачите.

Файлът .problems.json съдържа обект, в който ключовете са имена на списъци със задачи (или задачите за съсредоточаване), а стойностите са масиви от обекти тип ProblemMetadata. За задачите за концентрация/съсредоточаване, масивът трябва да има дължина точно едно. Освен това файлът .problems.json трябва да има ключ MODULE_ID който да съдържа идентификатора (ID) на модула.

За повече информация относно дефинициите на задачите и какви полета/ключове/атрибути могат да съдържат, вижте файла src/models/problem.ts.

Пример за използване на списъка със задачи:

<Problems problems="zadachki-zakachki-1"/>

[модул].problems.json трябва да има ключ zadachki-zakachki-1, който се съпоставя с масив с обекти от типа ProblemMetadata.

Съществува разлика между `ProblemInfo` и `ProblemMetadata`.

ProblemMetadata е това, което се съхранява в [module].problems.json. Gatsby (Front Еnd framework-ът на сайта) приема ProblemMetadata и го преобразува в ProblemInfo по време на изграждане; React компонентите използват ProblemInfo, когато взаимодействат с информацията за дадената задача. Документацията по-долу е за ProblemMetadata, което всъщност Вие като автор на модул ще трябва да напишете.

Полетата на ProblemMetadata

uniqueId -- Уникалният идентификатор на задачата. Статусът на задачата, както и напредъка по модула, са свързани с него, затова не го променяйте (в противен случай информацията за напредъка ще бъде загубена). По конвенция това е [source]-[SlugifiedProblemNameKebabCased]. Ако сте несигурни как точно да форматирате идентификатора, можете да погледнете идентификатори на подобни задачи използвани в други модули от GitHub.

Няколко примера за уникални ID-та:

ipho-1969-t3 \\ IPhO 1969 T3
ipho-1969-e1 \\ IPhO 1969 E1
nof3-2024-1112-t1 \\ НОФ3 2024 11-12 клас теоретичен кръг задача 1
nof3-2024-1112-e2 \\ НОФ3 2024 11-12 клас експериментален кръг задача 2
esenni-2019-7-p1 \\ Есенни 2019 7 клас задача 1
200ppp-p125 \\ 200 Puzzling Physics Problems, Problem 125
200mppp-p78 \\ 200 More Puzzling Physics Problems, Problem 78

Внимание!

Задачи с едно и също уникално ID се очаква да имат еднакви имена, източници и URL адреси.

name -- Името на задачата. Не трябва да включва източникa. Ако задачата си няма име, просто посочете коя подред е от източника.

Примери:

Theoretical Problem 1 
Experimental Problem 2
Задача 1. Гюлетласкач
Изследване на n(w) за захарен разтвор
Задача 1. Градуиране на термометър
P125
P78

source -- Източникът на задачата. Вижте предварително дефинирани източници в src/models/problem.ts

difficulty -- Трудността на задачата е относителна спрямо модула. Допустими стойности: Very Easy, Easy, Normal, Hard, Very Hard, Insane

isStarred -- Дали задачата да е със звездичка или не. Допустими стойности: true, false

tags -- Списък с тагове за задачата. Правят търсенето и групирането на задачи по-лесно.

solutionMetadata -- Информация за решението на задачата.

kind -- Тип на решението. Допустими стойности:

  • 'in-module' -- Решение в модула.
    • moduleId -- Това поле посочква в кой модул се намира решението, използвайте интентификатора на модула.
  • 'link' -- Външно решение, изисква URL адрес към него.
    • url -- Полето за URL адрес към решението.
  • 'internal' -- Има вградено решение в самия сайт. Вградените решенията не са в самия модул, а са отделно, но са обработени пак в същия формат.
  • 'none' -- Няма решение все още.

За вградените решения

Това е за решенията, които не са в самия модул, но са вградени в сайта. Те са много подобни на модулите като външен вид, защото се пишат на MDX. Техният frontmatter изглежда по следния начин:

---
id: problem-id
title: 'Решение на: [Име на задачата]'
description: Кратко описание на какво ще има в решението.
author: Авторът на решението
---

## Тук започва решението...

Идентификаторът (ID) на решението трябва да е същият като уникалния идентификатор на задачата (uniqueId). Уверете се, че сте актуализирали и полето kind от solutionMetadata на 'internal' за всички свързани проблеми. Предполагаме, че ако има вградено решение, трябва да го използваме; следователно компилаторът ще хвърли грешка, ако има вградено решение, но в информацията за задачата полето kind от solutionMetadata не е зададено на 'internal'. Модулът Добавяне на решения описва как се добавя ново решение.

Задача за съсредоточаване/концентрация

Показва единичен проблем, който най-вече демонстрира някоя нова идея.

<FocusProblem problem problem="focusProblemIdea" />

В [module].problems.json трябва да има ключ focusProblemIdea, който се съотнася към масив с дължина 1, който съдържа задачата.

Списъци с ресурси

Те имат подобни атрибути като задачите. По-подробно вижте тук.

<Resources>
  <Resource
    source="Основи на физиката част 1"
    title="Кинематика на материална точка"
    url="https://olympiads-xyz-bg.vercel.app/archive/physics/Книги/Учебници/Основи%20на%20физиката%20част%201.pdf#page=9"
    starred
  >
    примерен ресурс
  </Resource>
  ...
</Resources>
Ресурси
Основи на физиката част 1

примерен ресурс

Изскачащи полета

Съществуват два основни типа изскачащи полета: текстови подсказки, които се бележат с пунктир под избрания текст, и звездички. Когато задържите мишката си върху тях или ги кликнете, ще се появи допълнителен текст до тях.

<TextTooltip>

<TextTooltip content="Текстът на изскачащото поле идва тук">краткият текст остава тук</TextTooltip>
краткият текст остава тук

<Asterisk>

<Asterisk>Изскачащият текст се пише тук</Asterisk>

Непълна секция

<IncompleteSection>

Текстът тук не е задължителен, но е полезно да уточните какво липсва (бъдете възможно най-конкретни):
- по-добра дефиниция
- по-подробно обяснение
- повече примери
- липсва информация за обобщен импулс и сила
и т.н.


</IncompleteSection>

Разделът не е завършен.

Всяка помощ е добре дошла! Просто изпратете Pull Request в GitHub.

Текстът тук не е задължителен, но е полезно да уточните какво липсва (бъдете възможно най-конкретни):

  • по-добра дефиниция
  • по-подробно обяснение
  • повече примери
  • липсва информация за обобщен импулс и сила

и т.н.

Тестове

<Quiz>
	<Quiz.Question>
		Binary search

		<Quiz.Answer>
			$O(\log n)$

			<Quiz.Explanation>
				Almost. Prefer $\mathcal{O}$ over $O$.
			</Quiz.Explanation>
		</Quiz.Answer>

		<Quiz.Answer correct>
			$\mathcal{O}(\log n)$

			<Quiz.Explanation>
				That's correct!
			</Quiz.Explanation>
		</Quiz.Answer>
		<Quiz.Answer>
			O(log n)

			<Quiz.Explanation>
				That's not right. Latex is important...
			</Quiz.Explanation>
		</Quiz.Answer>
	</Quiz.Question>
	<Quiz.Question>
		```cpp
		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < m; j++) {
				// constant time code here
			}
		}
		```

		<Quiz.Answer>
			$O(100m)$

			<Quiz.Explanation>
				That's not correct. Constant factors are ignored.
			</Quiz.Explanation>
		</Quiz.Answer>
		<Quiz.Answer correct>
			$O(m)$

			<Quiz.Explanation>
				That's correct!
			</Quiz.Explanation>
		</Quiz.Answer>
	</Quiz.Question>
</Quiz>

Степени на свобода на многоатомна молекула (само транслационни и ротационни):

Въпрос 1 от 2

Напредък по модули: