code for bearblog book theme
CSS Code (dashboard -> theme)
:root {
--book_width: clamp(100px, 134.38vh , min(100vw, 1000px));
--max_book_height: min( 100vh, calc( var(--book_width) / 1.3438));
--book_height: clamp(100px, 100vh, var(--max_book_height));
--header_height: 200px;
--left-arrow-space: calc( var(--book_width) * 0.035) ;
--right-arrow-space: calc( var(--book_width) * 0.045) ;
--right-pad: calc(var(--left-arrow-space) + 3.5vh);
--left-pad: calc(var(--left-arrow-space) + 2.5vh);
/** distance from the edge of the page? */
--arrow-margin: calc((100vw - var(--book_width))/2);
--arrow-margin: 0px;
--arrow_font_size: var(--right-arrow-space);
--color_cream: rgba(240, 224, 200, 1);
--color_brown: rgba(54,30,23, 1);
/*
--url_scroll_bg: url("/scroll.jpeg");
--url_background_leather: url('/background-leather.jpeg');
--url_header_bg: url('/shelf.jpeg');
--url_book: url("/book1.jpeg");
*/
--url_header_bg: url('https://bear-images.sfo2.cdn.digitaloceanspaces.com/reedybear/shelf.webp');
--url_scroll_bg: url('https://bear-images.sfo2.cdn.digitaloceanspaces.com/reedybear/scroll.webp');
--url_book: url('https://bear-images.sfo2.cdn.digitaloceanspaces.com/reedybear/book1.webp');
--url_background_leather: url('https://bear-images.sfo2.cdn.digitaloceanspaces.com/reedybear/background-leather.webp');
}
* {
box-sizing: border-box;
}
html {
background: var(--url_background_leather);
background-repeat: repeat;
}
body {
overflow-x: hidden;
margin:0;
margin-left: auto;
margin-right: auto;
height: 100vh;
height: calc(100vh + var(--header_height));
width: var(--book_width);
background: var(--url_background_leather);
background-repeat: repeat;
position:relative;
}
footer {
top:0;
right:0;
position: absolute;
height:var(--header_height);
display:flex;
flex-direction: column;
justify-content:space-between;
text-align: right;
font-size: 0.8em;
}
footer > span#footer-directive > p {
display:flex;
flex-direction: column;
color: var(--color_cream);
justify-content:end;
background: rgba(54,30,23, 0.5);
border-radius: 4px;
box-shadow: 0px 0px 3px 3px var(--color_brown);
}
footer > span#footer-directive > p > a {
color:var(--color_cream);
text-decoration: none;
}
footer > span#footer-directive > p > a:hover {
text-decoration: underline;
}
footer > span {
color: var(--color_cream);
}
footer > span > a {
color: var(--color_cream);
}
footer > span > a:hover {
text-decoration: none;
}
header {
background: var(--url_header_bg);
background-size:cover;
height: var(--header_height);
width: var(--book_width);
color: white;
padding: 16px;
box-shadow: 0px -8px 5px 10px var(--color_brown)
}
header a {
color:white;
}
header > a {
display: inline-block;
padding: 4px 12px;
border-radius: 27% 12px;
border: 1px solid rgba(171,155,130,1);
text-decoration:none;
background:var(--color_brown);
color: var(--color_cream);
}
header > a:hover {
border-color: var(--color_brown);
background-color: var(--color_cream);
color: var(--color_brown);
}
header > a > h1 {
margin-top: 8px;
margin-bottom: 12px;
}
header > nav > p {
display: inline-block;
padding: 0px 8px 0px 8px;
text-decoration:none;
background: rgba(54,30,23, 0.9);
border: 1px solid rgba(171,155,130,0.9);
border-radius: 12px 15%;
}
header > nav > p > a {
display: inline-block;
text-decoration:none;
padding: 6px 6px;
border-left: 1px solid transparent;
border-right: 1px solid transparent;
margin-left: 8px;
color: var(--color_cream);
}
header > nav > p > a:hover {
border-color: var(--color_cream);
background-color: var(--color_cream);
color:var(--color_brown);
}
main {
color: var(--color_brown);
box-sizing: border-box;
columns: 2;
background: var(--url_book);
background-size: contain;
overflow-x: scroll;
background-repeat: no-repeat;
grid-gap: var(--right-pad);
scroll-snap-type: x mandatory;
width: var(--book_width);
height: var(--book_height);
padding-right: var(--right-pad);
padding-left: var(--left-pad);
padding-top: 5.5vh;
padding-bottom: 2.5vh;
box-shadow: 0px -4px 10px 10px var(--color_brown)
}
main a {
color: var(--color_brown);
}
main .highlight:has(> pre) {
max-height: calc(var(--book_height) - 9.5vh);
overflow-y: scroll;
overflow-x: scroll;
}
main > p {
scroll-snap-align: start;
scroll-margin-left: 55px;
scroll-margin-left: calc( var(--book_width) * .0610 );
/* width: 378px vs book_width of 805 */
/* need ration so that I can set the scroll-margin-left so that scroll snap positions are correct */
}
.leftarrow, .rightarrow {
position: absolute;
top:0;
margin-top: var(--header_height);
color: var(--color_cream);
height: var(--book_height);
line-height: var(--book_height);
cursor: pointer;
text-align: center;
font-size: var(--arrow_font_size);
user-select: none;
background: none;
border: none;
}
.leftarrow:hover, .rightarrow:hover {
background: rgba(54, 30, 23, 0.3);
}
.rightarrow {
right: 0;
margin-right: var(--arrow-margin);
width: var(--right-arrow-space);
}
.leftarrow {
left: 0;
margin-left: var(--arrow-margin);
width: var(--left-arrow-space);
}
.pagesleft {
position: absolute;
top:0;
margin-top: var(--header_height);
padding-top: 2vh;
margin-left: calc(var(--left-pad) + 1.5vh);
color: white;
text-align: center;
vertical-align:top;
color: var(--color_brown);
font-weight: bolder;
}
.pagesright {
position: absolute;
top:0;
right:0;
margin-top: var(--header_height);
padding-top: 2vh;
margin-right: calc(var(--arrow-margin) + var(--right-pad) + 3.5vh);
color: white;
text-align: center;
vertical-align:top;
color: var(--color_brown);
font-weight: bolder;
}
@media (max-width: 600px) {
:root {
--header_height: 250px;
}
body {
height: unset;
overflow-x: visible;
}
main {
overflow-x: visible;
columns: 1;
height: unset;
background-repeat: repeat;
background: var(--url_scroll_bg);
}
.leftarrow, .rightarrow, .pagesright, .pagesleft {
display:none;
}
}
Javsacript
Goes in Dashboard -> Settings -> Header and footer directives -> Head directive
<!-- MY BOOK THEME -->
<script>
const BookScroller = {
min_width: 600,
/* tracking the right-hand page number because it works with the maths */
current_page: 2,
book_el: null,
rightarrow: null,
leftarrow: null,
pagesright: null,
pagesleft: null,
timeout: null,
};
BookScroller.get_num_pages =
function(){
const book_el = BookScroller.book_el;
if (book_el.scrollLeftMax == 0){
return 2;
}
const page_width = book_el.offsetWidth / 2;
const page_count = Math.round(book_el.scrollWidth / page_width);
//console.log(" ------ get_num_pages ------");
//console.log("scrollWidth: "+book_el.scrollWidth);
//console.log("offsetWidth: "+book_el.offsetWidth);
//console.log("pageWidth: "+page_width);
//console.log("numpages: "+page_count);
return page_count;
};
BookScroller.setup_dynamic_stuff =
function(){
const page_count = BookScroller.get_num_pages();
if (page_count <= 2){
BookScroller.rightarrow.style.display = "none";
}
for (const n of document.querySelectorAll('p.book_page_extender')){
n.parentNode.removeChild(n);
}
// ENSURE EVEN NUMBER OF PAGES
const max_loops = 25;
let num_loops = 0;
while ((BookScroller.get_num_pages() % 2) != 0){
const p = document.createElement('p');
p.classList.add('book_page_extender');
p.innerHTML = ' ';
book_el.appendChild(p);
// SANITY CHECK just to prevent infinte loops in case of bug
if (num_loops++ >= max_loops)break;
}
const max_scroll_loops = 50;
let scroll_loop_count = 0;
while (BookScroller.current_page >2){
BookScroller.scroll(-1);
// Sanity check to prevent infinite loop in case of bug
if (scroll_loop_count++ > max_scroll_loops)break;
}
};
BookScroller.init
= function(){
BookScroller.book_el = book_el = document.querySelector('body > main');
BookScroller.rightarrow = rightarrow = document.createElement('button');
rightarrow.classList.add("rightarrow");
rightarrow.setAttribute("tabindex", 1);
rightarrow.innerHTML = ">";
rightarrow.innerHTML = "➤"; // I couldn't find the left-hand equivalent
rightarrow.innerHTML = "⮞";
document.querySelector('body').appendChild(rightarrow);
BookScroller.leftarrow = leftarrow = document.createElement('button');
leftarrow.classList.add("leftarrow");
leftarrow.setAttribute("tabindex", 2);
leftarrow.style.display = "none";
leftarrow.innerHTML = "<";
leftarrow.innerHTML = "⮜";
document.querySelector('body').appendChild(leftarrow);
BookScroller.pagesleft = pagesleft = document.createElement('div');
pagesleft.classList.add('pagesleft');
pagesleft.innerText = "1";
document.querySelector('body').appendChild(pagesleft);
BookScroller.pagesright = pagesright = document.createElement('div');
pagesright.classList.add('pagesright');
pagesright.innerText = "2";
document.querySelector('body').appendChild(pagesright);
rightarrow.addEventListener('click',
BookScroller.scroll.bind(this,1)
);
leftarrow.addEventListener('click',
BookScroller.scroll.bind(this,-1)
);
book_el.addEventListener("wheel",
function (e) {
if (window.innerWidth <= 600){
return;
}
if (e.target.tagName == 'pre'
&& e.target.parentNode.classList.contains('highlight')
|| e.target.closest("div.highlight > pre") != null){
return;
}
if (e.deltaY > 0){
BookScroller.scroll(1);
} else {
BookScroller.scroll(-1);
}
e.preventDefault();
e.stopPropagation();
}
);
window.addEventListener("keydown",
function (e) {
if (window.innerWidth <= 600){
return;
}
if (e.key == 'ArrowRight'){
BookScroller.scroll(1);
e.preventDefault();
e.stopPropagation();
} else if (e.key == 'ArrowLeft') {
BookScroller.scroll(-1);
e.preventDefault();
e.stopPropagation();
}
}
);
BookScroller.setup_dynamic_stuff();
}
document.addEventListener('DOMContentLoaded',
function(){
BookScroller.init();
}
);
window.addEventListener('resize',
function(){
clearTimeout(BookScroller.timeout);
setTimeout(BookScroller.setup_dynamic_stuff, 250);
}
);
BookScroller.scroll =
/** direction is 1 or -1 for right or left */
function(direction){
//console.log(BookScroller);
//console.log(BookScroller.get_num_pages());
if (window.innerWidth <= BookScroller.min_width){
// we're showing mobile view, no book view
return;
}
if (direction > 0 && BookScroller.current_page >= BookScroller.get_num_pages()){
// trying to scroll right, but there are no pages to scroll to
return;
}
if (direction < 0 && BookScroller.current_page <= 2){
// trying to scroll left, but we're at the first two pages already
return;
}
BookScroller.current_page += (direction * 2);
const book_el = BookScroller.book_el;
// scroll distance is the book width - left pad - right pad + grid gap
// grid gap & right pad are the same
// these formulas are defined in the CSS
let left_pad = book_el.offsetWidth * 0.035 + .025*window.innerHeight;
let scroll_distance = book_el.offsetWidth - left_pad;
scroll_pos = scroll_distance * ((BookScroller.current_page/2)-1);
//book_el.scrollIntoView();
book_el.scroll(scroll_pos, 0);
//console.log("CurrentPage: "+BookScroller.current_page);
if (BookScroller.current_page >= BookScroller.get_num_pages()){
//console.log("hide right arrow!");
BookScroller.rightarrow.style.display = "none";
} else {
BookScroller.rightarrow.style.display = "block";
}
if (BookScroller.current_page <= 2){
BookScroller.leftarrow.style.display = "none";
} else {
BookScroller.leftarrow.style.display = "block";
}
pagesleft.innerText = BookScroller.current_page - 1;
pagesright.innerText = BookScroller.current_page;
//console.log(BookScroller);
//console.log(BookScroller.get_num_pages());
};
</script>