Травник
by GoldenBear872293 lines43.1 KB
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Травник</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500;600;700&family=IM+Fell+English+SC&display=swap');
*{
box-sizing:border-box;
-webkit-tap-highlight-color:transparent;
}
html,body{
margin:0;
width:100%;
height:100%;
overflow:hidden;
background:#10130f;
color:#fff;
font-family:"Cormorant Garamond",Georgia,serif;
touch-action:none;
}
button{
font:inherit;
}
#forest{
position:fixed;
inset:0;
width:100%;
height:100%;
object-fit:cover;
z-index:0;
user-select:none;
animation:forestBreath 14s ease-in-out infinite alternate;
}
@keyframes forestBreath{
from{
transform:scale(1);
}
to{
transform:scale(1.035);
}
}
.scene-dark{
position:fixed;
inset:0;
z-index:1;
pointer-events:none;
background:
radial-gradient(
ellipse at 50% 42%,
rgba(74,92,52,.06),
rgba(0,0,0,.65) 75%
),
linear-gradient(
to bottom,
rgba(0,0,0,.16),
rgba(0,0,0,.7)
);
}
.scene-dark::after{
content:"";
position:absolute;
inset:-10%;
background:
radial-gradient(
ellipse at 25% 65%,
rgba(190,220,170,.07),
transparent 30%
),
radial-gradient(
ellipse at 75% 35%,
rgba(220,210,150,.05),
transparent 28%
);
animation:lightDrift 12s ease-in-out infinite alternate;
}
@keyframes lightDrift{
from{
transform:translateX(-2%) translateY(1%);
opacity:.5;
}
to{
transform:translateX(2%) translateY(-2%);
opacity:1;
}
}
/* =================================
МЕНЮ
================================= */
#menu{
position:relative;
z-index:2;
width:100%;
height:100%;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
padding:16px 10px;
animation:menuAppear .9s ease both;
}
@keyframes menuAppear{
from{
opacity:0;
transform:translateY(18px);
}
to{
opacity:1;
transform:translateY(0);
}
}
.title{
margin:0 0 4px;
font-family:"IM Fell English SC",serif;
font-size:clamp(36px,7vw,64px);
letter-spacing:4px;
text-align:center;
color:#efe2bf;
text-shadow:
0 3px 12px #000,
0 0 20px rgba(225,207,151,.25);
animation:titleFloat 5s ease-in-out infinite;
}
@keyframes titleFloat{
0%,100%{
transform:translateY(0);
}
50%{
transform:translateY(-3px);
}
}
.subtitle{
margin:0 0 10px;
color:#eadfbe;
font-size:clamp(15px,3vw,20px);
text-align:center;
text-shadow:0 2px 8px #000;
animation:softAppear 1.2s ease both;
}
@keyframes softAppear{
from{
opacity:0;
}
to{
opacity:1;
}
}
/* =================================
КАРУСЕЛЬ
================================= */
.carousel{
position:relative;
width:min(1100px,100%);
height:min(64vh,570px);
overflow:hidden;
border-radius:30px;
touch-action:pan-y;
}
.carousel::before{
content:"";
position:absolute;
left:50%;
bottom:2%;
width:min(900px,90%);
height:28%;
transform:translateX(-50%);
background:radial-gradient(
ellipse,
rgba(0,0,0,.8),
rgba(0,0,0,.28) 55%,
transparent 75%
);
filter:blur(13px);
z-index:0;
}
.books{
position:absolute;
left:50%;
top:0;
width:max-content;
min-width:max-content;
height:100%;
display:flex;
align-items:center;
gap:28px;
transform:translate3d(-50%,0,0);
transition:
transform .75s cubic-bezier(.16,.85,.2,1);
will-change:transform;
}
.book{
position:relative;
flex:0 0 clamp(210px,45vw,330px);
height:clamp(310px,58vh,470px);
overflow:visible;
border-radius:9px 16px 16px 9px;
cursor:pointer;
opacity:.43;
transform:
scale(.82)
rotateY(0deg)
translateY(18px);
filter:
brightness(.65)
saturate(.72)
drop-shadow(0 15px 18px rgba(0,0,0,.65));
transition:
transform .75s cubic-bezier(.16,.85,.2,1),
opacity .55s ease,
filter .55s ease;
transform-style:preserve-3d;
perspective:1000px;
}
.book::before{
content:"";
position:absolute;
inset:-8px;
border-radius:16px;
background:
radial-gradient(
ellipse,
rgba(225,204,146,.2),
transparent 65%
);
opacity:0;
filter:blur(12px);
transition:opacity .6s ease;
pointer-events:none;
}
.book.selected::before{
opacity:1;
}
.book::after{
content:"";
position:absolute;
top:2%;
right:-8px;
width:9px;
height:96%;
border-radius:0 8px 8px 0;
background:
repeating-linear-gradient(
to bottom,
#c9a970 0 2px,
#80633d 3px 4px
);
opacity:.7;
box-shadow:
3px 5px 8px rgba(0,0,0,.45);
z-index:4;
}
.book.selected{
opacity:1;
transform:
scale(1)
rotateY(0deg)
translateY(0);
filter:
brightness(1)
saturate(1)
drop-shadow(0 22px 30px rgba(0,0,0,.8))
drop-shadow(0 0 22px rgba(255,224,153,.28));
z-index:5;
}
.book.selected:hover{
transform:
scale(1.025)
rotateY(0deg)
translateY(-4px);
}
.book.left{
transform:
scale(.82)
rotateY(27deg)
translateY(18px);
}
.book.right{
transform:
scale(.82)
rotateY(-27deg)
translateY(18px);
}
.book-cover-wrap{
position:absolute;
inset:0;
overflow:hidden;
border-radius:8px 15px 15px 8px;
background:#392d20;
box-shadow:
inset 0 0 0 2px rgba(255,235,180,.18),
inset 8px 0 18px rgba(0,0,0,.25);
}
.book-cover{
width:100%;
height:100%;
display:block;
object-fit:cover;
object-position:center;
border-radius:8px 15px 15px 8px;
user-select:none;
-webkit-user-drag:none;
transition:
transform .8s cubic-bezier(.16,.85,.2,1),
filter .5s ease;
}
/* Усиленная обрезка Травника */
.book.herbal .book-cover{
transform:scale(1.48);
object-position:center center;
}
.book.herbal.selected .book-cover{
transform:scale(1.62);
}
/* =================================
НАЗВАНИЯ
================================= */
.book-name{
position:absolute;
left:50%;
bottom:-43px;
transform:translateX(-50%);
min-width:170px;
text-align:center;
padding:8px 15px;
border-radius:20px;
background:rgba(15,12,8,.78);
border:1px solid rgba(255,226,166,.28);
color:#eadbb8;
font-size:19px;
letter-spacing:.6px;
opacity:0;
transition:
opacity .45s ease,
transform .45s ease;
white-space:nowrap;
pointer-events:none;
box-shadow:
0 5px 15px rgba(0,0,0,.35);
}
.book.selected .book-name{
opacity:1;
transform:
translateX(-50%)
translateY(-2px);
}
.swipe-hint{
margin-top:7px;
height:22px;
color:rgba(255,240,205,.72);
font-size:13px;
letter-spacing:1.5px;
text-shadow:0 2px 6px #000;
animation:hintPulse 3s ease-in-out infinite;
}
@keyframes hintPulse{
0%,100%{
opacity:.55;
}
50%{
opacity:1;
}
}
/* =================================
ТОЧКИ
================================= */
.dots{
display:flex;
justify-content:center;
gap:9px;
margin-top:10px;
}
.dot{
width:8px;
height:8px;
border-radius:50%;
background:rgba(255,240,205,.3);
transition:
width .45s ease,
background .45s ease,
box-shadow .45s ease;
}
.dot.active{
width:25px;
border-radius:8px;
background:#ead09a;
box-shadow:
0 0 9px rgba(255,220,150,.45);
}
/* =================================
КНОПКИ
================================= */
#openButton,
#backButton{
border:
1px solid rgba(255,232,175,.4);
color:#f5e6c4;
background:
linear-gradient(
180deg,
rgba(94,71,40,.95),
rgba(44,31,19,.95)
);
border-radius:15px;
padding:13px 28px;
min-width:220px;
font-size:19px;
cursor:pointer;
box-shadow:
0 8px 18px rgba(0,0,0,.5),
inset 0 1px rgba(255,255,255,.15);
transition:
transform .18s ease,
filter .25s ease,
box-shadow .35s ease;
margin-top:12px;
animation:buttonGlow 4s ease-in-out infinite;
}
@keyframes buttonGlow{
0%,100%{
box-shadow:
0 8px 18px rgba(0,0,0,.5),
inset 0 1px rgba(255,255,255,.15);
}
50%{
box-shadow:
0 8px 20px rgba(0,0,0,.55),
0 0 17px rgba(220,197,140,.17),
inset 0 1px rgba(255,255,255,.18);
}
}
#openButton:active,
#backButton:active{
transform:scale(.94);
filter:brightness(1.3);
box-shadow:
0 3px 10px rgba(0,0,0,.5),
0 0 25px rgba(255,220,150,.35);
}
/* =================================
ОТКРЫТИЕ
================================= */
#opening{
position:fixed;
inset:0;
z-index:10;
display:none;
align-items:center;
justify-content:center;
background:
radial-gradient(
circle,
rgba(92,76,42,.18),
#080906 70%
);
opacity:0;
}
#opening.show{
display:flex;
animation:
openingSceneIn .35s ease forwards;
}
@keyframes openingSceneIn{
from{
opacity:0;
}
to{
opacity:1;
}
}
.opening-book{
width:min(62vw,430px);
aspect-ratio:.7;
border-radius:8px;
overflow:hidden;
box-shadow:
0 0 70px rgba(255,230,170,.2),
0 25px 60px rgba(0,0,0,.8);
transform-origin:left center;
}
.opening-book img{
width:100%;
height:100%;
display:block;
object-fit:cover;
}
.opening-book.animate{
animation:
bookOpen .95s
cubic-bezier(.18,.82,.2,1)
forwards;
}
@keyframes bookOpen{
0%{
transform:
perspective(1000px)
rotateY(0deg)
scale(.72);
opacity:0;
}
22%{
opacity:1;
}
55%{
transform:
perspective(1000px)
rotateY(-22deg)
scale(1.02);
opacity:1;
}
100%{
transform:
perspective(1000px)
rotateY(-82deg)
scale(1.08);
opacity:0;
}
}
/* =================================
ЧИТАТЕЛЬ
================================= */
#reader{
position:fixed;
inset:0;
z-index:9;
display:none;
flex-direction:column;
align-items:center;
justify-content:center;
padding:12px;
background:
radial-gradient(
circle,
rgba(0,0,0,.12),
rgba(0,0,0,.78)
);
opacity:0;
}
#reader.show{
display:flex;
animation:
readerIn .65s ease forwards;
}
@keyframes readerIn{
from{
opacity:0;
transform:scale(.97);
}
to{
opacity:1;
transform:scale(1);
}
}
#reader.closing{
display:flex;
animation:
readerOut .65s ease forwards;
}
@keyframes readerOut{
from{
opacity:1;
transform:scale(1);
}
to{
opacity:0;
transform:scale(.96) translateY(15px);
}
}
.book-spread{
position:relative;
width:min(96vw,1050px);
height:min(76vh,680px);
display:flex;
overflow:hidden;
border-radius:7px;
box-shadow:
0 25px 60px rgba(0,0,0,.75),
0 0 30px rgba(255,220,150,.12);
perspective:1400px;
}
.book-spread.page-turn{
animation:
spreadTurn .45s ease;
}
@keyframes spreadTurn{
0%{
transform:
rotateY(0deg)
scale(1);
}
45%{
transform:
rotateY(2deg)
scale(.985);
}
100%{
transform:
rotateY(0deg)
scale(1);
}
}
.page{
position:relative;
width:50%;
height:100%;
overflow:hidden;
background-image:url(
"https://img.magnific.com/premium-vector/old-parchment-paper-sheet-vintage-aged-texture-vector-illustration_969400-501.jpg?semt=ais_hybrid&w=740&q=80"
);
background-size:cover;
background-position:center;
color:#3e2d1c;
padding:clamp(20px,4vw,48px);
box-shadow:
inset 0 0 30px rgba(60,35,10,.18);
transition:
filter .4s ease;
}
.page:first-child{
border-right:
1px solid rgba(60,35,10,.35);
}
.page h2{
margin:0 0 18px;
font-family:
"IM Fell English SC",
"Cormorant Garamond",
Georgia,
serif;
font-size:
clamp(23px,4vw,36px);
text-align:center;
color:#49331d;
font-weight:600;
letter-spacing:.4px;
}
.page p{
margin:0;
font-size:
clamp(16px,2.3vw,22px);
line-height:1.58;
text-align:left;
font-weight:500;
}
.page::after{
content:"";
position:absolute;
inset:0;
pointer-events:none;
background:
linear-gradient(
90deg,
rgba(70,40,10,.08),
transparent 15%,
transparent 85%,
rgba(70,40,10,.08)
);
}
.reader-controls{
display:flex;
gap:10px;
align-items:center;
justify-content:center;
margin-top:12px;
}
.reader-controls button{
min-width:52px;
height:45px;
border:
1px solid rgba(255,232,175,.35);
border-radius:12px;
background:rgba(40,28,16,.9);
color:#eadbb8;
font-size:25px;
cursor:pointer;
transition:
transform .18s ease,
filter .25s ease;
}
.reader-controls button:active{
transform:scale(.9);
filter:brightness(1.35);
}
#pageInfo{
min-width:110px;
text-align:center;
color:#eadbb8;
font-size:15px;
}
#backButton{
min-width:150px;
margin-top:8px;
}
/* =================================
ВЫХОД ИЗ КНИГИ
================================= */
#reader.exiting .book-spread{
animation:
bookClose .65s
cubic-bezier(.2,.8,.2,1)
forwards;
}
@keyframes bookClose{
0%{
transform:
perspective(1400px)
rotateY(0deg)
scale(1);
opacity:1;
}
45%{
transform:
perspective(1400px)
rotateY(-8deg)
scale(.98);
opacity:.9;
}
100%{
transform:
perspective(1400px)
rotateY(72deg)
scale(.78)
translateX(20px);
opacity:0;
}
}
/* =================================
МОБИЛЬНАЯ ВЕРСИЯ
================================= */
@media(max-width:650px){
.carousel{
height:60vh;
}
.books{
gap:18px;
}
.book{
flex-basis:245px;
height:390px;
}
.book.left{
transform:
scale(.76)
rotateY(30deg)
translateY(18px);
}
.book.right{
transform:
scale(.76)
rotateY(-30deg)
translateY(18px);
}
.book.herbal .book-cover{
transform:scale(1.54);
}
.book.herbal.selected .book-cover{
transform:scale(1.67);
}
.book-name{
bottom:-39px;
font-size:16px;
}
.book-spread{
width:98vw;
height:68vh;
}
.page{
padding:16px;
}
.page p{
font-size:15px;
line-height:1.45;
}
}
</style>
</head>
<body>
<img
id="forest"
src="https://images.pexels.com/photos/17491580/pexels-photo-17491580.jpeg"
alt=""
>
<div class="scene-dark"></div>
<!-- =================================
МЕНЮ
================================= -->
<section id="menu">
<h1 class="title">
ТРАВНИК
</h1>
<p class="subtitle">
Выберите книгу
</p>
<div
class="carousel"
id="carousel"
>
<div
class="books"
id="books"
>
<!-- ЦВЕТНИК -->
<div
class="book selected"
data-index="0"
>
<div class="book-cover-wrap">
<img
class="book-cover"
src="https://basket-15.wbbasket.ru/vol2261/part226117/226117052/images/big/1.webp"
alt="Цветник"
>
</div>
<div class="book-name">
Цветник
</div>
</div>
<!-- ЛЕЧЕБНИК -->
<div
class="book"
data-index="1"
>
<div class="book-cover-wrap">
<img
class="book-cover"
src="https://cdn.eksmo.ru/v2/ITD000000000608288/COVER/cover1__w820.jpg"
alt="Лечебник"
>
</div>
<div class="book-name">
Лечебник
</div>
</div>
<!-- ТРАВНИК -->
<div
class="book herbal"
data-index="2"
>
<div class="book-cover-wrap">
<img
class="book-cover"
src="https://ogorod.ua/_sh/47/4703b_4.jpg"
alt="Травник"
>
</div>
<div class="book-name">
Травник
</div>
</div>
</div>
</div>
<div class="swipe-hint">
СВАЙП ВЛЕВО ИЛИ ВПРАВО
</div>
<div class="dots">
<span class="dot active"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
<button id="openButton">
Открыть книгу
</button>
</section>
<!-- =================================
АНИМАЦИЯ ОТКРЫТИЯ
================================= -->
<section id="opening">
<div class="opening-book">
<img
id="openingCover"
src=""
alt=""
>
</div>
</section>
<!-- =================================
ЧИТАТЕЛЬ
================================= -->
<section id="reader">
<div class="book-spread">
<article
class="page"
id="leftPage"
>
<h2></h2>
<p></p>
</article>
<article
class="page"
id="rightPage"
>
<h2></h2>
<p></p>
</article>
</div>
<div class="reader-controls">
<button id="prevPage">
‹
</button>
<div id="pageInfo">
1 / 7
</div>
<button id="nextPage">
›
</button>
</div>
<button id="backButton">
Вернуться
</button>
</section>
<script>
/* =================================
ЭЛЕМЕНТЫ
================================= */
const carousel =
document.getElementById("carousel");
const booksContainer =
document.getElementById("books");
const books =
[...document.querySelectorAll(".book")];
const dots =
[...document.querySelectorAll(".dot")];
const openButton =
document.getElementById("openButton");
const menu =
document.getElementById("menu");
const opening =
document.getElementById("opening");
const openingCover =
document.getElementById("openingCover");
const openingBook =
document.querySelector(".opening-book");
const reader =
document.getElementById("reader");
const backButton =
document.getElementById("backButton");
const spread =
document.querySelector(".book-spread");
const leftPage =
document.getElementById("leftPage");
const rightPage =
document.getElementById("rightPage");
const prevPage =
document.getElementById("prevPage");
const nextPage =
document.getElementById("nextPage");
const pageInfo =
document.getElementById("pageInfo");
let selectedBook = 0;
let currentPage = 0;
let touchStartX = 0;
let touchStartY = 0;
let readerStartX = 0;
let readerStartY = 0;
/* =================================
КНИГИ
================================= */
const booksData = [
{
name:"Цветник",
pages:[
{
title:"Ромашка",
text:"Ромашка — знакомый полевой цветок с белыми лепестками. В травниках её часто описывают как растение с приятным ароматом и нежным цветением."
},
{
title:"Василёк",
text:"Василёк отличается яркими синими цветками. Он растёт среди луговых трав и особенно хорошо заметен летом."
},
{
title:"Одуванчик",
text:"Одуванчик легко узнать по жёлтой корзинке цветков. После цветения появляются лёгкие семена, которые ветер разносит далеко."
},
{
title:"Календула",
text:"Календула имеет яркие оранжевые или жёлтые цветки. Её часто выращивают в садах как декоративное растение."
},
{
title:"Мак",
text:"Мак известен крупными цветками с тонкими лепестками. В разных видах и сортах окраска может отличаться."
},
{
title:"Лютик",
text:"Лютики встречаются на лугах и влажных участках. Их блестящие жёлтые лепестки хорошо заметны среди зелёной травы."
},
{
title:"Колокольчик",
text:"Колокольчики получили название благодаря форме своих цветков. Они могут иметь голубую, синюю, фиолетовую или белую окраску."
},
{
title:"Незабудка",
text:"Незабудку легко узнать по небольшим цветкам нежных оттенков. Это невысокое растение часто встречается во влажных местах."
},
{
title:"Ландыш",
text:"Ландыш образует небольшие белые цветки, похожие на колокольчики. Растение имеет сильный характерный аромат."
},
{
title:"Иван-чай",
text:"Иван-чай — высокое растение с розовыми или пурпурными цветками. Он часто появляется на солнечных полянах и открытых местах."
},
{
title:"Клевер",
text:"Клевер образует округлые соцветия. Его цветки привлекают множество насекомых, особенно пчёл."
},
{
title:"Тысячелистник",
text:"Тысячелистник имеет множество мелких цветков, собранных в плотные соцветия. Его листья отличаются характерной рассечённой формой."
},
{
title:"Мальва",
text:"Мальва — высокое растение с крупными цветками. Её часто выращивают возле домов и в садовых цветниках."
},
{
title:"Конец цветника",
text:"Вы закончили раздел Цветника. Здесь собраны описания растений. Не используйте незнакомые растения в пищу или для лечения."
}
]
},
{
name:"Лечебник",
pages:[
{
title:"Мята",
text:"Мята имеет свежий характерный аромат. Её листья часто используют в напитках и кулинарии."
},
{
title:"Крапива",
text:"Крапива покрыта мелкими жалящими волосками. В природе она встречается на опушках, возле дорог и в местах с влажной почвой."
},
{
title:"Мелисса",
text:"Мелисса обладает приятным лимонным ароматом. Её выращивают в садах и используют преимущественно как ароматное растение."
},
{
title:"Шалфей",
text:"Шалфей имеет плотные серо-зелёные листья и характерный запах. Разные виды шалфея сильно отличаются друг от друга."
},
{
title:"Чабрец",
text:"Чабрец — небольшое ароматное растение. Он образует низкие кустики и хорошо переносит солнечные места."
},
{
title:"Ромашка аптечная",
text:"Аптечная ромашка имеет небольшие соцветия с белыми лепестками и жёлтой серединой. Её часто выращивают специально для сбора."
},
{
title:"Липа",
text:"Липа — крупное дерево с сердцевидными листьями. Во время цветения она наполняет воздух заметным сладким ароматом."
},
{
title:"Шиповник",
text:"Шиповник — кустарник с цветками и красными плодами. Его легко узнать по многочисленным шипам на ветвях."
},
{
title:"Малина",
text:"Малина образует кусты с колючими побегами и знакомыми ягодами. Она встречается в садах и в дикой природе."
},
{
title:"Чистотел",
text:"Чистотел — растение с жёлтыми цветками и характерным оранжевым соком. Дикорастущие растения нельзя использовать самостоятельно."
},
{
title:"Подорожник",
text:"Подорожник часто растёт вдоль тропинок. Его листья имеют заметные продольные жилки."
},
{
title:"Зверобой",
text:"Зверобой отличается небольшими жёлтыми цветками. Он встречается на солнечных полянах и сухих участках."
},
{
title:"Безопасность",
text:"Не пробуйте неизвестные растения, ягоды или семена. Даже растение, похожее на знакомое, может оказаться другим видом."
},
{
title:"Конец лечебника",
text:"Лечебник закончен. Настоящее лечение должно проводиться по совету родителей, врача или другого квалифицированного специалиста."
}
]
},
{
name:"Травник",
pages:[
{
title:"Крапива",
text:"Крапива — многолетнее травянистое растение. Её легко узнать по зелёным листьям с характерными зубчатыми краями."
},
{
title:"Подорожник",
text:"Подорожник часто растёт рядом с тропинками и дорогами. Его широкие листья имеют заметные продольные жилки."
},
{
title:"Зверобой",
text:"Зверобой — растение с небольшими жёлтыми цветками. В природе он встречается на солнечных местах и полянах."
},
{
title:"Мята",
text:"Мята любит достаточно влажную почву и быстро разрастается. Её легко узнать по свежему запаху листьев."
},
{
title:"Мелисса",
text:"Мелисса похожа на некоторые другие растения семейства яснотковых. Главная особенность — приятный лимонный аромат."
},
{
title:"Чабрец",
text:"Чабрец образует маленькие кустики и любит солнечные места. Во время цветения над ним часто можно увидеть насекомых."
},
{
title:"Шиповник",
text:"Шиповник — колючий кустарник. Его красные плоды появляются после цветения и сохраняются довольно долго."
},
{
title:"Клевер",
text:"Клевер имеет характерные тройчатые листья и округлые цветочные головки. На лугах его часто посещают пчёлы."
},
{
title:"Тысячелистник",
text:"Название растения связано с сильно рассечёнными листьями. Соцветия состоят из большого количества маленьких цветков."
},
{
title:"Иван-чай",
text:"Иван-чай может образовывать большие заросли. Его высокие стебли хорошо заметны среди другой растительности."
},
{
title:"Липовый цвет",
text:"Липа во время цветения становится особенно заметной благодаря приятному аромату. Её цветки появляются рядом с крупными листьями."
},
{
title:"Одуванчик",
text:"Одуванчик умеет быстро распространять семена. Лёгкие семянки подхватывает ветер, поэтому растение встречается почти повсюду."
},
{
title:"Правила травника",
text:"Всегда точно определяйте растение. Не собирайте растения возле загрязнённых дорог и промышленных территорий."
},
{
title:"Конец травника",
text:"Вы дочитали Травник. В природе много интересных растений, но наблюдать за ними безопаснее всего вместе со взрослыми."
}
]
}
];
/* =================================
ЦЕНТРИРОВАНИЕ
================================= */
function centerSelectedBook(){
const selected =
books[selectedBook];
if(!selected) return;
const rowCenter =
booksContainer.offsetWidth / 2;
const bookCenter =
selected.offsetLeft +
selected.offsetWidth / 2;
const shift =
rowCenter - bookCenter;
booksContainer.style.transform =
`translate3d(calc(-50% + ${shift}px),0,0)`;
}
/* =================================
ВИД КНИГ
================================= */
function updateBookAppearance(){
books.forEach(
(book,index)=>{
book.classList.remove(
"selected",
"left",
"right"
);
if(index === selectedBook){
book.classList.add(
"selected"
);
}
else if(index < selectedBook){
book.classList.add(
"left"
);
}
else{
book.classList.add(
"right"
);
}
}
);
dots.forEach(
(dot,index)=>{
dot.classList.toggle(
"active",
index === selectedBook
);
}
);
requestAnimationFrame(
centerSelectedBook
);
}
/* =================================
ВЫБОР
================================= */
function selectBook(index){
if(index < 0){
index =
books.length - 1;
}
if(index >= books.length){
index = 0;
}
selectedBook = index;
updateBookAppearance();
}
/* =================================
ОТКРЫТЬ
================================= */
function openBook(){
const selected =
books[selectedBook];
if(!selected) return;
const cover =
selected.querySelector(
".book-cover"
);
if(!cover) return;
openingCover.src =
cover.src;
menu.style.display =
"none";
opening.style.display =
"flex";
opening.classList.remove(
"show"
);
openingBook.classList.remove(
"animate"
);
void opening.offsetWidth;
opening.classList.add(
"show"
);
openingBook.classList.add(
"animate"
);
setTimeout(
()=>{
opening.classList.remove(
"show"
);
opening.style.display =
"none";
reader.classList.remove(
"closing"
);
reader.style.display =
"flex";
void reader.offsetWidth;
reader.classList.add(
"show"
);
currentPage = 0;
showSpread();
},
980
);
}
/* =================================
КНОПКА
================================= */
openButton.addEventListener(
"click",
openBook
);
/* =================================
НАЖАТИЕ НА КНИГИ
================================= */
books.forEach(
(book,index)=>{
book.addEventListener(
"click",
()=>{
if(index !== selectedBook){
selectBook(index);
}
else{
openBook();
}
}
);
}
);
/* =================================
СВАЙП КНИГ
================================= */
carousel.addEventListener(
"touchstart",
event=>{
const touch =
event.changedTouches[0];
touchStartX =
touch.clientX;
touchStartY =
touch.clientY;
},
{passive:true}
);
carousel.addEventListener(
"touchend",
event=>{
const touch =
event.changedTouches[0];
const dx =
touch.clientX -
touchStartX;
const dy =
touch.clientY -
touchStartY;
if(Math.abs(dx) < 45){
return;
}
if(
Math.abs(dx) <=
Math.abs(dy)
){
return;
}
if(dx < 0){
selectBook(
selectedBook + 1
);
}
else{
selectBook(
selectedBook - 1
);
}
},
{passive:true}
);
/* =================================
КЛАВИАТУРА
================================= */
window.addEventListener(
"keydown",
event=>{
if(
menu.style.display !==
"none"
){
if(
event.key ===
"ArrowRight"
){
selectBook(
selectedBook + 1
);
}
if(
event.key ===
"ArrowLeft"
){
selectBook(
selectedBook - 1
);
}
if(
event.key ===
"Enter"
){
openBook();
}
}
}
);
/* =================================
ПОКАЗ СТРАНИЦ
================================= */
function showSpread(){
const data =
booksData[selectedBook];
if(!data) return;
const total =
data.pages.length;
const leftData =
data.pages[currentPage];
const rightData =
data.pages[
currentPage + 1
];
leftPage.querySelector("h2")
.textContent =
leftData
? leftData.title
: "";
leftPage.querySelector("p")
.textContent =
leftData
? leftData.text
: "";
rightPage.querySelector("h2")
.textContent =
rightData
? rightData.title
: "";
rightPage.querySelector("p")
.textContent =
rightData
? rightData.text
: "";
const spreadNumber =
Math.floor(
currentPage / 2
) + 1;
const spreadTotal =
Math.ceil(
total / 2
);
pageInfo.textContent =
`${spreadNumber} / ${spreadTotal}`;
prevPage.disabled =
currentPage <= 0;
nextPage.disabled =
currentPage + 2 >= total;
prevPage.style.opacity =
prevPage.disabled
? ".35"
: "1";
nextPage.style.opacity =
nextPage.disabled
? ".35"
: "1";
spread.classList.remove(
"page-turn"
);
void spread.offsetWidth;
spread.classList.add(
"page-turn"
);
}
/* =================================
ВПЕРЁД
================================= */
nextPage.addEventListener(
"click",
()=>{
const total =
booksData[
selectedBook
].pages.length;
if(
currentPage + 2 <
total
){
currentPage += 2;
showSpread();
}
}
);
/* =================================
НАЗАД
================================= */
prevPage.addEventListener(
"click",
()=>{
if(
currentPage - 2 >= 0
){
currentPage -= 2;
showSpread();
}
}
);
/* =================================
КРАСИВЫЙ ВЫХОД ИЗ КНИГИ
================================= */
function closeReader(){
reader.classList.remove(
"show"
);
reader.classList.add(
"closing"
);
setTimeout(
()=>{
reader.style.display =
"none";
reader.classList.remove(
"closing"
);
menu.style.display =
"flex";
menu.style.animation =
"none";
void menu.offsetWidth;
menu.style.animation =
"menuAppear .75s ease both";
requestAnimationFrame(
centerSelectedBook
);
},
650
);
}
backButton.addEventListener(
"click",
closeReader
);
/* =================================
СВАЙП СТРАНИЦ
================================= */
reader.addEventListener(
"touchstart",
event=>{
const touch =
event.changedTouches[0];
readerStartX =
touch.clientX;
readerStartY =
touch.clientY;
},
{passive:true}
);
reader.addEventListener(
"touchend",
event=>{
const touch =
event.changedTouches[0];
const dx =
touch.clientX -
readerStartX;
const dy =
touch.clientY -
readerStartY;
if(
Math.abs(dx) < 55
){
return;
}
if(
Math.abs(dx) <=
Math.abs(dy)
){
return;
}
if(dx < 0){
nextPage.click();
}
else{
prevPage.click();
}
},
{passive:true}
);
/* =================================
ЗАПУСК
================================= */
updateBookAppearance();
window.addEventListener(
"load",
()=>{
updateBookAppearance();
setTimeout(
centerSelectedBook,
100
);
setTimeout(
centerSelectedBook,
500
);
}
);
window.addEventListener(
"resize",
()=>{
requestAnimationFrame(
centerSelectedBook
);
}
);
</script>
</body>
</html>Game Source: Травник
Creator: GoldenBear87
Libraries: none
Complexity: complex (2293 lines, 43.1 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-goldenbear87" to link back to the original. Then publish at arcadelab.ai/publish.