863 lines
28 KiB
Plaintext
863 lines
28 KiB
Plaintext
---
|
||
import config from 'virtual:starlight/user-config';
|
||
|
||
import LanguageSelect from 'virtual:starlight/components/LanguageSelect';
|
||
import Search from 'virtual:starlight/components/Search';
|
||
import SocialIcons from 'virtual:starlight/components/SocialIcons';
|
||
|
||
const shouldRenderSearch =
|
||
config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
|
||
|
||
const topLinks = [
|
||
{ label: 'Старт', href: '/getting-started/' },
|
||
{ label: 'Команды', href: '/commands/' },
|
||
{ label: 'Города', href: '/cities/' },
|
||
{ label: 'FAQ', href: '/faq/' },
|
||
{ label: 'Правила', href: '/rules/' }
|
||
];
|
||
---
|
||
|
||
<div class="wiki-header-shell">
|
||
<div class="header wiki-header">
|
||
<div class="title-wrapper sl-flex">
|
||
<a class="wiki-brand" href="/" aria-label="PARABOX PROJECT">
|
||
<span class="wiki-brand__icon" aria-hidden="true">
|
||
<img src="/brand-logo.png" alt="" loading="eager" decoding="async" />
|
||
</span>
|
||
<span class="wiki-brand__copy">
|
||
<span class="wiki-brand__title">PARABOX</span>
|
||
<span class="wiki-brand__subtitle">PROJECT</span>
|
||
</span>
|
||
</a>
|
||
<nav class="wiki-top-nav" aria-label="Быстрая навигация">
|
||
{
|
||
topLinks.map((link) => (
|
||
<a href={link.href} class="wiki-top-nav__link">
|
||
{link.label}
|
||
</a>
|
||
))
|
||
}
|
||
</nav>
|
||
</div>
|
||
|
||
<div class="sl-flex print:hidden header-tools">
|
||
{shouldRenderSearch && <Search />}
|
||
<button
|
||
class="theme-toggle-btn mobile-theme-toggle md:sl-hidden"
|
||
type="button"
|
||
aria-label="Переключить тему"
|
||
data-theme-toggle
|
||
>
|
||
<svg class="icon-sun" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||
<circle cx="12" cy="12" r="4" />
|
||
<line x1="12" y1="2.5" x2="12" y2="5.5" />
|
||
<line x1="12" y1="18.5" x2="12" y2="21.5" />
|
||
<line x1="2.5" y1="12" x2="5.5" y2="12" />
|
||
<line x1="18.5" y1="12" x2="21.5" y2="12" />
|
||
<line x1="5" y1="5" x2="7.3" y2="7.3" />
|
||
<line x1="16.7" y1="16.7" x2="19" y2="19" />
|
||
<line x1="5" y1="19" x2="7.3" y2="16.7" />
|
||
<line x1="16.7" y1="7.3" x2="19" y2="5" />
|
||
</svg>
|
||
<svg class="icon-moon" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||
<path d="M15.3 3.8A8.9 8.9 0 1 0 20.2 16a7.4 7.4 0 1 1-4.9-12.2Z" />
|
||
<path d="m19.9 4.4.7 1.6 1.6.7-1.6.7-.7 1.6-.7-1.6-1.6-.7 1.6-.7.7-1.6Z" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="sl-hidden md:sl-flex print:hidden right-group">
|
||
<div class="sl-flex social-icons">
|
||
<SocialIcons />
|
||
</div>
|
||
<button class="theme-toggle-btn" type="button" aria-label="Переключить тему" data-theme-toggle>
|
||
<svg class="icon-sun" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||
<circle cx="12" cy="12" r="4" />
|
||
<line x1="12" y1="2.5" x2="12" y2="5.5" />
|
||
<line x1="12" y1="18.5" x2="12" y2="21.5" />
|
||
<line x1="2.5" y1="12" x2="5.5" y2="12" />
|
||
<line x1="18.5" y1="12" x2="21.5" y2="12" />
|
||
<line x1="5" y1="5" x2="7.3" y2="7.3" />
|
||
<line x1="16.7" y1="16.7" x2="19" y2="19" />
|
||
<line x1="5" y1="19" x2="7.3" y2="16.7" />
|
||
<line x1="16.7" y1="7.3" x2="19" y2="5" />
|
||
</svg>
|
||
<svg class="icon-moon" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||
<path d="M15.3 3.8A8.9 8.9 0 1 0 20.2 16a7.4 7.4 0 1 1-4.9-12.2Z" />
|
||
<path d="m19.9 4.4.7 1.6 1.6.7-1.6.7-.7 1.6-.7-1.6-1.6-.7 1.6-.7.7-1.6Z" />
|
||
</svg>
|
||
</button>
|
||
<LanguageSelect />
|
||
</div>
|
||
</div>
|
||
<div class="wiki-read-progress" aria-hidden="true">
|
||
<div class="wiki-read-progress__fill" data-read-progress></div>
|
||
</div>
|
||
</div>
|
||
|
||
<button class="wiki-back-to-top" type="button" aria-label="Прокрутить в начало" data-back-to-top>
|
||
<svg aria-hidden="true" class="wiki-back-to-top__icon" viewBox="0 0 24 24" fill="none">
|
||
<path d="M12 18V6" />
|
||
<path d="m6.8 11.2 5.2-5.2 5.2 5.2" />
|
||
</svg>
|
||
</button>
|
||
|
||
<script>
|
||
const emojiPattern = (() => {
|
||
try {
|
||
return new RegExp('[\\p{Extended_Pictographic}\\u2600-\\u27BF]', 'gu');
|
||
} catch {
|
||
return /[\u2600-\u27BF]/g;
|
||
}
|
||
})();
|
||
|
||
const stripDecorativeSymbols = (value) =>
|
||
value
|
||
.replace(emojiPattern, '')
|
||
.replace(/\s{2,}/g, ' ')
|
||
.trim();
|
||
|
||
const normalizeLabelKey = (value) => stripDecorativeSymbols(value).toLowerCase();
|
||
|
||
const minimalIconByHeading = new Map([
|
||
['настройки', '/icons/minimal-solid/gear.png'],
|
||
['личные сообщения', '/icons/minimal-solid/message.png'],
|
||
['игнор', '/icons/minimal-solid/safe.png'],
|
||
['развлечения', '/icons/minimal-solid/game-controller.png'],
|
||
['rp и взаимодействие', '/icons/minimal-solid/community.png'],
|
||
['статус игрока', '/icons/minimal-solid/user-profile.png'],
|
||
['информация', '/icons/minimal-solid/exclamation.png'],
|
||
['символы', '/icons/minimal-solid/keyboard.png']
|
||
]);
|
||
|
||
const sanitizeNavLabels = () => {
|
||
const navLinks = document.querySelectorAll('.sidebar-content a, starlight-toc a, mobile-starlight-toc a');
|
||
|
||
navLinks.forEach((linkNode) => {
|
||
if (!(linkNode instanceof HTMLElement)) return;
|
||
|
||
const sourceText = linkNode.textContent;
|
||
if (!sourceText) return;
|
||
|
||
const normalizedText = stripDecorativeSymbols(sourceText);
|
||
|
||
if (!normalizedText || normalizedText === sourceText.trim()) return;
|
||
linkNode.textContent = normalizedText;
|
||
});
|
||
};
|
||
|
||
const sanitizeDocHeadings = () => {
|
||
const headings = document.querySelectorAll('.sl-markdown-content :is(h1, h2, h3, h4, h5, h6)');
|
||
|
||
headings.forEach((headingNode) => {
|
||
if (!(headingNode instanceof HTMLElement)) return;
|
||
|
||
const sourceText = headingNode.textContent;
|
||
if (!sourceText) return;
|
||
|
||
const normalizedText = stripDecorativeSymbols(sourceText);
|
||
|
||
if (!normalizedText || normalizedText === sourceText.trim()) return;
|
||
headingNode.textContent = normalizedText;
|
||
});
|
||
};
|
||
|
||
const decorateSectionIcons = () => {
|
||
const headings = document.querySelectorAll('.sl-markdown-content h3');
|
||
|
||
headings.forEach((headingNode) => {
|
||
if (!(headingNode instanceof HTMLElement)) return;
|
||
|
||
const sourceText = headingNode.textContent;
|
||
if (!sourceText) return;
|
||
|
||
const normalizedText = normalizeLabelKey(sourceText);
|
||
const iconPath = minimalIconByHeading.get(normalizedText);
|
||
if (!iconPath) return;
|
||
|
||
if (headingNode.querySelector('.minimal-heading-icon')) return;
|
||
|
||
const iconNode = document.createElement('span');
|
||
iconNode.className = 'minimal-heading-icon';
|
||
iconNode.setAttribute('aria-hidden', 'true');
|
||
iconNode.style.setProperty('--icon-url', `url('${iconPath}')`);
|
||
headingNode.prepend(iconNode);
|
||
});
|
||
};
|
||
|
||
const trimDestination = (value, maxLength = 42) => {
|
||
if (value.length <= maxLength) return value;
|
||
return `${value.slice(0, Math.max(0, maxLength - 1))}…`;
|
||
};
|
||
|
||
const decodePath = (value) => {
|
||
try {
|
||
return decodeURIComponent(value);
|
||
} catch {
|
||
return value;
|
||
}
|
||
};
|
||
|
||
const annotateLinkDestinations = () => {
|
||
const links = document.querySelectorAll('a[href]');
|
||
|
||
links.forEach((linkNode) => {
|
||
if (!(linkNode instanceof HTMLAnchorElement)) return;
|
||
if (linkNode.dataset.linkAnnotated === 'true') return;
|
||
|
||
const rawHref = linkNode.getAttribute('href')?.trim();
|
||
if (!rawHref || rawHref.toLowerCase().startsWith('javascript:')) return;
|
||
|
||
let parsedUrl;
|
||
try {
|
||
parsedUrl = new URL(rawHref, window.location.href);
|
||
} catch {
|
||
return;
|
||
}
|
||
|
||
const isHashOnly = rawHref.startsWith('#');
|
||
const isHttp = parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
|
||
const isMail = parsedUrl.protocol === 'mailto:';
|
||
const isTel = parsedUrl.protocol === 'tel:';
|
||
const isExternal = isHttp && parsedUrl.origin !== window.location.origin;
|
||
const isSamePageAnchor =
|
||
!isExternal && !!parsedUrl.hash && parsedUrl.pathname === window.location.pathname;
|
||
|
||
const isContentLink = linkNode.closest('.sl-markdown-content') instanceof HTMLElement;
|
||
const shouldDecorate =
|
||
isContentLink &&
|
||
!isHashOnly &&
|
||
!linkNode.classList.contains('sl-anchor-link') &&
|
||
!linkNode.classList.contains('map-cta-button') &&
|
||
!linkNode.classList.contains('map-ghost-button') &&
|
||
!linkNode.classList.contains('sl-link-button');
|
||
|
||
if (shouldDecorate) {
|
||
let kind = 'internal';
|
||
if (isExternal) kind = 'external';
|
||
else if (isMail) kind = 'mail';
|
||
else if (isTel) kind = 'tel';
|
||
else if (isSamePageAnchor) kind = 'anchor';
|
||
linkNode.dataset.linkKind = kind;
|
||
|
||
let destination = '';
|
||
if (isExternal) destination = parsedUrl.hostname.replace(/^www\./, '');
|
||
else if (isMail) destination = rawHref.replace(/^mailto:/i, '');
|
||
else if (isTel) destination = rawHref.replace(/^tel:/i, '');
|
||
else destination = `${decodePath(parsedUrl.pathname)}${parsedUrl.hash || ''}`;
|
||
if (destination) {
|
||
linkNode.dataset.linkDestination = trimDestination(destination);
|
||
}
|
||
}
|
||
|
||
if (isExternal) {
|
||
const relValues = new Set((linkNode.rel || '').split(/\s+/).filter(Boolean));
|
||
relValues.add('noopener');
|
||
relValues.add('noreferrer');
|
||
linkNode.rel = Array.from(relValues).join(' ');
|
||
if (!linkNode.target) {
|
||
linkNode.target = '_blank';
|
||
}
|
||
}
|
||
|
||
if (!linkNode.title) {
|
||
if (isHashOnly || isSamePageAnchor) {
|
||
linkNode.title = `Переход к разделу: ${parsedUrl.hash || rawHref}`;
|
||
} else if (isExternal) {
|
||
linkNode.title = `Внешняя ссылка: ${parsedUrl.hostname.replace(/^www\./, '')}`;
|
||
} else if (isMail) {
|
||
linkNode.title = `Написать: ${rawHref.replace(/^mailto:/i, '')}`;
|
||
} else if (isTel) {
|
||
linkNode.title = `Позвонить: ${rawHref.replace(/^tel:/i, '')}`;
|
||
} else {
|
||
linkNode.title = `Перейти: ${decodePath(parsedUrl.pathname)}${parsedUrl.hash || ''}`;
|
||
}
|
||
}
|
||
|
||
linkNode.dataset.linkAnnotated = 'true';
|
||
});
|
||
};
|
||
|
||
const copyTextToClipboard = async (value) => {
|
||
if (navigator.clipboard?.writeText) {
|
||
await navigator.clipboard.writeText(value);
|
||
return;
|
||
}
|
||
|
||
const helperInput = document.createElement('textarea');
|
||
helperInput.value = value;
|
||
helperInput.setAttribute('readonly', '');
|
||
helperInput.style.position = 'fixed';
|
||
helperInput.style.opacity = '0';
|
||
document.body.appendChild(helperInput);
|
||
helperInput.select();
|
||
document.execCommand('copy');
|
||
helperInput.remove();
|
||
};
|
||
|
||
const bindCopyIpChips = () => {
|
||
const copyButtons = document.querySelectorAll('[data-copy-ip]');
|
||
|
||
copyButtons.forEach((buttonNode) => {
|
||
if (!(buttonNode instanceof HTMLButtonElement)) return;
|
||
if (buttonNode.dataset.copyBound === 'true') return;
|
||
|
||
buttonNode.dataset.copyBound = 'true';
|
||
buttonNode.classList.add('is-copy-ready');
|
||
if (!buttonNode.title) {
|
||
buttonNode.title = 'Нажмите, чтобы скопировать';
|
||
}
|
||
buttonNode.addEventListener('click', async () => {
|
||
const value = buttonNode.dataset.copyIp?.trim();
|
||
if (!value) return;
|
||
|
||
try {
|
||
await copyTextToClipboard(value);
|
||
buttonNode.classList.add('is-copied');
|
||
buttonNode.setAttribute('aria-label', `Скопировано: ${value}`);
|
||
window.setTimeout(() => {
|
||
buttonNode.classList.remove('is-copied');
|
||
buttonNode.setAttribute('aria-label', `Скопировать: ${value}`);
|
||
}, 1200);
|
||
} catch {
|
||
buttonNode.classList.add('is-copy-error');
|
||
buttonNode.setAttribute('aria-label', `Не удалось скопировать: ${value}`);
|
||
window.setTimeout(() => {
|
||
buttonNode.classList.remove('is-copy-error');
|
||
buttonNode.setAttribute('aria-label', `Скопировать: ${value}`);
|
||
}, 1400);
|
||
}
|
||
});
|
||
});
|
||
};
|
||
|
||
const normalizeCraftSearch = (value) =>
|
||
stripDecorativeSymbols(value)
|
||
.toLowerCase()
|
||
.replace(/ё/g, 'е')
|
||
.replace(/\s+/g, ' ')
|
||
.trim();
|
||
|
||
const bindCraftCatalogFilters = () => {
|
||
const catalogNodes = document.querySelectorAll('[data-craft-catalog]');
|
||
|
||
catalogNodes.forEach((catalogNode) => {
|
||
if (!(catalogNode instanceof HTMLElement)) return;
|
||
if (catalogNode.dataset.craftBound === 'true') return;
|
||
catalogNode.dataset.craftBound = 'true';
|
||
|
||
const searchInput = catalogNode.querySelector('[data-craft-search]');
|
||
const filterButtons = Array.from(catalogNode.querySelectorAll('[data-craft-filter]')).filter(
|
||
(node) => node instanceof HTMLButtonElement
|
||
);
|
||
const groupNodes = Array.from(catalogNode.querySelectorAll('[data-craft-group]')).filter(
|
||
(node) => node instanceof HTMLElement
|
||
);
|
||
const emptyState = catalogNode.querySelector('[data-craft-empty]');
|
||
|
||
let activeFilter = 'all';
|
||
const activeButton = filterButtons.find(
|
||
(buttonNode) =>
|
||
buttonNode.classList.contains('is-active') ||
|
||
buttonNode.getAttribute('aria-pressed') === 'true'
|
||
);
|
||
|
||
if (activeButton?.dataset.craftFilter) {
|
||
activeFilter = activeButton.dataset.craftFilter;
|
||
}
|
||
|
||
const applyFilters = () => {
|
||
const searchQuery =
|
||
searchInput instanceof HTMLInputElement ? normalizeCraftSearch(searchInput.value) : '';
|
||
|
||
filterButtons.forEach((buttonNode) => {
|
||
const isActive = (buttonNode.dataset.craftFilter || 'all') === activeFilter;
|
||
buttonNode.classList.toggle('is-active', isActive);
|
||
buttonNode.setAttribute('aria-pressed', String(isActive));
|
||
});
|
||
|
||
let visibleCount = 0;
|
||
|
||
groupNodes.forEach((groupNode) => {
|
||
const defaultCategory = groupNode.dataset.craftCategory || '';
|
||
const itemNodes = Array.from(groupNode.querySelectorAll('[data-craft-item]')).filter(
|
||
(node) => node instanceof HTMLElement
|
||
);
|
||
|
||
let groupVisibleCount = 0;
|
||
|
||
itemNodes.forEach((itemNode) => {
|
||
const itemCategory = itemNode.dataset.craftCategory || defaultCategory;
|
||
const itemName =
|
||
itemNode.dataset.craftName || itemNode.querySelector('h3')?.textContent || '';
|
||
const normalizedName = normalizeCraftSearch(itemName);
|
||
const matchesCategory = activeFilter === 'all' || itemCategory === activeFilter;
|
||
const matchesSearch = !searchQuery || normalizedName.includes(searchQuery);
|
||
const isVisible = matchesCategory && matchesSearch;
|
||
|
||
itemNode.hidden = !isVisible;
|
||
if (isVisible) groupVisibleCount += 1;
|
||
});
|
||
|
||
groupNode.hidden = groupVisibleCount === 0;
|
||
visibleCount += groupVisibleCount;
|
||
});
|
||
|
||
if (emptyState instanceof HTMLElement) {
|
||
emptyState.hidden = visibleCount > 0;
|
||
}
|
||
};
|
||
|
||
filterButtons.forEach((buttonNode) => {
|
||
buttonNode.addEventListener('click', () => {
|
||
const nextFilter = buttonNode.dataset.craftFilter || 'all';
|
||
if (nextFilter === activeFilter) return;
|
||
activeFilter = nextFilter;
|
||
applyFilters();
|
||
});
|
||
});
|
||
|
||
if (searchInput instanceof HTMLInputElement) {
|
||
searchInput.addEventListener('input', applyFilters);
|
||
searchInput.addEventListener('search', applyFilters);
|
||
}
|
||
|
||
applyFilters();
|
||
});
|
||
};
|
||
|
||
const enhanceSidebarGroupLinks = () => {
|
||
const targets = [];
|
||
if (targets.length === 0) return;
|
||
const labelNodes = document.querySelectorAll('.sidebar-content details > summary .group-label .large');
|
||
|
||
labelNodes.forEach((labelNode) => {
|
||
if (!(labelNode instanceof HTMLElement)) return;
|
||
|
||
const text = labelNode.textContent?.trim();
|
||
const target = targets.find((item) => item.label === text);
|
||
if (!target) return;
|
||
|
||
if (labelNode.querySelector('a[data-sidebar-group-link]')) return;
|
||
|
||
const link = document.createElement('a');
|
||
link.href = target.href;
|
||
link.className = 'sidebar-group-link';
|
||
link.dataset.sidebarGroupLink = 'true';
|
||
link.textContent = target.label;
|
||
link.addEventListener('click', (event) => {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
window.location.href = target.href;
|
||
});
|
||
|
||
labelNode.replaceChildren(link);
|
||
});
|
||
};
|
||
|
||
const setReadProgress = () => {
|
||
const progressEl = document.querySelector('[data-read-progress]');
|
||
const backToTopBtn = document.querySelector('[data-back-to-top]');
|
||
if (!(progressEl instanceof HTMLElement)) return;
|
||
|
||
const doc = document.documentElement;
|
||
const scrollTop = window.scrollY || doc.scrollTop;
|
||
const scrollable = doc.scrollHeight - window.innerHeight;
|
||
const ratio = scrollable > 0 ? Math.min(1, Math.max(0, scrollTop / scrollable)) : 0;
|
||
|
||
progressEl.style.transform = `scaleX(${ratio})`;
|
||
|
||
if (backToTopBtn instanceof HTMLElement) {
|
||
backToTopBtn.classList.toggle('is-visible', scrollTop > 420);
|
||
}
|
||
};
|
||
|
||
const bindReadProgress = () => {
|
||
const backToTopBtn = document.querySelector('[data-back-to-top]');
|
||
const themeToggleBtns = document.querySelectorAll('[data-theme-toggle]');
|
||
|
||
if (backToTopBtn instanceof HTMLElement) {
|
||
if (backToTopBtn.parentElement !== document.body) {
|
||
document.body.appendChild(backToTopBtn);
|
||
}
|
||
|
||
backToTopBtn.addEventListener('click', () => {
|
||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
});
|
||
}
|
||
|
||
themeToggleBtns.forEach((btn) => {
|
||
if (!(btn instanceof HTMLButtonElement)) return;
|
||
btn.addEventListener('click', () => {
|
||
const root = document.documentElement;
|
||
const current = root.dataset.theme === 'light' ? 'light' : 'dark';
|
||
const next = current === 'dark' ? 'light' : 'dark';
|
||
root.dataset.theme = next;
|
||
localStorage.setItem('starlight-theme', next);
|
||
});
|
||
});
|
||
|
||
enhanceSidebarGroupLinks();
|
||
sanitizeNavLabels();
|
||
sanitizeDocHeadings();
|
||
decorateSectionIcons();
|
||
annotateLinkDestinations();
|
||
bindCopyIpChips();
|
||
bindCraftCatalogFilters();
|
||
setReadProgress();
|
||
window.addEventListener('scroll', setReadProgress, { passive: true });
|
||
window.addEventListener('resize', setReadProgress);
|
||
};
|
||
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', bindReadProgress, { once: true });
|
||
} else {
|
||
bindReadProgress();
|
||
}
|
||
|
||
document.addEventListener('astro:page-load', () => {
|
||
enhanceSidebarGroupLinks();
|
||
sanitizeNavLabels();
|
||
sanitizeDocHeadings();
|
||
decorateSectionIcons();
|
||
annotateLinkDestinations();
|
||
bindCopyIpChips();
|
||
bindCraftCatalogFilters();
|
||
setReadProgress();
|
||
});
|
||
</script>
|
||
|
||
<style>
|
||
@layer starlight.core {
|
||
.wiki-header-shell {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.wiki-header {
|
||
display: flex;
|
||
gap: var(--sl-nav-gap);
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
height: 100%;
|
||
padding-block: 0.34rem;
|
||
}
|
||
|
||
.title-wrapper {
|
||
overflow: clip;
|
||
padding: 0.25rem;
|
||
margin: -0.25rem;
|
||
min-width: 0;
|
||
gap: 1.1rem;
|
||
align-items: center;
|
||
}
|
||
|
||
.wiki-brand {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.55rem;
|
||
text-decoration: none;
|
||
flex-shrink: 0;
|
||
border: 1px solid transparent;
|
||
border-radius: 0.3rem;
|
||
padding: 0.2rem 0.28rem 0.2rem 0.22rem;
|
||
transition: border-color 150ms ease, background 150ms ease;
|
||
}
|
||
|
||
.wiki-brand:hover {
|
||
border-color: color-mix(in srgb, var(--sl-color-accent) 32%, transparent);
|
||
background: color-mix(in srgb, var(--sl-color-accent-low) 64%, transparent);
|
||
}
|
||
|
||
.wiki-brand__icon {
|
||
width: 1.85rem;
|
||
height: 1.85rem;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 0;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.wiki-brand__icon img {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
border-radius: 0;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.wiki-brand__copy {
|
||
display: inline-flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
line-height: 1;
|
||
}
|
||
|
||
.wiki-brand__title {
|
||
font-family: 'Sora', sans-serif;
|
||
font-size: 1.43rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.02em;
|
||
color: var(--sl-color-white);
|
||
}
|
||
|
||
.wiki-brand__subtitle {
|
||
margin-top: 0.14rem;
|
||
font-family: 'Sora', sans-serif;
|
||
font-size: 0.56rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.28em;
|
||
color: var(--sl-color-gray-3);
|
||
}
|
||
|
||
.wiki-top-nav {
|
||
display: none;
|
||
gap: 0.45rem;
|
||
align-items: center;
|
||
}
|
||
|
||
.wiki-top-nav__link {
|
||
border: 1px solid transparent;
|
||
border-radius: 0.18rem;
|
||
padding: 0.36rem 0.74rem;
|
||
text-decoration: none;
|
||
color: var(--sl-color-gray-2);
|
||
font-size: 0.82rem;
|
||
font-family: 'Sora', sans-serif;
|
||
font-weight: 600;
|
||
letter-spacing: 0.01em;
|
||
transition: border-color 150ms ease, background 150ms ease, color 150ms ease;
|
||
}
|
||
|
||
.wiki-top-nav__link:hover {
|
||
border-color: color-mix(in srgb, var(--sl-color-accent) 28%, transparent);
|
||
background: color-mix(in srgb, var(--sl-color-accent-low) 65%, transparent);
|
||
color: var(--sl-color-white);
|
||
}
|
||
|
||
.right-group,
|
||
.social-icons {
|
||
gap: 1rem;
|
||
align-items: center;
|
||
}
|
||
|
||
.header-tools {
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.theme-toggle-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 2.25rem;
|
||
height: 2.25rem;
|
||
border: 1px solid color-mix(in srgb, var(--sl-color-hairline) 78%, transparent);
|
||
border-radius: 50%;
|
||
background: color-mix(in srgb, var(--sl-color-bg-nav) 88%, transparent);
|
||
color: #2a5f4d;
|
||
box-shadow: 0 0 0 1px color-mix(in srgb, var(--sl-color-hairline) 28%, transparent);
|
||
transition: color 160ms ease, transform 160ms ease, background 160ms ease, border-color 160ms ease,
|
||
box-shadow 160ms ease;
|
||
}
|
||
|
||
.theme-toggle-btn:hover {
|
||
transform: translateY(-1px) scale(1.02);
|
||
border-color: color-mix(in srgb, var(--sl-color-accent) 46%, transparent);
|
||
box-shadow:
|
||
0 0 0 1px color-mix(in srgb, var(--sl-color-accent) 24%, transparent),
|
||
0 6px 14px color-mix(in srgb, var(--sl-color-accent) 22%, transparent);
|
||
}
|
||
|
||
.theme-toggle-btn svg {
|
||
width: 1.15rem;
|
||
height: 1.15rem;
|
||
stroke: currentColor;
|
||
stroke-width: 1.9;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
}
|
||
|
||
.theme-toggle-btn .icon-sun,
|
||
.theme-toggle-btn .icon-moon {
|
||
display: none;
|
||
}
|
||
|
||
:global(:root[data-theme='dark']) .theme-toggle-btn .icon-moon {
|
||
display: block;
|
||
}
|
||
|
||
:global(:root[data-theme='light']) .theme-toggle-btn .icon-sun {
|
||
display: block;
|
||
}
|
||
|
||
:global(:root[data-theme='dark']) .theme-toggle-btn {
|
||
color: #66f5df;
|
||
background: color-mix(in srgb, #0f1b2a 86%, transparent);
|
||
border-color: color-mix(in srgb, #2b4c5a 65%, transparent);
|
||
}
|
||
|
||
:global(:root[data-theme='light']) .theme-toggle-btn {
|
||
color: #2e6b57;
|
||
background: color-mix(in srgb, #f2f7ff 92%, transparent);
|
||
border-color: color-mix(in srgb, #b4c5db 72%, transparent);
|
||
}
|
||
|
||
.wiki-read-progress {
|
||
position: fixed;
|
||
inset-inline: 0;
|
||
top: calc(var(--sl-nav-height) + var(--sl-mobile-toc-height));
|
||
height: 2px;
|
||
z-index: calc(var(--sl-z-index-navbar) - 1);
|
||
pointer-events: none;
|
||
background: color-mix(in srgb, var(--sl-color-hairline) 65%, transparent);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.wiki-read-progress__fill {
|
||
height: 100%;
|
||
width: 100%;
|
||
transform-origin: left center;
|
||
transform: scaleX(0);
|
||
background: linear-gradient(
|
||
90deg,
|
||
color-mix(in srgb, var(--wiki-purple-2) 88%, #ffffff),
|
||
color-mix(in srgb, var(--wiki-blue-2) 90%, #ffffff)
|
||
);
|
||
transition: transform 90ms linear;
|
||
}
|
||
|
||
.wiki-back-to-top {
|
||
position: fixed;
|
||
top: auto;
|
||
right: max(1.35rem, calc(env(safe-area-inset-right) + 0.8rem));
|
||
bottom: max(1.45rem, calc(env(safe-area-inset-bottom) + 0.7rem));
|
||
z-index: 30;
|
||
border: 1px solid color-mix(in srgb, var(--sl-color-accent) 74%, transparent);
|
||
border-radius: 999px;
|
||
background: linear-gradient(
|
||
140deg,
|
||
color-mix(in srgb, var(--wiki-purple-2) 74%, #101522),
|
||
color-mix(in srgb, var(--wiki-blue-2) 84%, #101522)
|
||
);
|
||
color: #f6f9ff;
|
||
width: 3.1rem;
|
||
height: 3.1rem;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 0;
|
||
box-shadow:
|
||
0 0 0 1px hsl(214 88% 70% / 0.24),
|
||
0 0 24px hsl(217 100% 68% / 0.38),
|
||
0 0 42px hsl(221 100% 65% / 0.22);
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transform: translateY(8px) scale(0.96);
|
||
pointer-events: none;
|
||
transition: opacity 180ms ease, transform 180ms ease, border-color 180ms ease, box-shadow 180ms ease;
|
||
}
|
||
|
||
.wiki-back-to-top__icon {
|
||
width: 1.5rem;
|
||
height: 1.5rem;
|
||
stroke: currentColor;
|
||
stroke-width: 2.15;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
}
|
||
|
||
.wiki-back-to-top.is-visible {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
transform: translateY(0) scale(1);
|
||
pointer-events: auto;
|
||
}
|
||
|
||
.wiki-back-to-top:hover {
|
||
border-color: color-mix(in srgb, #9ec4ff 80%, transparent);
|
||
box-shadow:
|
||
0 0 0 1px hsl(214 88% 70% / 0.35),
|
||
0 0 28px hsl(219 97% 70% / 0.44),
|
||
0 0 50px hsl(221 98% 68% / 0.27);
|
||
}
|
||
|
||
.social-icons::after {
|
||
content: '';
|
||
height: 2rem;
|
||
border-inline-end: 1px solid var(--sl-color-gray-5);
|
||
}
|
||
|
||
@media (min-width: 64rem) {
|
||
.wiki-top-nav {
|
||
display: inline-flex;
|
||
}
|
||
}
|
||
|
||
@media (min-width: 50rem) {
|
||
:global(:root[data-has-sidebar]) {
|
||
--__sidebar-pad: calc(2 * var(--sl-nav-pad-x));
|
||
}
|
||
|
||
:global(:root:not([data-has-toc])) {
|
||
--__toc-width: 0rem;
|
||
}
|
||
|
||
.wiki-header {
|
||
--__sidebar-width: max(0rem, var(--sl-content-inline-start, 0rem) - var(--sl-nav-pad-x));
|
||
--__main-column-fr: calc(
|
||
(
|
||
100% + var(--__sidebar-pad, 0rem) - var(--__toc-width, var(--sl-sidebar-width)) -
|
||
(2 * var(--__toc-width, var(--sl-nav-pad-x))) - var(--sl-content-inline-start, 0rem) -
|
||
var(--sl-content-width)
|
||
) / 2
|
||
);
|
||
display: grid;
|
||
grid-template-columns: minmax(
|
||
calc(var(--__sidebar-width) + max(0rem, var(--__main-column-fr) - var(--sl-nav-gap))),
|
||
auto
|
||
)
|
||
1fr auto;
|
||
align-content: center;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 50rem) {
|
||
.wiki-brand {
|
||
padding: 0.14rem 0.2rem;
|
||
gap: 0.42rem;
|
||
}
|
||
|
||
.wiki-brand__icon {
|
||
width: 1.55rem;
|
||
height: 1.55rem;
|
||
}
|
||
|
||
.wiki-brand__title {
|
||
font-size: 1.08rem;
|
||
}
|
||
|
||
.wiki-brand__subtitle {
|
||
font-size: 0.46rem;
|
||
letter-spacing: 0.24em;
|
||
}
|
||
|
||
.wiki-back-to-top {
|
||
top: auto;
|
||
right: max(1rem, calc(env(safe-area-inset-right) + 0.52rem));
|
||
bottom: max(1.18rem, calc(env(safe-area-inset-bottom) + 0.58rem));
|
||
width: 2.85rem;
|
||
height: 2.85rem;
|
||
}
|
||
|
||
.wiki-back-to-top__icon {
|
||
width: 1.34rem;
|
||
height: 1.34rem;
|
||
}
|
||
}
|
||
}
|
||
</style>
|