<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
  <title>nv://blog</title>
  <subtitle>личный техноблог</subtitle>
  <link href="https://nullvert.uz/" rel="alternate" type="text/html"/>
  <link href="https://nullvert.uz/atom.xml" rel="self" type="application/atom+xml"/>
  <id>https://nullvert.uz/</id>
  <updated>2026-08-08T00:00:00.000Z</updated>
  <entry>
    <title>Шпаргалка по Markdown и Shirone</title>
    <link href="https://nullvert.uz/posts/markdown-showcase/" rel="alternate" type="text/html"/>
    <id>https://nullvert.uz/posts/markdown-showcase/</id>
    <published>2026-08-08T00:00:00.000Z</published>
    <updated>2026-08-08T00:00:00.000Z</updated>
    <summary>Полный обзор возможностей оформления постов: код, диаграммы, формулы, файловые деревья, аннотации и уникальные расширения Shirone.</summary>
    <content type="html"><![CDATA[<p>Полный обзор инструментов разметки в Shirone. От стандартного Markdown до эксклюзивных расширений темы — всё, что нужно для красивых и информативных постов.</p>
<p>&lt;!-- more --&gt;</p>
<hr />
<h2>1. Форматирование текста и акценты</h2>
<p><strong>Базовые стили:</strong></p>
<ul>
<li><strong>Полужирное начертание</strong> (<code>**bold**</code>)</li>
<li><em>Курсивное выделение</em> (<code>*italic*</code>)</li>
<li><em><strong>Полужирный курсив</strong></em> (<code>***bold italic***</code>)</li>
<li><s>Зачёркнутый текст</s> (<code>~~strikethrough~~</code>)</li>
<li><code>Встроенный код</code> (<code>`inline code`</code>)</li>
<li>Индексы: H&lt;sub&gt;2&lt;/sub&gt;O, 2&lt;sup&gt;10&lt;/sup&gt; = 1024</li>
<li>Скрытый ответ: :spoiler[<strong>Astro</strong> — победитель State of JS 2024 в категории «Фреймворки»]</li>
</ul>
<p><strong>Маркеры выделения</strong> (<code>==text==</code>) — Shirone поддерживает ==семантические маркеры== без лишнего HTML:</p>
<ul>
<li>==Основной акцент темы (primary)=={.primary}</li>
<li>==Вторичный, ненавязчивый сигнал=={.secondary}</li>
<li>==Третичный редакторский акцент=={.tertiary}</li>
<li>==Ошибка или критическая ситуация=={.error}</li>
<li>==Практический совет читателю=={.tip}</li>
</ul>
<p><strong>Аннотации к тексту</strong> (<code>[+label]</code>) — Astro строит большинство страниц заранее, гидратируя только <strong>интерактивные острова</strong> [+islands] по требованию.</p>
<p>[+islands]:
<strong>Islands Architecture</strong> — паттерн, при котором страница — это статичный HTML, а интерактивные компоненты (Svelte, React, Vue) гидратируются независимо. Это сводит к минимуму количество JS, отправляемого клиенту.</p>
<p>Подробнее — <a href="https://docs.astro.build/en/concepts/islands/">docs.astro.build/islands</a></p>
<p><strong>Сноски</strong> — блог работает на Astro[^1] с темой Shirone[^2].</p>
<p>[^1]: Astro — статический генератор с Islands Architecture, написанный на TypeScript.
[^2]: Shirone — M3E-совместимая тема для Astro с Svelte 5, Tailwind 4 и богатым набором Markdown-расширений.</p>
<hr />
<h2>2. Уведомления (Callouts)</h2>
<blockquote>
<p>[!NOTE]
<strong>Информация:</strong> Блог автоматически оптимизирует изображения в AVIF/WebP и генерирует поисковый индекс Pagefind.</p>
</blockquote>
<blockquote>
<p>[!TIP]
<strong>Совет:</strong> Используйте <code>:::collapse</code> для длинных пояснений — это сохраняет фокус читателя на главном.</p>
</blockquote>
<blockquote>
<p>[!IMPORTANT]
<strong>Важно:</strong> Все записи поддерживают Obsidian-совместимые вики-ссылки вида <code>[[slug|Заголовок]]</code>.</p>
</blockquote>
<blockquote>
<p>[!WARNING]
<strong>Предупреждение:</strong> Проверяйте актуальность версий пакетов в <code>package.json</code> перед сборкой.</p>
</blockquote>
<blockquote>
<p>[!CAUTION]
<strong>Внимание:</strong> Никогда не храните приватные API-ключи и токены в публичном репозитории!</p>
</blockquote>
<hr />
<h2>3. Структурированный контент</h2>
<p><strong>Шаги</strong> (<code>:::steps</code>) — для пошаговых инструкций:</p>
<p>:::steps[Запуск Shirone-блога]</p>
<ol>
<li>
<p><strong>Установить зависимости</strong></p>
<p>Запустите менеджер пакетов из корня репозитория.</p>
<pre><code>pnpm.cmd install
</code></pre>
</li>
<li>
<p><strong>Запустить dev-сервер</strong></p>
<p>Сайт будет доступен на <code>localhost:4321</code>.</p>
<pre><code>pnpm.cmd astro dev --port 4321
</code></pre>
</li>
<li>
<p><strong>Проверить типы и Astro</strong></p>
<p>Убедитесь, что диагностика чиста перед публикацией.</p>
<pre><code>npx.cmd astro check
pnpm.cmd type-check
</code></pre>
</li>
<li>
<p><strong>Собрать продакшн-сборку</strong></p>
<p>Генерирует статические страницы и поисковый индекс.</p>
<pre><code>pnpm.cmd build
</code></pre>
</li>
</ol>
<p>:::</p>
<p><strong>Раскрывающиеся панели</strong> (<code>:::collapse</code>) — для FAQ и дополнительных деталей:</p>
<p>::: collapse accordion</p>
<ul>
<li>
<p><strong>Почему Astro, а не Next.js?</strong></p>
<p>Astro генерирует ==чистый статический HTML=={.primary} без клиентского JavaScript по умолчанию. Это означает мгновенную загрузку и отличный SEO. Интерактивность добавляется точечно через острова.</p>
</li>
<li>
<p><strong>Что такое M3E?</strong></p>
<p><strong>Material 3 Extended</strong> — дизайн-система Shirone, развивающая спецификацию Google Material 3. Использует динамические HCT-палитры, токены формы (<code>--shape-corner-*</code>) и токены движения (<code>--m3e-duration-*</code>).</p>
</li>
<li>
<p><strong>Зачем нужен Pagefind?</strong></p>
<p>Pagefind — это ==поиск на стороне клиента=={.secondary} без серверной части. Он строит индекс во время сборки и весит меньше 50 КБ. Подходит для статических сайтов с нулевым backend.
:::</p>
</li>
</ul>
<hr />
<h2>4. Кодовая база (Expressive Code)</h2>
<p><strong>TypeScript</strong> — асинхронный клиент с повторными попытками:</p>
<pre><code>interface FetchOptions {
	retries?: number;
	backoffMs?: number;
}

export async function fetchWithRetry&lt;T&gt;(
	url: string,
	options: FetchOptions = {},
): Promise&lt;T&gt; {
	const { retries = 3, backoffMs = 500 } = options;
	// const res = await fetch(url);
	for (let attempt = 1; attempt &lt;= retries; attempt++) {
		try {
			const response = await fetch(url);
			if (!response.ok) throw new Error(`HTTP ${response.status}`);
			return (await response.json()) as T;
		} catch (err) {
			if (attempt === retries) throw err;
			await new Promise((r) =&gt; setTimeout(r, backoffMs * attempt));
		}
	}
	throw new Error("Unexpected end of retries loop");
}
</code></pre>
<p><strong>Многоязычные вкладки</strong> (<code>:::code-group</code>):</p>
<p>:::code-group</p>
<pre><code>package main

import (
	"fmt"
	"sync"
)

func worker(id int, jobs &lt;-chan int, results chan&lt;- int, wg *sync.WaitGroup) {
	defer wg.Done()
	for j := range jobs {
		results &lt;- j * 2
		fmt.Printf("worker %d processed job %d\n", id, j)
	}
}
</code></pre>
<pre><code>use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    loop {
        let (mut socket, _) = listener.accept().await?;
        tokio::spawn(async move {
            let mut buf = [0; 1024];
            while let Ok(n) = socket.read(&amp;mut buf).await {
                if n == 0 { return; }
                let _ = socket.write_all(&amp;buf[..n]).await;
            }
        });
    }
}
</code></pre>
<pre><code>import torch
import torch.nn as nn

class ConvNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2, 2)
        )
        self.fc = nn.Linear(32 * 16 * 16, 10)

    def forward(self, x):
        x = self.features(x)
        return self.fc(x.view(x.size(0), -1))
