[#153] add footer login page
@amirhraj Привет! Футер - это такой блок, который должен быть на каждой странице сайта, а не только на странице регистрации. При подходе "в лоб" разметку футера придется копировать на каждую страницу сайта и не забывать добавлять ее при появлении новых. А если захотим что-то изменить в футере, опять же придется править каждую страницу. Чтобы этого избежать, всю общую для всех страниц разметку выносят в отдельный шаблон - layout. А сами страницы содержат только уникальную для каждой страницы разметку. Затем эти уникальные фрагменты "вставляются" в общий шаблон. Посмотри пожалуйста, как это сделано в нашем демо приложении. Это общий шаблон, в котором есть плейсхолдеры. На их место будут вставляться конкретные фрагменты разметки. А вот сама страница. При рендере этой страницы в шаблонизаторе этот фрагмент будет подставлен на место плейсхолдера в шаблоне и получится такая вот комбинированная разметка. Таким образом получается, что вся общая разметка находится в одном месте, ее не приходится дублировать и без труда можно поправить. Попробуй сделать по аналогии здесь
И здорово будет потом задеплоить полученный результат куда-нибудь, например на railway или render. Чтобы можно было потыкать, посмотреть, как работает приложение
Принято буду исправлять
Задеплоить не получилось выдало такие ошибки Dockerfile:19
-------------------
17 | # build phase
18 | COPY . /app/.
19 | >>> RUN --mount=type=cache,id=s/b2df31d2-734d-4c0e-8490-2044fbfee1b2-m2/repository,target=/app/.m2/repository chmod +x ./mvnw && ./mvnw -DoutputFile=target/mvn-dependency-list.log -B -DskipTests clean dependency:list install
20 |
21 |
-------------------
ERROR: failed to solve: process "/bin/bash -ol pipefail -c chmod +x ./mvnw && ./mvnw -DoutputFile=target/mvn-dependency-list.log -B -DskipTests clean dependency:list install" did not complete successfully: exit code: 1
Error: Docker build failed
Я докер файл не трогал почему вышли ошибки не могу сказать
@amirhraj локально выглядит криво.
Потерялся фон и футер наезжает на контент.
@amirhraj Привет! Идем в верном направлении, переиспользуем футер и уже не дублируем код футера. Это хорошо. Давай пойдем еще дальше и сделаем именно наследование шаблонов. Представь такую ситуацию, мы захотим добавить на страницы помимо футера еще общие элементы. Например, флеш-сообщения, панель навигации и тд. При нынешнем подходе придется делать отдельные файлы для навигации, для флеш сообщений. А затем вставлять их на каждую страницу, где они должны быть при помощи th:replace. А страниц ведь могут быть сотни. Легко запутаться и что-нибудь забыть. При наследовании этого получится избежать. То есть у нас будет одна страница - костяк, например layout.html. Она будет содержать все общие элементы - футер и тд. А также точки, которые мы позже заменим соответствующими фрагментами из конкретных страниц. А конкретные станицы будут содержать только уникальные фрагменты - контент. Почитай про layot:decorate в доке тимлифа https://ultraq.github.io/thymeleaf-layout-dialect/processors/decorate/
Теперь, когда мы будем рендерить конкретную страницу, он возьмет костяк - шаблон layout с общими вещами и "навтыкает" туда фрагментов конкретной страницы в те места, которые мы указали в шаблоне. И получится итоговая станица - такое сочетание базовой и конкретной.
При таком подходе становится гораздо проще добавлять новые общие элементы - достаточно будет поменять один раз layout, а все остальные страницы, использующие этот layout, останутся неизменными
@amirhraj Привет! Нужна еще какая-то помощь с ПРом?
Привет послезавтра примусь за реализацию, не подскажешь мне все фрагменты нужно будет так реализовать?
Ну да. Нужно будет сделать один layout - костяк страницы со всеми общими элементами, а затем на отдельных страницах сделать фрагменты, которые в этот layout будут подставляться
@amirhraj Привет! Вот наш layout - костяк страницы:
<!DOCTYPE html>
<html lang="en" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<title>Hexlet Typo Reporter</title>
<link rel="stylesheet" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" type="text/css" />
<script th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}" type="text/javascript"></script>
</head>
<body>
<main class="container">
<section layout:fragment="content"></section>
</main>
<footer class="bg-dark text-light fixed-bottom">
<div class="container-xl">
<div class="row justify-content-lg-around">
<div class="col-sm-6 col-md-3 col-lg-auto">
<a class="text-dark px-0 py-0 text-decoration-none " href="https://ru.hexlet.io">
<p class="h3 mb-2 text-light">© Hexlet</p>
</a>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://sicp.hexlet.io/ru/pages/about">
О проекте
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-correction"
target="_blank">
Исходный код
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://t.me/hexletcommunity/12"
target="_blank">
Telegram Hexlet канал Волонтеры
</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-md-3 col-lg-auto">
<p class="h5 mb-3">Помощь</p>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://ru.hexlet.io/blog">
Блог
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://ru.hexlet.io/knowledge">
База знаний
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light"
href="https://ru.hexlet.io/pages/recommended-books">
Рекомендуемые книги
</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-md-3 col-lg-auto">
<p class="h5 mb-3">Другие open-source проекты</p>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-cv">
Хекслет-резюме
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-editor">
Хекслет-редактор
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-friends">
Друзья Хекслета
</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-md-3 col-lg-auto">
<p class="h5 mb-3">Дополнительно</p>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://ru.code-basics.com/">
Code Basics
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://codebattle.hexlet.io/">
Кодбаттл
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://guides.hexlet.io/">
Гайды Хекслета
</a>
</li>
</ul>
</div>
</div>
</div>
</footer>
</body>
</html>
Тут у нас все общие для всех страниц элементы, в данном случае футер. Обрати внимание на кусок кода
<section layout:fragment="content"></section>
Это то место, куда будет вставлен контент конкретной страницы
Дальше сама страница регистрации
<!DOCTYPE html>
<html lang="en" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{fragments/layout.html}">
<section layout:fragment="content">
<div th:replace="~{fragments/header :: head}"></div>
<div style="padding-top: 4.5rem">
<div th:replace="~{fragments/panels :: mainNavbarTop}"></div>
<div class="row">
<div class="col">
<div class="alert alert-danger" role="alert" th:if="${param.error}">
Bad credential
</div>
<div class="alert alert-warning" role="alert" th:if="${param.logout}">
You have been logged out.
</div>
<form method="post" th:action="@{/login}">
<div class="form-floating mb-3">
<input autofocus class="form-control" id="inputUsername"
name="username" placeholder="Username" required type="text">
<label for="inputUsername">Username</label>
</div>
<div class="form-floating mb-3">
<input class="form-control" id="inputPassword" name="password"
placeholder="Password" required type="password">
<label for="inputPassword">Password</label>
</div>
<button class="btn btn-primary" type="submit">Login</button>
</form>
</div>
</div>
</div>
</section>
</html>
Тут мы указываем, от какого шаблона наследуемся:
<html lang="en" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{fragments/layout.html}">
И указываем фрагмент, который будет вставлен в layout:
<section layout:fragment="content">
...
</section>
Такие же фрагменты делаем в остальных страницах
<html lang="en" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/header :: head}"></head>
<body style="padding-top: 4.5rem">
<nav th:replace="~{fragments/panels :: mainNavbarTop}"></nav>
<main class="container">
<div class="row">
<div class="col">
<div class="alert alert-danger" role="alert" th:if="${param.error}">
Bad credential
</div>
<div class="alert alert-warning" role="alert" th:if="${param.logout}">
You have been logged out.
</div>
<form method="post" th:action="@{/login}">
<div class="form-floating mb-3">
<input autofocus class="form-control" id="inputUsername"
name="username" placeholder="Username" required type="text">
<label for="inputUsername">Username</label>
</div>
<div class="form-floating mb-3">
<input class="form-control" id="inputPassword" name="password"
placeholder="Password" required type="password">
<label for="inputPassword">Password</label>
</div>
<button class="btn btn-primary" type="submit">Login</button>
</form>
</div>
</div>
</main>
<section layout:fragment="foot"></section>
</body>
</html>
вот логин сюда хочу перенести свой footer
<html lang="en"
xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{login.html}">
<section layout:fragment="foot" class="bg-dark text-light fixed-bottom">
<div class="container-xl">
<div class="row justify-content-lg-around">
<div class="col-sm-6 col-md-3 col-lg-auto">
<a class="text-dark px-0 py-0 text-decoration-none " href="https://ru.hexlet.io">
<p class="h3 mb-2 text-light">© Hexlet</p>
</a>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://sicp.hexlet.io/ru/pages/about">
О проекте
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-correction"
target="_blank">
Исходный код
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://t.me/hexletcommunity/12"
target="_blank">
Telegram Hexlet канал Волонтеры
</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-md-3 col-lg-auto">
<p class="h5 mb-3">Помощь</p>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://ru.hexlet.io/blog">
Блог
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://ru.hexlet.io/knowledge">
База знаний
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light"
href="https://ru.hexlet.io/pages/recommended-books">
Рекомендуемые книги
</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-md-3 col-lg-auto">
<p class="h5 mb-3">Другие open-source проекты</p>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-cv">
Хекслет-резюме
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-editor">
Хекслет-редактор
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://github.com/Hexlet/hexlet-friends">
Друзья Хекслета
</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-md-3 col-lg-auto">
<p class="h5 mb-3">Дополнительно</p>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://ru.code-basics.com/">
Code Basics
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://codebattle.hexlet.io/">
Кодбаттл
</a>
</li>
<li class="nav-item">
<a class="nav-link px-0 py-1 text-light" href="https://guides.hexlet.io/">
Гайды Хекслета
</a>
</li>
</ul>
</div>
</div>
</div>
</section>
</html>
Вот мой footer все тоже самое делаю как и в рекомендациях у меня не подтягивается эта библиотека имен
Pom.xml добавил эту библиотеку
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
Добавляю и понижая версию этой библиотеки так же не дает результата, я не знаю куда смотреть где посмотреть логи и ошибки связанные с этой библиотекой и почему не отображается фотер
А бин LayoutDialect не забыл подключить?
@Bean
public LayoutDialect layoutDialect() {
return new LayoutDialect();
}
Да он у меня подключен, хотел спросить ты вроде его у себя запускал и у тебя footer отобразился, не подскажешь какие у тебя там конфигурация была ? Версия этой Таймлиф библиотеки плюс Бин?
Ещё импорт в файл Таймлиф конфигурации
Я как будто гадаю и собираю комбинации чтобы у меня заработала
Нашел такую запись Бин @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.addDialect(new LayoutDialect()); return templateEngine; }в чем отличие не особо понимаю
@amirhraj Привет! Есть успехи? Посмотри плиз, аналогичная работа ведется в соседнем ПРе https://github.com/Hexlet/hexlet-correction/pull/161. Можно скоординироваться и поделить задачи, чтоб над одними вещами не работать
Привет, не получилось
что то я у себя не увидел зеленой кнопки по добавлении ПР
Привет! Изменения автоматом попадают в открытый ПР, когда ты пушишь в эту ветку
Посмотри пожалуйста, как коллега ваш вот тут делает https://github.com/RedGradient/hexlet-correction/blob/add-footer/src/main/resources/templates/application.html. Это наш макет страницы. Тут уже есть общиэ элементы для всех страниц - [навбар](https://github.com/RedGradient/hexlet-correction/blob/37ffe126eb62b9c5425761388c14e9ce52bf586c/src/main/resources/templates/application.html#L7) и футер. Так как они лежат в отдельных файлах, их черех relace сюда вставляем. И есть "дырка", куда будем вставлять контент конкретной страницы.
А вот конкретная страница https://github.com/RedGradient/hexlet-correction/blob/37ffe126eb62b9c5425761388c14e9ce52bf586c/src/main/resources/templates/login.html#L5
Вот этот фрагмент будет вставляться на место "дырки" в наш макет
Вышел в отпуск, две недели не смогу что-то сделать, если спешит , можете передать другому коллеге