Теперь давайте сделаем так, чтобы у наших страниц был общий шаблон,с общей шапкой, с логотипом нашего сайта и верхним меню.
Для этого объявим общий компонент, Layout
export function Layout( props: {title:string}, ...children: any) {
return <html>
<body>
<div class="mb-5 border-bottom pb-2">
Верхнее меню
</div>
{children}
</body>
</html>
}
Эта функция имеет 2 аргумента:
<Layout title="Заголовок">
<Layout>
<h1>Новая страница</h1>
<div>Некий текст, который тоже придет в children</div>
</Layout>
Теперь, мы можем использовать его как обертку для наших страниц, вместо тега <html>
const mainScreen = app.html('/', async(ctx,req) => {
let items = await catalogTable.findAll(ctx)
return <Layout title="Каталог картин">
<h1 class={"fs-1 fs-header fs-bold"}>Каталог картин</h1>
{/*содержание нашего каталога*/}
</Layout>
}
Давайте обернем все наши страницы этим Layout (заменим в них <html> и общие теги типа <head> на <Layout>) и немного изменим код шаблона Layout, добавив в него элементы верхнего меню:
import {jsx} from '@app/html-jsx'
import {Heap} from '@app/heap'
const catalogTable = Heap.Table('pictures', {
title: Heap.String(), // название. строка
image: Heap.ImageFile(), // изображение. обязательный
material: Heap.Optional( Heap.String() ), // материал. необязательный. строка.
dimensions: Heap.Optional( Heap.String() ), // размеры. необязательный. строка.
price: Heap.NonRequired( Heap.Number(),0 ), // цена. число. по умолчанию 0
})
let currency = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
maximumFractionDigits:0,
});
app.html('/', async(ctx,req) => {
const items = await catalogTable.findAll(ctx)
return <Layout title="Каталог картин">
<h1 class={"fs-1 fs-header fs-bold"}>Каталог картин</h1>
{items.map( item =>
<a class="card" href={cardScreen({id: item.id}).url()}>
<img src={item.image?.getThumbnailUrl(500,300)}/>
<div class='card-body p-2'>
<h3>{item.title}</h3>
<div>{item.material}</div>
<div>{item.dimensions}</div>
</div>
</a>
)}
</Layout>
})
const cardScreen = app.html('/card/:id', async(ctx,req) => {
const item = await catalogTable.getById(ctx, req.params.id !)
return <Layout title={item.title}>
<h3 class="mb-3"><a href={mainScreen.url()}>Каталог картин</a></h3>
<div class={"row g-10"}>
<div class={"col-md-8 col-12"}>
<img class="mw-100" src={item.image?.getThumbnailUrl(900)}/>
</div>
<div class={"col-md-4 col-12"}>
<h1 class={"fs-1 fs-header fw-bold"}>{item.title}</h1>
<div>{item.material}</div>
<div>{item.dimensions}</div>
{ item.price && <div class={"fs-2"}>{currency.format(item.price)}</div> }
</div>
</div>
</Layout>
})
function Layout( props: {title:string}, ...children: any) {
return <html>
<head>
<title>{props.title}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css" integrity="sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"></meta>
</head>
<body>
<div class={'container py-2 py-md-5'}>
<div class={"col-md-8 col-12 mx-md-auto"}>
<div class={"mb-5 border-bottom pb-2"}>
<div class="d-flex flex-row justify-content-between">
<div class="d-flex flex-row">
<img class="me-3" height='30' width='30' src='https://chatium.com/s/static/img/logos/logo_round.png'/>
<div class={"p-1 me-3 d-none d-md-block"}>
<a href={mainScreen.url()}>
Главная
</a>
</div>
</div>
</div>
</div>
{children}
</div>
</div>
</body>
</html>
}