Компоненты: шапка, меню и подвал
Шапку и подвал удобно держать отдельными кусочками и подключать в любой шаблон. Такие кусочки называются компонентами. Сделаем три: меню, шапку и подвал.
Зачем нужны компоненты
Скоро у сайта появятся другие шаблоны: для кухонь, для каталога, для проектов. Шапка и подвал нужны везде. Если копировать их в каждый шаблон, то, чтобы поменять телефон в подвале, придётся править пять мест и не забыть ни одно.
Компонент решает это: шапка пишется один раз и подключается одной строкой. Поменяли компонент, и все шаблоны получили новую шапку.
Меню из дерева
Начнём с меню. Оно должно показывать страницы верхнего уровня и само обновляться, когда вы добавляете страницу. Создайте компонент: на вкладке Элементы нажмите + рядом со словом «Компоненты» и напишите имя Nav.
<!-- @component
Меню сайта: страницы верхнего уровня.
-->
<script>
import { children, current, link } from '$core';
const here = current();
const items = children(null);
</script>
<nav class="nav">
{#each items as item (item.id)}
<a
href={link(item.id)}
aria-current={here?.id === item.id ? 'page' : undefined}
>
{item.menuTitle || item.title}
</a>
{/each}
</nav>
<style>
.nav {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.25rem;
}
.nav a {
color: inherit;
text-decoration: none;
}
.nav a[aria-current] {
font-weight: 700;
}
</style>Что здесь происходит:
<!-- @component … -->: описание компонента. Менеджер покажет его рядом с именем, а вы через месяц вспомните, зачем он нужен.import { children, current, link } from '$core';: берём из$coreтри функции.$coreэто модуль, через который шаблоны и компоненты получают данные сайта.children(null): страницы верхнего уровня, в том порядке, как они стоят в дереве. Вместоnullможно передать id страницы, и получите её дочерние.link(item.id): адрес страницы по её номеру. Переименуете страницу, и ссылка поменяется сама.current(): страница, которую сейчас смотрит посетитель. Сравнив номера, мы помечаем текущий пункт меню, и он становится жирным.(item.id)послеas item: ключ пункта списка. Svelte по нему отличает пункты друг от друга.
Шапка
Новый компонент Header:
<!-- @component
Шапка: название сайта и меню.
-->
<script>
import Nav from '$components/Nav';
import { site } from '$core';
</script>
<header class="header">
<a class="logo" href="/">{site().name}</a>
<Nav />
</header>
<style>
.header {
display: flex;
flex-wrap: wrap;
align-items: baseline;
justify-content: space-between;
gap: 1rem;
max-width: 48rem;
margin: 0 auto;
padding: 1.5rem;
}
.logo {
color: inherit;
font-size: 1.25rem;
font-weight: 800;
letter-spacing: 0.12em;
text-transform: uppercase;
text-decoration: none;
}
</style>Компонент подключает другой компонент так же, как шаблон: import Nav from '$components/Nav'; и дальше <Nav />. Название сайта берём через site().name: в компонент site не приходит параметром, его спрашивают у $core.
Подвал с параметром
У подвала будет параметр: строка рядом с названием. Так один компонент может выглядеть по-разному в разных шаблонах.
<!-- @component
Подвал: название, строка о студии и год.
-->
<script>
import { site } from '$core';
let {
/** Строка рядом с названием */
note = 'кухни на заказ',
} = $props();
const year = new Date().getFullYear();
</script>
<footer class="footer">
<p><b>{site().name}</b> · {note}</p>
<p>© {year}</p>
</footer>
<style>
.footer {
max-width: 48rem;
margin: 0 auto;
padding: 1.5rem;
color: #6b6862;
font-size: 0.9rem;
}
</style>Параметры компонент получает через $props(), как шаблон получает page. После знака = стоит значение по умолчанию: если параметр не передали, подвал напишет «кухни на заказ». Комментарий /** … */ над параметром менеджер покажет как подсказку.
Собрать шаблон из компонентов
Теперь шаблон Base становится короче. Замените его код целиком:
<script>
import Content from '$core/Content';
import Footer from '$components/Footer';
import Header from '$components/Header';
let { page, site } = $props();
</script>
<svelte:head>
<title>{page.longTitle || page.title} — {site.name}</title>
</svelte:head>
<Header />
<main>
<h1>{page.longTitle || page.title}</h1>
<Content of={page} />
</main>
<Footer note="кухни по вашим размерам" />
<style>
:global(body) {
margin: 0;
background: #f1efeb;
color: #1f1e1c;
font: 18px/1.6 system-ui, sans-serif;
}
main {
max-width: 48rem;
margin: 0 auto;
padding: 0 1.5rem 2rem;
}
h1 {
font-size: 2.75rem;
line-height: 1.05;
letter-spacing: -0.02em;
}
</style>Подвалу мы передали свою строку: <Footer note="кухни по вашим размерам" />. Параметры пишутся как атрибуты тега.