</code></pre>
<p>:::</p>
<p><strong>Интерактивное дерево кода</strong> (<code>:::code-tree</code>) — IDE-подобная навигация по файлам:</p>
<p>:::code-tree{title="Shirone M3E — пример атома" height="320px" entry="src/Button.svelte"}</p>
<pre><code>&lt;script lang="ts"&gt;
  let { label = "Нажмите", variant = "filled" } = $props();
&lt;/script&gt;

&lt;button class="m3-btn m3-btn--{variant}"&gt;{label}&lt;/button&gt;
</code></pre>
<pre><code>.m3-btn
  background: var(--primary)
  color: var(--on-primary)
  border-radius: var(--shape-corner-full)
  padding: 0 var(--m3e-space-4)
  font: var(--m3e-type-label-large)
  transition: box-shadow var(--m3e-duration-short) var(--m3e-easing-standard)
</code></pre>
<pre><code>{
  "name": "button-demo",
  "version": "1.0.0",
  "dependencies": {
    "shirones": "^0.1.5"
  }
}
</code></pre>
<p>:::</p>
<hr />
<h2>5. Файловые деревья</h2>
<p><strong>Структура проекта</strong> (<code>:::file-tree</code>) — с диффами <code>++/--</code> и комментариями:</p>
<p>:::file-tree{title="nullvert.uz — структура блога"}</p>
<ul>
<li>shirones/
<ul>
<li>config/
<ul>
<li><strong>siteConfig.ts</strong> # главная конфигурация сайта</li>
<li>profileConfig.ts</li>
<li>musicConfig.ts</li>
</ul>
</li>
<li>content/
<ul>
<li>posts/
<ul>
<li>markdown-showcase/
<ul>
<li>++ index.md # этот пост</li>
<li>keyboard.webp</li>
</ul>
</li>
</ul>
</li>
<li>spec/
<ul>
<li>credits-and-licenses.md</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>src/
<ul>
<li>components/
<ul>
<li>organisms/
<ul>
<li>Footer.astro</li>
</ul>
</li>
</ul>
</li>
<li>pages/
<ul>
<li>credits-and-licenses.astro</li>
</ul>
</li>
</ul>
</li>
<li>public/
<ul>
<li>assets/
<ul>
<li>images/</li>
<li>music/</li>
</ul>
</li>
</ul>
</li>
<li>package.json
:::</li>
</ul>
<p><strong>Из терминала</strong> (<code>```file-tree</code>):</p>
<pre><code>dist
├── _astro/
│   ├── index.css
│   └── client.js
├── posts/
│   └── markdown-showcase/
│       └── index.html
├── sitemap-index.xml
└── pagefind/
    └── pagefind.js
</code></pre>
<hr />
<h2>6. Формулы и математика (KaTeX)</h2>
<p>Уравнение Шрёдингера:
$$i\hbar \frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \left [ -\frac{\hbar^2}{2m}\nabla^2 + V(\mathbf{r},t) \right ] \Psi(\mathbf{r},t)$$</p>
<p>Формула Байеса:
$$P(A|B) = \frac{P(B|A) \cdot P(A)}{P(B)}$$</p>
<p>Реакция термоядерного синтеза:
$$\ce{^2_1H + ^3_1H -&gt; ^4_2He + ^1_0n + 17.6 MeV}$$</p>
<hr />
<h2>7. Диаграммы (Mermaid)</h2>
<pre><code>sequenceDiagram
    autonumber
    actor User as Читатель
    participant Browser as Браузер
    participant CDN as Cloudflare Edge
    participant Pagefind as Pagefind

    User-&gt;&gt;Browser: Переход на nullvert.uz
    Browser-&gt;&gt;CDN: GET /posts/markdown-showcase/
    CDN--&gt;&gt;Browser: Статический HTML + CSS (кэш)
    User-&gt;&gt;Browser: Поиск по сайту
    Browser-&gt;&gt;Pagefind: Запрос к локальному индексу
    Pagefind--&gt;&gt;Browser: Результаты без сетевых запросов
</code></pre>
<hr />
<h2>8. Интеграция с GitHub</h2>
<p>Репозиторий фреймворка, на котором работает блог:</p>
<p>::github{repo="withastro/astro"}</p>
<p>Компонентный движок интерфейса:</p>
<p>::github{repo="sveltejs/svelte"}</p>
<hr />
<h2>9. Изображения</h2>
<p>Одиночное изображение с подписью:</p>
<p><img src="https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&amp;fit=crop&amp;w=1200&amp;q=80" alt="Атмосферное игровое рабочее место с неоновой подсветкой" title="Игровой сетап (Unsplash License)" /></p>
<p>Сетка изображений (<code>[grid]</code>):</p>
<p>[grid]
<img src="https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?auto=format&amp;fit=crop&amp;w=600&amp;q=80" alt="Футуристическая абстракция" />
<img src="https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?auto=format&amp;fit=crop&amp;w=600&amp;q=80" alt="Исходный код на экране" />
<img src="https://images.unsplash.com/photo-1511512578047-dfb367046420?auto=format&amp;fit=crop&amp;w=600&amp;q=80" alt="Геймпад и консоль" />
[/grid]</p>
<hr />
<h2>10. Таблица возможностей</h2>
<table>
<thead>
<tr>
<th>Категория</th>
<th>Расширение</th>
<th>Синтаксис</th>
<th>Гидратация JS</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Структура</strong></td>
<td>File Tree</td>
<td><code>:::file-tree</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>Структура</strong></td>
<td>Code Tree</td>
<td><code>:::code-tree</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>Навигация</strong></td>
<td>Steps</td>
<td><code>:::steps</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>UX</strong></td>
<td>Collapse</td>
<td><code>:::collapse</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>Акценты</strong></td>
<td>Marker</td>
<td><code>==text==</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>UX</strong></td>
<td>Spoiler</td>
<td><code>:spoiler[text]</code></td>
<td>Минимальная</td>
</tr>
<tr>
<td><strong>Пояснения</strong></td>
<td>Annotations</td>
<td><code>[+label]</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>Диаграммы</strong></td>
<td>Mermaid</td>
<td><code>```mermaid</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>Формулы</strong></td>
<td>KaTeX</td>
<td><code>$$...$$</code></td>
<td>Нет</td>
</tr>
<tr>
<td><strong>Виджеты</strong></td>
<td>GitHub Card</td>
<td><code>::github{repo}</code></td>
<td>Ленивая</td>
</tr>
</tbody>
</table>
<p><em>Все расширения рендерятся в семантический HTML во время сборки и следуют токенам M3E.</em></p>
]]></content>
    <author><name>nullvert</name></author>
    <category term="Тест"/>
  </entry>
</feed>
